构建个人组件库,类似Element-ui使用方式,vue confirm公共弹框组件

一、要做什么?

我们在引入Element-ui的时候有看到这种使用Vue.use()的用法,然后element-ui里所有的组件我们都可以全局使用,这到底是怎么做到的呢,下面我以一个公共弹框组件为例,说一说我的写法,仅供参考。

呈现的最后效果:

(1)简单的标题

(2)提示内容可交互(v-html中的点击事件)

二、实践之前可以了解一下Vue的api

(1)vue-extend的用法,和compont创建组件的区别

https://cn.vuejs.org/v2/api/#Vue-extend

我觉得比较大的区别是 vue-extend创建的实例更加灵活,因为挂载的节点可以是任意指定的。

(2)使用Vue.use() 创建插件的方式

https://cn.vuejs.org/v2/api/#Vue-use

https://cn.vuejs.org/v2/guide/plugins.html

三、实践

(一)首先使用Vue.extend(options)创建弹框的模板实例

(1)创建message_box.vue 文件

<template>
  <transition name="fade">
    <div class="message-box" v-if="ifShow">
      <div class="message-box-mask" @click.stop="closeMask"></div>
      <transition name="msgbox-bounce">
        <div class="message-box-line" :class="[ifShow ? 'v-modal-enter' : 'v-modal-leave']" v-if="ifShow">
          <div class="message-box-header" v-if="showTitle">
            {{title}}
          </div>
          <!-- 在父级标签定义点击事件(事件委托) -->
          <div class="message-box-content" @click.stop="clickItem($event)" v-html='content'>
          </div>
          <div class="message-box-footer">
            <span v-if="showLeftBtn" class="btn-cancel" @click.stop="left">
              {{leftBtnText}}
            </span>
            <span @click.stop="right">
              {{rightBtnText}}
            </span>
          </div>
        </div>
      </transition>
    </div>
  </transition>
</template>
<script>
export default {
  computed: {
    showTitle() {
      if(this.title){
        return true
      }
      return false
    },
    showLeftBtn() {
      if(this.leftBtnText){
        return true
      }
      return false
    },
  },
  data() {
    return {
      ifShow: false,
      title: '',
      content: '',
      leftBtnText: '',        // 左按钮文本为空时,左按钮不显示
      rightBtnText: '',
      resolve: '',
      reject: '',
      isClickCloseMask: true, // 是否可以点击mask蒙版关闭弹框(除弹框以外的区域)
      promise: ''             // promise实例
    };
  },
  mounted(){
  },
  methods: {
    clickItem(event){
      // content内容为v-html形式传入,事件如 click会被当成html 字符串,点击事件无效
      // 如果当前内容文本有很多地方需要点击或其他事件,可以给每个需要点击的文本加上一个id作区分
      switch (event.target.id) {
        case 'baidu':
          // 当前点击到的具体标签是,对应的id是 baidu
          window.location.href='https://www.baidu.com/';         
          break;
        case 'blog':
          // 当前点击到的具体标签是,对应的id是 blog
          window.location.href='https://blog.csdn.net/qq_35430000';         
          break;    
        default:
          break;
      }
    },
    closeMask(){
      if (!this.isClickCloseMask) {
        return
      }
      this.ifShow = false;
      this.remove();
    },
    right() {
      this.ifShow = false;
      this.resolve('yes');
      this.remove();
    },
    left() {
      this.ifShow = false;
      this.reject('no');
      this.remove();
    },
    showMsgBox(data) {
      this.title = data.title;
      this.content = data.content;
      this.leftBtnText = data.leftBtnText;
      this.rightBtnText = data.rightBtnText;
      if (data.isClickCloseMask === false) {
        this.isClickCloseMask = false ; 
      }
      this.ifShow = true;
      this.promise = new Promise((resolve, reject) => {
        this.resolve = resolve;
        this.reject = reject;
      });
      return this.promise;
    },
    remove() {
      setTimeout(() => {
        this.destroy();
      }, 300);
    },
    destroy() {
      // 销毁vm实例与DOM之间的关联
      this.$destroy();
      // document.body.removeChild(this.$el);
    }
  }
};
</script>
<style lang="less" scoped>
.fade-leave-active{
  transition: opacity 0.5s;
}
.fade-leave-to{
  opacity: 0;
}

