夜猫子的知识栈 夜猫子的知识栈
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

夜猫子

前端练习生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 基础

  • 响应式

  • 组件

  • 过渡&动画

  • 可复用性

    • Mixin混入
    • 渲染函数
    • 全局API
    • Teleport
    • 组合式API
    • 引入css样式
    • 自定义hook
    • 自定义插件
      • Vue3 自定义插件
        • 基本逻辑
        • 常见定义
        • 使用
        • 复杂实例:挂载 VNode ,并 添加全局方法
        • VNode
        • 编写插件
        • 挂载插件
        • 组件中使用
      • 拓展:Vue2 方法
        • 对外暴露一个install方法
        • 全局引入后注册(也可以传入一个可选的选项对象)
        • 相关
        • 封装echarts插件案例
    • 自定义事件
    • 自定义指令
  • 工具

  • 规模化

  • 路由(核心)

  • 组合式

  • Vuex

  • Pinia

  • 其他

  • Vue3 源码学习记录

  • 《Vue》笔记
  • 可复用性
夜猫子
2022-04-13
目录

自定义插件

# Vue3 自定义插件

插件是自包含的代码,通常向 Vue 添加全局级功能。它可以是公开 install() 方法的 object,也可以是 function。

# 基本逻辑

// plugins/myPlugins.js
export default {
  install: (app, options) => {
    // Plugin code goes here
  }
}
1
2
3
4
5
6

# 常见定义

