美文网首页
Vue.use 详解

Vue.use 详解

作者: Alaricming | 来源:发表于2020-02-21 11:20 被阅读0次
    一,基本用法

    插件通常为 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 的好处:

    1. 统一在一个位置注册全局内容,避免main.js过度臃肿;
    2. 全局注册,避免重复引入问题;
    3. 避免重复注册组件。
    三,常见的几种用法
    • 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.usenew Vue() ?

      首先回顾下 Vue.use 做了什么:

      • 检测是否注册过此插件
      • 插件注入到 Vue 构造函数 (TODO:不知道是不是这么说)
      • 存储注册过的插件

      而在 new Vue(options) 时,会执行 Vue.prototype._init 进行初始化,将Vue 本身属性与options合并,然后进行事件,生命周期初始化。(比如:vue-router, vuex 等需要将 store, router 选项插入options)

      所以,如果 Vue.usenew Vue() 之前执行,那么调用_init()时,插件中使用的内容还没有注入到 Vue.options.component, Vue.options.directives 等属性中,初始化的实例也无从访问。

    相关文章

      网友评论

          本文标题:Vue.use 详解

          本文链接:https://www.haomeiwen.com/subject/xrxcqhtx.html