Vue组件系列开发之模态框


Posted in Javascript onApril 18, 2019

项目基础工程文件是使用vue-cli3.0搭建的,这里不过多介绍。开发Vue组件系列之模态框,主要有标题、内容、定时器、按钮文案、按钮事件回调、遮罩层这些可配置项。本次开发得组件是本系列的第一个组件,后期也会有更多系列教程推出。

使用命令行

$ Vue create echi-modal
$ cd echi-modal
$ npm install
$ npm run serve
$ npm run build
$ npm run lint

添加vue.config.js文件,配置如下

const path = require("path");

function resolve(dir) {
 return path.join(__dirname, dir);
}

module.exports = {
 // 基本路径
 publicPath: "./",
 // eslint-loader 是否在保存的时候检查
 lintOnSave: false,
 // webpack配置
 // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
 chainWebpack: config => {
 config.resolve.alias
  .set("@", resolve("src"))
 },
 // 生产环境是否生成 sourceMap 文件
 productionSourceMap: false,
 // css相关配置
 css: {
 // 是否使用css分离插件 ExtractTextPlugin
 extract: true,
 // 开启 CSS source maps?
 sourceMap: false,
 // css预设器配置项
 loaderOptions: {},
 // 启用 CSS modules for all css / pre-processor files.
 modules: false
 },
 // use thread-loader for babel & TS in production build
 // enabled by default if the machine has more than 1 cores
 parallel: require("os").cpus().length > 1,
 devServer: {
 port: 9595, // 端口号
 open: true, // 自动开启浏览器
 compress: true, // 开启压缩
 overlay: {
  warnings: true,
  errors: true
 }
 }
};

项目结构

├── src       # 项目源码。开发的时候代码写在这里。
│ ├── components     # 组件目录
| | |--EchiModal    # 模态框组件
│ ├── App.vue     # 项目根视图
│ ├── main.js     # 程序主入口

部分截图

Vue组件系列开发之模态框

Vue组件系列开发之模态框

Vue组件系列开发之模态框

modal组件模板

使用 transition 可以为组件添加动效;对应的组件模板内容如下

<template>
 <transition name="toggle">
 <section class="modal" v-show="visible">
  <div class="modal-mask" v-show="showMask" @click="clickMask"></div>
  <section class="modal-content modal-center" :style="contentStyle">
  <header class="modal-header" :class="{ 'modal-plain': plain }" v-if="showHeader">
   <slot name="header">{{ title }}</slot>
   <span class="closed" v-if="showClose" @click.stop="onClose">
   关闭
   </span>
  </header>
  <main class="modal-body">
   <slot>
   <div class="text-tips">{{ text }}</div>
   </slot>
  </main>
  <footer class="modal-footer" v-if="showFooter">
   <slot name="footer">
   <button class="modal-btn modal-btn-primary" @click.stop="onConfirm">
    {{ confirmBtnText }}
   </button>
   <button class="modal-btn modal-btn-default" @click.stop="onClose">
    {{ cancelBtnText }}
   </button>
   </slot>
  </footer>
  </section>
 </section>
 </transition>
</template>

添加组件属性及操作方法

添加组件的属性,其中duration属性如果设定的数值小于10,则会乘以1000;否则按传递的数值计算

<script>
 export default {
 name: "EchiModal",
 props: {
  visible: {
  type: Boolean,
  default: false
  },
  title: {
  type: String,
  default: "标题"
  },
  text: {
  type: String,
  default: "提示信息"
  },
  tinyBar: {
  type: Boolean,
  default: false
  },
  confirmBtnText: {
  type: String,
  default: "确定"
  },
  cancelBtnText: {
  type: String,
  default: "返回"
  },
  contentStyle: {
  type: Object,
  default: () => {}
  },
  showClose: {
  type: Boolean,
  default: true
  },
  plain: {
  type: Boolean,
  default: false
  },
  showHeader: {
  type: Boolean,
  default: true
  },
  showFooter: {
  type: Boolean,
  default: true
  },
  showMask: {
  type: Boolean,
  default: true
  },
  onMask: {
  type: Boolean,
  default: false
  },
  duration: {
  type: Number,
  default: 0
  }
 },
 watch: {
  visible(nv) {
  if (nv) {
   this.closeTimerHandle()
  }
  }
 },
 data() {
  return {
  closeTimer: null,
  }
 },
 methods: {
  onClose() {
  this.$emit("on-close");
  this.hide();
  },
  onConfirm() {
  this.$emit("on-confirm");
  },
  hide() {
  this.$emit("update:visible", false);
  this.$emit("on-closed");
  clearTimeout(this.closeTimer);
  this.closeTimer = null;
  },
  clickMask() {
  if (this.onMask && this.showMask) {
   this.hide();
  }
  },
  closeTimerHandle() {
  try {
   if (this.duration <= 0) {
   return;
   }
   const duration = (this.duration < 10) ? (this.duration * 1000) : this.duration;
   clearTimeout(this.closeTimer);
   this.closeTimer = setTimeout(() => {
   this.onClose();
   }, duration);
  } catch (e) {
   console.log(e)
  }
  }
 }
 };
