函数调用式Message组件

3 years ago
# 编程
121
2

为什么需要函数式调用

函数式组件是使用vue中提供的hrender函数编写组件,可以在使用时只需要调用相应函数即可,不需要写在<template/>标签中,适合用来编写提示,Modal等组件。

例如Message组件

Message.vue 布局组件

<script setup lang="ts">
import { ref,onMounted } from 'vue'

const props = defineProps({
    msg:{
        type: String
    },
    onClose: {
        type: Function,
        required: false,
    },
    top:{
        type: Number,
        required: false
    }

})

defineEmits(['destroy'])
const visible = ref(false)

function close(){
    visible.value = false
}

function startTimer(){
    setTimeout(()=>{
        close()
    },3000)
}

onMounted(() =>{
    startTimer()
    visible.value = true
})

defineExpose({
  visible,
  close,
})
</script>

<template>
    <transition
        @before-leave="onClose"
        @after-leave="$emit('destroy')">
        <div class="message" v-show="visible" :style="{top: props.top + 'px'}">
            <div>{{props.msg}}</div>
        </div>
    </transition>
</template>

<style scoped>

.message{

    /* border: 1px solid red; */
    position: fixed;
    top: 1rem;
    left: 50%;
    transform: translateX(-50%);
    box-shadow: 0 3px 12px rgba(0,0,0,0.2);
    padding: 6px 12px;
    border-radius: 0.25rem;
    user-select: none;
    transition: top .2s;
}

.v-enter-active,
.v-leave-active {
  transition: opacity 0.2s ease;
}

.v-enter-from,
.v-leave-to {
  opacity: 0;
}

</style>

Message/index.ts

import { createVNode, render, shallowReactive } from 'vue'
import type {VNode,ComponentInternalInstance} from 'vue'
import Message from './message.vue'
interface MessageContext {
    id: string
    vNode: VNode
    vm: ComponentInternalInstance | null
    props: any
}

export const instances = shallowReactive<MessageContext[]>([])

const message = (msg: string)=>{
    createMessage(msg)
}

let seed = 1
function createMessage(msg: string){
    let top = 12
    if(instances.length){
        let pre = instances[instances.length-1]
        top = pre.props.top + 40
    }
    const container = document.createElement('div')
    const props = {
        msg,
        top,
        onClose: ()=>{
            closeMessage(instance)
        };
        onDestroy: ()=>{
            render(null,container)
            console.log('destroy')
        }
    }

    let vNode = createVNode(Message,props)
    let vm = vNode.component
    render(vNode,container)
    document.body.appendChild(container.firstElementChild!)
    const instance = {
        id: `message_${seed++}`,
        vNode,
        vm,
        props: vNode.component?.props
    }
    instances.push(instance)
    return instance
}

function closeMessage(instance: MessageContext){
    const idx = instances.findIndex(i=>i.id === instance.id)
    if(idx === -1) return
    instances.splice(idx,1)
    console.log('closeMessage',idx)
    instances.forEach((i) =>{
      i.props.top -= 40  
    })
}

export default message

组件使用

<script setup lang="ts">
import Message from './components/Message'
function handleClick(){
  Message("成功的消息")
}
</script>

<template>
  <div>
    <button @click="handleClick">Click</button>
  </div>
</template>
文章标题:函数调用式Message组件
文章作者:灰色の青
最后修改时间: 2022 年 12 月 26 日 15:32
版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
还没有人踏及此处,留下足迹吧