从vue2插件到vue3插件

主要总结确认弹窗组件(comfirm)的封装,和插件封装的主要知识点

共同点

1.都需要要一个已经实现的comfirm.vue组件文件(以下是组件在vue2中的实现)

<template>
  <div class="comfirm-box" v-show="modelShow">
    <transition name="fade">
      <div class="comfirm" v-if="show">
        <div class="btn-close" @click="cancelEvent" v-if="showCloseBtn"></div>
        <h4 class="title" v-if="!hideTitle">{{title}}</h4>
        <div class="message"
          :class="{'message-add' : addMessageDistance}" 
          v-html="content"></div>
        <div class="btn-box" :class="{'btn-box-center':hideCancel}">
          <!-- 取消按钮 -->
          <div class="btn btn-cancel" 
            :style="{fontSize : (btnFontSize || '' )}" 
            @click="cancelEvent"
            v-if="!hideCancel">
              {{cancelText || '取消'}}
          </div>
          <!-- 确定按钮 -->
          <div class="btn btn-submit" 
            :style="{fontSize : (btnFontSize || '' )}"
            :class="{'big-btn-submit':hideCancel}" 
            @click="onOkEvent">
              {{okText || '确定'}}
          </div>
        </div>
      </div>
    </transition>
  </div>
</template>
 
<script>
  import {debounce} from '@/utils/utils';
  let that;
  export default {
    name: 'comfirm',
    props : {
      //标题
      title : {
        type : String
      },
      // 内容
      content : {
        type : String
      },
      //是否隐藏标题
      hideTitle : {
        type : Boolean,
        default : false
      },
      //取消按钮文本
      cancelText : {
        type : String,
        default : '取消'
      },
      //隐藏取消按钮
      hideCancel : {
        type : Boolean,
        default : false
      },
      // 确定按钮文案
      okText : {
        type : String,
        default : '确定'
      },
      //v-model对外开放值
      value : {
        type : Boolean
      },
      //按钮字体字号
      btnFontSize : {
        type : String
      },
      //显示关闭按钮
      showCloseBtn : {
        type : Boolean
      }
    },
    data(){
      that = this;
      return{
        //显示弹窗
        modelShow : this.value,
        show : false,
        //判断是否是通过方法调用
        isComfirm : false
      }
    },
    mounted(){},
    computed:{
      //增加文本间距
      addMessageDistance(){
        let {showCloseBtn,hideTitle} = this;
        //显示关闭按钮,并且隐藏标题,则增加段落文本距离顶部距离
        return (showCloseBtn && hideTitle);
      }
    },
    methods:{
      //确认事件
      onOkEvent : debounce(()=>{
        let {onOk} = that;
        //判断是否有确认回调,如果有的话执行
        onOk && onOk();
        //提交父组件确认事件
        that.$emit('on-ok');
        //关闭弹窗
        that.close();
      },false),
      //取消事件
      cancelEvent : debounce(()=>{
        let {onCancel} = that;
        //判断是否有取消回调
        onCancel && onCancel();
        try{
          //提交父组件取消事件
          that.$emit('on-cancel');
        }
        catch(err){
          console.log(err);
        }
        //关闭弹窗
        that.close();
      },false),
      // 关闭弹窗
      close(){
        let {isComfirm} = this;
        //隐藏弹窗
        this.modelShow = false;
        if(isComfirm){
          setTimeout(()=>{
            // 彻底销毁实例
            that.$destory && that.$destory();
            //删除节点
            if(that.$el && document.body.contains(that.$el)){
             that.$el.remove()
            }
          },100);
        }
      }
    },
    watch : {
      //监听外部值变化,赋值给模板显隐
      value(modelShow){
        this.modelShow= modelShow;
      },
      //监听显隐变化传递给外层组件
      modelShow(value){
          this.$nexttick(()=>{
              this.show = value;
              this.$emit('input',value);
          })
      }
    }
  }
</script>
 