</script>

添加样式声明

<style scoped lang="scss">
 *,
 :after,
 :before {
 box-sizing: border-box;
 outline: none;
 -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
 }

 $color-tips: #1ab394;
 $color-text: rgba(255, 255, 255, 0.6);
 $color-info: #ff9900;
 $color-default: #ccc;

 .modal {
 display: block;
 width: 100%;
 height: 100%;
 position: fixed;
 top: 0;
 left: 0;
 z-index: 99;

 .modal-mask {
  display: block;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.5);
 }

 .modal-center {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
 }

 .modal-content {
  display: flex;
  flex-direction: column;
  min-width: 360px;
  box-shadow: 0 1px 8px 0 rgba(0, 30, 24, 0.05);
  background-color: #fff;
  border-radius: 6px;
  overflow: hidden;
 }

 .modal-header {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 44px;
  font-size: 18px;
  padding: 0 20px;
  font-weight: 500;
  color: #fff;
  background-color: $color-tips;
  z-index: 9999;

  .closed {
  position: absolute;
  top: 50%;
  right: 0;
  font-size: 12px;
  padding: 8px 16px;
  border-radius: 4px;
  cursor: pointer;
  color: #fff;
  transform: translateY(-50%);
  }

  &.modal-plain {
  background-color: rgba(245,
   245,
   245,
   1);
  color: $color-tips;

  .closed {
   color: $color-info;
  }
  }
 }

 .modal-body {
  display: block;
  flex: 1;
  background-color: #fff;
  overflow: hidden;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
 }

 .modal-footer {
  display: block;
  width: 100%;
  padding: 20px 30px;
  text-align: center;
  background-color: #fff;

  .modal-btn {
  width: 80px;

  +.modal-btn {
   margin-left: 8px;
  }
  }
 }
 }

 .text-tips {
 display: block;
 width: 100%;
 font-size: 16px;
 text-align: center;
 color: #333;
 padding: 40px 60px;
 }

 .modal-btn {
 display: inline-flex;
 padding: 0 12;
 margin: 0;
 align-items: center;
 justify-content: center;
 font-size: 14px;
 font-weight: 400;
 height: 32px;
 text-align: center;
 white-space: nowrap;
 touch-action: manipulation;
 -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
 cursor: pointer;
 user-select: none;
 background-image: none;
 text-decoration: none;
 border: 1px solid transparent;
 border-radius: 4px;
 transition: all .3s ease;

 &:link,
 &:visited,
 &:hover,
 &:active {
  text-decoration: none;
 }
 }

 .modal-btn-default {
 background-color: $color-default;
 color: #fff;

 &:link {
  color: #fff;
  background-color: $color-default;
 }

 &:visited {
  color: #fff;
  background-color: $color-default;
 }

 &:hover {
  color: #fff;
  background-color: rgba(170, 170, 170, .85);
 }

 &:active {
  color: #fff;
  background-color: $color-default;
 }

 &[plain] {
  background-color: #fff;
  color: $color-default;
  border: 1px solid $color-default;
 }
 }

 .modal-btn-primary {
 background-color: $color-tips;
 color: #fff;

 &:link {
  color: #fff;
  background-color: $color-tips;
 }

 &:visited {
  color: #fff;
  background-color: $color-tips;
 }

 &:hover {
  color: #fff;
  background-color: rgba(26, 179, 148, 0.85);
 }

 &:active {
  color: #fff;
  background-color: $color-tips;
 }

 &[plain] {
  background-color: #fff;
  color: $color-tips;
  border: 1px solid $color-tips;
 }
 }

 .toggle-enter,
 .toggle-leave-active {
 opacity: 0;
 transform: translatey(-10px);
 }

 .toggle-enter-active,
 .toggle-leave-active {
 transition: all ease .2s;
 }
</style>

使用

<template>
 <div id="app">
 <img alt="Vue logo" src="./assets/logo.png" />
 <div>
  <button @click.stop="showModel_0 = true">
  显示默认样式
  </button>
  <button @click.stop="showModel_1 = true">
  显示素样式
  </button>
  <button @click.stop="showModel_2 = true">
  修改提示语
  </button>
  <button @click.stop="showModel_3 = true">
  自定义内容
  </button>
  <button @click.stop="showModel_4 = true">
  去除Footer
  </button>
  <button @click.stop="showModel_5 = true">
  去除Header
  </button>
  <button @click.stop="showModel_6 = true">
  设置3秒后自动关闭
  </button>
 </div>
 <EchiModal :visible.sync="showModel_0" title="显示默认样式"></EchiModal>
 <EchiModal :visible.sync="showModel_1" title="显示素样式" plain></EchiModal>
 <EchiModal :visible.sync="showModel_2" title="修改提示语" text="哈哈哈哈哈,我把提示信息修改了"></EchiModal>
 <EchiModal :visible.sync="showModel_3" title="自定义内容" :contentStyle="{width: '600px'}">
  <img alt="Vue logo" src="./assets/logo.png" />
 </EchiModal>
 <EchiModal :visible.sync="showModel_4" title="去除Footer" :showFooter="false"></EchiModal>
 <EchiModal :visible.sync="showModel_5" title="去除Header" :showHeader="false"></EchiModal>
 <EchiModal :visible.sync="showModel_6" title="设置3秒后自动关闭" :duration="3"></EchiModal>
 </div>
