vue3 与 vue2 写提示(Toast)组件的区别

vue3 也出来一段时间了,去年的新项目也用上了 vue3 + ts,所以一直想写点东西。对比两个版本的博客比比皆是,所以我就不写那些了(怕水平不够,文笔也不行,让人笑话)。所以干脆写点小东西,比如 – Toast 轻提示组件。有不正之处,望各位指正。

vue3 的写法

<!-- ./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: '', // 可以根据不同的 type 显示不同的图标
      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>

复制代码
// index.js

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

let instance

const initInstance = () => {
  // 这里就是与 vue2 最大的区别了
  // 在 vue2 的时候,我们只需 instance.$mount() 便能得到节点,现在不行
  const app = createApp(main)
  // 需要一个容器
  const container = document.createElement('div')
  // 再进行挂载 - 挂载之后返回实例上下文
  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 default Toast

// // 或者挂载在根实例的全局配置上
// export default app => app.config.globalProperties.$Toast = Toast

复制代码

vue2 的写法

<!-- ./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, .scale-leave-to {
  transform: scale(0)
}
</style>

复制代码
// index.js

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

// vue2 需要使用 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

复制代码

完整代码

vue3 Toast

vue2 Toast

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享