VUE2实现事件驱动弹窗示例


Posted in Javascript onOctober 21, 2017

前几天想了解vue如何写弹窗组件

有以下两种可取的写法:

1.状态管理 如果弹窗组件放在根组件,使用vuex来管理组件的show和hide。放在组件内,通过增加v-show或v-if来控制,可结合slot,定义不同需求的弹窗

2.事件管理 注册一个全局事件来打开弹窗,传入需展示的文字和相关的逻辑控制,可结合promise,实现异步

觉得对用像confirme和propmt这类弹窗,还是事件驱动的好。最好就是能使用promise回调。

于是手痒就写了一个。下面是代码。

propmt.js

import Vue from 'vue'
import promptComponent from './prompt.vue' // 引入弹窗的vue文件
const promptConstructor = Vue.extend(promptComponent); // 注册组件
let instance = new promptConstructor().$mount(''); // 获得组件的实例

document.body.appendChild(instance.$el); // 将组件的element插入到body中
const Alert = (text,okText)=>{
  if(instance.show === true) { //防止多次触发
    return;
  }
  // 为弹窗数据赋值
  instance.show = true; 
  instance.isAlert = true;
  instance.okText = okText||'确定';
  instance.message = text;
  //返回一个promise对象,并为按钮添加事件监听
  return new Promise(function(resolve,reject) {
    instance.$refs.okBtn.addEventListener('click',function() {
      instance.show = false;
      resolve(true);
    })
  })
};
const Confirm = (text,okText,cancelText)=>{
  if(instance.show === true) {
    return;
  }
  instance.show = true;
  instance.okText = okText||'确定';
  instance.cancelText = cancelText||'取消';
  instance.message = text;
  return new Promise(function(resolve,reject) {
    instance.$refs.cancelBtn.addEventListener('click',function() {
      instance.show = false;
      resolve(false);
    });
    instance.$refs.okBtn.addEventListener('click',function() {
      instance.show = false;
      resolve(true);
    })
  })
};
const Prompt = (text,okText,inputType, defaultValue)=>{
  if(instance.show === true) {
    return;
  }
  instance.show = true;
  instance.isPrompt = true;
  instance.okText = okText||'确定';
  instance.message = text;
  instance.inputType = inputType || 'text';
  instance.inputValue = defaultValue || '';
  return new Promise(function(resolve,reject) {
    instance.$refs.okBtn.addEventListener('click',function() {
      instance.show = false;
      resolve(instance.inputValue);
    })
  })
};

export {Alert,Confirm,Prompt}

prompt.vue

<style lang="less" scoped>
  .confirm-enter-active {
    transition: all .2s;
  }

  .confirm-leave-active {
    transition: opacity .2s;
  }

  .confirm-leave-to {
    opacity: 0;
  }

  .confirm-enter {
    opacity: 0;
  }

  .confirm {
    position: relative;
    font-family: PingFangSC-Regular;
    font-size: 17px;
    -webkit-user-select: none;
    user-select: none;
    // 遮罩层样式
    .masker {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, .4);
      -webkit-transition: opacity .1s linear;
      transition: opacity .1s linear;
      z-index: 100;
    }
    // 入库数据错误样式
    .box {
      position: absolute;
      top: 50%;
      left: 50%;
      width: 72%;
      -webkit-transform: translate(-50%, -50%);
      transform: translate(-50%, -50%);
      text-align: center;
      border-radius: 12px;
      background-color: #fff;
      .message {
        height: 97px;
        line-height: 24px;
        font-family: PingFangSC-Regular;
        font-size: 17px;
        vertical-align: middle;
        color: #999;
        letter-spacing: -0.41px;
        p {
          margin: 20px auto 0 auto;
          vertical-align: middle;
        }
        &::after {
          content: '';
          height: 100%;
        }
      }
      .prompt {
        margin: 20px 0;
        width: 100%;
        p {
          margin: 5px auto;
          font-size: 17px;
          line-height: 24px;
        }
        input {
          margin: 5px auto;
          border: 1px solid #333;
          border-radius: 6px;
          width: 100px;
          height: 30px;
          font-size: 14px;
          line-height: 20px;
          text-align: center;
        }
      }
      .button-group {
        a {
          width: calc(50% - 0.5px);
          text-align: center;
          font-size: 17px;
          line-height: 43px;
          color: blue;
        }
        .max-width {
          width: 100% !important;;
        }
      }
    }
  }
</style>
<template>
  <transition name="confirm">
    <div class="confirm" v-show="show">
      <div class="masker" @touchmove.prevent>
        <div class="box">
          <div class="message" v-if="!isPrompt">
            <p>{{message}}</p>
          </div>
          <div class="prompt" v-if="isPrompt">
            <p>{{message}}</p>
            <input type="text" v-model="inputValue" v-if="inputType === 'text'" ref="inputEl">
            <input type="tel" v-model.number="inputValue" @keydown="enterCheck" v-if="inputType === 'tel'" ref="inputEl">
          </div>
          <div class="button-group clearfix bd-top">
            <a class="bd-right fl" ref="cancelBtn" v-show="!isAlert && !isPrompt">{{cancelText}}</a>
            <a class="fr" ref="okBtn" :class="{'max-width': isAlert || isPrompt}">{{okText}}</a>
          </div>
        </div>
      </div>
    </div>
  </transition>
