vue 采用promise方式开发弹窗插件

传统弹窗插件不足:

1.传统弹窗插件是按照vue官网文档组件的开发范式,把弹窗插件当成一个子组件开发,通过emit向父组件通信,这种做法一般情况都能胜任.
但是当一个父组件里的孙子组件需要弹窗的话就非常麻烦,要么孙子组件通过emit通知子组件,子组件再$emit通知父组件.或者vuex,eventbus.体验很糟糕

2.确认消息弹窗和消息提示弹窗要想使用一个组件来实现非常麻烦,要多传一个参数,回调也是.

为什么还要造轮子:

弹窗插件挺多的,比较成熟好用的有elemetui的,但是elementUI的弹窗插件,确认消息和消息提示是两个插件,大部分业务是不需要分这么细节的,本着代码能缩就缩的原则开发了一个插件有消息提示和确认消息两个功能,降低代码大小.

消息提示
确认消息

调用方式为:

this.$toast({
          showCancle:true,
          dialogname:'提示',
          alert_text:'这是内容'
        })
        .then( ()=>{
          console.log('promise then')
        })
        .catch( ()=>{
          console.log('promise catch')
        })

开发步骤:

1.初始化一个vue-cli脚手架或者在你当前项目中,assets文件夹下新建toasttemplate.vue和toast.js文件,

2.toasttemplate.vue

这是弹窗组件所在的文件,大概思路是父div包两个子div,一个子div是cover层占满屏幕,另一个子div是内容层,z-index最大.和标准组件稍微不一样的是当点击确定或者取消的时候,调用的是toast.js加在原型上的函数而不是$emit

<!-- 弹窗组件 -->
<template>
  <div class="tanchuang_wrap" v-if="isShow">
     <div class="dialog_cover"  @click="closeMyself"></div>

     <transition name="drop">
     <div class="dialog_content" v-if="isShow">
         <div class="alert_title">
             <div class="alert_title_left">{{dialogname}}</div>
             <div class="alert_title_right" @click="closeMyself"></div>
         </div>
         
        <div style="padding: 10px 15px;;text-align:left;
                    font-size:14px;color:#606266">
              {{alert_text}}
        </div>

         <div class="down" > 
             <div v-if="showCancle" class="down_button_cancle" @click="closeMyself">取消</div>
             <div class="down_button" @click="besure">确定</div>
         </div>
     </div>
     </transition>
  </div>
</template>

<script>
export default {
data() {
  return {
    isShow: false,
    showCancle:false,
    dialogname:null,
    alert_text:'',
  }    
},
methods: {
  show(params){  //初始化参数
     let { showCancle,dialogname,alert_text } = params
     this.showCancle = showCancle
     this.dialogname = dialogname
     this.alert_text = alert_text

     this.isShow = true
  },
  closeMyself () {
     this.isShow = false
     this.callBack(false)
  },
  besure(){  //确定按钮
     this.isShow = false
     this.callBack(true)
  },
}
}
</script>

<style lang="scss" scoped>
.drop-enter-active {
  transition: all .5s ease;
}
.drop-leave-active {
  transition: all .5s ease;
}
.drop-enter {
  transform: translateY(-500px);
}
.drop-leave {
  transform: translateY(-500px);
}


