用vue实现模态框组件
基本上每个项目都需要用到模态框组件,由于在最近的项目中,alert组件和confirm是两套完全不一样的设计,所以我将他们分成了两个组件,本文主要讨论的是confirm组件的实现。
组件结构
<template>
    <div class="modal" v-show="show" transition="fade">
        <div class="modal-dialog">
            <div class="modal-content">
                <!--头部-->
                <div class="modal-header">
                    <slot name="header">
                        <p class="title">{{modal.title}}</p>
                    </slot>
                    <a v-touch:tap="close(0)" class="close" href="javascript:void(0)"></a>
                </div>
                <!--内容区域-->
                <div class="modal-body">
                    <slot name="body">
                        <p class="notice">{{modal.text}}</p>
                    </slot>
                </div>
                <!--尾部,操作按钮-->
                <div class="modal-footer">
                    <slot name="button">
                        <a v-if="modal.showCancelButton" href="javascript:void(0)" class="button {{modal.cancelButtonClass}}" v-touch:tap="close(1)">{{modal.cancelButtonText}}</a>
                        <a v-if="modal.showConfirmButton" href="javascript:void(0)" class="button {{modal.confirmButtonClass}}" v-touch:tap="submit">{{modal.confirmButtonText}}</a>
                    </slot>
                </div>
            </div>
        </div>
    </div>
    <div v-show="show" class="modal-backup" transition="fade"></div>
</template>
模态框结构分为三部分,分别为头部、内部区域和操作区域,都提供了slot,可以根据需要定制。
样式
.modal {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 1001;
    -webkit-overflow-scrolling: touch;
    outline: 0;
    overflow: scroll;
    margin: 30/@rate auto;
}
.modal-dialog {
    position: absolute;
    left: 50%;
    top: 0;
    transform: translate(-50%,0);
    width: 690/@rate;
    padding: 50/@rate 40/@rate;
    background: #fff;
}
.modal-backup {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1000;
    background: rgba(0, 0, 0, 0.5);
}
这里只是一些基本样式,没什么好说的,这次项目是在移动端,用了淘宝的自适应布局方案,@rate是切稿时候的转换率。
接口定义
/**
 * modal 模态接口参数
 * @param {string} modal.title 模态框标题
 * @param {string} modal.text 模态框内容
 * @param {boolean} modal.showCancelButton 是否显示取消按钮
 * @param {string} modal.cancelButtonClass 取消按钮样式
 * @param {string} modal.cancelButtonText 取消按钮文字
 * @param {string} modal.showConfirmButton 是否显示确定按钮
 * @param {string} modal.confirmButtonClass 确定按钮样式
 * @param {string} modal.confirmButtonText 确定按钮标文字
 */