.message-box {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2000;
}
.message-box-mask {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.5);
}
@keyframes scaleIn {
  0%{
    opacity: 1;
    transform: translate3d(-50%, -50%, 0) scale(0);
  }
  50%{
    opacity: 1;
    transform: translate3d(-50%, -50%, 0) scale(0.6);
  }
  70%{
    opacity: 1;
    transform: translate3d(-50%, -50%, 0) scale(0.9)
  }
  100%{
    opacity: 1;
    transform: translate3d(-50%, -50%, 0) scale(1)
  }
}
.model-in{
  animation: scaleIn 0.3s ease-in;
}
.message-box-line {
  margin-top: -36px;
  padding-top: 0.4rem;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate3d(-50%, -50%, 0) scale(1);
  width: 8rem;
  border-radius: 6px;
  background-color: #fff;
  transition: all 0.2s;
}
.message-box-header {
  margin: 0 auto;
  padding-top: 0.2rem;
  padding-bottom: 0;
  font-size: 0.48rem;
  color: #333;
  text-align: center;
}
.message-box-content {
  margin: 0 auto;
  padding: 0.45rem 0.8rem 0.7rem 0.8rem;
  line-height: 0.6rem;
  font-size: 0.4rem;
  color: #666;
  text-align: left;
  border-bottom: .01rem solid #DFDFDF;
}

.message-box-footer {
  display: flex;
  height: 1.3rem;
  line-height: 1.3rem;
  text-align: center;
  font-size: 0.48rem;
  color: #F8931B;
  span{
    flex: 1;
    text-align: center;
  }
}
.btn-cancel{
  color: #666;
  border-right: .01rem solid #DFDFDF;
}
.msgbox-bounce-enter {
  opacity: 0;
  -webkit-transform: translate3d(-50%, -50%, 0) scale(0.7);
  transform: translate3d(-50%, -50%, 0) scale(0.7);
}
.msgbox-bounce-leave-active {
  opacity: 0;
  -webkit-transform: translate3d(-50%, -50%, 0) scale(0.9);
  transform: translate3d(-50%, -50%, 0) scale(0.9);
}
.v-modal-enter {
  -webkit-animation: v-modal-in 0.2s ease;
  animation: v-modal-in 0.2s ease;
}
.v-modal-leave {
  -webkit-animation: v-modal-out 0.2s ease forwards;
  animation: v-modal-out 0.2s ease forwards;
}
@-webkit-keyframes v-modal-in {
  0% {
    opacity: 0;
  }
  100% {
  }
}
@keyframes v-modal-in {
  0% {
    opacity: 0;
  }
  100% {
  }
}
@-webkit-keyframes v-modal-out {
  0% {
  }
  100% {
    opacity: 0;
  }
}
@keyframes v-modal-out {
  0% {
  }
  100% {
    opacity: 0;
  }
}
</style>

(2)把实例挂载到document.body 上(或者挂载到你指定的某个节点上)。

创建 index.js文件

import Vue from 'vue'
import msgboxVue from './message_box.vue';
const MessageBox = function (options) {
  const MessageBoxInstance = Vue.extend(msgboxVue);
  // 实例化vue实例
  let currentMsg = new MessageBoxInstance().$mount();
  // let currentMsg = new MessageBoxInstance().$mount('#app'); 
  // $mount()中参数可以为空,也可以任意指定一个节点,但注意挂载后这个节点将会被覆盖
  // $el记录了new实例的dom,可以把这个dom任意插入到哪个节点
  // 此时不指定节点,我们把弹框的实例挂载到 body上
  document.body.appendChild(currentMsg.$el);
  return currentMsg.showMsgBox(options);
};
export default MessageBox;

值得注意的是,上面的$mount('#app')中的参数可以为空也可以指定某个具体节点。

