message组件(vite5+vue3.4)

60 阅读2分钟

组件分析

三种样式,priamry,error,info->三种样式->三种类名

无需事件。 组件特殊性:其他组件引用该组件时一般是用js调用,该组件调用后需要销毁。

代码

message/index.vue

<template>
    <transition name="down" @after-leave="destroy">
        <div v-show="isVisable"
            class="min-w-[420px] fixed top-[20px] left-[50%] translate-x-[-50%] z-50 flex items-center px-3 py-1.5 rounded-sm border cursor-pointer"
            :class="styles[type].containerClass">
            <m-svg-icon :name="styles[type].icon" :fillClass="styles[type].fillClass"
                class="h-1.5 w-1.5 mr-1.5"></m-svg-icon>
            <span class="text-sm" :class="styles[type].textClass">
                {{ content }}
            </span>
        </div>
    </transition>
</template>

<script>
import mSvgIcon from '../svg-icon/index.vue'

/**
 * 消息类型可选项
 */
const typeEnum = ['success', 'warn', 'error']
</script>

<script setup>
import { ref, onMounted } from 'vue'
const props = defineProps({
    /**
     * message 的消息类型
     */
    type: {
        type: String,
        required: true,
        validator(val) {
            const result = typeEnum.includes(val)
            if (!result) {
                throw new Error(`你的 type 必须是 ${typeEnum.join('、')} 中的一个`)
            }
            return result
        }
    },
    /**
     * 描述文本
     */
    content: {
        type: String,
        required: true
    },
    /**
     * 展示时长
     */
    duration: {
        type: Number
    },
    /**
     * 关闭时的回调
     */
    destroy: {
        type: Function
    }
})

// 样式表数据
const styles = {
    // 警告
    warn: {
        icon: 'warn',
        fillClass: 'fill-warn-300',
        textClass: 'text-warn-300',
        containerClass:
            'bg-warn-100 border-warn-200  hover:shadow-lg hover:shadow-warn-100'
    },
    // 错误
    error: {
        icon: 'error',
        fillClass: 'fill-error-300',
        textClass: 'text-error-300',
        containerClass:
            'bg-error-100 border-error-200  hover:shadow-lg hover:shadow-error-100'
    },
    // 成功
    success: {
        icon: 'success',
        fillClass: 'fill-success-300',
        textClass: 'text-success-300',
        containerClass:
            'bg-success-100 border-success-200  hover:shadow-lg hover:shadow-success-100'
    }
}

// 控制显示处理
const isVisable = ref(false)
/**
 * 保证动画展示,需要在 mounted 之后进行展示
 */
onMounted(() => {
    isVisable.value = true
    /**
     * 延迟时间关闭
     */
    setTimeout(() => {
        isVisable.value = false
    }, props.duration)
})
</script>

<style lang="scss" scoped>
.down-enter-active,
.down-leave-active {
    transition: all 0.5s;
}

.down-enter-from,
.down-leave-to {
    opacity: 0;
    transform: translate3d(-50%, -100px, 0);
}
</style>

message/index.js

import { h, render } from 'vue'
import messageComponent from './index.vue'

export const message = (type, content, duration = 3000) => {
/**
* 动画结束时的回调
*/
const onDestroy = () => {
// 3. message 销毁
render(null, document.body)
}

// 1. 返回 vnode
const vnode = h(messageComponent, {
type,
content,
duration,
destroy: onDestroy
})
// 2. render
render(vnode, document.body)
}

在其他组件下用JS调用该组件

message('success','图片下载完成')