h5-vantUI-Toast二次封装(函数式)

170 阅读1分钟

对vant ui 中的toast进行二次封装

Toast组件

Toast.vue

<template>
  <van-toast class="xd-toast" v-model:show="visible" :position="'top'" style="padding: 0" :duration="durationTime">
    <template #message>
      <div class="message-content">
        <SvgIcon :name="`toast-${iconName}`" :color="typeObj[iconName]"></SvgIcon>
        <span>{{ message }}</span>
      </div>
    </template>
  </van-toast>
</template>

<script setup lang="ts">
interface Options {
  msg: string
  type?: string
  duration?: number
}
const typeObj: any = {
  info: '#FF6F66',
  success: '#49D74E'
}

const visible = ref(false)
const message = ref('')
const iconName = ref('info')
const durationTime = ref(2000)
// 如有需求,可以自定义入参
const show = ({ msg, type, duration }: Options) => {
  visible.value = true
  message.value = msg
  iconName.value = formatType(type || 'info')
  durationTime.value = duration || 2000
  console.log('......', visible.value)
}

const formatType = (type: string): string => {
  return typeObj[type] ? type : 'info'
}

defineExpose({
  show
})
</script>

<style lang="scss" scoped>
.xd-toast {
  z-index: 2500;

  .message-content {
    display: flex;
    align-items: center;
    padding: 14px 50px;
    font-size: 24px;
    color: #fff;
    line-height: 28px;

    .svg-icon {
      margin-right: 20px;
    }
  }
}
</style>

index.ts

import XdToast from './Toast.vue'
import { render, createVNode } from 'vue'

const instances: any[] = []
let node: HTMLElement | null = null
const duration = 2000
let timer: any = null
const onDestroy = () => {
  if (node && instances.length) {
    document.body.removeChild(node)
    instances.pop()
  }
}
export default function Toast(options: any) {
  if (instances.length) return
  if (timer) {
    clearInterval(timer)
  }
  const parentNode = document.createElement('div')
  const id = 'xd-toast'
  
  // 这里传入的props在组件中通过 Props接收
  const vnode = createVNode(XdToast, { id, props: { ...options }, zIndex: 2500 })
  render(vnode, parentNode)
  node = document.body.appendChild(parentNode)

  const instance = vnode.component!
  instances.push(instance)
  if (instance) {
    // 调用组件对外暴露的show方法
    instance.exposed?.show(options)
    timer = setTimeout(onDestroy, (options.duration || duration) + 500)
  }
}
  • 创建toast实例时,参数可以通过Props接受,也可以通过调用组件方法,通过入参接受。
  • 创建时需要考虑多个toast同时创建的场景
  • 实例结束之后需要及时销毁,不然元素节点会一直增加