<style lang="scss" scoped>
  .comfirm-box{
    width: 100%;
    height: 100vh;
    overflow: hidden;
    background-color: rgba(0,0,0,0.3);
    position: fixed;
    left: 0;
    top: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 11;
  }
  .comfirm{
    padding: 40px;
    border-radius: 32px;
    background-color: #fff;
    width: 600px;
    max-height: 70vh;
    box-sizing: border-box;
    text-align: center;
    overflow-y: auto;
    position: relative;
  }
  .btn-close{
    width: 85px;
    height: 85px;
    background: url(../../assets/components/comfirm/close.png) no-repeat;
    background-position: center center;
    position: absolute;
    right: 0;
    top: 0;
  }
  .title{
    font-size: 38px;
    color: #353535;
    line-height: 50px;
  }
  .message{
    font-size: 28px;
    color: #353535;
    line-height: 36px;
  }
  .message-add{
    margin-top: 30px;
  }
  .btn-box{
    display: flex;
    justify-content: space-around;
    margin-top: 36px;
  }
  .btn-box-center{
    justify-content: center;
  }
  .btn{
    min-width: 240px;
    max-width: 250px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding: 22px;
    height: 92px;
    line-height: 44px;
    font-size: 34px;
    border: 2px solid transparent;
    border-radius: 44px;
    box-sizing: border-box;
  }
  .btn-cancel{
    border-color: #EAEAEA;
    color: #737373;
    background-color: #FFFFFF;
  }
  .btn-submit{
    background: #FFD321;
    border-color: #FFD321;
    color: #282121;
  }
  .big-btn-submit{
    width: 320px;
    max-width: 320px;
  }
  .fade-enter-active, .fade-leave-active {
    transition: all .3s;
  }
  .fade-enter /* .fade-leave-active below version 2.1.8 */ {
    transform: scale(0.3);
    opacity: .8;
  }
  .fade-leave-to{
    transform: scale(0.8);
    opacity: .8;
  }
</style>
 

不同点

1. vue3中使用comfirm.vue文件(功能不变的情况),有几个地方是需要改动的

//props中要增加onCancel、onOk方法的定义
//把data中的isComfirm参数移到 props中
props : {
    //取消事件
    onCancel : {
        type : Function
    },
    //确认事件
    onOk : {
        type : Function
    },
    //是否为插件调用
    isComfirm : {
        type : Boolean
    }
}

//动画样式改动
//vue3取消了 .fade-enter和.fade-leave-to
//.fade-enter-active, .fade-leave-active 样式重新调整如下
.fade-enter-active{
    animation: moveIn .3s;
}
.fade-leave-active {
    animation: moveOut .3s;
}
@keyframes moveIn{
    from{
      transform: scale(0.3);
      opacity: .8;
    }
    to{
      transform: scale(1);
      opacity: 1;
    }
}
@keyframes moveOut{
    from{
      transform: translateY(0);
      opacity: 1;
    }
    to{
      transform: translateY(100%);
      opacity: 0;
    }
}

2.入口文件不同

以下是vue2的入口文件
import Vue from 'vue';
//引入确认弹窗组件
import comfirm from './comfirm.vue';

// 创建一个vue子类
const ComfirmConstructor = Vue.extend(comfirm);

const Comfirm = ({
  title='',
  content='',
  hideTitle,
  hideCancel,
  cancelText,
  okText,
  onOk,
  btnFontSize,
  onCancel,
  showCloseBtn
}={}) => {
  //实例化组件
  const ComfirmInstance = new ComfirmConstructor({
    data : {
      isComfirm : true
    }
  });

  ComfirmInstance.vm = ComfirmInstance.$mount();

  {
    //赋值外部传进来的数据
    //参数定义在组件内查看
    ComfirmInstance.title = title;
    ComfirmInstance.content = content;
    ComfirmInstance.hideTitle = Boolean(hideTitle);
    ComfirmInstance.hideCancel = Boolean(hideCancel);
    ComfirmInstance.btnFontSize = btnFontSize;
    //显示关闭按钮
    ComfirmInstance.showCloseBtn = Boolean(showCloseBtn);
    if(cancelText){
      ComfirmInstance.cancelText = cancelText + '';
    }
    if(okText){
      ComfirmInstance.okText = okText + '';
    }
    //赋值确定按钮回调事件
    if(onOk && typeof onOk === 'function'){
      ComfirmInstance.onOk = onOk;
    }
    //取消回调事件
    if(onCancel && typeof onCancel === 'function'){
      ComfirmInstance.onCancel = onCancel;
    }
  }

  // 控制组件的显隐
  ComfirmInstance.modelShow = true;

  //获取dom
  ComfirmInstance.dom = ComfirmInstance.vm.$el;
  //往body里增加弹窗
  document.body.appendChild(ComfirmInstance.dom);

  return ComfirmInstance.vm;
} 

