您好,登錄后才能下訂單哦!
這篇“怎么封裝一個更易用的Dialog組件”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“怎么封裝一個更易用的Dialog組件”文章吧。
在項目中,我們經(jīng)常會遇到使用彈窗的場景,但有時組件庫自帶的彈窗不能滿足我們的需求,需要我們自己封裝,這時我們?nèi)绾稳プ远x一個更加方便調(diào)用的彈窗?
首先我們需要搭建一個Vue3+ts的環(huán)境。
用vite的官方模板:
yarn create vite demo-app --template vue-ts
進入并安裝依賴
cd demo-app yarn
依賴安裝完成后啟動app
yarn dev
先在src/components目錄下創(chuàng)建MyDialog.vue,搭建一個組件的基本框架
<script lang="ts" setup> import { ref, reactive } from "vue"; defineProps({ message: { type: String, default: "", }, title: { type: String, default: "", }, }); const emits = defineEmits<{ (e: "confirm"): void; (e: "close"): void; }>(); const visible = ref(true); function clickConfirm() { console.log("確認"); emits("confirm"); } function clickClose() { console.log("取消"); emits("close"); } </script> <template> <div class="wrap" v-if="visible"> <div class="container"> <div class="title">{{ title }}</div> <div class="content"> <div>{{ message }}</div> </div> <div class="controll"> <button @click="clickConfirm">確認</button> <button @click="clickClose">取消</button> </div> </div> </div> </template> <style scoped> .wrap { position: absolute; top: 0; left: 0; background: rgba(15, 15, 15, 0.5); width: 100%; height: 100%; } .container { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); min-width: 300px; min-height: 200px; padding: 10px; background: white; display: flex; flex-direction: column; } .content { flex: 1; padding: 10px; text-align: left; } .title { min-height: 30px; } .controll { display: flex; width: 100%; justify-content: space-around; } </style>
在src目錄下創(chuàng)建hooks目錄,然后再hooks目錄下創(chuàng)建useMyDialog.ts.
函數(shù)調(diào)用組件我們需要:
將組件轉換成VNode
將VNode轉換成DOM然后渲染到頁面
import { createVNode, render, ComponentPublicInstance } from "vue"; export default function useMyDialog(option?: any) { const props = { ...option, }; const vm = createVNode(MyDialog, props); const container = document.createElement("div"); render(vm, container); document.querySelector("#app")?.appendChild(container.firstElementChild!); }
ps:
container.firstElementChild!中的!表示container.firstElementChild不為null或者undefined
接下來我們在App.vue中測試一下
<script setup lang="ts"> import useMyDialog from "./hooks/useMyDialog"; function showDialog() { useMyDialog({ message: "test1", onClose: () => { console.log("self"); }, }); } </script> <template> <button @click="showDialog">顯示Dialog</button> </template>
我們需要將close返回出去,這樣我們就可以手動調(diào)用close函數(shù)關閉Dialog.
在useMyDialog.ts中添加
import { ComponentPublicInstance,VNode } from "vue"; export default function useMyDialog(option?: any) { const userCloseFn = option?.onClose; props.onClose = () => { close(); userCloseFn ?? userCloseFn(); }; function close(vm: VNode) { ( vm.component!.proxy as ComponentPublicInstance<{ visible: boolean }> ).visible = false; } return { close: close.bind(null, vm), } }
現(xiàn)在每次點擊顯示Dialog按鈕時都會創(chuàng)建一個新的組件實例,這不是我們的預期,所以我們需要將組件進行緩存.
在useMyDialog.ts中添加
import { ComponentPublicInstance } from 'vue' const instances: any[] = []; export default function useMyDialog(option?: any) { const tempVm: any = instances.find( (item) => `${item.vm.props?.message ?? ""}` === `${(option as any).message ?? ""}` ); if (tempVm) { ( tempVm.vm.component!.proxy as ComponentPublicInstance<{ visible: boolean; }> ).visible = true; return { close: close.bind(null, tempVm.vm), }; } }
src/hooks/useMyDialog.ts
import { createVNode, render, ComponentPublicInstance, VNode } from "vue"; import MyDialog from "../components/MyDialog.vue"; const instances: any[] = []; export default function useMyDialog(option?: any) { const props = { ...option, }; const userCloseFn = option?.onClose; props.onClose = () => { close(vm); userCloseFn ?? userCloseFn(); }; function close(vm: VNode) { ( vm.component!.proxy as ComponentPublicInstance<{ visible: boolean }> ).visible = false; } const tempVm: any = instances.find( (item) => `${item.vm.props?.message ?? ""}` === `${(option as any).message ?? ""}` ); if (tempVm) { ( tempVm.vm.component!.proxy as ComponentPublicInstance<{ visible: boolean; }> ).visible = true; return { close: close.bind(null, tempVm.vm), }; } const vm = createVNode(MyDialog, props); const container = document.createElement("div"); render(vm, container); document.querySelector("#app")?.appendChild(container.firstElementChild!); instances.push({ vm }); return { close: close.bind(null, vm), }; }
以上就是關于“怎么封裝一個更易用的Dialog組件”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關的知識內(nèi)容,請關注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。