2021-03-10

缘起

有时候, 我们希望组件在我们任何需要的时候呼之即来,而不是固定在HTML的DOM中.
在 element-plus中 是事先通过 el-dialog 定义 然后 控制起是否可见来决定对话框的弹出还是隐藏。
这在涉及复杂逻辑可能会不太方便。

设想中的写法:

import LocMarkDialog from 'LocMarkDialog.vue'

///省略代码 ....
let {proxy} = getCurrentInstance();
proxy.$mount(LocMarkDialog).then(res)=>{
//点击了确定
}).catch(()=>{
//点击了取消
}

MyDialog 组件并不写在<template></template> 标签中,而是在任何业务需要的地方临时创建,并且在使用完后自动销毁.

组件的实现代码:

import { markRaw, ref, createVNode, defineComponent} from 'vue'


let componentMap = ref([])

let id=0;

const factory = defineComponent({
    props:{
    },
    render(){
        var children = componentMap.value.map((item, i)=>createVNode(item.c, item.p))
        return createVNode('div', {class:'ui-app-component-container'}, children);
    },
    setup(props)
    {
        return {
            componentMap
        }
    },
    install(app){
        app.component('CompFactory', factory);
        app.config.globalProperties.$mount = (comp, props) => {
            return new Promise((resolve, reject)=>{
                let p = props || {};
                Object.assign(p, {q:{resolve, reject}, _compId: id++, finish:(id)=>{
                    let ret = componentMap.value.findIndex(v=>v.p.id===id)
                    if(ret >=0)
                        componentMap.value.splice(ret, 1);
                }});
                console.log('mount component.', comp);
                componentMap.value.push({c:markRaw(comp), p});
            })
        }
    }
})

export default factory;

用法

第一步: 首先全局引入组件

// 引入前面写的组件
import CompFactory from '/@/uiframe/layout/components/CompFactory.vue'
const app = createApp(App);
app.use(CompFactory)

第二步: 在全局使用一次组件

这么做的目的是在document 中创建一个容器节点.

App.vue

<CompFactory></CompFactory>

第三步: 如何使用

定义一个对话框组件

<template>
    <el-dialog custom-class="ui-loc-mark-dialog ui-dialog-autow" v-model="dialogVisible" destroy-on-close :modal="true" @closed="finalThings" title="地理位置标注">
        <BaiduMap :location="location" width="100%" height="100%"></BaiduMap>
        <template #footer>
            <el-button type="primary" size="mini" @click="onSure">保存</el-button>
            <el-button size="mini" @click="onCancel">取消</el-button>
        </template>
    </el-dialog>
</template>
<script>
import { ref } from '@vue/reactivity';
import BaiduMap from '/@/uiframe/layout/components/BaiduMap.vue'
import { onUnmounted } from '@vue/runtime-core';

import LocMarkDialog from '/@/uiframe/layout/components/LocMarkDialog.vue'

export default {
    components:{
        BaiduMap
    },
    props:{
        q:Object, //这里是 resolve 和reject
        _compId:Number, //这里是组件id
        finish:Function, //这里是组件销毁后的回调。
        location: {type:Object, default:{lng:113.97, lat:28.36300}},
    },
    setup(props, ctx)
    {
        let dialogVisible = ref(true); //对话框默认显示

        const onCancel = ()=>{
            dialogVisible.value = false;
            props.q.reject('cancel');
        }
        const onSure = ()=>{
            dialogVisible.value = false;
            props.q.resolve({success:true});
        }
		
		//对话框销毁后, 通知CompFactory 销毁节点.
        const finalThings = ()=>{
            props.finish(props.id);
        }
        onUnmounted(()=>{
            console.log('bye!');
        })
        return {
            location:props.location,
            dialogVisible,
            onCancel,
            onSure,
            finalThings
        }
    }
}
</script>
<style lang="scss">
.ui-loc-mark-dialog .el-dialog__body {
  height: 23rem;padding:.5rem;
}
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值