详解用vue编写弹出框组件


Posted in Javascript onJuly 04, 2017

前言

最近研究了用vue编写弹出框的组件,发现其实这里面的门道还是有很多的。这篇文完全是用来记录总结下最近的学习成果,同时也希望能够帮得上正在学习纠结的你~ps:本文假设你已经了解vue2.0相关框架,因此适合有一定vue2.0基础的同学阅读。

设计组件的思考

其实单纯的编写一个弹出框组件并不难,写一个模板,然后用v-if或者v-show指令还控制组件的出现与消失。真正困扰我的是,这个组件的调用方式,这个问题纠结了我好久。

调研了下资料,有些人建议,直接把组件标签插进模板中,然后通过直接控制组件的显示隐藏来控制组件。这样写有好处,就是结构清晰,一目了然,人家一看你的代码就知道你这个页面可能会有弹出框,并且编写的组件就更容易,只需关注内部方法就好了,也不存在事件调用的困扰,维护起来也特别容易。但是缺点也很明显,如果有多个弹窗,并且不知道会有几个弹窗的情况下,感觉就不太好做,并且这种提前写模板的形式,难免会在不弹窗的时候要下载一些js文件,有可能会造成性能浪费。

也有些人建议,在写好的弹出框组件之外再做一层封装,通过动态调用的方式来控制弹出框的显示与隐藏。这样写的好处是不用事先在模板里面写好该组件的标签,只需要在想调用的地方调用下该组件,就实现了按需使用的目的,符合之前传统前端框架的编码习惯。缺点就是感觉代码写起来比较复杂,层层嵌套,并且感觉这个与MVVM模式的状态驱动界面的思想相违背。

于是我天秤座的纠结病犯了,在选择哪种技术方案的问题上,思考了很久。但是网上搜了很多,发现还是后一种实现方法用的人比较多。后来我又研究了了elementUI和iView的弹出框组件,他们也是沿用的后一种方法,想了一下后一种方法虽然代码易读性不强,但是它真正模拟了浏览器默认的alert事件,在用户需要的地方来调用,一方面节省了代码量,另一方面也很容易解决多个弹窗的情况。最后还是决定用这种模式写一个简单的弹出框组件。主要是体会这其中的机理。废话不多说,来上干货了。有啥不对的地方还请大家多多指教。(ps:对于天秤座的我,虽然选择了后一种方法,但是内心还是钟爱第一种方法,并且后一种方法并没有足够的理由说服我呀,不知道哪位有识之士能够帮忙点醒一下我,晚辈感激不尽)。

alert组件设计

单独的设计alert弹出框的逻辑是很简单的,我就直接上代码了:

 

<template>
<transition name='fade'>
 <div class="alert" v-if="showAlert">
  <div class="wrap">
   <div class="head">{{title}}</div>
   <div class="body">
    <slot>
     <p>{{message}}</p>
    </slot>
   </div>
   <div class="foot">
    <div v-if="type === 'confirm'">
     <button class="btn-base" @click="sure">确定</button>
     <button class="btn-gray" @click="cancel">取消</button>
    </div>
    <div v-else-if="type === 'inform'">
     <button class="btn-base" @click="cancel">知道了</button>
    </div>
   </div>
  </div>
 </div>
