1.Vue.use()
Vue.use()用来注册插件。它要在调用new Vue之前完成
源码:
export function initUse (Vue: GlobalAPI) {
Vue.use = function (plugin: Function | Object) {
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
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()方法,接收一个函数或者对象作为参数,如果参数注册了install方法,会执行install方法,如果没有注册且参数是函数,则会执行该函数。
执行的时候,会将Vue作为参数,传入到函数中。
通过Vue.use,可以完成下面的一些操作:
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或属性
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 3. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
2.mixin
mixin:可以对组件中的公用部分进行提取,做封装。
很通用的场景就是,多个组件都公用了一些接口或者变量,可以把它做成公共的部分,然后混入到各个组件中。
使用方式:
// 定义一个混入对象
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
//在组件中
import myMixin from '@/mixin/myMixin.js'
export default {
mixins: [myMixin],
}
这样,就可以把混入对象合并到组件的配置中。
除了混入单个组件的mixin,还有全局混入Vue.mixin(全局混入官方不推荐在业务代码中使用)
像vue-router等插件,就是利用全局混入,将实例混入到每一个组件中。
vue-router源码中的src/install.js中:
export let _Vue
export function install (Vue) {
if (install.installed && _Vue === Vue) return
install.installed = true
_Vue = Vue
const isDef = v => v !== undefined
const registerInstance = (vm, callVal) => {
let i = vm.$options._parentVnode
if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
i(vm, callVal)
}
}
//这里把beforeCreate,destroyed混入到了每一个vue组件中
Vue.mixin({
beforeCreate () {
if (isDef(this.$options.router)) {
this._routerRoot = this
this._router = this.$options.router
this._router.init(this)
Vue.util.defineReactive(this, '_route', this._router.history.current)
} else {
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
}
registerInstance(this, this)
},
destroyed () {
registerInstance(this)
}
})
Object.defineProperty(Vue.prototype, '$router', {
get () { return this._routerRoot._router }
})
Object.defineProperty(Vue.prototype, '$route', {
get () { return this._routerRoot._route }
})
Vue.component('RouterView', View)
Vue.component('RouterLink', Link)
const strats = Vue.config.optionMergeStrategies
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}
在选项合并的时候,如果遇到同名选项时:
- 数据对象会在内部进行递归合并,并在发生冲突时以组件数据优先
- 同名的钩子函数都会执行,并且混入对象的钩子函数比组件的钩子函数先执行。
- 值为对象的选项,如
methods,componets等,将被合并为同一个对象。键名冲突时,取组件对象的键值对。
3.Vue.directive()
Vue.directive用来注册全局自定义指令。可以把自定义指令看作是对当前绑定DOM元素的命令,可以在特定的钩子函数中,操作DOM元素。
几种常用的钩子:
bind:只调用一次,指令第一次绑定到元素时调用inserted:被绑定元素插入父节点时调用update:被绑定的元素所在的模板更新时调用
可以通过自定义指令,实现对按钮的权限控制
//permission.js
import store from '@/store';
export default {
//inserted钩子函数:-被绑定元素插入父节点时调用。
inserted(el, binding) {
// bind.value 即为 按钮权限的key值
if (binding.value) {
/**
* key不存在该数组中 移除元素
*/
if (!store.state.user.permissionKey.includes(binding.value)) {
el.parentNode.removeChild(el);
}
} else {
throw new Error('need permission key! Like v-permission="\'addUser\'"');
}
},
};
注册指令
//index.js
import permission from './permission';
const install = (Vue) => {
Vue.directive('permission', permission);
};
export default { install };
//main.js,其实就是调用下Vue.directive()注册下
import {install} from "./diretives/index.js"
Vue.use(install)
使用
<button v-permission="key">解冻</button>
4.为什么组件中的 data 必须是一个函数,然后 return 一个对象,而 new Vue 实例里,data 可以直接是一个对象
因为组件是用来复用的,且 JS 里对象保存在堆内存中,是引用关系,如果组件中 data 是一个对象,那么多个组件会公用这份数据,子组件中的 data 属性值会相互影响,如果组件中 data 选项是一个函数,那么每个实例可以维护一份被返回对象的独立的拷贝,组件实例之间的 data 属性值不会互相影响;而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。
5.Proxy 与 Object.defineProperty 优劣对
Proxy 的优势如下:
- Proxy 可以直接监听对象而非属性;
- Proxy 可以直接监听数组的变化;
- Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
- Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;
- Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;
Object.defineProperty 的优势如下:
兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。