vue组件---element-ul的messageBox组件的仿写

604 阅读4分钟

一、前言

这次分享一下之前仿写过的element-ul的messageBox组件,只实现了简单的效果,样式还有很大的欠缺,在开始之前需要先了解一个方法vue.extend,在后面封装的时候需要用到。

二、vue.extend

作用: 生成一个新的带有默认参数的vue的子类,所以生成的这个子类它也是vue,它也具备vue的所有功能,这玩意儿说白了就是给vue产生默认值,如果你有,那么就使用你的,如果你没有,那么就使用我的默认值。

好处: 我们可以通过 Vue.extend 方法来创建符合我们业务需求的定制化组件构造器,让我们的应用逻辑更加清晰和模块化。

与new关键字实例化的区别:

  • Vue.extend 返回的是一个组件构造器,而不是一个具体的组件实例。通过这个构造器,可以创建多个相同的组件实例。而直接使用 new 关键字实例化,则直接得到一个组件实例。

  • 使用 Vue.extend 创建了一个组件构造器,可以根据这个构造器来创建多个组件实例。而直接使用 new 关键字实例化,则只能得到一个组件实例。

  • 使用 Vue.extend 定义的组件构造器,可以使用 mixin、父子组件通信等高级特性,使得开发更加灵活。而直接使用 new 关键字实例化的组件,则不能很方便地使用以上这些高级特性。

使用:

// 举例:
const vueChild = Vue.extend({
    data() {
        return {
            msg: 2
        }
    }
})

const vm = new vueChild({
    // 如果这里不写data的这个配置项,那么就使用上面的默认值的data,
    // 使用this.msg的话呢得到的结果是2
    
    // 如果这里书写了data的配置项那么就会以自己的为准,跟之前说过的
    // 混入有点类似,这里的this.msg的值为3
    data() {
        return {
            msg: 3
        }
    }
})

三、messageBox组件的结构和样式

// messageBox组件的main.vue

<template>
  // 使用v-if控制messageBox的显示与隐藏
  <div class="co-message-box" v-if="messageBoxVisible">
    <div class="co-message-box__header">{{ title }}</div>
    <div class="co-message-box__content">{{ message }}</div>
    <div class="co-message-box__btns">
      <Button @click="cancel">{{ options.cancelButtonText }}</Button>
      <Button @click="confirm" type="primary">{{
        options.confirmButtonText
      }}</Button>
    </div>
  </div>
</template>

<script>
// 引入之前封装好的button按钮
import Button from '@/components/Button/main.vue';
export default {
  name: 'co-message-box',
  components: { Button },
  methods: {
    hide() {
      this.messageBoxVisible = false;
      // this.$nextTick() 是 Vue.js 中的一个方法,表示在下一个 DOM
      // 更新周期之前执行一个回调函数,这里将messageBox隐藏起来属于
      // 异步操作,而将messageBox销毁属于同步操作,如果不做任何改变
      // 那这里会出现还没将messageBox隐藏起来就被销毁了,会出现报错,
      // 所以这里需要this.$nextTick()来将销魂放在更新完毕之后才执行
      this.$nextTick(() => this.$destroy());
    },
    cancel() {
      this.reject();
      this.hide();
    },
    confirm() {
      this.resolve();
      this.hide();
    },
  },
};
</script>

// scoped的作用:当样式重名的时候并不会相互影响
<style lang="scss" scoped>
.co-message-box {
  display: inline-block;
  width: 420px;
  padding-bottom: 10px;
  vertical-align: middle;
  background-color: #fff;
  border-radius: 4px;
  border: 1px solid #ebeef5;
  font-size: 18px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  text-align: left;
  overflow: hidden;
  backface-visibility: hidden;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -100%);
  &__header {
    position: relative;
    padding: 15px;
    padding-bottom: 10px;
  }
  &__content {
    padding: 10px 15px;
    color: #606266;
    font-size: 14px;
  }
  &__btns {
    padding: 5px 15px 0;
    text-align: right;
  }
}
</style>

四、messageBox组件的核心逻辑

// messageBox组件的index.js

import Main from './main.vue';
let Vue = null;
// 将实例化messageBox的逻辑封装成为一个函数,如果不封装的话呢它就会不
// 受控制的执行。
function message(
  // 使用时可以传递的参数,如果不传的话,就使用给的默认值
  message = '我是一条消息!',
  title = '标题',
  options = {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'info',
  }
) {
  // 这个函数返回的东西就是将messageBox组件渲染出来,然后根据文档上面的格式,
  // 会使用到catch和then的方法,那么这个函数会返回一个promise,里面的resolve
  // 和reject就是确认按钮和取消按钮所执行的回调函数,然后这两个方法可以通过
  // methods的配置项将其传递到组件内部来提供给按钮使用。
  return new Promise((resolve, reject) => {
    // 生成一个带有默认参数的vue
    const MessageBox = Vue.extend(Main);
    // 实例化MessageBox组件并传参
    const messagebox = new MessageBox({
      data() {
        return {
          message,
          title,
          options,
          messageBoxVisible: true,
        };
      },
      methods: {
        resolve,
        reject,
      },
    });
    // 调用$mount()不传递参数 触发模板编译流程
    messagebox.$mount();
    // 通过messagebox实例的$el属性获取到编译后的结果 手动添加到页面中
    document.body.appendChild(messagebox.$el);
  });
}

// 万物皆对象,函数也属于对象的一种,所以我可以为它添加一个install的方法,
// 方便使用use去实例化
message.install = function (_Vue) {
  Vue = _Vue;
  // 将message这个函数绑定到vue的原型上面,这样就可以通过vue.$message来
  // 执行这个函数了。
  _Vue.prototype.$message = this;
};

// 函数封装完成之后再将其导出,然后在使用的地方将这个函数导入使用,通过变量
// 来控制这个弹框的显示与隐藏。
export default message;