利用渲染函数,实现动态创建弹窗-Vue3.X

Posted IT飞牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用渲染函数,实现动态创建弹窗-Vue3.X相关的知识,希望对你有一定的参考价值。

Vue2.0版本的动态弹窗创建,请参考:vue利用渲染函数创建弹窗组件,完美支持传值和事件监听(Vue2.X)

基于element-plus框架

文件目录结构

├─ src
│  ├─ ...
│  ├─ package
│  │  ├─ index.ts
│  │  ├─ layer
│  │  │  ├─ alert.vue
│  │  │  ├─ confirm.vue
│  │  │  └─ modal.vue
│  │  └─ layer.ts

代码

src\\package\\layer.ts

import  createApp, h, render, ref  from "vue";
import alert from "./layer/alert.vue";
import confirm from "./layer/confirm.vue";
import modal from "./layer/modal.vue";
import  ElMessage, MessageParams, ElLoading  from "element-plus";

const layer = function (app: any) 
    return 
        _create(component: any, props: any, children = ) 
            const defPropsMap: any = 
                alert: 
                    title: "提示",
                    content: "",
                    width: 400
                ,
                confirm: 
                    title: "提示",
                    content: "",
                    width: 500
                ,
                modal: 
                    title: "提示",
                    content: "",
                    width: 500
                
            ;
            let Props =  ...defPropsMap[component.name], ...props ;
            const layerDom = document.createElement('div');
            let close = () => 
                // console.log("remove dom");
                layerDom.remove();
            ;
            let comRef = ref(null) as any;
            let vNode = h(
                render() 
                    return h(component,  ...Props, ref: comRef, "before-close": close , children)
                
            );

            let root = Props["_top"] ? (top || self) : self;
            root.document.body.appendChild(layerDom);
            vNode.appContext = app._context;
            render(vNode, layerDom);
            return 
                el: layerDom,
                vm: comRef.value,
                close
            ;
        ,
        alert: function (option: any) 
            /**调用方式:   后两个参数参照渲染函数传参
                    this.$layer.alert("hello world",title:"title reset",this.$refs.slotRef.innerhtml);
                    this.$layer.alert("hello world",title:"title reset","<div>内容</div>");
                    this.$layer.alert("hello world",title:"title reset",h("p","内容"));
                    this.$layer.alert("hello world",title:"title reset",()=>h(自定义组件,"内容"));
             */
            let opt = ;
            let children = ;
            if (typeof option === "string") 
                opt = Object.assign(,  content: option, ...arguments[1] )
                children = arguments[2] || ;
             else 
                opt = option;
                children = arguments[1] || ;
            
            let layer = this._create(alert, opt || , children);
            return layer;
        ,
        confirm: function (option: any) 
            /**
             * the same to alert
             */
            let opt = ;
            let children = ;
            if (typeof option === "string") 
                opt = Object.assign(,  content: option, ...arguments[1] )
                children = arguments[2] || ;
             else 
                opt = option;
                children = arguments[1] || ;
            
            let layer = this._create(confirm, opt || , children);
            return layer;
        ,
        modal: function (props = , children = ) 
            let layer = this._create(modal, props, children);
            return layer;
        ,
        message: function (message: string = "", type: Type = Type.success, option: Object = ) 
            let opt: MessageParams =  message: message, type: "success", ...option ;
            return ElMessage(opt);
        ,
        loading: function () 
            return ElLoading.service(
                lock: true,
                text: '加载中...',
                background: 'rgba(0, 0, 0, 0.7)',
            );
        
    ;


export default 
    install(app: any, option = ) 
        app.config.globalProperties.$layer = layer(app);
    
;

declare module "@vue/runtime-core" 
    interface ComponentCustomProperties 
        $layer: 
            alert: Function,
            confirm: Function,
            modal: Function,
            loading: Function,
            message: Function
        ,
    


enum Type 
    success = "success",
    warning = "warning",
    error = "error",
    message = "message"

src\\package\\index.ts

import layer from "./layer"; 

const install = function (app:any) 
  app.config.globalProperties.$layer = layer;
;

export default  install ; 

src\\package\\layer\\alert.vue

