Vue3插件开发实战

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2022-02-19

本文介绍Vue3中插件是如何开发的,下面为开发一个“键盘”插件的代码。

引入

// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import Keyboard from './plugins/keyboard/index'
import './index.css'

const app = createApp(App)
app.use(Keyboard)
app.mount('#app')

插件编写

1、该插件需要在应用中插入一个“键盘”组件,DOM部分

<!-- ./plugins/keyboard/keyboard.vue -->
<template>
  <div v-if="show">
    <div class="key-wrapper">
      <p v-for="i in 10" :key="i" @click="handleClick(i-1)">
        {{ i - 1 }}
      </p>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  props: {
    show: {
      type: Boolean
    }
  },
  emits: ['keypress'],
  setup(props, { emit }) {
    function handleClick(i: number) {
      emit('keypress', i)
    }

    return {
      handleClick
    }
  }
})
</script>

<style >
.key-wrapper p {
  background: pink;
}
</style>

2、插件的API部分,最重要的部分

// ./plugins/keyboard/index.ts
import { App, createApp, h, reactive, ComponentPublicInstance } from 'vue';
import Keyboard from './keyboard.vue';

/** 组件dom挂在后得到的组件实例 */
let $vm: ComponentPublicInstance | null = null;

/** keyboard需要接收并跟踪变化的的props */
const props = reactive({
  show: false
})

/** 空函数 */
const loop = (...args: any[]) => {};

/** 默认配置 */
const globalConfig = {
  onKeypress: loop
}

/** 插件控制器 controller */
const $keyboard = {
  /** 调用show方法可以改变默认的配置 */
  show(config: { onKeypress: (i: number) => void }) {
    /** 响应式状态,改变该状态,相当于传给组件的props变化了 */
    props.show = true;
    /** 修改默认的keypress监听处理为show方法传入的 */
    globalConfig.onKeypress = config.onKeypress;
  },
  hide() {
    props.show = false;
  }
}

export default function register(app: App) {
  if (!$vm) {
    const wrapper = document.createElement('div');
    wrapper.id = 'keyboard';
    document.body.appendChild(wrapper)

    $vm = createApp({
      setup() {
        return () => { // setup 可以返回一个render函数
          // h函数接收3个参数,“组件或dom”、props、children
          return h(Keyboard, {
            // 其他属性,会被当做组件的props <Keyboard :show="props.show" />
            ...props,
            // onXxx 相当于 <Keyboard @Xxx="globalConfig.onKeypress" />
            onKeypress: globalConfig.onKeypress
          })
        }
      }
    }).mount(wrapper) as ComponentPublicInstance;

    /** 将插件controller注册到全局上 */
    app.config.globalProperties.$keyboard = $keyboard;
  }
}

3、插件的使用

<!-- App.vue -->
<template>
  <button @click="hiddenKey">隐藏</button>
  <button @click="showKey">展示</button>

  {{ showValue }}
</template>

<script lang="ts">
import { defineComponent, getCurrentInstance, ref } from 'vue'

export default defineComponent({
  name: 'App',
  setup() {
    const appCtx = getCurrentInstance()?.appContext;

    const keyboard = appCtx?.config.globalProperties.$keyboard;

    const showValue = ref('');

    function showKey() {
      keyboard.show({
        // 调用show的时候传入业务需要监听的事件处理器
        onKeypress(i: number) {
          showValue.value = showValue.value += i;
        }
      });
    }

    function hiddenKey() {
      keyboard.hide();
    }

    return {
      hiddenKey,
      showKey,
      showValue
    }
  }
})
</script>