vue利用渲染函数创建弹窗组件,完美支持传值和事件监听(Vue2.X)
弹窗组件和其他组件不同,在页面初始化的时候,页面dom结构中是不存在弹窗组件的div节点,只有在调用时弹窗组件的div在会被动态的添加到页面中,并且当删除时,也需要在页面中删除;结合弹窗组件的使用场景,比较合适的实现是使用createElement渲染函数,渲染函数可以动态的创建组件,并且通过props、on属性,传入组件的标题、内容,监听组件的事件;观察看下面这段代码:const vm = ne
·
弹窗组件和其他组件不同,在页面初始化的时候,页面dom结构中是不存在弹窗组件的div节点,只有在调用时弹窗组件的div在会被动态的添加到页面中,并且当删除时,也需要在页面中删除;
Vue3.x版本的动态弹窗,请查看:利用渲染函数,实现动态创建弹窗-Vue3.X
结合弹窗组件的使用场景,比较合适的实现是使用createElement渲染函数,渲染函数可以动态的创建组件,并且通过props、on属性,传入组件的标题、内容,监听组件的事件;
观察看下面这段代码:
const vm = new Vue({
render: h => {
return h(component, {
props,
on: Object.assign({}, eventMap[component.name], on)
});
}
}).$mount();
render字段中,h方法就是createElement方法的别名,可以动态创建虚拟Dom节点,h方法传入两个参数,component可以是html标签,也可以是vue组件,这里显然是要传入我们需要显示的alert弹窗组件,第二个参数用于props传值,on用于监听组件内的事件;最终$mount()方法用于生成真实的dom节点。
到这里,大家可以想象一下,整个弹出alert弹窗的过程,需要一下几个角色参与:
- 一个通用layer方法,可以挂载在Vue原型上,也可以在使用时手动引入;
- 一个alert.vue组件,提供alert页面和样式
- 调用弹窗:
layer(alert.vue,{props:{title:弹窗标题,content:弹窗内容},on:{sure:确定时回调}})
下面是全部代码:
- /src/components/layer/alert.vue
onSure和onClose向外emit的方法,在渲染函数中有对应的on:{sure:xxx,close:xxx}来监听;
<template>
<div v-if="isShow" class="layer mask">
<div class="layer_alert">
<div class="layer_alert_title">
{{ title }}
<div class="close" @click="onClose">x</div>
</div>
<div class="layer_alert_content">{{ content }}</div>
<div class="layer_alert_button">
<div class="tbtn sure fr" @click="onSure">确定</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "alert",
props: {
title: {
type: String,
default: "提示",
},
content: {
type: String,
default: "这里是alert提示内容!",
},
},
data() {
return {
isShow: false,
};
},
methods: {
onSure() {
this.$emit("sure", this);
},
onClose() {
this.$emit("close", this);
},
show() {
this.isShow = true;
},
hide() {
this.isShow = false;
},
},
};
</script>
<style>
</style>
- src\assets\css\layer.css
弹窗对应的css样式文件,可以在main.js中手动import引入,也可以在webpack中配置entry来自动化导入。
.layer {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.layer.mask {
background: rgba(0, 0, 0, 0.3);
}
.layer .layer_alert {
width: 600px;
/* height: 450px; */
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: white;
border-radius: 3px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
padding: 10px;
}
.layer .layer_alert .layer_alert_title {
height: 50px;
line-height: 50px;
border-bottom: 1px solid #ddd;
font-size: 16px;
position: relative;
}
.layer .layer_alert .layer_alert_title>div.close {
width: 40px;
height: 40px;
text-align: center;
line-height: 40px;
position: absolute;
right: 0;
top: 5px;
font-size: 16px;
cursor: pointer;
}
.layer .layer_alert .layer_alert_content {
height: 250px;
padding: 10px 0;
font-size: 14px;
line-height: 120%;
}
.layer .layer_alert .layer_alert_button {
height: 40px;
}
- /src/utils/layer.js
这里借助node中的require.context对组件目录做了扫描,@/components/layer中的组件,都会被自动加载,很方便;
这里仅仅以alert组件为例,其他confirm、popup、modal组件也是一样的架构。最终创建后,返回一个vue实例layer,可以通过layer.$remove()销毁组件在页面上的dom和内存中的存储。
import Vue from "vue";
const modulesFiles = require.context('@/components/layer', true, /\.vue$/);
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.vue$/, '$1');
const value = modulesFiles(modulePath);
modules[moduleName] = value.default;
return modules;
}, {});
export default {
_index: 10000,
_create(component, { props, on }) {
//各类组件的事件监听,component.name是key,必填;
const eventMap = {
alert: {
sure: function (vm) {
//vm===返回的layer
console.log("sure", vm);
},
close: function (vm) {
vm.$remove();
}
}
};
//方案一:渲染函数
const vm = new Vue({
render: h => {
return h(component, {
props,
style: { "z-index": ++this._index },
on: Object.assign({}, eventMap[component.name], on)
});
}
}).$mount();
const layer = vm.$children[0];
layer.$remove = function () {
document.body.removeChild(layer.$el);
layer.$destroy();
}
document.body.appendChild(layer.$el);
return layer;
//方案二:也可使用Vue.extend()来实现弹窗,使用propsData。
},
alert: function (option) {
let layer = this._create(modules.alert, option || {});
layer.show();
return layer;
}
};
- 调用
这里直接使用plugin,将layer挂在到了Vue原型上,方便全局调用;plugin的实现可以参考vue插件实现
...
mounted() {
this.$layer.alert({
props: { title: "弹窗标题", content: "弹窗内容" },
on: {
close: function (layer) {
console.log("close 2");
layer.$remove();
},
},
});
},
...
最终效果:
更多推荐
已为社区贡献1条内容
所有评论(0)