vue-弹出框组件

创建一个公用的弹出框组件,包括消息弹出框,确认弹出框,自定义内容弹出框

一、创建

1、创建一个基础弹出框:dialog-base.vue

<template>
<div class="dialog-pop" v-bind:data-level="levelNum" v-bind:style="'z-index:'+zIndex" v-bind:ref="'dialog-'+levelNum">
    <div class="dialog-pop-bg"></div>
    <div   v-bind:class="'dialog-pop-panel '+umMoveClass" v-bind:style="'width:'+initWidth+';height:'+initHeight+';top:'+top+'px;left:'+left+'px;min-height:'+minHeight+';min-width:'+minWidth+';'">
        <div class="dialog-pop-panelmain">
            <div   class="dialog-pop-top">
                <span class="dialog-pop-title">{{title}}</span>
                <button class="dialog-pop-close" type="button" v-on:click.stop="closedialog"></button>
                <button class="dialog-pop-full" type="button" v-on:click.stop="fullScreenCallback" v-if="fullScreen"></button>
                <div v-drag="greet" v-bind:style="'height: 100%;position: absolute;top:0;left: 0;right:'+(fullScreen?'60':'30')+'px;'"></div>
            </div>
            <div class="dialog-pop-body" >
                <dialog-message v-if="dialogType=='0'" v-bind:options="options" v-bind:message="message" ></dialog-message>
                <dialog-confirm v-if="dialogType=='1'" v-bind:options="options" v-bind:message="message"></dialog-confirm>
                <component :is="message" v-if="dialogType=='2'"></component>
            </div>
        </div>
    </div>
</div>
</template>
<script>
import Vue from 'vue';
import '../../css/utils/popupWindow.css'
import '../../css/utils/botton.css'
import message from '../../vue/component/dialog-message.vue';
import confirm from '../../vue/component/dialog-confirms.vue';
Vue.directive('drag',//弹出框拖动指令
    {bind:function (el, binding) {
        let oDiv = el;   //当前元素
        let self = this;  //上下文
        oDiv.onmousedown = function (e) {
            let parent=e.target.parentNode.parentNode.parentNode;
           //鼠标按下,计算当前元素距离可视区的距离
            let disX = e.clientX - parent.offsetLeft;
            let disY = e.clientY - parent.offsetTop;
            document.onmousemove = function (e) {
                //通过事件委托,计算移动的距离
                let l = e.clientX - disX;
                let t = e.clientY - disY;
                //将此时的位置传出去
                binding.value({x:l,y:t})
            };
            document.onmouseup = function (e) {
                document.onmousemove = null;
                document.onmouseup = null;
            };
        };
    }
    }
);
export default {
    name: 'dialog-base',
    data () {
        return {
            dialogType:"0",//弹出框类型:0:消息弹出,1:确认弹出,2::自定义弹出
            options:{},//各种类型弹出框特有参数
            initHeight:"",//初始化高度
            initWidth:"400px",//初始化宽度
            minHeight:"",//最小高度
            minWidth:"",//最小宽度
            levelNum:0,//层级
            top:0,//位置;x
            left:0,//位置:y
            title:'提示',//弹出框标题
            message:null,//弹出框内容
            fullScreen:false,//是否全屏
            zIndex:-1,//显示层级
            oldPosition:{},//存储初始位置
            umMoveClass:''
        }
    },
    components:{
        "dialog-message":message,
        "dialog-confirm": confirm,
    },
    mounted () {
        this.fullScreen=this.options&&this.options.fullScreen?true:false;
        this.minHeight=this.options&&this.options.minHeight?this.options.minHeight:"";
        this.minWidth=this.options&&this.options.minWidth?this.options.minWidth:"";
        //DOM渲染完成
        this.$nextTick(function () {
           this.windowResize();
        });
        window.onresize = (function resize() {
            this.windowResize();
        }).bind(this);
    },
    methods: {
        greet(val){
            let x=val.x;
            let y=val.y;
            if(x<0)x=0;
            if(y<0)y=0;
            this.left=x;
            this.top=y;
        },
        closedialog(e){
            if (this.options && typeof this.options.closeCallback == "function") {
                this.options.closeCallback();
            }
            let pop=this.$refs['dialog-'+this.levelNum];
            if(pop){
                document.querySelector('body').removeChild(pop);
            }

        },
       //窗口改变时间
        windowResize(){
            if(this.umMoveClass){//如果为最大化窗口,窗口样式不需改变,仅调用改变窗口的回调函数
                if (this.options && typeof this.options.fullScreenCallback == "function") {
                    this.options.fullScreenCallback();
                }
                return;
            }
            let winWidth=document.documentElement.clientWidth;
            let winHeight=document.documentElement.clientHeight;
            let width=this.$refs['dialog-'+this.levelNum].getElementsByClassName("dialog-pop-panel")[0].offsetWidth;
            let height=this.$refs['dialog-'+this.levelNum].getElementsByClassName("dialog-pop-panel")[0].offsetHeight;
            this.top= Math.max(20,(winHeight-height)/2-10);
            this.left=(winWidth-width)/2;
            if(this.top<0)this.top=0;
            if(this.left<0)this.left=0;
            this.zIndex=1000+this.levelNum*100;
            this.oldPosition={
                oldHeigth:this.initHeight,
                oldWidth:this.initWidth,//初始化宽度
                oldtop:this.top,//位置;x
                oldleft:this.left,//位置:y
            }
        },
//全屏或者恢复弹窗大小是的回调
        fullScreenCallback(){
            if (this.options && typeof this.options.fullScreenCallback == "function") {
                this.options.fullScreenCallback();
            }
            if(this.umMoveClass){//已经是最大化窗口,点击后需要恢复正常大小
                this.umMoveClass='';
                this.top=this.oldPosition.oldtop;
                this.left=this.oldPosition.oldleft;
                this.initWidth=this.oldPosition.oldWidth;
                this.initHeight=this.oldPosition.oldHeigth;
            }else{
                this.umMoveClass='dialog-pop-ummove';
                this.top=0;
                this.left=0;
                this.initWidth="100%";
                this.initHeight="100%";
            }

        }
    }
}
</script>

