基于Ant-design-vue的Modal彈窗 封裝 命令式與Hooks用法
前言
通常大家在使用彈窗有多樣化的使用方式,常見的是直接使用該 Modal
組件,然后顯隱的狀態(tài)放在父容器里面維護(hù)。
其次就是在全局掛載一個(gè)公共的彈窗組件,然后通過 store
來傳遞不同的參數(shù),并且通過 store
中的方法來改變 state.visble
的狀態(tài),從而使得彈窗展示。
雖然說這些種方式可以實(shí)現(xiàn)同等功能,但總覺得用的不是很直接, 邏輯片段寫的也很分散, 后期代碼量越多維護(hù)成本越高,那有沒有一種比較好的思路處理這個(gè)問題呢?將邏片段進(jìn)行統(tǒng)一管理。
下面我逐一說一下正常開發(fā)中 model
彈窗的組件和我自己研究出來的使用方式,在 命令式 跟 hooks 兩種方式中可以完全的解決代碼邏輯分散問題。
組件式-用法
使用方式
<template> <Modal v-model:visible="visible" title="彈窗"> ...content </Modal> <Button type="primary" @click="visible = true">打開彈窗</Button> </template> <script lang="ts"> import { defineComponent, ref } from "vue"; import { Modal, Button } from "ant-design-vue"; export default defineComponent({ components: { Modal, Button, }, setup() { const visible = ref(false); return { visible }; }, }); </script>
組件式用法也可以說是傳統(tǒng)用法實(shí)際就是把市面上一些封裝好的ui
組件導(dǎo)入進(jìn)來使用,或者是自己封裝的組件。這樣使用確實(shí)很方便也很快捷。
比如說現(xiàn)在有一個(gè)需求,在當(dāng)前頁面中有 2 按鈕需要打開 2 個(gè)不同的彈窗。此時(shí)我們需要在當(dāng)前組件中聲明 2 個(gè) visible
初始值為 ref(false)
的變量,這還僅僅是控制一個(gè)顯隱的功能,那么隨著業(yè)務(wù)的復(fù)雜度增加,當(dāng)前頁面需要打開彈窗的按鈕增加,那么當(dāng)前組件就會(huì)變得越來越復(fù)雜,維護(hù)成本隨之也會(huì)增高。很有可能一個(gè)邏輯清晰的組件就會(huì)變得如下代碼一樣。
<template> <Modal v-model:visible="editVisible" title="彈窗"> <Form> <FormItem label="名稱"> <Input v-memo="editFormData.name" placeholder="請(qǐng)輸入" /> </FormItem> </Form> </Modal> <Button type="primary" @click="editVisible = true">修改數(shù)據(jù)</Button> <Modal v-model:visible="detailVisible" title="彈窗"> ...detailContent </Modal> <Button type="primary" @click="detailVisible = true">查看詳情</Button> </template> <script lang="ts"> import { defineComponent, reactive, ref } from "vue"; import { Modal, Button, Form, FormItem, Input } from "ant-design-vue"; export default defineComponent({ components: { Modal, Button, Form, FormItem, Input, }, setup() { const editVisible = ref(false); const detailVisible = ref(false); const editFormData = reactive({ name: "" }); return { editVisible, detailVisible, editFormData }; }, }); </script>
隨隨便便增加一點(diǎn)業(yè)務(wù)邏輯兩個(gè)彈窗組件的數(shù)據(jù)就會(huì)混在一起,當(dāng)然我們可以把彈窗渲染的一部分內(nèi)容抽離出來,這樣也不能排除你增加按鈕的邏輯。
命令式-用法
使用方式
<template> <Button @click="openAModal"></Button> </template> <script> import { Button } from "ant-design-vue"; import openAModal from "./openAModal"; export default defineComponent({ components: { Button, }, setup() { return { openAModal, }; }, }); </script>
通過以上代碼,可以看出命令式使用方式要比組件式 使用方式簡(jiǎn)單的多,直接調(diào)用一個(gè)方法就可以實(shí)現(xiàn)同等等功能,非常的快捷方便,后期需要修改業(yè)務(wù)路基即可一針見血的直接奔向這個(gè)方法來做修改就好,相比組件式用法也更易于維護(hù)。
使用命令式用法,我們需要?jiǎng)?chuàng)建一個(gè)工具函數(shù)來包裝一下 Modal
。下面的代碼是針對(duì) ant-design-vue@2.x
做的封裝這部分的邏輯我就不分析了,主要是看如何使用這個(gè)命令式的調(diào)用方法,感興趣的同仁們,可以自行研究。當(dāng)然下面代碼也針對(duì)于 ant
的 Modal
特殊優(yōu)化了一下,用過的人可能知道 使用Ant Modal
如果對(duì) onOk
事件不做處理的話他是無法主動(dòng)關(guān)閉彈窗的。而且 ant Modal
的 okText、cancelText
一定要給一個(gè)名稱 不然他默認(rèn)第一次顯示的是中文,關(guān)閉后再次打開卻是英文。
核心實(shí)現(xiàn)邏輯
// modal.js import { createVNode, render as vueRender } from "vue"; import { Modal as AntModal } from "ant-design-vue"; /** * @param {import("vue").DefineComponent} content * @param {import("vue").Prop} props * @param {Omit<import("ant-design-vue").ModalProps, 'visible'>} config */ export default function modal(content, props, config) { const container = document.createDocumentFragment(); const _contentVnode = createVNode(content, props); const metadata = Object.create({ okText: "確定", cancelText: "取消", visible: true, ...config, }); metadata.onCancel = async function (...arg) { await config.onCancel?.(...arg); close(); }; metadata.onOk = async function () { if (!(config.onOk instanceof Function)) { close(); return; } const result = config.onOk(); if (!(result instanceof Promise)) { close(); return; } update({ confirmLoading: true }); return result .then(() => { update({ confirmLoading: false }); close(); }) .catch(() => { update({ confirmLoading: false }); }); }; let vm = createVNode(AntModal, metadata, () => _contentVnode); /** * * @param {typeof config} config */ function update(config) { Object.assign(vm.component.props, config); vm.component.update(); } function close() { metadata.visible = false; update(metadata); } function destroy() { if (vm) { vueRender(null, container); vm = null; } } /** 渲染 */ vueRender(vm, container); return { ..._contentVnode, close, destroy, update, }; }
主要工具實(shí)現(xiàn)完了后,現(xiàn)在假設(shè)有一個(gè) A.vue
的組件,需要在 modal
彈窗中渲染,并且支持一個(gè)可配的 title
,通常我們的寫法是直接在 template中寫入 <Modal> <A title="名稱" /> </Modal>
,但這次我們不這么做,我們先寫一個(gè) A.vue
的組件 代碼如下:
// A.vue <template> <h1>我是A組件</h1> <div>{{ title }}</div> </template> <script> import { defineComponent } from "vue"; export default defineComponent({ props: { title: { type: String, default: "", }, }, }); </script>
現(xiàn)在基于 A.vue
來聲明一個(gè)調(diào)用彈窗的方法,因?yàn)闆]有業(yè)務(wù)場(chǎng)景 所以下面的方法簡(jiǎn)單點(diǎn)沒有去設(shè)置形參,如果后面業(yè)務(wù)有需求可以傳遞參數(shù)來使用。代碼如下:
// openAModal.js import A from './A.vue' import modal from './modal.js' export default function openAModal() { modal(A, {title: 'A組件的props'}, {...彈窗的配置項(xiàng)}) }
后面使用直接調(diào)用 openAModal
即可在彈窗中展現(xiàn) A.vue
。這樣在使用的時(shí)候無需在意 template
結(jié)構(gòu),更不用去聲明 visible
的屬性,彈窗的邏輯也不會(huì)與業(yè)務(wù)混合在一起,后期也方便維護(hù),完全符合設(shè)計(jì)原則中的單一職責(zé)。
當(dāng)然這樣也會(huì)有缺陷,因?yàn)閺棿敖M件是使用 render
函數(shù)渲染的,所以在modal
中的組件無法獲取到 vue
實(shí)例中全局注冊(cè)的一些方法,比如你全局 app.use(router)
,那么你在 A.vue
中是無法通過 useRouter()
來獲取路由實(shí)例。
通常這樣打開彈窗,組件內(nèi)使用的參數(shù)建議以傳遞參數(shù)的形式,不要全局獲取。 如果你非要在組件中使用 useRouter
、useStore
等一些全局注冊(cè)的工具,請(qǐng)繼續(xù)閱讀下面的 hooks 用法,該方法模擬了 arco-design-react
的 useModal
用法,相對(duì)命令式封裝做的事情要少的多。
Hooks-用法
使用方式
<template> <component :is="contextHolder" /> <Button @click="openAModal">打開彈窗</Button> </template> <script lang="ts"> import { defineComponent } from "vue"; import { Button } from "ant-design-vue"; import useModal from "./useModal.js"; import A from "./A.vue"; export default defineComponent({ components: { Button, }, setup() { const [modal, contextHolder] = useModal({ title: "彈窗", content: A }); return { openAModal: modal.show, contextHolder, }; }, }); </script>
通過以上使用示例,使用方式類似于命令式,也是調(diào)用api
去操作彈窗。但是比 命令式 多了一個(gè) contextHolder
,為了處理 modal
不脫離當(dāng)前 vue
的實(shí)例,直接借助于vue component
組件去渲染當(dāng)前我們自己定義的 Component
。這樣一來完美的解決了 命令式 調(diào)用方法的缺陷問題。
hook 的使用方式,應(yīng)該也可說是一種高級(jí)封裝組件的方式,需要傳遞一個(gè)你要渲染的組件然后,暴露一個(gè) contextHolder
和一些 Api
即可, 然后操作當(dāng)前hooks的 Api
來控制 modal
。
核心實(shí)現(xiàn)邏輯
// useModal import { createVNode, ref, defineComponent } from "vue"; import { Modal as AntModal } from "ant-design-vue"; /** * @typedef {ReturnType<typeof defineComponent>} Component * @typedef {Omit<import("ant-design-vue").ModalProps, 'visible'>} ModalProps * @param {Omit<import("ant-design-vue").ModalProps, 'visible'> & {content: Component}} props * * @returns {[{show:() => void}, Component]} */ export default function useModal(props = {}) { const visible = ref(false); // 定義需要渲染的組件即Modal const contextHolder = defineComponent({ render() { return createVNode(AntModal, { ...props, visible: visible.value }, () => createVNode(props.content) ); }, }); const show = () => { visible.value = true; }; return [{ show }, contextHolder]; } }
上面簡(jiǎn)單的實(shí)現(xiàn)了一個(gè) useModal
,使用 jsDoc
定義了一下入?yún)⒑头祷貐?shù),可以看到出來入?yún)⒃诨?modal
的props
基礎(chǔ)之上增加了一個(gè)content
屬性,就是用來接受你要渲染不同的組件的。
在 useModal
簡(jiǎn)單的暴露了一個(gè) show
方法,還有一些方法大家都可以自由發(fā)揮的,比如說,傳入的組件怎么怎么傳參數(shù),傳入的組件props變更怎么去更新,點(diǎn)擊 onOk
的時(shí)候怎么獲取到傳入組件的里面的數(shù)據(jù)。這些都是可以通過方法去實(shí)現(xiàn)的,一些邊界問題我就沒有去細(xì)處理了。主要能夠了解這種寫法的思路。有思路之后,就可以隨意改造。并且還能保留原有的類型提示。讓你在使用與排錯(cuò)的時(shí)候不會(huì)迷路。
總結(jié)
相對(duì)于正常開發(fā)我們使用了 vue
的 render 、component 的 is 、createVnode
,借助了 arco-design-react
封裝的 useModal
, ant-design-vue
的 Modal.confirm
思路來自動(dòng)動(dòng)手改造了一版,vue
版本的 useModal
與 命令式 的使用方法。當(dāng)然如果能夠在vue
中熟練使用 jsx
語法, 那基于這個(gè)封裝簡(jiǎn)直是再簡(jiǎn)單不過了。
最后感謝大家的閱讀,希望本文對(duì)你在前端開發(fā)的學(xué)習(xí)和實(shí)踐中有所幫助。繼續(xù)保持好奇心,追求卓越,享受前端開發(fā)的旅程!
以上就是基于Ant-design-vue的Modal彈窗封裝命令式與Hooks用法的詳細(xì)內(nèi)容,更多關(guān)于Ant-design-vue彈窗封裝與Hooks用法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
深入學(xué)習(xí)Vue nextTick的用法及原理
這篇文章主要介紹了深入學(xué)習(xí)Vue nextTick的用法及原理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10Vue實(shí)現(xiàn)移動(dòng)端左右滑動(dòng)效果的方法
最近得到一個(gè)新需求,需要在Vue項(xiàng)目的移動(dòng)端頁面上加上左右滑動(dòng)效果,經(jīng)過一番折騰,最終決定四月vue-touch。下面小編把實(shí)現(xiàn)代碼分享給大家,感興趣的朋友一起看看吧2018-11-11Element中Upload組件上傳功能實(shí)現(xiàn)(圖片和文件的默認(rèn)上傳及自定義上傳)
這篇文章主要介紹了Element中Upload組件上傳功能實(shí)現(xiàn)包括圖片和文件的默認(rèn)上傳及自定義上傳,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01vue中計(jì)算屬性computed理解說明包括vue偵聽器,緩存與computed的區(qū)別
這篇文章主要介紹了對(duì)vue中計(jì)算屬性computed理解說明包括vue偵聽器,緩存與computed的區(qū)別,需要的朋友可以參考下2022-05-05Vue 設(shè)置axios請(qǐng)求格式為form-data的操作步驟
今天小編就為大家分享一篇Vue 設(shè)置axios請(qǐng)求格式為form-data的操作步驟,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-10-10