.tanchuang_wrap{
  .dialog_cover {
    background: #000;
    opacity: 0.3 ;
    position: fixed;
    z-index: 35;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
  .dialog_content {
    width: 422px;
    position: fixed;
    overflow: auto;
    background: #fff;
    top: 15%;
    left: 50%;
    margin-left: -211px;
    z-index: 40;
    line-height: 1.6;
    border-radius:4px;
    padding-bottom:10px;
    .alert_title{
        background:white;
        width:100%;
        height:43px;
        overflow: hidden;
        .alert_title_left{
           float:left;
           margin-left: 15px;
           margin-top: 15px;
           font-size:18px;
           color:#303133;
           line-height: 1;
        }
        .alert_title_right{
          float:right;
          width:12px;
          height: 12px;
          margin-top: 20px;
          margin-right: 20px;
          background-image: url('../../static/关闭.png');
          background-repeat: no-repeat;
          background-size: 12px 12px;
          cursor: pointer;
        }
        .right:hover{
          color: #4fc08d;
        }
    }
    .down{
      padding: 5px 15px 0;
      display: flex;
      flex-direction:row-reverse;
      .down_button{
         width: 55px;
         height: 30px;
         font-size: 12px;
         cursor: pointer;
         background:#2389ff;
         border-radius:3px;
         text-align: center;
         line-height: 30px;
         color: white;
         font-weight: 500;

      }
      .down_button_cancle{
         margin-left:15px;
         width: 55px;
         height: 30px;
         font-size: 12px;
         cursor: pointer;
         background:#fff;
         border:1px solid #CCCCCC;
         border-radius:3px;
         text-align: center;
         line-height: 30px;
         color: #999;
         font-weight: 500;
      }
    }
  }
}
</style>

3.开发toast.js
这是比较重要的地方,思路为:

a.创建一个函数,根据参数bool值,返回存贮promise结果变量的resolve或reject属性,这个函数会被toasttemplate.vue来调用

b.根据vue官方文档插件开发规范,创建一个对象,用来对外暴露

c.在这个对象里使用vue.extend把toasttemplate.vue构造成一个vue类,再由这个类生成的对象(dom)放在dom上使用

d.在对象里要返回一个promise对象,promise的resolve和reject存在一个变量中,由a步骤中的函数调用,并把这个函数放在新建vue类的原型上

import Toasttemplate from './toasttemplate.vue'
function defaultCallBack (action){
    if(!action) currentMsg.reject()
    currentMsg.resolve()
}

let Toast = {}
let currentMsg = null

Toast.install = function(Vue,options={}){
    const VueToast = Vue.extend(Toasttemplate)  //创建模板
    let toast = null
    VueToast.prototype.callBack = defaultCallBack

    Vue.prototype.$toast = (params) =>{
        if(!toast){
            toast = new VueToast().$mount()  //创建实例
            document.body.appendChild(toast.$el)  //挂载实例
        }
        toast.show(params)
        
        return new Promise((resolve,reject) => {
            currentMsg = {resolve,reject}
        })
    }
 }



export default Toast

4.注册
在main.js中
import Toast from './assets/Toast'
Vue.use(Toast)

5.使用

this.$toast({
          showCancle:true,//true->确认消息弹窗,false->消息提示弹窗
          dialogname:'提示',//弹窗的标题
          alert_text:'这是内容'//弹窗的内容
        })
        .then( ()=>{
          console.log('promise then')
        })
        .catch( ()=>{
          console.log('promise catch')
        })

到第五步就可以直接在项目里用了,下面是制作成npm插件
6.制作成npm插件
下载webpack-simple,然后初始化一个项目
在src目录下面新建文件夹lib,将上述文件和用到的静态资源拷贝进去


目录结构

修改webpack.config.js的entry和ouput

webpack.config.js

package.json新增main属性,路径为打包后的入口js路径

package.json

修改index.html
引入打包后的文件

index.html

发布到npm上即可

总结

该插件已经被作者制作成npm插件,GitHub地址:https://github.com/bill-mark/vue-toast-plus

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容

  • 内容 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 UI组件 element ★13489...
    秋玄语道阅读 13,707评论 3 116
  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生_X自主阅读 15,979评论 3 119
  • 机器环境 操作系统:CentOS release 6.5 (Final)内核版本:Linux version 2....
    chensiyu2014阅读 164评论 0 0
  • 群资料共享 比特币白皮书以太坊白皮书 区块链的使用和对国家的改造视频区块链的一个公司的应用的演讲视频 比特币白皮书...
    百里求一阅读 384评论 0 0
  • 文/秦溯之 党旗颂 ——献给中国共产党诞辰95周年生日 长天万里,春色无限。 红艳当空,风舞翩翩。 仰望党旗,...
    秦溯之阅读 269评论 3 10