2、创建一个消息弹出框:dialog-message.vue

<template>
<div class="dialog-msg">
    <div class="dialogmsg-content">{{message}}</div>
    <i v-bind:class="'dialogicon '+iClass"></i>
    <div class="dialogmsg-bottom">
        <button class="dialogbtn-detail" type="button" v-if="options.detailMessage!=''" v-on:click="showDetail"><i v-bind:class="detailClass"></i>显示详细信息</button>
        <button class="mt-btn__type1 dialogbtn-ok" type="button" v-on:click="closedialog">确认</button>
        <transition name="fade">
            <div class="dialogmsg-detail" v-if="isShowDetail" v-bind:style="'overflow:'+overflow">
                {{options.detailMessage}}
            </div>
        </transition>
    </div>
</div>
</template>

<script>
export default {
    name: 'dialog-message',
    props:{
        message:{
            type:String,
            required:true
        },
        options:{
            type:Object,
            required:true,
        }
    },
    data () {
        return {
            isShowDetail:false,
            levelNum:20,
            iClass:'dialogicon-1',
            detailClass:'dialogbtn-ddown',
            overflow:'hidden'
        }
    },
    mounted () {
        if(this.options&&this.options.iType){
            this.iClass="dialogicon-"+this.options.iType;
        }
    },
    methods: {
        closedialog:function () {
            if(this.options&&typeof this.options.callbackMessageOK === "function"){
                this.options.callbackMessageOK(111);
            }
            this.$parent.closedialog();

        },
        showDetail:function(){
            if(this.isShowDetail){
                this.isShowDetail=false;
                this.overflow="hidden";
                this.detailClass="dialogbtn-ddown"
            }else{
                this.isShowDetail=true;
                this.detailClass="dialogbtn-dup";
                this.overflow="auto";

            }
        }
    }
}
</script>

2、创建一个确认弹出框:dialog-confirms.vue

<template>
<div class="dialog-msg">
    <div class="dialogconf-content">
        {{message}}
    </div>
    <i class="dialogicon dialogicon-4"></i>
    <div class="dialogconf-bottom">
        <button class="mt-btn__type1 dialogbtn-yes" type="button" v-on:click="yesCallbackFunction">  {{yesText}}  </button>
        <button class="mt-btn__type3 dialogbtn-no" type="button" v-on:click="noCallbackFunction"> {{noText}} </button>
    </div>
</div>
</template>

<script>
export default {
    name: 'dialog-confirm',
    props:{
        message:{
            type:String,
            required:true
        },
        options:{
            type:Object,
            required:true,
        }
    },
    data () {
        return {
            yesText:'确认',
            noText:'取消',
            confirmData:null,
        }
    },
    mounted () {
        if(this.options&&this.options.yesText){
            this.yesText=this.options.yesText;
        }
        if(this.options&&this.options.noText){
            this.noText=this.options.noText;
        }
        if(this.options&&this.options.data){
            this.confirmData=this.options.data;
        }
        this.iClass="dialogicon-"+this.iType;
    },
    methods: {
        yesCallbackFunction () {
            try{
                if(this.options&&typeof this.options.yesCallbackFunction === "function"){
                    let result=this.options.yesCallbackFunction(this.confirmData);
                    if (typeof result == "boolean" && result == false) {
                        return;
                    }
                }
            }
            catch(e){
            }
            this.closeDialog();
        },
        noCallbackFunction(){
            try{
                if(this.options&&typeof this.options.noCallbackFunction === "function"){
                    let result=this.options.noCallbackFunction(this.confirmData);
                    if (typeof result == "boolean" && result == false) {
                        return;
                    }
                }
            }
            catch(e){
            }
            this.closeDialog();
        },
        closeDialog(){
            this.confirmData=null;
            this.$parent.closedialog();
        }
    },

}
</script>

