基本上每个项目都需要用到模态框组件,由于在最近的项目中,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实现模态框组件的更多相关文章

  1. Angular2+之模态框-使用ngx-bootstrap包中的模态框组件实现

    模态框是项目中经常会用到的一个公共功能,通常会被用左提示框或者扩展选项框. 下面,我用一个小例子来简单展示实现模态框功能的过程: 1.为项目加包: ng add ngx-bootstrap 2.在xx ...

  2. 教你使用HTML5原生对话框元素,轻松创建模态框组件

    HTML 5.2草案加入了新的dialog元素.但是是一种实验技术. 以前,如果我们想要构建任何形式的模式对话框或对话框,我们需要有一个背景,一个关闭按钮,将事件绑定在对话框中的方式安排我们的标记,找 ...

  3. 解决vue中模态框内数据和外面的数据绑定的问题

    1.做表格的修改,把整条数据传到模态框做修改,但是出现模态框改变数据没有保存时,表格的数据也会跟着改变,我想实现保存以后表格数据才会改变的功能. html:使用item整条数据都上传过去了,在upda ...

  4. vue 自定义modal 模态框组件

    参数名 类型 说明 visible Boolean 是否显示,默认false title String 标题 update:visible Boolean 更新visible, 使用:visible. ...

  5. 打造 Vue.js 可复用组件

    Vue.js 是一套构建用户界面的渐进式框架.我们可以使用简单的 API 来实现响应式的数据绑定和组合的视图组件. 从维护视图到维护数据,Vue.js 让我们快速地开发应用.但随着业务代码日益庞大,组 ...

  6. vue2.X 自定义 模态框 modal

    1.自定义 modal Modal.vue <!-- 模态框 --> <template> <div class="modal-mask" v-sho ...

  7. 用jQuery写了一个模态框插件

    用jQuery写了一个模态框插件 大家觉得下面的框框好看么, 水印可以去掉(这个任务交给你们了(- o -)~zZ); "info"框 $("div").con ...

  8. 每日质量NPM包模态框_react-modal

    一.react-modal 官方定义: Accessible modal dialog component for React.JS 理解: 一个容易使用的React模态框组件 二.用法 有时候我们不 ...

  9. 基于Vue.js PC桌面端弹出框组件|vue自定义弹层组件|vue模态框

    vue.js构建的轻量级PC网页端交互式弹层组件VLayer. 前段时间有分享过一个vue移动端弹窗组件,今天给大家分享一个最近开发的vue pc端弹出层组件. VLayer 一款集Alert.Dia ...

随机推荐

  1. 彻底理解ThreadLocal二

    首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的.各 ...

  2. Disabling default console handler in Java Logger by codes

    The open source packages usu. relies on log4j or Java Logger to print logs, by default the console h ...

  3. [Xamarin] 動態載入Fragment (转帖)

    這篇我們來動態加入,一樣務求好懂簡單 1.一樣先將專案調整成3.0以上版本 2.首先建立自定Control的Layout \Resources\Layout\MyControlLayout1.axml ...

  4. Angular Input格式化

    今天在Angular中文群有位同学问到:如何实现对input box的格式化.如下的方式对吗? <input type="text" ng-model="demo. ...

  5. 来看看Windows9到底是什么

    今天有新闻一直在说windows 8.2 windows9,还给出了一张很有趣的图 我们就假设这张图是真的. 这张图透漏出两个信息 其一:开始菜单真的回来了. 不过还是不死心,绝不放弃开始屏,确实,开 ...

  6. LuaAlchemy API 介绍

    The AS3 Sugar provides a Lua-like way to access AS3 class and instance creation, property getter/set ...

  7. XCode v8.11 重量级分表分库(无视海量数据)

    XCode天生就有分表分库功能,设计于2005年!历时9年,这是分表分库功能第一次针对性正式更新. 在XCode里面,分表分库非常简单,在操作数据(查询/更新)前修改Meta.ConnName/Met ...

  8. Jetty 9 源码分析 Connector及Server类(一)

    本文的源码基于Jetty9,主要分析了Jetty 的Connector与Server类间在Jetty启动过程中的一些细节.Jetty9 对以前的Connector体系进行了重构, 结构与6和7都不同, ...

  9. rabbitmq消息队列——"发布订阅"

    三."发布订阅" 上一节的练习中我们创建了一个工作队列.队列中的每条消息都会被发送至一个工作进程.这节,我们将做些完全不同的事情--我们将发送单个消息发送至多个消费者.这种模式就是 ...

  10. mvc 权限设计

    1.http://blog.csdn.net/vera514514/article/details/8285154 2.http://www.cnblogs.com/cmsdn/p/3433995.h ...