</template>
<script type="text/ecmascript-6">
  import {mapState} from 'vuex'
  export default{
    data() {
      return {
        show: false,
        message: '请输入提示语',
        okText: '确定',
        cancelText: '取消',
        isAlert: false,
        isPrompt: false,
        inputValue: '',
        inputType: ''
      }
    },
    methods: {
      // 金额输入框校验
      enterCheck(event) {
        // 只允许输入数字,删除键,11位数字
        if (event.keyCode === 46 || event.keyCode === 8) {
          return;
        }
        if (event.keyCode < 47 || event.keyCode > 58 || event.keyCode === 190) {
          event.returnValue = false;
        }
      },
    },
    watch: {
      show(){
        if (this.show) {
          this.$nextTick(() => {
            console.log(this.$refs.inputEl);
            console.log(this.inputType);
            this.$refs.inputEl.focus();
          });
        }
      }
    }
  }
</script>

main.js

import {Alert,Prompt,Confirm} from '../lib/components/prompt/prompt.js'

Vue.prototype.Alert = function(text,okText) {
  return Alert(text,okText)
};
Vue.prototype.Confirm = function(text,okText,cancelText) {
  return Confirm(text,okText,cancelText)
};
Vue.prototype.Prompt = function(text,okText,inputType, defaultValue) {
  return Prompt(text,okText,inputType, defaultValue)
};
component.vue:

inputName() {
  this.Prompt('请输入名称','确认','text').then(res =>{
    // do something use res
  });
},

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

Javascript 相关文章推荐
Extjs学习笔记之一 初识Extjs之MessageBox
Jan 07 Javascript
javascript 获取页面的高度及滚动条的位置的代码
May 06 Javascript
基于JavaScript代码实现兼容各浏览器的设为首页和加入收藏
Jan 07 Javascript
基于JS如何实现给字符加千分符(65,541,694,158)
Aug 03 Javascript
vue组件生命周期详解
Nov 07 Javascript
vue 文件目录结构详解
Nov 24 Javascript
基于js Canvas实现二次贝塞尔曲线
Dec 25 Javascript
说说如何在Vue.js中实现数字输入组件的方法
Jan 08 Javascript
electron 安装,调试,打包的具体使用
Nov 06 Javascript
解决vue 子组件修改父组件传来的props值报错问题
Nov 09 Javascript
Vue 3.0中jsx语法的使用
Nov 13 Javascript
js判断两个数组相等的5种方法
May 06 Javascript
vue+socket.io+express+mongodb 实现简易多房间在线群聊示例
Oct 21 #Javascript
vue使用keep-alive实现数据缓存不刷新
Oct 21 #Javascript
详解在WebStorm中添加Vue.js单文件组件的高亮及语法支持
Oct 21 #Javascript
Vue filter介绍及其使用详解
Oct 21 #Javascript
详解node nvm进行node多版本管理
Oct 21 #Javascript
JS实现瀑布流布局
Oct 21 #Javascript
js实现Tab选项卡切换效果
Jul 17 #Javascript
You might like
PHP mail 通过Windows的SMTP发送邮件失败的解决方案
2009/05/27 PHP
phpMyAdmin 安装配置方法和问题解决
2009/06/08 PHP
关于尾递归的使用详解
2013/05/02 PHP
PHP过滤黑名单关键字的方法
2014/12/01 PHP
javascript demo 基本技巧
2009/12/18 Javascript
jQuery最佳实践完整篇
2011/08/20 Javascript
利用百度地图JSAPI生成h7n9禽流感分布图实现代码
2013/04/15 Javascript
jQuery插件zoom实现图片全屏放大弹出层特效
2015/04/15 Javascript
JS实现仿新浪黄色经典滑动门效果代码
2015/09/27 Javascript
解决js函数闭包内存泄露问题的办法
2016/01/25 Javascript
JavaScript+html5 canvas实现图片破碎重组动画特效
2016/02/22 Javascript
Vuex2.0+Vue2.0构建备忘录应用实践
2016/11/30 Javascript
ES6 Promise对象概念与用法分析
2017/04/01 Javascript
详解基于webpack和vue.js搭建开发环境
2017/04/05 Javascript
浅谈vue方法内的方法使用this的问题
2018/09/15 Javascript
我要点爆”微信小程序云开发之项目建立与我的页面功能实现
2019/05/26 Javascript
详解一些适用于Node.js的命名约定
2019/12/08 Javascript
JS中准确判断变量类型的方法
2020/06/01 Javascript
在Python编程过程中用单元测试法调试代码的介绍
2015/04/02 Python
学习python 之编写简单乘法运算题
2016/02/27 Python
python进阶_浅谈面向对象进阶
2017/08/17 Python
Python数据结构与算法之列表(链表,linked list)简单实现
2017/10/30 Python
Python模拟浏览器上传文件脚本的方法(Multipart/form-data格式)
2018/10/22 Python
Python3.6实现带有简单界面的有道翻译小程序
2019/04/16 Python
Python lambda表达式filter、map、reduce函数用法解析
2019/09/11 Python
python图形开发GUI库wxpython使用方法详解
2020/02/14 Python
详解基于Scrapy的IP代理池搭建
2020/09/29 Python
使用css3做0.5px的细线的示例代码
2018/01/18 HTML / CSS
Ibood荷兰:互联网每日最佳在线优惠
2019/02/28 全球购物
美国传奇滑手Paul Rodriguez创办的街头滑板品牌:Primitive Skateboarding
2019/10/29 全球购物
Blue Nile中国官网:全球知名的钻石和珠宝网络零售商
2020/03/22 全球购物
介绍一下EJB的分类及其各自的功能及应用
2016/08/23 面试题
财务负责人任命书
2014/06/06 职场文书
2014年营业员工作总结
2014/11/18 职场文书
婚前保证书范文
2015/02/28 职场文书
Requests什么的通通爬不了的Python超强反爬虫方案!
2021/05/20 Python