// plugins/myPlugins.js
export default {
    // 一个简单的i18n翻译转化
  install: (app, options) => {//接收一个 key 字符串,并使用在用户提供的选项中查找转换后的字符串
    app.config.globalProperties.$translate = (key) => {
      return key.split('.')
        .reduce((o, i) => { if (o) return o[i] }, options)
    }

    app.provide('i18n', options)

    app.directive('my-directive', {
      mounted (el, binding, vnode, oldVnode) {
        // some logic ...
      }
      ...
    })

    app.mixin({
      created() {
        // some logic ...
      }
      ...
    })
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 使用

1.全局注册

//main.ts
import { createApp } from 'vue'
import App from './App.vue'
import myPlugins from './plugins/myPlugins.js'

const app = createApp(App)
const myPluginStrings = {
  greetings: {
    hi: 'Hallo!'
  }
}
//用于查找的翻译字典对象则应当在插件被安装时作为 app.use() 的额外参数被传入
app.use(myPlugins, myPluginStrings)
app.mount('#app')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$translate('greetings.hi') // 'Hallo!'
1
  1. Provide / Inject 将插件接收到的 options 参数提供给整个应用,让任何组件都能使用这个翻译字典对象。
<script setup>
import { inject } from 'vue'

const i18n = inject('i18n')

console.log(i18n.greetings.hello)
</script>
1
2
3
4
5
6
7

# 复杂实例:挂载 VNode ,并 添加全局方法

# VNode

// component/Loading.vue
<template>
    <div v-if="flag">true</div>
    <div v-else="flag">false</div>
</template>

<script setup lang="ts">
import { ref, defineExpose } from 'vue'
let flag = ref<Boolean>(false)
const flagTrueFn = () => {
    flag.value = true
}
const flagFalseFn = () => {
    flag.value = false
}
defineExpose({
    flag,
    flagTrueFn,
    flagFalseFn
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 编写插件

// component/index.ts
import { App, createApp, h, render, VNode, createVNode } from "vue";
import loading from "./loading.vue";

export default {
  install(app: App, options: any) {
    //方法一:使用 render 函数实例化插件并挂载到 body 中
    // const vnode: VNode = createVNode(loading);
    // render(vnode, document.body);
    // app.config.globalProperties.$loading = {
    //   flag: vnode.component?.exposed?.flag,
    //   flagTrueFn: vnode.component?.exposed?.flagTrueFn,
    //   flagFalseFn: vnode.component?.exposed?.flagFalseFn,
    // };

    //方法二:使用 createApp.mount 挂载实例
    const plugin = createApp(loading);
    const vnode = plugin.mount(document.createElement("div"));
    document.body.appendChild(vnode.$el);    
    app.config.globalProperties.$loading = {
        flag: vnode.flag,
        flagTrueFn: vnode.flagTrueFn,
        flagFalseFn: vnode.flagFalseFn,
      };
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 挂载插件

import { createApp } from "vue";
import App from "./App.vue";
import Loading from "./components/loading";

let app = createApp(App);
//没有类型限制,可能会 ts 警告,需要给它定义泛型
declare module "@vue/runtime-core" {
  export interface ComponentCustomProperties {
      flag:Boolean
      flagTrueFn: () => void;
      flagFalseFn: () => void;
  }
}
app.use(Loading);
app.mount("#app");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 组件中使用

<script setup lang="ts">
import { ComponentInternalInstance, getCurrentInstance } from 'vue'
// getCurrentInstance 支持访问内部组件实例,类似于 this。
const { appContext } = getCurrentInstance() as ComponentInternalInstance
const changeFlag = () => {
  appContext.config.globalProperties.$loading.flagTrueFn()
  console.log(appContext)
  setTimeout(() => {
    appContext.config.globalProperties.$loading.flagFalseFn()
  }, 2000)
}
</script>

<template>
  <Button @click="changeFlag">切换</Button>
</template>

<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 拓展:Vue2 方法

# 对外暴露一个install方法

暴露了一个 install 方法。其第一个参数是vue,第二个参数是自定义传参(可选的选项对象)

let MyPlugin={}
MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或 property
  Vue.myGlobalMethod = function () {
    // 逻辑...
  }

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

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

  // 4. 添加实例方法
  Vue.prototype.$myMethod = function (methodOptions) {
    // 逻辑...
  }
}
export default MyPlugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 全局引入后注册(也可以传入一个可选的选项对象)

Vue.use(MyPlugin, { options: '一个插件' })
1

# 相关

使用方法四直接挂载到原型上,虽然所有的实例都能访问到,但有一个风险:即同时也可以通过访问来修改该方法,存在风险,不严谨。

可以使用js原生方法Object.defineProperty()方法代替

# 封装echarts插件案例

import echarts from "echarts"
let MyPlugin = {}
MyPlugin.install = function (Vue) {
    Object.defineProperties(Vue.prototype, {
        //$myChart即为实例上添加的一个方法名
        $myChart: {
            //此处只用到get()没有用set()因为不涉及修改和双向绑定
            get() {
                return {
                    //绘制折线图
                    line(id) {
                        //以下来自echarts折线图官方配置
                        // 基于准备好的dom,初始化echarts实例
                        var myChart = echarts.init(document.getElementById(id))
                        // 指定图表的配置项和数据
                        var option = {
                            title: {
                                text: "ECharts 入门示例",
                            },
                            tooltip: {},
                            legend: {
                                data: ["销量"],
                            },
                            xAxis: {
                                data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"],
                            },
                            yAxis: {},
                            series: [
                                {
                                    name: "销量",
                                    type: "bar",
                                    data: [5, 20, 36, 10, 10, 20],
                                },
                            ],
                        };
                        // 使用刚指定的配置项和数据显示图表。
                        myChart.setOption(option);
                    },
                    //绘制地图
                    chinaMap(){
					...
                    }
                }
            }
        }
    })
}
export default MyPlugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

在main.js中use后,在任意组件中使用以下代码即表示使用折线图(折线图的相关样式规范参考echarts官网)

this.$myChart.line('main')
1
编辑 (opens new window)
上次更新: 2023/7/11 18:57:41
自定义hook
自定义事件

← 自定义hook 自定义事件→

最近更新
01
IoC 解决了什么痛点问题?
03-10
02
如何调试 Nest 项目
03-10
03
Provider注入对象
03-10
更多文章>
Copyright © 2019-2025 Study | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式