一起來做一下Vue全局提示組件
全局提示組件在前端中算是比較重要的,在開發業務時候肯定能用的上,畢竟任何報錯隻要提示“服務器異常”就可以完美把鍋扔給後臺(手動滑稽)
全局提示組件在人氣比較🔥的 UI 組件庫必有他身影,可能叫法不太相同,有叫 message、toast、alert 等,但就是這麼一玩意。
拿 ant-design-vue 組件庫為例
其核心代碼
message.info('This is a normal message')
他是API的方式進行調用組件,以平常使用components註冊組件,之後在template中使用的方式不太相同
想要實現這個,其實並不困難
但在之前我想聲明一下:ant-design-vue 的 message 做個type分類,有info、success、error等。但為瞭讀者方便理解,我們統一就用message來進行調用,讀者可以根據本文提供的demo源碼自行進行調整(貼一下 ant-design-vue 源碼)
首先,我們在 components 目錄下創建 message 目錄,同時創建 Message.vue 和 index.js 文件
然後在 Message.vue 中寫
<!-- Message.vue --> <template> <div>{{ content }}</div> </template> <script> export default { name: 'Message', props: { content: { type: String, default: '' } } } </script>
再者在 index.js 中寫
// index.js import { render, createVNode } from 'vue' import Message from './Message.vue' export default function message (content) { const div = document.createElement('div') const vm = createVNode(Message, { content }) render(vm, div) document.body.appendChild(div) }
最後在 app.vue 引入使用
<!-- app.vue --> <template> </template> <script> import message from './components/message' export default{ setup() { message('消息組件1') message('消息組件2') } } </script>
效果:
ok,這樣就實現瞭以API的方式進行調用組件
其核心代碼其實隻有以下
const div = document.createElement('div') const vm = createVNode(Message, { content }) render(vm, div) document.body.appendChild(div)
createVNode 可以認為就是h函數,支持直接轉成虛擬dom對象
再去調用 render,渲染至div下,再將div插入body中
由於我們做的是全局組件,應該不被任何因素幹擾,比如 vue-router
但是上面例子我們會發現,我們隻要調用一個 message 方法,就要創建一個div插入至body,這顯然不是符合vue數據驅動視圖的理念
那,接下裡進行改造
先從 Message.vue 文件開始
我們先定義一個消息列表messages,之後提供添加 add 和刪除delete消息列兩方法,再暴露add方法出去
當然,刪除消息是需要根據id進行刪除,可不能瞎刪
<!-- Message.vue --> <script> import { ref, unref } from 'vue' export default { name: 'Message', setup (props, { expose }) { // 消息列表 const messages = ref([]) let id = 0 // 生成id const uuid = () => `message_${id++}` // 添加消息對象 const add = (message) => { const id = uuid() const _message = { ...message, id } unref(messages).push(_message) const { duration = 3 } = message // 設置定時器 const timer = setTimeout(() => { clearTimeout(timer) remove(id) }, duration * 1000) } // 根據 id 刪除消息對象 const remove = (id) => { messages.value = unref(messages).filter(message => message.id !== id) } // 暴露出add 和 remove expose({ add }) return { messages } } } </script>
用v-for把消息列表渲染出來,同時使用transition-group做一些列表過渡動畫
<!-- Message.vue --> <template> <transition-group class="message" tag="div" > <div class="message-content" v-for="message in messages" :key="message.id" > {{ message.content }} </div> </transition-group> </template>
再編寫一點消息列表樣式和其彈出動畫樣式
<!-- Message.vue --> <style scoped> .message { position: fixed; z-index: 999; top: 10px; left: 50%; transform: translateX(-50%); } .message-content { padding: 8px 16px; border-radius: 3px; box-shadow: 0 1px 6px rgba(0, 0, 0, .2); background: #fff; margin-bottom: 20px; } .v-enter-active, .-leave-active { transition: all 200ms ease-in; } .v-enter-from, .v-leave-to { opacity: 0; transform: translateY(-30px); } </style>
再改造一下入口文件
之前我們發現在 app.vue 中調用一次 message方法,就會一次 dom 操作,那我們使用閉包寫一個單例模式進行改造
再者我們在 Message.vue 暴露出add的方法可以直接進行操作消息列表
// index.js import { render, createVNode } from 'vue' import Message from './Message.vue' let vm // 使用單例模式,不再重新插入body function getMessageInstance () { if (vm) return const div = document.createElement('div') vm = createVNode(Message) render(vm, div) document.body.appendChild(div) } export default function message (content = '', duration) { getMessageInstance() vm.component.exposed.add({ content, duration }) }
最後在 app.vue 文件中隨便編寫一些測試代碼
<!-- app.vue --> <template> <button @click="onClick">測試</button> </template> <script> import message from './components/message' export default{ setup() { message('消息組件1', 4) message('消息組件2', 2) let index = 3 const onClick = () => { message(`消息組件${index++}`) } return { onClick } } } </script>
看看最終效果
好,這就是全局提示組件設計大致思路。
回顧一下會發現,其實Vue的組件開發依舊繞不開 JavaScript,可見 JavaScript 在前端的份量。
總結
到此這篇關於Vue全局提示組件的文章就介紹到這瞭,更多相關Vue全局提示組件內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- vue 動態創建組件的兩種方法
- Vue3封裝 Message消息提示實例函數詳解
- Vue封裝全局toast組件的完整實例
- Vue3內置組件Teleport使用方法詳解
- 簡單談一談Vue中render函數