利用vue实现模态框组件


Posted in Javascript onDecember 19, 2016

基本上每个项目都需要用到模态框组件,由于在最近的项目中,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.js dynamic create nest modal
es6 Promise对象
vue-bootstrap-modal

本文已被整理到了《Vue.js前端组件学习教程》,欢迎大家学习阅读。

关于vue.js组件的教程,请大家点击专题vue.js组件学习教程进行学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Javascript模块化编程(三)require.js的用法及功能介绍
Jan 17 Javascript
JS实现倒计时和文字滚动的效果实例
Oct 29 Javascript
jquery中show()、hide()和toggle()用法实例
Jan 15 Javascript
JQuery中属性过滤选择器用法实例分析
May 18 Javascript
JavaScript中通过提示框跳转页面的方法
Feb 14 Javascript
检查表单元素的值是否为空的实例代码
Jun 16 Javascript
Bootstrap 过渡效果Transition 模态框(Modal)
Mar 17 Javascript
详解Vue2+Echarts实现多种图表数据可视化Dashboard(附源码)
Mar 21 Javascript
3分钟掌握常用的JS操作JSON方法总结
Apr 25 Javascript
用vue和node写的简易购物车实现
Apr 25 Javascript
微信小程序-可移动菜单的实现过程详解
Jun 24 Javascript
详解gantt甘特图可拖拽、编辑(vue、react都可用 highcharts)
Nov 27 Vue.js
JS中如何实现复选框全选功能
Dec 19 #Javascript
BootStrapValidator校验方式
Dec 19 #Javascript
详解js的延迟对象、跨域、模板引擎、弹出层、AJAX【附实例下载】
Dec 19 #Javascript
JavaScript中this的用法实例分析
Dec 19 #Javascript
JS填写银行卡号每隔4位数字加一个空格
Dec 19 #Javascript
JavaScript中校验银行卡号的实现代码
Dec 19 #Javascript
快速入门Vue
Dec 19 #Javascript
You might like
php设计模式之观察者模式的应用详解
2013/05/21 PHP
thinkphp5框架扩展redis类方法示例
2019/05/06 PHP
javascript 对象比较实现代码
2009/04/27 Javascript
js 数组实现一个类似ruby的迭代器
2009/10/27 Javascript
复制Input内容的js代码_支持所有浏览器,修正了Firefox3.5以上的问题
2010/06/21 Javascript
按钮JS复制文本框和表格的代码
2011/04/01 Javascript
js编码之encodeURIComponent使用介绍(asp,php)
2012/03/01 Javascript
jQuery bxCarousel实现图片滚动切换效果示例代码
2013/05/15 Javascript
实现只能输入数字的input不用replace方法
2013/09/12 Javascript
实例说明为什么不要行内使用javascript
2014/04/18 Javascript
jQuery右下角旋转环状菜单特效代码
2015/08/10 Javascript
jQuery实现简单的列表式导航菜单效果代码
2015/08/31 Javascript
jQuery实现带动画效果的多级下拉菜单代码
2015/09/08 Javascript
Knockout自定义绑定创建方法
2015/12/26 Javascript
js获取鼠标点击的对象,点击另一个按钮删除该对象的实现代码
2016/05/13 Javascript
底部悬浮通栏可以关闭广告位的实现方法
2016/06/01 Javascript
Javascript之Number对象介绍
2016/06/07 Javascript
JavaScript运动框架 多物体任意值运动(三)
2017/05/17 Javascript
详解Axios统一错误处理与后置
2018/09/26 Javascript
VUE中使用MUI方法
2019/02/12 Javascript
layer.open提交子页面的form和layedit文本编辑内容的方法
2019/09/27 Javascript
js实现图片跟随鼠标移动效果
2019/10/16 Javascript
jQuery实现颜色打字机的完整代码
2020/03/19 jQuery
[02:08:58]2014 DOTA2国际邀请赛中国区预选赛 Ne VS CIS
2014/05/22 DOTA
[01:13:08]2018DOTA2亚洲邀请赛4.6 淘汰赛 mineski vs LGD 第二场
2018/04/10 DOTA
Ubuntu 14.04+Django 1.7.1+Nginx+uwsgi部署教程
2014/11/18 Python
Python数据结构之双向链表的定义与使用方法示例
2018/01/16 Python
python实现对csv文件的列的内容读取
2018/07/04 Python
Python实现的对本地host127.0.0.1主机进行扫描端口功能示例
2019/02/15 Python
PyTorch 解决Dataset和Dataloader遇到的问题
2020/01/08 Python
python读取hdfs上的parquet文件方式
2020/06/06 Python
澳大利亚第一的设计师礼服租赁网站:GlamCorner
2017/08/13 全球购物
青年教师培训方案
2014/02/06 职场文书
学校消防安全责任书
2014/07/23 职场文书
代办社保委托书范文
2014/10/06 职场文书
保卫工作个人总结
2015/03/03 职场文书