Vue—关于插件(源码级别的插件分析+实践)
2022/10/21 4:24:52
本文主要是介绍Vue—关于插件(源码级别的插件分析+实践),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
在Vue中提供了use方法来安装插件,那么Vue插件的原理是什么呢?
一、Vue.use
use方法官方描述如下图:
也就是说Vue.use()方法接收一个函数或者提供install方法的对象作为参数(必须提供install方法),如果传入的参数是函数,这个函数会被当做install方法。
文档:https://cn.vuejs.org/v2/api/#Vue-use
Vue2.6.11版本use源码如下:
这段源码很好理解,initUse函数中给Vue添加了一个静态方法use,use方法接收一个参数plugin,判断参数是对象还是函数并执行相关逻辑。
以vuex3.6.2版本为例,直接看源码:
它暴露了一个install方法,验证了我们前面的学习:Vue.use(vuex)是使用这个install方法来安装插件的。
那么vuex的install函数做了什么?
可以看到它调用了applyMixin函数并把Vue传过去了
applyMixin函数源码如下:
如果是vue2.x版本,vuex直接使用Vue.mixin来扩展功能,它利用混入的钩子会在组件钩子之前调用的特性,给应用添加一个beforeCreate钩子,在这里初始化vuex插件。
二、mixin
不得不说一下mixin
what:mixin是一种js的设计模式,可以轻松被子类继承功能,目的是函数复用,Vue中也应用了这一设计模式,通过Vue.mixin可以用来分发可复用逻辑。
why:试想,当多个组件具有类似的数据和方法时,是不是可以将这些数据和方法提取出来,通过混入的方式将逻辑注入到需要这些数据和方法的组件中呢?这将会为我们节省很多代码,也是Vue设计mixin的理由
how:使用方式有两种:全局混入和局部混入,具体使用方式可参考文档:https://cn.vuejs.org/v2/guide/mixins.html#基础
注意:尽量避免使用全局混入,因为它会影响所有的vue实例(有时候莫名其妙功能被搞乱了都不知道咋回事,排查非常困难),如果组件中与mixin中具有同名的属性,会进行选项合并,除了生命周期外,其它的所有属性都会被组件自身的属性覆盖,与继承的原理是类似的,如果子类本身有这个属性或方法就不会再沿着原型链往上找了,生命周期会被合并成数组,混入的钩子会在组件的钩子之前被调用。
mixin的源码非常简单,只是调用mergeOptions函数进行选项合并
其它的插件开发原理是差不多的,官方文档如下:
三、自己实现一个插件
现在,我们来实现一个提示框插件,要求可以通过this.$notify()来进行调用,并且可以传入自定义模板
分析需求:
- 要实现一个Vue插件,首先按照Vue.use的约定我们需要提供一个对象,这个对象必须要有install函数,或者提供一个函数
- 通过this来调用它,说明这个方法需要挂在Vue的原型对象上,所以我们需要给Vue的prototype添加一个$notify方法
- 可以传入自定义模板,说明我们需要调用API来编译传入的模板
现在我们创建一个vue工程,在src目录下新建plugin目录,然后创建一个notify目录,新建index.js和Notify.vue
你可能会好奇为什么要新建一个Notify.vue,不急,后面会讲
按照我们前面的分析,我们知道一个插件的基本结构大致如下:
// index.js function notify() { function install(Vue) { } return { install }; } export default notify();
然后我们要给Vue的原型对象添加KaTeX parse error: Expected 'EOF', got '方' at position 7: notify方̲法,这样我们可以通过this.notify()来调用
// index.js function install(Vue) { Vue.prototype.$notify = notifyInit; } function notifyInit(options) { console.log('调用成功') }
这样一个插件的基本功能就实现了,我们可以通过Vue.use来使用它,在main.js中:
// main.js import notify from './plugins/notify/index' Vue.use(notify);
然后我们到App.vue中验证一下功能是否正常,点击的时候调用this.notify()
<template> <div id="app"> <button @click="handleShow">显示</button> </div> </template> <script> export default { name: 'App', methods: { handleShow() { this.$notify() } } } </script>
到这一步功能正常,我们已经实现了调用this.notify()来进行提示
接着我们需要实现传入模板并且显示出来,那么问题来了,传入模板好理解,怎么编译模板并且显示出来呢?
这就要用到Vue给我们提供的$mount API了,官方描述如下:
文档:https://cn.vuejs.org/v2/api/#vm-mount
既然可以手动挂载一个实例,那么我们可以创建一个Vue组件,在组件中将dom、js、style都创建好,最后在调用$notify的时候将挂载的元素插入到文档中,这就是Notify.vue的作用了
Notify.vue我们先简单创建好结构,代码如下:
<template> <div class="notify" v-if="isShow"> <div id="content"></div> </div> </template> <script> export default { name: "notify", }; </script> <style> .notify #content { position: fixed; bottom: 10px; right: 10px; z-index: 999; width: 200px; height: 150px; border-radius: 5px; border: 1px solid #e5e5e5; } </style>
在index.js中,我们需要引入这个组件,通过install方法中注入的Vue来完成功能,分为如下几步:
- 调用Vue.extend声明扩展单文件组件Notify
- 获取Notify组件的实例
- 调用$mount来挂载实例
- 获取KaTeX parse error: Expected 'EOF', got '并' at position 3: el并̲将el插入到文档中
注意:实例挂载之后才可以访问$el选项,这在官方文档上说的很清楚
文档:https://cn.vuejs.org/v2/api/#el
代码如下:
import Notify from "./Notify.vue"; function notify() { function install(Vue) { elementInit(Vue); Vue.prototype.$notify = notifyInit; } function elementInit(Vue) { // 声明扩展组件 const ClassNotify = Vue.extend(Notify); // 获取组件实例 const instance = new ClassNotify(); // 挂载组件,添加el选项 instance.$mount(); // 获取el const el = instance.$el; // 插入el document.body.appendChild(el); } function notifyInit(options) { console.log('调用成功') } return { install, }; } export default notify();
现在我们已经将组件成功插入到body中了,不出意外你将在页面右下角找到下图显示的框
接下来要实现传入模板,vue中也为我们提供了v-html指令来插入模板
文档:https://cn.vuejs.org/v2/api/#v-html
我们需要做的只是在调用this.notify()方法的时候,将接收到的配置参数传递给Notify组件,由Notify组件通过v-html指令来进行渲染
如果我们直接在notifyInit函数中访问Notify实例,显然是访问不到的,this指向的是当前调用$notify方法的组件,本例中也就是App.vue
那么借助$mount调用返回vm(实例自身)的特性,我们可以将Notify组件存下来,然后再到notifyInit函数中进行访问
import Notify from "./Notify.vue"; function notify() { let NotifyComponent; function install(Vue) { elementInit(Vue); Vue.prototype.$notify = notifyInit; } function elementInit(Vue) { // 声明扩展组件 const ClassNotify = Vue.extend(Notify); // 获取组件实例 const instance = new ClassNotify(); // 挂载组件,添加el选项,并将vm赋值给NotifyComponent NotifyComponent = instance.$mount(); // 获取el const el = instance.$el; // 插入el document.body.appendChild(el); } function notifyInit(options) { // 调用notify组件的方法,将配置参数透传过去 NotifyComponent.notify(options); } return { install, }; } export default notify();
然后我们只需要在Notify.vue中新增该方法来接收参数即可
<template> <div class="notify" v-if="isShow"> <div id="content" v-html="content"></div> </div> </template> <script> export default { name: "notify", data() { return { isShow: false, content: "张三", }; }, methods: { notify(options) { this.isShow = true; // 两秒后隐藏 setTimeout(() => { this.isShow = false; }, 2000) // 传了配置参数则使用,否则使用默认 options && options.content && (this.content = options.content); }, }, }; </script> <style> .notify #content { position: fixed; bottom: 10px; right: 10px; z-index: 999; width: 200px; height: 150px; border-radius: 5px; border: 1px solid #e5e5e5; } </style>
此时我们在App.vue中传递一段模板
页面上操作的效果为下图,且两秒后消失
这篇关于Vue—关于插件(源码级别的插件分析+实践)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-15useCallback教程:React Hook入门与实践
- 2024-11-15React中使用useContext开发:初学者指南
- 2024-11-15拖拽排序js案例详解:新手入门教程
- 2024-11-15React中的自定义Hooks案例详解
- 2024-11-14受控组件项目实战:从零开始打造你的第一个React项目
- 2024-11-14React中useEffect开发入门教程
- 2024-11-14React中的useMemo教程:从入门到实践
- 2024-11-14useReducer开发入门教程:轻松掌握React中的useReducer
- 2024-11-14useRef开发入门教程:轻松掌握React中的useRef用法
- 2024-11-14useState开发:React中的状态管理入门教程