【Vue】基于Vue封装的无需页面声明的弹出层

说在正文之前:封装的FastDialog-Vue适用于页面级Vue开发,即采用引入Vue.js来进行html页面开发

20190124更新:现已支持Vue工程开发模式中使用dialog,详情请见:

https://gitee.com/grassprogramming/FastDialog-Vue/tree/vue-using/

最近在使用Vue开发基于springboot的后台管理系统前端部分,因为没有采用webpack进行Vue的单页面工程开发而是将html与后端进行整合在springboot工程中,而前端Vue涉及到的UI框架中的Modal都是需要事先在页面中声明,导致很多页面逻辑都在一个html中,如果层叠打开多个Modal,那一个html会显得非常臃肿,代码逻辑也会很多不利于后续的代码阅读与维护,所以就封装了一个dialog以js的方式引用进页面,直接调用方法动态将Modal添加到页面,进行各个页面的逻辑分离。

项目地址:https://gitee.com/grassprogramming/FastDialog-Vue

说明:

master分支:开发的最早版本,以js,html页面的方式开发组件

vue分支:以vue工程形式开发的组件,打包js,css供html调用

test分支:测试代码

演示地址:http://grassprogramming.gitee.io/fastdialog-vue/example.html

dialog会提供以下一些常用功能:

引用vue工程版本的js时需要在Vue初始化时进行变量声明,即

 var app1 = new Vue({})

调用方法的形式为app1.$fastdialog.functionname

引用master分支下的直接调用方法即可

1.打开一个html页面

OpenDialog("111", "打开窗口", "newpage1.html", "600", "1200");

2.打开一个html页面并指定宽高的单位

OpenDialog("111", "打开窗口", "newpage1.html", "70", "80",null,null,"%");

3.打开一个html页面传值并制定回调函数

 OpenDialog("444", "有回调函数并传参", "newpage1.html", "600", "1200", AfterCloseWithReturn, "125sds");

这些都是调用的OpenDialog方法,我们来看下这个方法定义的参数

function OpenTopDialog(id, title, url, height, width, callback, params, screenunit)

id:dialog标识,title:dialog的head部分的文字,url:打开的页面地址,height:打开页面的高度,width:打开页面的宽度,callback:关闭打开页面后的父级页面调用的回调函数,params:父级页面给打开的子页面传递的参数,screenunit:打开页面宽高的单位

注:OpenDialog方法是在本级页面打开窗口,该组件同时提供在顶级窗口打开全局页面,为OpenTopDialog,参数完全一致

4.子页面获取父级页面传递的参数

 var params = GetParams();

5.关闭页面

 CloseDialog("page2回传111111","page3");

看下方法定义

function CloseDialog(ReturnValue,id)

第一个参数为页面回传给父级页面的值,配合父级页面使用如下

 function AfterCloseWithReturn(ReturnValue) {
        alert("page1回传的参数:" + ReturnValue);
    }

第二个参数为打开的diaog的id,普通打开页面可以不指定,使用OpenTopDialog的页面必须指定,后面会详细说明

6.提供Alert类型的提示dialog

 OpenAlert("提示", "请在规定期限内处理完成!",AfterClose);

看下提示框打开方法的参数定义

function OpenAlert(title, message, callback, btnclosetext)

第一个参数为提示框标题,第二个参数为提示内容,第三个参数为关闭提示框后的回调函数,第四个参数为关闭按钮文字的个性化指定,同时还有成功,警告,失败等提示框,如下

OpenSuccess("提示", "请在规定期限内处理完成!");
OpenWaring("提示", "请在规定期限内处理完成!",null,"知道了");
OpenFail("提示", "请在规定期限内处理完成!");

7.提供Confirm类型确认框的dialog

 OpenConfirm("确认提示", "是否删除当前数据", function () {

                }, "确认删除", "取消操作");

看下函数定义,相信一看就懂了

function OpenConfirm(title, message, okcallback, btnoktext, btncanceltext)

接下来说一下开发中到问题的解决方案

1.用原生js开发如何动态请求template模板

如果不是用字符串定义的话,直接请求定义模板的html文件即可,这里需要注意的是,引用组件到工程的目录不同,这里需要自己改下,这是缺点1,缺点2是每次打开dialog会有额外的网络请求,所以后续版本采用vue工程形式开发,避免了这种问题

    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工程中的代码)

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,触发监听,进行关闭页面或者调用回调函数的操作,类似于

//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数组即可,看如下代码

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的全局属性注册上去即可

fastdialog.install = function(Vue) {

Vue.prototype.$fastdialog = fastdialog

};

if (typeof window !== 'undefined' && window.Vue) {

window.Vue.use(fastdialog)

}

说在最后:本插件只在chrome浏览器做了测试,还希望大家多多提意见,共同进步,如果觉得还不错的话,记得码云给个Star哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章