props: ['modalOptions'],
computed: {
    /**
     * 格式化props进来的参数,对参数赋予默认值
     */
    modal: {
        get() {
            let modal = this.modalOptions;
            modal = {
                title: modal.title || '提示',
                text: modal.text,
                showCancelButton: typeof modal.showCancelButton === 'undefined' ? true : modal.showCancelButton,
                cancelButtonClass: modal.cancelButtonClass ? modal.showCancelButton : 'btn-default',
                cancelButtonText: modal.cancelButtonText ? modal.cancelButtonText : '取消',
                showConfirmButton: typeof modal.showConfirmButton === 'undefined' ? true : modal.cancelButtonClass,
                confirmButtonClass: modal.confirmButtonClass ? modal.confirmButtonClass : 'btn-active',
                confirmButtonText: modal.confirmButtonText ? modal.confirmButtonText : '确定',
            };
            return modal;
        },
    },
},
这里定义了接口的参数,可以自定义标题、内容、是否显示按钮和按钮的样式,用一个computed来做参数默认值的控制。
模态框内部方法
data() {
    return {
        show: false,   // 是否显示模态框
        resolve: '',
        reject: '',
        promise: '',  // 保存promise对象
    };
},
methods: {
    /**
     * 确定,将promise断定为完成态
     */
    submit() {
        this.resolve('submit');
    },
    /**
     * 关闭,将promise断定为reject状态
     * @param type {number} 关闭的方式 0表示关闭按钮关闭,1表示取消按钮关闭
     */
    close(type) {
        this.show = false;
        this.reject(type);
    },
    /**
     * 显示confirm弹出,并创建promise对象
     * @returns {Promise}
     */
    confirm() {
        this.show = true;
        this.promise = new Promise((resolve, reject) => {
            this.resolve = resolve;
            this.reject = reject;
        });
        return this.promise;   //返回promise对象,给父级组件调用
    },
},
在模态框内部定义了三个方法,最核心部分confirm方法,这是一个定义在模态框内部,但是是给使用模态框的父级组件调用的方法,该方法返回的是一个promise对象,并将resolve和reject存放于modal组件的data中,点击取消按钮时,断定为reject状态,并将模态框关闭掉,点确定按钮时,断定为resolve状态,模态框没有关闭,由调用modal组件的父级组件的回调处理完成后手动控制关闭模态框。
调用
<!-- template -->
<confirm v-ref:dialog :modal-options.sync="modal"></confirm>
<!-- methods -->
this.$refs.dialog.confirm().then(() => {
    // 点击确定按钮的回调处理
    callback();
    this.$refs.dialog.show = false;
}).catch(() => {
    // 点击取消按钮的回调处理
    callback();
});
用v-ref创建一个索引,就很方便拿到模态框组件内部的方法了。这样一个模态框组件就完成了。
其他实现方法
在模态框组件中,比较难实现的应该是点击确定和取消按钮时,父级的回调处理,我在做这个组件时,也参考了一些其实实现方案。
使用事件转发
这个方法是我的同事实现的,用在上一个项目,采用的是$dispatch和$broadcast来派发或广播事件。
首先在根组件接收dispatch过来的transmit事件,再将transmit事件传递过来的eventName广播下去
events: {
    /**
     * 转发事件
     * @param  {string} eventName 事件名称
     * @param  {object} arg       事件参数
     * @return {null}
     */
    'transmit': function (eventName, arg) {
        this.$broadcast(eventName, arg);
    }
},
其次是模态框组件内部接收从父级组件传递过来的确定和取消按钮所触发的事件名,点击取消和确定按钮的时候触发
// 接收事件,获得需要取消和确定按钮的事件名
events: {
    'tip': function(obj) {
        this.events = {
            cancel: obj.events.cancel,
            confirm: obj.events.confirm
        }
    }
}
// 取消按钮
cancel:function() {
    this.$dispatch('transmit',this.events.cancel);
}
// 确定按钮
submit: function() {
    this.$dispatch('transmit',this.events.submit);
}
在父级组件中调用模态框如下:
this.$dispatch('transmit','tip',{
    events: {
        confirm: 'confirmEvent'
    }
});
this.$once('confirmEvent',function() {
    callback();
}
先是传递tip事件,将事件名传递给模态框,再用$once监听确定或取消按钮所触发的事件,事件触发后进行回调。
这种方法看起来是不是很晕?所以vue 2.0取消了$dispatch和$broadcast,我们在最近的项目中虽然还在用1.0,但是也不再用$dispatch和$broadcast,方便以后的升级。
使用emit来触发
这种方法来自vue-bootstrap-modal,点击取消和确定按钮的时候分别emit一个事件,直接在组件上监听这个事件,这种做法的好处是事件比较容易追踪。
// 确定按钮
ok () {
    this.$emit('ok');
    if (this.closeWhenOK) {
        this.show = false;
    }
},
// 取消按钮
cancel () {
    this.$emit('cancel');
    this.show = false;
},
调用:
<modal title="Modal Title" :show.sync="show" @ok="ok" @cancel="cancel">
    Modal Text
</modal>
但是我们在使用的时候经常会遇到这样的场景,在一个组件的内部,经常会用到多个对话框,对话框可能只是文字有点区别,回调不同,这时就需要在template中为每个对话框都写一次,有点麻烦。
参考资料
照例放张公众号的二维码,欢迎关注哈:
用vue实现模态框组件的更多相关文章
- Angular2+之模态框-使用ngx-bootstrap包中的模态框组件实现
		模态框是项目中经常会用到的一个公共功能,通常会被用左提示框或者扩展选项框. 下面,我用一个小例子来简单展示实现模态框功能的过程: 1.为项目加包: ng add ngx-bootstrap 2.在xx ... 
- 教你使用HTML5原生对话框元素,轻松创建模态框组件
		HTML 5.2草案加入了新的dialog元素.但是是一种实验技术. 以前,如果我们想要构建任何形式的模式对话框或对话框,我们需要有一个背景,一个关闭按钮,将事件绑定在对话框中的方式安排我们的标记,找 ... 
- 解决vue中模态框内数据和外面的数据绑定的问题
		1.做表格的修改,把整条数据传到模态框做修改,但是出现模态框改变数据没有保存时,表格的数据也会跟着改变,我想实现保存以后表格数据才会改变的功能. html:使用item整条数据都上传过去了,在upda ... 
- vue 自定义modal 模态框组件
		参数名 类型 说明 visible Boolean 是否显示,默认false title String 标题 update:visible Boolean 更新visible, 使用:visible. ... 
- 打造 Vue.js 可复用组件
		Vue.js 是一套构建用户界面的渐进式框架.我们可以使用简单的 API 来实现响应式的数据绑定和组合的视图组件. 从维护视图到维护数据,Vue.js 让我们快速地开发应用.但随着业务代码日益庞大,组 ... 
- vue2.X 自定义 模态框 modal
		1.自定义 modal Modal.vue <!-- 模态框 --> <template> <div class="modal-mask" v-sho ... 
- 用jQuery写了一个模态框插件
		用jQuery写了一个模态框插件 大家觉得下面的框框好看么, 水印可以去掉(这个任务交给你们了(- o -)~zZ); "info"框 $("div").con ... 
- 每日质量NPM包模态框_react-modal
		一.react-modal 官方定义: Accessible modal dialog component for React.JS 理解: 一个容易使用的React模态框组件 二.用法 有时候我们不 ... 
- 基于Vue.js PC桌面端弹出框组件|vue自定义弹层组件|vue模态框
		vue.js构建的轻量级PC网页端交互式弹层组件VLayer. 前段时间有分享过一个vue移动端弹窗组件,今天给大家分享一个最近开发的vue pc端弹出层组件. VLayer 一款集Alert.Dia ... 
随机推荐
- IOS 获取当前对象所在的VC
			id next = [self nextResponder] ; while (next != nil) { next = [next nextResponder]; if ([next isKind ... 
- Windows Azure 服务器时间问题
			最近一直在做学校的一个小项目,前期在没有服务器端的情况下意淫做出来了手机客户端.在寒假里使用ASP.NET快速做了一个网站并且设计好了需要使用其他内容,在Windows Azure上测试评估,为学校的 ... 
- VS2012编译的Windows服务启动后立即停止的解决方案
			ATL中的BUG,在没有COM的服务中,使用_ATL_NO_COM_SUPPORT. 并在服务中添加下面的代码 #if defined(_ATL_NO_COM_SUPPORT) HRESULT Pre ... 
- 使用Guava提供的transform批量转换
			实际开发了,为了快速查询,我们会把日期以Long类型的方式存储到数据库中,比如20000000000000L,但显示的时候,要完整的日期,即yyyy-MM-dd的格式显示. 这个时候,我们就可以使用C ... 
- 【转】优化Web程序的最佳实践
			自动排版有点乱,看着蛋疼,建议下载中文PDF版阅读或阅读英文原文. Yahoo!的Exceptional Performance团队为改善Web性能带来最佳实践.他们为此进行了 一系列的实验.开发了各 ... 
- Weibo用户地图
			1.1.1 摘要 现在,许多应用都提供地理位置定位的功能,只要用户开放他们的位置信息就可以实现定位了,今天我们将创建一个基于Google 地图的微博用户地图,这里我们将通过Weibo API获取微博用 ... 
- html5 postMessage解决跨域、跨窗口消息传递
			一些麻烦事儿 平时做web开发的时候关于消息传递,除了客户端与服务器传值还有几个经常会遇到的问题 1.页面和其打开的新窗口的数据传递 2.多窗口之间消息传递 3.页面与嵌套的iframe消息传递 4. ... 
- 在github上写个人简历——最简单却又不容易的内容罗列
			前篇博客分享了一下自己初入github的过程,傻瓜式一步步搭建好主页后,终于该做正事儿了——写简历.在脑袋中构思了很多版本,最后终于决定,先写一个最传统的版本,于是我在箱子中翻出我word版本的简历, ... 
- AI-随机迷宫&迷宫求解
			本文记录了,人工智能中简单的搜索策略中的路径搜索策略中的A*算法,来实现迷宫寻路的问题.(这只是一次本人的课外作业) 完整的程序源码已经发送到我的Git.这里只记录了我的思路和感想以及收获. 产生随机 ... 
- 杂谈X509证书, Java Keystore与Jetty
			很多人对JSSE组成部分的Key Tool 工具不太明白,希望本文能有帮助 科班出身的同学应该学过课程“密码学”, 这门课详细解释了现代对称加密的算法原理, 当时学的我云里雾里. 直到现在使用过SSL ... 
