【Vue】命令式api组件的封装方法

2023/03/06 14:41:58

Message 组件示例

vue 组件除了常规的注册使用之外还可以通过 api 来调用,例如 ElementUI 中的 this.$message() 方法,一个简单的命令式 api 组件如下:

  • message.vue
<template>
  <div class="message" v-if="visible">{{ msg }}</div>
</template>

<script>
import Vue from "vue";
const defaultDuration = 1000;
const Message = {
  data() {
    return {
      visible: false,
      timer: null,
    };
  },
  props: {
    msg: {
      type: String,
    },
    duration: {
      type: Number,
      default: defaultDuration,
    },
  },
  methods: {
    close() {
      this.visible = false;
    },
    show() {
      this.visible = true;
      clearInterval(this.timer);
      this.timer = setTimeout(() => {
        this.close();
      }, this.duration);
    },
  },
};

export default Message;

let instanceCache;
export function message(option) {
  const msg = option.msg || "";
  const duration = option.duration || defaultDuration;
  function getInstanceCache() {
    if (instanceCache) {
      instanceCache.msg = msg;
      instanceCache.duration = duration;
    } else {
      const div = document.createElement("div");
      const MessageCtor = Vue.extend(Message);
      instanceCache = new MessageCtor({
        propsData: {
          msg,
          duration,
        },
      });
      document.body.append(div);
      instanceCache.$mount(div);
    }
    return instanceCache;
  }
  const instance = getInstanceCache();

  instance.show();
}
</script>

上面的组件有两种使用方式:

  • 注册并使用:

    <template>
      <Message msg="xxx" duration="3000" />
    </template>
    <script>
    import Message from "../components/Message.vue";
    export default {
      components: {
        Message,
      },
    };
    </script>
    
  • 通过 api 方式调用:

    <script>
    import { message } from "../components/Message.vue";
    message({
      msg: "xxx",
      duration: 2000,
    });
    </script>
    

命令式 api 组件的封装思路

  1. Vue.extend() 创建一个用于构造组件实例的组件构造器
  2. Vue.extend() 创建的组件构造器创建组件实例,并初始化 props 等数据。
  3. 调用组件实例的 $mount() 方法将组件挂载到页面的某个元素上。
  4. 通过暴露 api 的方式将组件实例的操作权限暴露出去,从而达到通过 api 来操控组件的目的。
import Vue from "vue";
import Message from "@/components/Message.vue";

// 初始化组件实例
const compCtor = Vue.extend(Message);
const compInstance = new compCtor();

// 将组件绑定到页面
const div = document.createElement("div");
document.body.appendChild(div);
compInstance.$mount(div);

如何控制组件实例

通过组件实例 compInstance 控制组件:

// 监听组件内部抛出的 $emit('close') 事件
compInstance.$on("close", () => {});

// 修改组件内部变量
compInstance.isShowMessage = true;

为什么组件可以这样用?(Vue 中的组件到底是什么?)

以下内容引自:探索 Vue 高阶组件 | HcySunYangopen in new window

在 Vue 中组件到底是什么?有的同学可能会有疑问,难道不是函数吗?对,Vue 中组件是函数没有问题,不过那是最终结果,比如我们在单文件组件中的组件定义其实就是一个普通的选项对象,如下:

export default {
  methods: {},
  mounted() {},
};

当我们从单文件中导入一个组件的时候其实导入的也是一个对象:

import BaseComponent from "./base-component.vue";
console.log(typeof BaseComponent); // object

当这个对象被注册为组件(components 选项)之后,Vue 最终会以该对象创建一个构造函数,该构造函数就是生产组件实例的构造函数。

所以在 Vue 中组件确实是函数,只不过这是最终结果罢了,在这之前我们可以说 Vue 中的组件也可以是一个普通对象,就像单文件组件中所导出的对象一样。

Tips

import 语句可以同时导出默认导出和具名导出:

import Message, { message } from "../components/Message.vue";

参考

探索 Vue 高阶组件 | HcySunYangopen in new window