锦囊(vue)

254 阅读3分钟

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 重写。