利用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 相关文章推荐
js常用数组操作方法简明总结
Jun 20 Javascript
JS实现简单的图书馆享元模式实例
Jun 30 Javascript
基于jQuery实现Div窗口震动特效代码-代码简单
Aug 28 Javascript
JavaScript 链式结构序列化详解
Sep 30 Javascript
WEB前端实现裁剪上传图片功能
Oct 17 Javascript
js倒计时显示实例
Dec 11 Javascript
Vue.js实例方法之生命周期详解
Jul 03 Javascript
JavaScript异步上传图片文件的实例代码
Jul 04 Javascript
vue技术分享之你可能不知道的7个秘密
Apr 09 Javascript
ES6 系列之 WeakMap的使用示例
Aug 06 Javascript
如何能分清npm cnpm npx nvm
Jan 17 Javascript
JS代码屏蔽F12,右键,粘贴,复制,剪切,选中,操作实例
Sep 17 Javascript
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 Parse Error: syntax error, unexpected $end 错误的解决办法
2012/06/05 PHP
PHP基本语法总结
2014/09/06 PHP
详解 PHP加密解密字符串函数附源码下载
2015/12/18 PHP
Yii中表单用法实例详解
2016/01/05 PHP
php工具型代码之印章抠图
2018/07/18 PHP
打开超链需要“确认”对话框的方法
2007/03/08 Javascript
List the Codec Files on a Computer
2007/06/18 Javascript
jQuery AJAX回调函数this指向问题
2010/02/08 Javascript
Javascript实现关联数据(Linked Data)查询及注意细节
2013/02/22 Javascript
jQuery异步验证用户名是否存在示例代码
2014/05/21 Javascript
js取得html iframe中的元素和变量值
2014/06/30 Javascript
jQuery ajax调用WCF服务实例
2014/07/16 Javascript
javascript无刷新评论实现方法
2015/05/13 Javascript
JavaScript中的splice()方法使用详解
2015/06/09 Javascript
Javascript编写俄罗斯方块思路及实例
2015/07/07 Javascript
jquery判断密码强度的验证代码
2020/04/22 Javascript
基于javascript实现泡泡大冒险网页版小游戏
2016/03/23 Javascript
使用 bootstrap modal遇到的问题小结
2016/11/09 Javascript
详解Vue监听数据变化原理
2017/03/08 Javascript
Require.JS中的几种define定义方式示例
2017/06/01 Javascript
vuejs使用递归组件实现树形目录的方法
2017/09/30 Javascript
vue 1.0 结合animate.css定义动画效果
2018/07/11 Javascript
微信小程序中使用ECharts 异步加载数据实现图表功能
2018/07/13 Javascript
Layui弹框中数据表格中可双击选择一条数据的实现
2020/05/06 Javascript
详解Python3中字符串中的数字提取方法
2017/01/14 Python
python TKinter获取文本框内容的方法
2018/10/11 Python
用Pycharm实现鼠标滚轮控制字体大小的方法
2019/01/15 Python
详解Python循环作用域与闭包
2019/03/21 Python
Python通用函数实现数组计算的方法
2019/06/13 Python
python tkinter的消息框模块(messagebox,simpledialog)
2020/11/07 Python
使用spring mvc+localResizeIMG实现HTML5端图片压缩上传的功能
2016/12/16 HTML / CSS
乌克兰在线电子产品商店:MTA
2019/11/14 全球购物
六年级学生评语
2014/04/22 职场文书
学校总务处领导班子民主生活会对照检查材料思想汇报
2014/09/27 职场文书
党员自我剖析材料(群众路线)
2014/10/06 职场文书
社区党员群众路线教育实践活动心得体会
2014/11/03 职场文书