export default{
    //导出安装的文件
  install : (vue) => {
    vue.prototype.$comfirm = Comfirm;
  }
}

/* 
使用说明 

第一种方式
在main.js中引入
import Comfirm from './components/comfirm';
Vue.use(Comfirm);

在业务模块通过方法调用
this.$comfirm({
  // hideTitle 是否隐藏头部,默认为false
  // hideCancel 是否隐藏取消按钮,默认为false
  content : '内容字符串,可以是带html结构的',
  cancelText : '取消按钮文案,默认是取消',
  okText : '确认按钮文案,默认是确认',
  //成功回调,可以不设置
  onOk(){
    console.log('xixihaha ')
  },
  //取消回调,可以不设置
  onCancel(){
    console.log('取消')
  }
})

第二种方式
在需要使用的页面作为组件引用
import comfirm from '../../components/common/comfirm/comfirm.vue';
<comfirm title="标题" content="内容" v-model="showComfirm"></comfirm>

value   对话框是否显示,可使用 v-model 双向绑定数据。   Boolean   false
title   标题
content 内容
ok-text   确定按钮文字  String  确定
cancel-text   取消按钮文字  String  取消
on-ok   点击确定的回调   
on-cancel   点击取消的回调
hide-title 隐藏标题
hide-cancel 是否隐藏取消按钮,默认为false
*/
以下是vue3的入口文件
import { createVNode, render } from 'vue';
//引入确认弹窗组件
import comfirm from './comfirm.vue';

const Comfirm = function(options:any={}){
  // 判断是否已经有节点
  const comfirmDom = document.getElementById('comfirm-box');
  //如果有节点删除
  if(comfirmDom && document.body.contains(comfirmDom)){
    document.body.removeChild(comfirmDom);
  }
  //定义是插件形式调用
  options.isComfirm = true;
  //显示弹窗
  options.value = true;
  //创建虚拟dom
  const vm:any = createVNode(comfirm,options);
  const container = document.createElement('div');
  container.id = 'comfirm-box';
  //执行渲染函数
  render(vm,container);
  //往body增加节点
  document.body.appendChild(container);
}

export default{
  install : (app:any) => {
    app.config.globalProperties.$comfirm = Comfirm;
  }
}

/* 
使用说明 

第一种方式
在main.js中引入
import Comfirm from './components/common/comfirm';
Vue.use(Comfirm);

在业务模块通过方法调用
this.$comfirm({
  // hideTitle 是否隐藏头部,默认为false
  // hideCancel 是否隐藏取消按钮,默认为false
  content : '内容字符串,可以是带html结构的',
  cancelText : '取消按钮文案,默认是取消',
  okText : '确认按钮文案,默认是确认',
  //成功回调,可以不设置
  onOk(){
    console.log('xixihaha ')
  },
  //取消回调,可以不设置
  onCancel(){
    console.log('取消')
  }
})

第二种方式
在需要使用的页面作为组件引用
import comfirm from '../../components/common/comfirm/comfirm.vue';
<comfirm title="标题" content="内容" v-model="showComfirm"></comfirm>

value   对话框是否显示,可使用 v-model 双向绑定数据。   Boolean   false
title   标题
content 内容
ok-text   确定按钮文字  String  确定
cancel-text   取消按钮文字  String  取消
on-ok   点击确定的回调   
on-cancel   点击取消的回调
hide-title 隐藏标题
hide-cancel 是否隐藏取消按钮,默认为false
*/

注意点

1.在vue3中的setup使用

import {getCurrentInstance} from 'vue';

setup(){
    const {ctx}:any = getCurrentInstance();
    ctx.$comfirm({
      // hideTitle 是否隐藏头部,默认为false
      // hideCancel 是否隐藏取消按钮,默认为false
       content : '内容字符串,可以是带html结构的',
       cancelText : '取消按钮文案,默认是取消',
      okText : '确认按钮文案,默认是确认',
      //成功回调,可以不设置
      onOk(){
        console.log('xixihaha ')
      },
      //取消回调,可以不设置
      onCancel(){
        console.log('取消')
      }
  });
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容