僅做代碼示例;當然改進的地方還是不少的,僅作為該類組件封裝方式的初步啟發;
理想大成肯定是想要像 `餓了么` 這些組件庫一樣。
有的人叫這函數式組件,有的人叫這命令式組件,我個人還是偏向于命令式組件的稱呼。因為以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 || 0el.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);
})