vue3-自定义vue插件

113 阅读1分钟

自定义vue插件

image.png

main.ts
import { createApp, Ref } from 'vue';

import App from './App.vue';

const app = createApp(App);

// 扩充声明
declare module 'vue' {
  export interface ComponentCustomProperties {
    $showMessage: {
      show: () => void;
      hide: () => void;
      isShow: Ref<any>;
    };
  }
}

import showMessage from './components/show-message';
// 注册全局插件
app.use(showMessage);

app.mount('#app');
./components/show-message/index.ts
import { App, VNode, createVNode, render } from 'vue';
import showMessage from './index.vue';

export default {
  // 注册插件必须实现install方法
  install: (app: App) => {
    // 组件转为vNode,虚拟dome结构
    const vNode: VNode = createVNode(showMessage);
    // 手动把虚拟节点挂载到全局,因为是全局,所以直接挂载到document.body
    render(vNode, document.body);
    app.config.globalProperties.$showMessage = {
      show: vNode.component.exposed.show,
      hide: vNode.component.exposed.hide,
      isShow: vNode.component.exposed.isShow,
    };
  },
};
./components/show-message/index.vue
<template>
  <div v-if="isShow" class="box">
    <pre>测试数据</pre>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const isShow = ref(false);
const show = () => {
  isShow.value = true;
};
const hide = () => {
  isShow.value = false;
}; 

// 把方法&变量暴露出去 
defineExpose({
  show,
  hide,
  isShow,
});

</script>

<style scoped>
.box {
  float: right;
  background-color: white;
  border: 2px solid black;
  height: 500px;
  width: 500px;
}
</style>
全局,任何地方都可以直接使用
<template>
  <div>
    <div>我是index</div>
    <hr />
    <t-button @click="hclick">点我</t-button>
  </div>
</template>

<script lang="ts">
export default {
  name: 'ApplyAWSIndex',
};
</script>
<script setup lang="ts">
import { getCurrentInstance } from 'vue';

// 获取当前组件实例
const instance = getCurrentInstance();

const hclick = () => {

  console.log(instance.proxy.$showMessage.isShow.value);
  
  // 调用方法
  instance.proxy.$showMessage.show();
  
  setTimeout(() => {
    instance.proxy.$showMessage.hide();
  }, 3000);
  
};
</script>

<style scoped lang="less">
.box {
  border: 3px solid black;
  height: 50px;
}
</style>

点击前 image.png 点击后 image.png