</template>

<script>
 import EchiModal from "./components/EchiModal.vue";

 export default {
 name: "app",
 components: {
  EchiModal
 },
 data() {
  return {
  showModel_0: false,
  showModel_1: false,
  showModel_2: false,
  showModel_3: false,
  showModel_4: false,
  showModel_5: false,
  showModel_6: false,
  }
 }
 };
</script>

感谢那您的观看,以上就是我为大家带来的模态框组件,本文同步更新于我的github点击前往。

Javascript 相关文章推荐
Firefox和IE浏览器兼容JS脚本写法小结
Jul 07 Javascript
jQuery+.net实现浏览更多内容(改编php版本)
Mar 28 Javascript
获取元素距离浏览器周边的位置的方法getBoundingClientRect
Apr 17 Javascript
JQuery中$(document)是什么意思有什么作用
Jul 21 Javascript
dreamweaver 8实现Jquery自动提示
Dec 04 Javascript
JQuery插件Quicksand实现超炫的动画洗牌效果
May 03 Javascript
原生JS实现的放大镜效果实例代码
Oct 15 Javascript
原生JS实现图片左右轮播
Dec 30 Javascript
fetch 使用及如何接收JS传值
Nov 11 Javascript
vue中设置、获取、删除cookie的方法
Sep 21 Javascript
laypage.js分页插件使用方法详解
Jul 27 Javascript
微信小程序实现列表滚动头部吸顶的示例代码
Jul 12 Javascript
详解vue的数据劫持以及操作数组的坑
Apr 18 #Javascript
微信小程序 setData 对 data数据影响问题
Apr 18 #Javascript
详解JavaScript中关于this指向的4种情况
Apr 18 #Javascript
vue.js高德地图实现热点图代码实例
Apr 18 #Javascript
基于vue实现滚动条滚动到指定位置对应位置数字进行tween特效
Apr 18 #Javascript
Vue的H5页面唤起支付宝支付功能
Apr 18 #Javascript
详解Vue中的scoped及穿透方法
Apr 18 #Javascript
You might like
Fine Uploader文件上传组件应用介绍
2013/01/06 PHP
PHP准确取得服务器IP地址的方法
2015/06/02 PHP
基于thinkPHP框架实现留言板的方法
2016/10/17 PHP
js form 验证函数 当前比较流行的错误提示
2009/06/23 Javascript
jQuery控制输入框只能输入数值的小例子
2013/03/20 Javascript
今天是星期几的4种JS代码写法
2013/09/17 Javascript
在每个匹配元素的外部插入新元素的方法
2013/12/20 Javascript
javascript替换已有元素replaceChild()使用介绍
2014/04/03 Javascript
通过JS来动态的修改url,实现对url的增删查改
2014/09/01 Javascript
jQuery实现html元素拖拽
2015/07/21 Javascript
延时加载JavaScript代码提高速度
2015/12/27 Javascript
浅谈js中同名函数和同名变量的执行问题
2017/02/12 Javascript
微信小程序实现列表页的点赞和取消点赞功能
2018/11/02 Javascript
three.js利用射线Raycaster进行碰撞检测
2020/03/12 Javascript
ES6字符串的扩展实例
2020/12/21 Javascript
vue watch监控对象的简单方法示例
2021/01/07 Vue.js
Nodejs 数组的队列以及forEach的应用详解
2021/02/25 NodeJs
[02:07]DOTA2超级联赛专访BBC:难忘网吧超神经历
2013/06/09 DOTA
[48:38]DOTA2亚洲邀请赛 3.31 小组赛 B组 Mineski vs Secret
2018/03/31 DOTA
python基础教程之数字处理(math)模块详解
2014/03/25 Python
python中的格式化输出用法总结
2016/07/28 Python
python3调用R的示例代码
2018/02/23 Python
python 通过麦克风录音 生成wav文件的方法
2019/01/09 Python
在pycharm 中添加运行参数的操作方法
2019/01/19 Python
python+rsync精确同步指定格式文件
2019/08/29 Python
python中函数返回多个结果的实例方法
2020/12/16 Python
css3 中translate和transition的使用方法
2020/03/26 HTML / CSS
字中字效果的实现【html5实例】
2016/05/03 HTML / CSS
比利时网上药店: Drogisterij.net
2017/03/17 全球购物
挂职自我鉴定
2014/02/26 职场文书
2014年党课学习心得体会
2014/07/08 职场文书
教师自查自纠工作情况报告
2014/10/29 职场文书
客房领班岗位职责
2015/02/11 职场文书
CSS3实现的文字弹出特效
2021/04/16 HTML / CSS
springboot @ConfigurationProperties和@PropertySource的区别
2021/06/11 Java/Android
SQLServer常见数学函数梳理总结
2022/08/05 MySQL