</transition>
</template>
<script>
export default {
 name: 'alert',
 data() {
  return {
   showAlert: false,
  };
 },
 props: {
  title: {
   type: String,
   default: '提示',
  },
  message: {
   type: String,
  },
  type: { // 可以有confirm, 和inform两个类型
   type: String,
   default: 'confirm',
   validator(value) {
    return value === 'confirm' || value === 'inform';
   },
  },
  sureBtn: {
   type: Function,
  },
  cancelBtn: {
   type: Function,
  },
  context: {
   type: Object,
  },
 },
 methods: {
  cancel() {
   if (this.cancelBtn) {
    this.cancelBtn.apply(this.context);
   }
   this.close();
  },
  sure() {
   if (this.sureBtn) {
    this.sureBtn.apply(this.context);
   }
   this.close();
  },
  show() {
   this.showAlert = true;
  },
  close() {
   this.showAlert = false;
  },
 },
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang='scss'>
.alert {
 position: fixed;
 top: 0;
 left: 0;
 right: 0;
 bottom: 0;
 background: rgba(0,0,0, 0.8);
 z-index: 1000;
 transition: all .3s ease-in-out;
}
.wrap {
 position: absolute;
 z-index: 1002;
 min-width: 400px;
 background: #fff;
 left: 50%;
 top: 50%;
 transform: translate(-50%, -50%);
 border-radius: 4px;
}
.head {
 height: 40px;
 line-height: 40px;
 border-bottom: 1px solid #dedede;
 padding-left: 10px;
 color: #333;
}
.body {
 padding: 40px 20px;
 text-align: center;
}
.foot {
 height: 50px;
 text-align: center;
 button {
  margin-right: 20px;
  &:last-child {
   margin-right: 0;
  }
 }
}
</style>

这里只是写了简单的功能,并没有考虑更复杂的情况,比如按钮颜色定制,大小定制,z-index层级的考虑,遮罩层的统一管理等等,只是为了掌握编写弹出框的主要思想,所以没有写太多的情况。这里只细分了是确认框还是通知框,可以定制弹出框的内容、标题等一些简单的常规操作。

其实这个组件写好,就可以在页面用起来了,直接在对应页面插入这段,可以也可以用:

<!--template-->
<button @click="showAlert">点我</button>
<alert ref="alert">我是一个确认框</alert>
<!--javascript-->
...
methods: {
  showAlert() {
    this.$refs.alert.show();
  }
}
...

当然,如果真要这么用,这个组件还是需要修改一些东西的,比如事件抛出,当点击确定或者取消按钮的时候,需要emit对应的事件,以提供给父组件捕获,并做相应的处理。

动态插入到页面中

为了能让组件动态的插入到页面中,需要对上面的组件进行封装,利用Vue.extend机制,可以轻松的做到这种封装,直接上代码:

import Vue from 'vue';
import alert from './alert';
const AlertConstructor = Vue.extend(alert);
const div = document.createElement('div');
AlertConstructor.show = (options) => {
 document.body.appendChild(div);
 options.type = 'inform';
 const propsData = Object.assign({}, options);
 const alertInstance = new AlertConstructor({
  propsData,
 }).$mount(div);
 alertInstance.show();
};
AlertConstructor.confirm = (options) => {
 document.body.appendChild(div);
 options.type = 'confirm';
 const propsData = Object.assign({}, options);
 const alertInstance = new AlertConstructor({
  propsData,
 }).$mount(div);
 alertInstance.show();
};
export default AlertConstructor;

这里,show对应的是通知框,confirm对应的是确认框。我知道这种封装有点简单了,有很多情况没有考虑,比如有多个弹出框时的处理等。这里只是做了简单的封装,为的就是让大家明白此种封装主要思路是什么。

总结

这篇文章仅仅是对自己这几天摸索弹出框组件问题的一个简短的总结与思考。可能还不是很成熟,当做抛砖引玉吧,欢迎大家多多提意见。希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Juqery Html(),append()等方法的Bug解决方法
Dec 13 Javascript
JQuery入门——用bind方法绑定事件处理函数应用介绍
Feb 05 Javascript
jquery插件开发注意事项小结
Jun 04 Javascript
jQuery中toggleClass()方法用法实例
Jan 05 Javascript
jQuery使用fadeout实现元素渐隐效果的方法
Mar 27 Javascript
javascript表单验证大全
Aug 12 Javascript
jQuery实现图片上传和裁剪插件Croppie
Nov 29 Javascript
jQuery实现的跨容器无缝拖动效果代码
Jun 21 Javascript
两行代码轻松搞定JavaScript日期验证
Aug 03 Javascript
Bootstrap如何创建表单
Oct 21 Javascript
Node.js  REPL (交互式解释器)实例详解
Aug 06 Javascript
从源码看angular/material2 中 dialog模块的实现方法
Oct 18 Javascript
使用vue构建一个上传图片表单
Jul 04 #Javascript
vue-resource 拦截器(interceptor)的使用详解
Jul 04 #Javascript
JavaScript在控件上添加倒计时功能的实现代码
Jul 04 #Javascript
JavaScript异步上传图片文件的实例代码
Jul 04 #Javascript
详解vue-router和vue-cli以及组件之间的传值
Jul 04 #Javascript
详解Angular.js中$http拦截器的介绍及使用
Jul 04 #Javascript
详解vue-cli 脚手架项目-package.json
Jul 04 #Javascript
You might like
PHP 简单数组排序实现代码
2009/08/05 PHP
PHP_Cooikes不同页面无法传递的解决方法
2014/03/07 PHP
Laravel中使用阿里云OSS Composer包分享
2015/02/10 PHP
ThinkPHP进程计数类Process用法实例详解
2015/09/25 PHP
Apache无法自动跳转却显示目录的解决方法
2020/11/30 PHP
php array_multisort 对数组进行排序详解及实例代码
2016/10/27 PHP
PHP读取并输出XML文件数据的简单实现方法
2017/12/22 PHP
javascript 火狐(firefox)不显示本地图片问题解决
2008/07/05 Javascript
js 变量类型转换常用函数与代码[比较全]
2009/12/01 Javascript
基于Jquery的表格隔行换色,移动换色,点击换色插件
2010/12/22 Javascript
jquery向.ashx文件post中文乱码问题的解决方法
2011/03/28 Javascript
JS实现图片翻书效果示例代码
2013/09/09 Javascript
jquery事件preventDefault()方法用法实例
2015/01/16 Javascript
JavaScript动态生成二维码图片
2016/04/20 Javascript
jQuery Mobile 和 Kendo UI 的比较
2016/05/05 Javascript
禁用backspace网页回退功能的实现代码
2016/11/15 Javascript
jQuery Validate 数组 全部验证问题
2017/01/12 Javascript
JScript实现地址选择功能
2017/08/15 Javascript
解决JavaScript中0.1+0.2不等于0.3问题
2018/10/23 Javascript
[00:12]DAC2018 Miracle-站上中单舞台,他能否再写奇迹?
2018/04/06 DOTA
Python产生Gnuplot绘图数据的方法
2018/11/09 Python
python实现LBP方法提取图像纹理特征实现分类的步骤
2019/07/11 Python
在PyCharm的 Terminal(终端)切换Python版本的方法
2019/08/02 Python
Python shutil模块用法实例分析
2019/10/02 Python
TensorFlow Autodiff自动微分详解
2020/07/06 Python
Jupyter notebook命令和编辑模式常用快捷键汇总
2020/11/17 Python
常用的四种CSS透明属性介绍
2014/04/12 HTML / CSS
美国最值得信赖的宠物药房:Allivet
2019/03/23 全球购物
电子商务专业个人的自我评价
2013/11/19 职场文书
管理信息系学生的自我评价
2014/01/11 职场文书
乡村卫生服务一体化管理实施方案
2014/03/30 职场文书
公务员学习习总书记“三严三实”思想汇报
2014/09/19 职场文书
2015年乡镇环保工作总结
2015/04/22 职场文书
你对自己的信用报告有过了解吗?
2019/07/09 职场文书
导游词之南京栖霞山
2019/10/18 职场文书
Nginx+Tomcat负载均衡多实例详解
2022/04/11 Servers