一,基本用法
插件通常为
Vue
来添加全局功能。而插件的应用范围没有明确规定,一般包括:
- 添加全局方法或属性。例如:
vue-custom-element
- 添加全局资源:指令/过滤器/过渡等。如:
v-touch
- 通过全局混入来添加一些组件选项。如:
vue-router
- 添加
Vue
实例方法,通过把他们添加到Vue.prototype
上实现- 一个库,提供自己的
API
,同时提供上面提到的一个或多个功能。如:vue-router
开发一个插件需要暴露一个 install
方法。这个方法的第一个参数是 Vue
构造器,第二个参数一个可选的选项对象。
编写一个组件:
import LoadingComponent from './LoadingComponent.vue';
const MyPlugin = {};
MyPlugin.install = function(Vue, options) {
// 1, 添加全局方法或属性
Vue.myGlobalVariable = "hahha";
Vue.myGlobalMethods = function(){ //... }
// 2, 添加全局资源
// 注册一个全局组件 `loading`, 不用 `import` 可以在任何位置使用
Vue.component('Loading', LoadingComponent)
Vue.directive('my-directive', {
bind(el, binding, vnode, oldnode){ // logic }
})
// 3, mixins
Vue.mixin({
created(){ // logic },
mounted(){ // logic }
})
// 4, 在原型上添加实例方法,被各个实例继承
Vue.prototype.$MyMethods = function(mOptions) { // logic }
}
把 Vue 引到一个新的位置,添加全局方法,组件,属性等内容,其实这些内容也可以通过其他方式写,那么这个API的用处在哪儿
如何使用:
// MyPlugin.vue
<template>
// 2, 添加全局资源 (无需引入,可全局使用的组件)
<Loading />
</template>
export default {
// other logic
mounted(){
// 1, 添加全局方法或属性 (TODO: 这种方式似乎不能访问 ??????)
const myGlobalVariable = this.myGlobalVariable; // undefined
this.myGlobalMethods(); // "this.myGlobalMethods is not a function"
// 3, mixins
// 4, 在原型上添加实例方法,被各个实例继承
this.$MyMethods(); // run logic
}
}
二,源码解析
// ./vue/src/core/global-api/use.js
import { toArray } from "../utils/index";
/* @flow */
import { toArray } from '../util/index'
export function initUse (Vue: GlobalAPI) {
// `plugin: Function | Object` 这种使FLOW写法,facebook 出品的一款Javascript静态类型检查工具。
// use 方法接受的参数为 function 或 object, 若为function, 默认为 install 方法,若为object, 里面必 须含有一个install 方法。
Vue.use = function (plugin: Function | Object) {
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
// 插件只能注册一次
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// 处理附加参数
// `toArray`: arguments是参数列表的一个类数组(不知道是不是这么说),toArray 将它转变成一个真的数组,截取除第一以外的所有参数。 ① 这些参数会在调用install 方法时传入;
const args = toArray(arguments, 1)
args.unshift(this)
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
installedPlugins.push(plugin)
return this
}
}
所以我们总结下,Vue.use
的好处:
- 统一在一个位置注册全局内容,避免
main.js
过度臃肿; - 全局注册,避免重复引入问题;
- 避免重复注册组件。
三,常见的几种用法
-
mixins
// 一个简单的栗子,可以用于 validation const myMixin = { install(Vue, options) { // 这里 this 指向 myMixin Vue.mixin({ // 每个组件创建都会执行 created 方法 created(){ const rules = this.$options.rules || null; if(rules) { Object.keys(rules).forEach(key => { const ruleItem = rules[key]; // $watch 接受两个参数:监测的属性名,callback(变化后的值) this.$watch(key, newValue => { const isValid = ruleItem.validate(newValue); if(!isValid) { console.log(ruleItem.message) } }) }) } } }) } } const vue = new Vue({ data: { foo: 10 }, // 检验规则 ③ rules: { foo: { validate: value => value > 1, message: "foo 必须大于 1" }, // more rules } }) // * 需要注意的是, ③处的 rules 只能在根组件通过 this.options.rules 访问,子组件的话得看嵌套关系,可能是 this.$options.parent.$options....parent.$options.rules 这种方式访问该属性
-
directives
// 注册一个全局自定义指令:`v-focus` // plugin 内部 function Myplugin(Vue){ Vue.directive('focus', { // 当被绑定元素插入到DOM中时,自动聚焦 inserted(el){ el.focus(); } }) } // template 内部 <input v-focus /> // 自动聚焦
-
axios
axios
不能直接用Vue.use
, 以为它本身没有暴露 install 方法。所以使用axios
只能是下面两种方法:-
使用的地方进行
import
:import axios from 'axios'; export const login = params => { return axios .post(`localhost:3000/login`, params) .then(res => res) }
-
使用
vue-axios
:// npm i -S axios vue-axios // main.js import Vue from 'vue'; import axios from 'axios'; import VueAxios from 'vue-axios'; // 由之前的 `vue.use` 用法我们知道,它可以接收第二个 `options` 参数,所以这里本质是将 `axios` 通过 `VueAxios` 包装以符合 "install 规范" Vue.use(VueAxios, axios); // usage this.axios.get(params).then(res => res); Vue.axios.get(params).then(res => res); this.$http.get(params).then(res => res);
-
-
vue-router
// ./route/index.js import Router from 'vue-router'; Vue.use(Router); let router = new Router({ routes: [ { path: "./home", component: homeComp } ] }) export default router; // main.js import router from ....; const vue = new Vue({ // other logic router })
-
Vuex
用法与vue-router 等同,不赘述
四,常见问题
-
为什么要先
Vue.use
再new Vue()
?首先回顾下 Vue.use 做了什么:
- 检测是否注册过此插件
- 插件注入到 Vue 构造函数 (TODO:不知道是不是这么说)
- 存储注册过的插件
而在 new Vue(options) 时,会执行
Vue.prototype._init
进行初始化,将Vue 本身属性与options合并,然后进行事件,生命周期初始化。(比如:vue-router, vuex 等需要将 store, router 选项插入options)所以,如果
Vue.use
在new Vue()
之前执行,那么调用_init()
时,插件中使用的内容还没有注入到Vue.options.component
,Vue.options.directives
等属性中,初始化的实例也无从访问。
网友评论