3、创建一个自定义出框:自定义.vue

    创建一个任意内容vue文件

二、调用

1、创建供调用的接口文件:dialogUtil.js

import Vue from 'vue'
import Message from '../../vue/component/dialog-base.vue'
export default{
installDialog(){
    return {
        message:this.installMessage.bind(this),
        confirm:this.installConfirm.bind(this),
        subPop:this.installSubPop.bind(this),
    }
},
/*
* 消息弹窗框
* options={
*    title:'',
*    message:'',
*    options:{
*       detailMessage:'',
*       iType:'1',//枚举值:1,2,3(警告类型图标,提示类型图标等,配合css使用)
*       callbackMessageOK:func
*    },
* }
* */
installMessage(options) {
    options.dialogType='0';
    options.initWidth="400px";
    options.levelNum=20;
    this.initBase(options);

},
/*
* 确认弹窗框
* options={
*    title:"",
*    message:"",
*    options:{
*       yesCallbackFunction:func,
*       noCallbackFunction:func,
*       yesText:'',
*       noText:'',
*       data:{}  //点击确认传给回调的数据
*    },
* }
* */
installConfirm(options) {
    options.dialogType='1';
    options.initWidth="400px";
    options.levelNum=10;
    this.initBase(options);
},
/* 弹出框
*  包含:子弹出窗(levelNum为0-9),通知框,确认框,加载中信息框
*  参数:
*  options={
*      titleText:string,标题
*      elemText:string,弹窗的html内容
*      levelNum:int,Z轴上的层,分0-9层(可缺,默认值为0)
*      initWidth: string('400px'),初始化宽度(可缺)(此参数在手机浏览器上不生效,采用固定值:96%)
*      initHeight: string,初始化高度(可缺)
*      options:{
*            minWidth: string,最小宽度,仅用于手机浏览器(可缺)
*            minHeight: string,最小高度,仅用于手机浏览器(可缺)
*            fullScreen:bool,是否显示全屏按钮(可缺)
*            fullScreenCallback:func,点击全屏按钮的回调函数(可缺)
*            closeCallback:func,点击窗口关闭事件的回调函数(可缺)
*    }
*  }
*/
installSubPop(options) {
    options.dialogType='2';
    options.levelNum=0;
    this.initBase(options);
},
initBase(options){
    var message = Vue.extend(Message)
    var component = new message({
        data: options
    }).$mount()
    document.querySelector('body').appendChild(component.$el)
  }
}

2、引入消息弹窗组件

import dialogMessage from '../utils/dialogUtil.js';
Vue.prototype.$installdialog = dialogMessage.installDialog();

3、使用弹窗

//消息弹窗    
let options= {
       title: "提示",
       message: "内容",
       options: {
            detailMessage: "detail",
            iType: "2",
           //callbackMessageOK:this.yesCallback.bind(this)
        }
   };
 this.$installdialog.message(options);
//确认弹窗
let options={
       title:"提示",
       message:"确定是否?",
       options:{
            yesCallbackFunction:this.yesCallbackFunction,
           //  noCallbackFunction:this.noCallbackFunction,
            //  yesText:'',
          //   noText:'',
                data:{
                    test:'111'
           }
        }
   }
 this.$installdialog.confirm(options);
//自定义弹窗
import page from "./page.vue";
let options={
            title:"弹出",
            message:page,
            initWidth:"300px",
            initHeight:"200px",
            options:{
                minWidth:"400px",
                minHeight:"300px",
                fullScreen:true,
                fullScreenCallback:this.fullScreenCallback,
                closeCallback:this.yesCallback,
            }

        }
        this.$installdialog.subPop(options);

    碰到一个问题 如果把v-drag 绑定到dialog-pop-top上,点击关闭按钮时会先触发drag事件,再点击一次才会正常关闭,阻止冒泡也没用,不知道是何原因。。。。
    新手入门,欢迎指正,接受批评!!!!

github地址:https://github.com/zh-huan/dialog-util

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容