前言
在做程序的时候发现了一种现象,页面上需要多个弹窗依次弹出,于是就开始了引用多个弹窗定义多个isShow的情况,于是我这边就在思考有没有一种封装能够动态的渲染我需要的组件呢
于是考虑了jsx的灵活性进行一种封装
方式一枚举弹窗,通过type控制,使render动态渲染出我需要的弹窗实例。
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'View',
props: {
text: String
},
//定义emit的事件
emits:['close','ok'],
setup(props, context) {
let isShow = ref(false)
let modalDom = ref('')
//定义弹窗的点击事件
const handleClick = () => {
isShow.value = false
//提交出去触发组件的自定义确认事件
context.emit('ok')
};
const open = ()=>{
isShow.value =true
}
const initModal = (params)=>{
isShow.value =false
//{name:'弹窗名称',okButtonTxt:'确定按钮文案',closeButtonTxt:'取消按钮文案',type:'1',contTxt:'弹窗内容'}
//通过枚举不同的弹窗样式渲染不通的弹窗
switch (params.type) {
case '1':
//弹窗1
modalDom.value = (<view onClick={handleClick}>弹窗A内容{params.value.name}</view>)
break;
case '2':
//弹窗2
modalDom.value = (<view onClick={handleClick}>弹窗B内容{params.value.name}</view>)
break;
default:
break;
}
}
//定义暴露出去的方法
context.expose({
open,
initModal
})
//渲染出不同的弹窗实例
return () => {
return (modalDom.value) || ''
}
}
});
使用方式
<template>
<modalA ref="modalARef" @ok="testOk"></modalA>
</template>
<script setup lang="ts">
import modalA from './components/is-image/demo.vue'
import { ref, onMounted, provide, getCurrentInstance, onUnmounted, computed, watchEffect, nextTick } from 'vue';
const testA = ()=>{
modalARef?.value?.initModal({name:'弹窗名称',okButtonTxt:'确定按钮文案',closeButtonTxt:'取消按钮文案',type:'1',contTxt:'弹窗内容'});
modalARef?.value?.open();
}
testA()
let modalList = ref(['3','2','1'])
const testOk=()=>{
if(modalList.value.length >0){
modalList.value = modalList.value.slice(0, modalList.value.length - 1)
modalARef?.value?.initModal({name:'弹窗名称',okButtonTxt:'确定按钮文案',closeButtonTxt:'取消按钮文案',type:modalList.value[modalList.value-1],contTxt:'弹窗内容'});
modalARef?.value?.open();
}
}
</script>
方式二使用拔插式的扩展方式优化代码
基于上述情况需要枚举不同的组件,不方便扩展,那么就使用拔插式的形式进行扩展
import { defineComponent, ref,h } from 'vue';
export default defineComponent({
name: 'View',
props: {
text: String
},
//定义emit的事件
emits:['close','ok'],
setup(props, context) {
let isShow = ref(false)
let modalDom = ref()
//定义弹窗的点击事件
const handleClick = () => {
isShow.value = false
//提交出去触发组件的自定义确认事件
context.emit('ok')
};
const open = ()=>{
isShow.value =true
}
const initModal = (modal)=>{
isShow.value =false
//传入啥就渲染啥
modalDom.value =modal
}
//定义暴露出去的方法
context.expose({
open,
initModal
})
return () => {
console.log('渲染了1次',modalDom.value);
return modalDom.value && isShow.value ? h(modalDom.value,{
'onClick': (val) => {
context.emit('ok')
},
'onClose': (val) => {
context.emit('close')
}
}):''
}
}
});
使用方式
const handleDemoClick =()=>{
import ('../index/components/is-image/view.vue').then((demo)=>{
demoRef?.value?.initModal(demo.default);
demoRef?.value?.open();
})
}
</script>
结果是动态的渲染到了页面上
总结
这样的优势是保证了页面弹窗只有一个这个特点
- 第一个方案是可以按需传入参数,弹出对应的弹窗,属于聚合式组件封装,相关的内容都封装在一起。
- 第二个方案是可以在点击的时候动态加载组件,传入组件挂载在页面上,属于拔插式封装,内容由外部给出,进行动态加载动态渲染组件。
这个是我的一个思路,大家有更好的办法也希望可以指导我。