Vue3 has been around for a while, and vuE3 + TS was used in a new project last year, so I’ve been trying to write something. There are many blogs that compare the two versions, so I will not write them (in case they are not good enough and the writing is not good enough to make people laugh). So write something small, like the -Toast widget. If there is anything wrong, please correct me.

Vue3 spelled

<! -- ./src/main.vue -->
<template>
  <transition name="scale">
    <div v-show="visible" class="jr-toast">
      <div class="jr-toast_content">
        {{ content }}
      </div>
    </div>
  </transition>
</template>

<script>
import { defineComponent, reactive, ref, toRefs } from 'vue'

export default defineComponent({
  setup() {
    const state = reactive({
      content: ' '.type: ' '.// You can display different ICONS according to different types
      delay: ' '
    })
  
    const visible = ref(false)
    let timer
    
    const close = () = > {
      clearTimeout(timer)
      visible.value = false
      timer = null
    }
    
    const open = () = > {
      if (timer) clearTimeout(timer)
      
      visible.value = true
      timer = setTimeout(close, state.delay)

      return close
    }
    
    return {
      ...toRefs(state),
      visible,
      open,
      close
    }
  }
})
</script>

<style lang="scss" scoped>
.jr-toast {
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
}

.jr-toast_content {
  padding: 10px 20px;
  color: #fff;
  word-break: break-all;
  background-color: rgba(0.0.0.7);
  border-radius: 10px;
}

.scale-enter-active..scale-leave-active {
  transition: transform .2s;
}

.scale-enter..scale-leave-to {
  transform: scale(0)}</style>

Copy the code
// index.js

import { createApp } from 'vue'
import main from './src/main.vue'

let instance

const initInstance = () = > {
  // This is the biggest difference from VUE2
  // In vue2, we just need instance.$mount() to get the node
  const app = createApp(main)
  // Need a container
  const container = document.createElement('div')
  // Mount again - After mounting, return the instance context
  instance = app.mount(container)
  
  document.body.appendChild(container)
}

const Toast = option= > {
  if(! instance) initInstance() option =typeof option === 'string' ? { content: option } : option
  
  const defaultOption = {
    content: ' '.delay: 1500.type: 'info'
  }
  
  for (const key in defaultOption)
    instance[key] = option[key] || defaultOption[key]
  
  return instance.open()
}

const types = ['success'.'error'.'warn'.'info']
types.forEach(type= > Toast[type] = content= > Toast({ content, type }))

// Export the method directly
export default Toast

// // or mount on the global configuration of the root instance
// export default app => app.config.globalProperties.$Toast = Toast

Copy the code

Vue2 spelled

<! -- ./src/main.vue -->
<template>
  <transition name="scale">
    <div v-show="visible" class="jr-toast">
      <div class="jr-toast_content">
        {{ content }}
      </div>
    </div>
  </transition>
</template>

<script>
export default {
  props: {
    content: String.type: String.delay: String
  },
  data() {
    return {
      timer: null.visible: false}},methods: {
    open() {
      const { timer, delay, close } = this
      
      if (timer) clearTimeout(timer)
      
      this.visible = true
      this.timer = setTimeout(close, delay)
      
      return close
    },
    close() {
      clearTimeout(this.timer)
      this.timer = null
      this.visible = false}}}</script>

<style lang="scss" scoped>
.jr-toast {
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
}

.jr-toast_content {
  padding: 10px 20px;
  color: #fff;
  word-break: break-all;
  background-color: rgba(0.0.0.7);
  border-radius: 10px;
}

.scale-enter-active..scale-leave-active {
  transition: transform .2s;
}

.scale-enter-from..scale-leave-to {
  transform: scale(0)}</style>

Copy the code
// index.js

import Vue from 'vue'
import main from './src/main.vue'

// Vue2 needs to extend a subclass with vue.extend ()
const Constructor = Vue.extend(main)

let instance

const Toast = option= > {
  if(! instance) { instance =new Constructor()
    instance.$mount()
    document.body.appendChild(instance.$el)
  }
  
  option = typeof option === 'string' ? { content: option } : option
  
  const defaultOption = {
    content: ' '.delay: 1500.type: 'info'
  }
  
  for (const key in defaultOption)
    instance[key] = option[key] || defaultOption[key]

  return instance.open()
}

const types = ['success'.'error'.'warn'.'info']
types.forEach(type= > Toast[type] = content= > new Toast({ content, type }))

export default Vue => Vue.prototype.$Toast = Toast

Copy the code

The complete code

vue3 Toast

vue2 Toast