return currentMsg.showMsgBox(options);  return的是一个promise实例

(二)使用Vue.use的方式构建一个全局可访问的插件

(1)了解api

https://cn.vuejs.org/v2/api/#Vue-use

https://cn.vuejs.org/v2/guide/plugins.html

import MessageBox from '../src/components/message_box';

const utils = {
  install:function (Vue,options) {
    // 1. 添加全局方法或属性
    Vue.myGlobalMethod = function () {
      // 逻辑...
    }

    // 2. 添加全局指令
    Vue.directive('my-directive', {
      bind (el, binding, vnode, oldVnode) {
        // 逻辑...
      }
    })

    // 3. 注入组件选项
    Vue.mixin({
      created: function () {
        // 逻辑...
      }
    })

    // 4. 添加实例方法
    Vue.prototype.$myMethod = function (methodOptions) {
      // 逻辑...
    }

  // 5.按照4的方式,添加一个公共弹框组件方法,这样全局可通过 this.confirm 访问
    /*
    * @param data {object}
    * title {string} 提示框title
    * message {string} 提示框内容
    * leftBtnText {string} 左侧按钮文字
    * rightBtnText {string} 右侧按钮文字
    **/
    Vue.prototype.confirm = function (data) {
    return MessageBox(data)
      .then(sucess => {
        return Promise.resolve(sucess);
      })
      .catch(err => {
        return Promise.reject(err);
      });
    };
  }
}
export default utils

(2)main.js中引入并使用插件

(三)、插件调用以及配置(样式等也可以根据需求,自行改造)

 mounted(){  
    let name1 = '百度';
    let name2 = '我的博客';
    let template = `<p>我是一行文字:</p>
                  <p>如果你点击<span id='baidu' style='color:#EE3B3B'>《${name1}》</span>可以跳转。</p>
                  <p>如果你点击<span id='blog' style='color:#EE3B3B'>《${name2}》</span>可以跳转。</p>
                  `                  
   

 // 弹框配置
    this.confirm({
      title: "标题",          // 标题
      content: template,      // 内容
      leftBtnText: "取消",    // 左按钮文本为空时,左按钮不显示
      rightBtnText: "确定",
      isClickCloseMask: true  // 是否可以点击mask蒙版关闭弹框(除弹框以外的区域)
    })
    .then(res => {
      // 点击了确定按钮,要做的操作
      console.log('点击了确定按钮');
    })
    .catch(err => {  
      // 点击了取消按钮,要做的操作   
      console.log('点击了取消按钮');       
    });
  }

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是使用element-uivue.js写一段批量删除表格内容的代码: <template> <div> <el-button type="danger" @click="handleDelete">批量删除</el-button> <el-table :data="tableData" ref="multipleTable" :row-key="row => row.id" :show-header="true" :highlight-current-row="true" :default-sort="{prop: 'date', order: 'descending'}"> <el-table-column type="selection" width="55"></el-table-column> <el-table-column prop="date" label="日期" width="180"></el-table-column> <el-table-column prop="name" label="姓名" width="180"></el-table-column> <el-table-column prop="address" label="地址"></el-table-column> </el-table> </div> </template> <script> export default { data() { return { tableData: [{ id: 1, date: '2022-01-01', name: '张三', address: '北京市朝阳区' }, { id: 2, date: '2022-01-02', name: '李四', address: '上海市浦东新区' }, { id: 3, date: '2022-01-03', name: '王五', address: '广州市天河区' }, { id: 4, date: '2022-01-04', name: '赵六', address: '深圳市南山区' }], multipleSelection: [] }; }, methods: { handleDelete() { if (this.multipleSelection.length === ) { this.$message({ message: '请选择要删除的数据', type: 'warning' }); return; } this.$confirm('确认删除选中的数据吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { const ids = this.multipleSelection.map(item => item.id); this.tableData = this.tableData.filter(item => !ids.includes(item.id)); this.multipleSelection = []; this.$message({ message: '删除成功', type: 'success' }); }).catch(() => {}); } } }; </script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值