仅做代码示例;当然改进的地方还是不少的,仅作为该类组件封装方式的初步启发;
理想大成肯定是想要像 `饿了么` 这些组件库一样。
有的人叫这函数式组件,有的人叫这命令式组件,我个人还是偏向于命令式组件的称呼。因为以vue官方文档里对函数式组件的描述,该组件不符合相关类型描述。
而且这种主要以`关注实现过程为主`的封装风格,感觉叫 命令式组件 贴切点,欢迎大家提出自身观点!
1、封装 message.vue 消息提示组件;
<template>
<div :ref="(el) => setRef(el, index)" v-for="(item, index) in showList" :key="item.message + index" class="message"
:class="[item.type]">
<span class="messageIcon">∮</span>
<span>{{ item.message }}</span>
<span class="closeIcon" @click="closeTarget(index)">×</span>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from "vue";
const props = defineProps({
closeAll: Function
})
const emit = defineEmits(['close'])
let lastRef = null
function setRef(el, index) {
console.log(el,index);
if (el) {
index ? (lastRef = el) : (lastRef = null)
const height = lastRef?.clientHeight || 0
el.style.top = (20 * (1 + index)) + height + 'px'
}
}
const showList = ref([])
function createMessage(options) {
console.log(options, showList);
showList.value.push({
...options,
timeout: setTimeout(() => {
showList.value.shift()
options.onClose()
if (!showList.value.length) {
props.closeAll()
}
}, 5000)
})
}
function closeTarget(i) {
const target = showList.value.splice(i, 1)[0]
target.onClose()
clearTimeout(target.timeout)
if (!showList.value.length) {
props.closeAll()
}
}
defineExpose({
createMessage
})
onMounted(() => {
console.log(props, 'props内容');
console.log('命令式组件加载');
})
onUnmounted(() => {
console.log('命令式组件卸载');
})
</script>
<style scoped lang="less">
.message {
display: flex;
align-items: center;
position: fixed;
top: 20px;
left: 50%;
transform: translate(-50%, 0px);
border-radius: 5px;
padding: 15px 20px;
font-size: 14px;
background-color: #f4f4f5;
border: 1px solid #e9e9eb;
color: #909399;
z-index: 3000;
&.success {
background-color: #f0f9eb;
border: 1px solid #e1f3d8;
color: #67c23a;
}
.messageIcon {
width: 16px;
height: 16px;
line-height: 16px;
margin-right: 5px;
}
.closeIcon {
width: 16px;
height: 16px;
line-height: 16px;
margin-left: 10px;
font-size: 18px;
cursor: pointer;
}
}
</style>
2、封装Message函数,在该函数内创建message组件实例、渲染提示信息;
import { createApp } from "vue";
import message from "./message.vue";
let newInstance = null;
export default function Message(options) {
function onClose() {
options.onClose && options.onClose();
}
if (!newInstance) {
const el = document.createElement("div");
const app = createApp(message,{
closeAll
});
const vm = app.mount(el);
document.body.appendChild(el);
newInstance = vm;
newInstance.createMessage({
...options,
onClose,
});
function closeAll(){
app.unmount();
el.remove();
newInstance = null;
}
} else {
newInstance.createMessage({
...options,
onClose,
});
}
}
3、正常开发内使用:
import { onMounted, onUnmounted, ref } from "vue";
import messageApi from "@/components/newApi/message";
onMounted(() => {
setTimeout(() => {
messageApi({
type:'success',
message:'消息内容测试,demo.',
onClose(){
console.log('年的槽');
}
})
setTimeout(() => {
messageApi({
type:'success',
message:'消息内容测试,demo222.',
onClose(){
console.log('年的槽*2');
}
})
}, 1000);
}, 1000*3);
})