说在正文之前:封装的FastDialog-Vue适用于页面级Vue开发,即采用引入Vue.js来进行html页面开发
20190124更新:现已支持Vue工程开发模式中使用dialog,详情请见
FastDialog-Vue: 基于vue.js封装的动态渲染弹出层 - Gitee.com
最近在使用Vue开发基于springboot的后台管理系统前端部分,因为没有采用webpack进行Vue的单页面工程开发而是将html与后端进行整合在springboot工程中,而前端Vue涉及到的UI框架中的Modal都是需要事先在页面中声明,导致很多页面逻辑都在一个html中,如果层叠打开多个Modal,那一个html会显得非常臃肿,代码逻辑也会很多不利于后续的代码阅读与维护,所以就封装了一个dialog以js的方式引用进页面,直接调用方法动态将Modal添加到页面,进行各个页面的逻辑分离。
说明:
master分支:开发的最早版本,以js,html页面的方式开发组件
vue分支:以vue工程形式开发的组件,打包js,css供html调用
test分支:测试代码
演示地址:vue组件
dialog会提供以下一些常用功能:
引用vue工程版本的js时需要在Vue初始化时进行变量声明,即
代码语言:javascript复制 var app1 = new Vue({})
调用方法的形式为app1.$fastdialog.functionname
引用master分支下的直接调用方法即可
1.打开一个html页面
代码语言:javascript复制OpenDialog("111", "打开窗口", "newpage1.html", "600", "1200");
2.打开一个html页面并指定宽高的单位
代码语言:javascript复制OpenDialog("111", "打开窗口", "newpage1.html", "70", "80",null,null,"%");
3.打开一个html页面传值并制定回调函数
代码语言:javascript复制 OpenDialog("444", "有回调函数并传参", "newpage1.html", "600", "1200", AfterCloseWithReturn, "125sds");
这些都是调用的OpenDialog方法,我们来看下这个方法定义的参数
代码语言:javascript复制function OpenTopDialog(id, title, url, height, width, callback, params, screenunit)
id:dialog标识,title:dialog的head部分的文字,url:打开的页面地址,height:打开页面的高度,width:打开页面的宽度,callback:关闭打开页面后的父级页面调用的回调函数,params:父级页面给打开的子页面传递的参数,screenunit:打开页面宽高的单位
注:OpenDialog方法是在本级页面打开窗口,该组件同时提供在顶级窗口打开全局页面,为OpenTopDialog,参数完全一致
4.子页面获取父级页面传递的参数
代码语言:javascript复制 var params = GetParams();
5.关闭页面
代码语言:javascript复制 CloseDialog("page2回传111111","page3");
看下方法定义
代码语言:javascript复制function CloseDialog(ReturnValue,id)
第一个参数为页面回传给父级页面的值,配合父级页面使用如下
代码语言:javascript复制 function AfterCloseWithReturn(ReturnValue) {
alert("page1回传的参数:" ReturnValue);
}
第二个参数为打开的diaog的id,普通打开页面可以不指定,使用OpenTopDialog的页面必须指定,后面会详细说明
6.提供Alert类型的提示dialog
代码语言:javascript复制 OpenAlert("提示", "请在规定期限内处理完成!",AfterClose);
看下提示框打开方法的参数定义
代码语言:javascript复制function OpenAlert(title, message, callback, btnclosetext)
第一个参数为提示框标题,第二个参数为提示内容,第三个参数为关闭提示框后的回调函数,第四个参数为关闭按钮文字的个性化指定,同时还有成功,警告,失败等提示框,如下
代码语言:javascript复制OpenSuccess("提示", "请在规定期限内处理完成!");
OpenWaring("提示", "请在规定期限内处理完成!",null,"知道了");
OpenFail("提示", "请在规定期限内处理完成!");
7.提供Confirm类型确认框的dialog
代码语言:javascript复制 OpenConfirm("确认提示", "是否删除当前数据", function () {
}, "确认删除", "取消操作");
看下函数定义,相信一看就懂了
代码语言:javascript复制function OpenConfirm(title, message, okcallback, btnoktext, btncanceltext)
接下来说一下开发中到问题的解决方案
1.用原生js开发如何动态请求template模板
如果不是用字符串定义的话,直接请求定义模板的html文件即可,这里需要注意的是,引用组件到工程的目录不同,这里需要自己改下,这是缺点1,缺点2是每次打开dialog会有额外的网络请求,所以后续版本采用vue工程形式开发,避免了这种问题
代码语言:javascript复制 var template;
var templatepath = GetRootPath() 'fastdialog/fastdialog-template.html';
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", templatepath, false);
xmlhttp.send();
template = xmlhttp.responseText;
2.如何让页面动态添加Modal
采用获取dialog的构造函数,动态挂载到页面的方式(这里展示的是Vue工程中的代码)
代码语言:javascript复制import dialog from './dialog.vue';
let dialogconstructor = Vue.extend(dialog);
var dialoginstace = new dialogconstructor({
data() {
return {
id: id,
title: title,
url: url,
height: height,
width: width
}
},
methods: {
close(id) {
CloseDialogWithOutReturn(id,istop);
},
callbackevent(RetrunValue){
if(callback){
if(RetrunValue){
callback(RetrunValue);
}else{
callback();
}
}
}
}
});
dialog.$mount();
document.body.appendChild(dialog.$el);
3.页面之间,或者说是dialog之间的通信,如传参,回调函数,关闭的实现方式
实现之初,我是用的是window.postmessage与addeventlistener的方式进行页面之间的通信,普通打开页面没问题,但是一旦和打开顶级页面混用,就会出现问题,这里先说下window.postmessage的一些坑
一般逻辑为,我打开一个二级页面dialog,我为父级页面注册一个监听,子页面关闭后向父级页面发送message,触发监听,进行关闭页面或者调用回调函数的操作,类似于
代码语言:javascript复制//open时
window.addEventListener('message', receiveMessage, false);
function receiveMessage(tag) {
var windowstag = tag.data.toString();
if(windowstag=='close'){
dialogInstance.onhidden = callback();
}else{
dialogInstance.onhidden = callback(tag.data);
}
dialogInstance.close();
}
//close时
window.parent.postMessage('close', '*');
后面会遇到一个问题是,如果我在page页面打开一个普通二级页面page1,在page1中打开顶级页面page2,那就相当于是page1,和page2的监听都注册在page中,回调事件会触发两次,即使我可以做到每次注册时清除监听,保证只有一个message监听,但是还是会带来后续的页面关闭问题,所以我将回调函数等传递性的东西都存在dialog中,在父级页面中维护dialog数组即可,看如下代码
代码语言:javascript复制fastdialog.OpenDialog=(id, title, url, height, width, callback, params, screenunit) =>{
var dialog = GetDialogInstance(id, title, url, height, width,callback, false, screenunit);
dialog.$mount();
document.body.appendChild(dialog.$el);
if(window.dialoglist){
console.log(window.dialoglist)
for(var i=0;i<window.dialoglist.length;i ){
if(window.dialoglist[i].id==id){
window.dialoglist.splice(i,1);
break;
}
}
window.dialoglist.push({"id":id,"instance":dialog})
}else{
var dialoglist = [];
dialoglist.push({"id":id,"instance":dialog});
window.dialoglist = dialoglist;
}
if (params) {
var iframe = window.document.getElementById(id '_fastdialogiframe').contentWindow;
iframe["fastdialog_params"] = params;
}
}
fastdialog.CloseDialog=(ReturnValue,id)=> {
if(id){
var obj = window.top.document.getElementById(id);
if(obj){
for(var i=0;i<window.top.dialoglist.length;i ){
if(window.top.dialoglist[i].id==id){
if(ReturnValue){
window.top.dialoglist[i].instance.callbackevent(ReturnValue);
}else{
window.top.dialoglist[i].instance.callbackevent();
}
window.top.dialoglist.splice(i,1);
break;
}
}
window.top.document.getElementById(id).remove();
}else{
if(ReturnValue){
window.parent.dialoglist[0].instance.callbackevent(ReturnValue);
}else{
window.parent.dialoglist[0].instance.callbackevent();
}
window.parent.dialoglist.splice(0,window.parent.dialoglist.length);
document.getElementById(id).remove();
}
}else{
if(ReturnValue){
window.parent.dialoglist[0].instance.callbackevent(ReturnValue);
}else{
window.parent.dialoglist[0].instance.callbackevent();
}
window.parent.dialoglist.splice(0,window.parent.dialoglist.length);
var modallist = window.parent.document.getElementsByClassName("fast-modal-bg");
for(var i=0;i<modallist.length;i ){
modallist[i].remove();
}
}
}
其中向打开页面传递参数通过iframe["fastdialog_params"] = params;实现,具体逻辑可以查看源码看下,需要注意的是dialog还提供右上角的x关闭页面,关闭时也需要同步维护dialoglist数组
4.使用Vue工程开发如何将dialog以插件的方式提供带页面,看代码就知道将dialog以Vue的全局属性注册上去即可
代码语言:javascript复制fastdialog.install = function(Vue) {
Vue.prototype.$fastdialog = fastdialog
};
if (typeof window !== 'undefined' && window.Vue) {
window.Vue.use(fastdialog)
}
说在最后:本插件只在chrome浏览器做了测试,还希望大家多多提意见,共同进步,如果觉得还不错的话,记得码云给个Star哦