<template>
  <el-dialog v-model="isShow" v-bind="$attrs">
    <div v-if="content"> content </div>
    <slot></slot>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="sure">关闭</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script>
import  reactive, toRefs, ref, onMounted  from "vue";

export default 
  name: "alert",
  emits: ["sure"],
  props: ["content"],
  setup(props,  expose, attrs, slots, emit ) 
    const state = reactive(
      isShow: true,
      attrs,
    );

    const actions = 
      sure() 
        emit("sure", paramCtx);
        attrs["before-close"]();
      ,
    ;
    let paramCtx =  ...attrs, close: attrs["before-close"] ;

    return 
      ...toRefs(state),
      ...actions,
    ;
  ,
;
</script>

src\\package\\layer\\confirm.vue

<template>
  <el-dialog v-model="isShow" v-bind="$attrs">
    <div v-if="content"> content </div>
    <slot></slot>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="cancel">取消</el-button>
        <el-button type="primary" @click="sure">确定</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script>
import  reactive, toRefs, ref  from "vue";

export default 
  name: "confirm",
  emits: ["sure", "cancel"],
  props: ["content"],
  setup(props,  expose, attrs, slots, emit ) 
    const state = reactive(
      isShow: true,
      attrs,
    );

    let paramCtx =  ...attrs, close: attrs["before-close"]  ;

    const actions = 
      sure() 
        emit("sure", paramCtx);
        attrs["before-close"]();
      ,
      cancel() 
        emit("cancel", paramCtx);
        attrs["before-close"]();
      ,
    ;

    return 
      ...toRefs(state),
      ...actions,
    ;
  ,
;
</script>

<style lang="scss" scoped>
</style>

src\\package\\layer\\modal.vue

<template>
  <el-dialog v-model="isShow" v-bind="$attrs">
    <div v-if="content"> content </div>
    <slot></slot>
  </el-dialog>
</template>

<script>
import  reactive, toRefs  from "vue";

export default 
  name: "modal",
  props: ["content"],
  setup(props,  expose, attrs, slots, emit ) 
    const state = reactive(
      isShow: true,
      attrs,
    );

    return 
      ...toRefs(state)
    ;
  ,
;
</script>

<style lang="scss" scoped>
</style>

src\\main.ts

import  createApp  from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import layer from "./package/layer";//******引入
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import  ComponentCustomProperties  from "vue";

createApp(App).use(store).use(router).use(ElementPlus).use(layer).mount('#app')

src\\views\\Home.vue (如何调用)

<template>
  <div class="home">
    <el-button @click="alert">alert</el-button>
    <el-button @click="confirm">confirm</el-button>
    <el-button @click="modal">modal</el-button>
    <el-button @click="loading">loading</el-button>
    <el-button @click="message">message</el-button>
  </div>
</template>

<script lang="ts">
import  defineComponent, h  from "vue";
import com from "@/views/com.vue";

export default defineComponent(
  name: "Home",
  data() 
    return  isShow: true ;
  ,
  methods: 
    loading() 
      let layer = this.$layer.loading();
      setTimeout(() => 
        layer.close();
      , 2000);
    ,
    message() 
      let layer = this.$layer.message("message提示内容");
    ,
    alert() 
      let layer = this.$layer.alert("alert提示内容");
    ,
    confirm() 
      let layer = this.$layer.confirm("confirm提示内容", 
        onSure() 
          alert("确定");
          layer.close();
        ,
        onCancel() 
          alert("取消");
          layer.close();
        ,
      );
    ,
    modal() 
      let layer = this.$layer.modal(null, () => 
        return h(com, 
          onSure() 
            alert("这里是自定义组件的确定");
            layer.close();
          ,
          onCancel() 
            alert("这里是自定义组件的取消");
            layer.close();
          ,
        );
      );
    ,
  ,
  components: 
    com,
  ,
);
</script>

最终效果

以上是关于利用渲染函数,实现动态创建弹窗-Vue3.X的主要内容,如果未能解决你的问题,请参考以下文章

vue利用渲染函数创建弹窗组件,完美支持传值和事件监听

vue3.x + threeJs 实现3d动画场景

Vue2和Vue3的区别

react实现Modal弹窗

react实现Modal弹窗

react实现Modal弹窗