vue-i 18 nからvueプラグインがどのように動作するかを分析する


物語の背景
vue-i 18 nはvueコードの貢献量2位のvue core teamの日本人のお兄さんが書いたもので、サードパーティのプラグインですが、使うと気持ちがいいです.githubでvue i 18 nを検索すると、結果は少なくなく、いくつかの粗いものがあり、jqueryのlibを使っても六七十人のstarがあります.(ツッコミを止める).すごい人は明らかにデザインの上でコードの上ですべてとても高いランクでしょう.
今日の物語の主役repoはvue-i 18 nとiViewです.彼らを使用している間にエラーを報告し、issueを表示し、issueでコードを取得し、問題を不明に解決しました.
Vue.use(iView, {
    i18n: (key, value) => i18n.vm._t(key, value)
})

これは私がVue.useが2番目のパラメータを伝えることができることを初めて知ったので、何が起こったのか知りたいです.
まず結果を述べると、iViewvue-i18nへの統合を行ったため、文書をよく見ていないために不適切に使用する問題である.研究期間中にelement uiのコードを見た.iViewの対vue-i18nの集積は彼らを写したものであることが分かった.(ツッコミを止める).
この文章を読んでどのような点がわかるかを話してみましょう.
  • Vue.use()何をしましたか
  • の上のコードはなぜiViewvue-i18nの統合使用のエラー
  • を回避したのか.
  • Vue.mixin()何をしましたか
  • vue-i 18 nの差分式$tの方法はどこから来たのか(私はこの方法しか使っていないので)次から私たちの物語を始めます.

  • Vue.use
    (冒頭の話に続く)、以前はVue.use()を使っていたシーンはVue.use(vuex)Vue.use(router)などであった.では、今回は2番目のパラメータがi18n: (key, value) => i18n.vm._t(key, value)に伝わった後、何が起こってプログラムを組織してエラーを報告したのでしょうか.
    まず、Vue.use()が何をしているのか、受け入れられた各パラメータが何をしているのかを理解しなければならない.vueのコードを見始めて、本文のVueのバージョンは2.5.2で、コードを貼って、ファイルの位置:src/core/global-api/use.js
    /* @flow */
    
    import { toArray } from '../util/index'
    
    export function initUse (Vue: GlobalAPI) {
      Vue.use = function (plugin: Function | Object) {
        //   4 :              ,       
        const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
        if (installedPlugins.indexOf(plugin) > -1) {
          return this
        }
    
        // additional parameters
        //   2 :           ,      :  Vue           
        const args = toArray(arguments, 1)
        args.unshift(this)
        //   4 :     api,             .
        if (typeof plugin.install === 'function') {
          plugin.install.apply(plugin, args)
        } else if (typeof plugin === 'function') {
          plugin.apply(null, args)
        }
        //         ,           
        installedPlugins.push(plugin)
        return this
      }
    }

    コードの文法解釈は注釈に書かれていますが、プラグインの名前がCwjであると仮定して、率直に説明します.
    //      
    Vue.use(Cwj)
    //       
    Cwj.install(Vue)
    //    api,    ,      lib   install  
    Cwj(Vue)
    
    //       :
    Vue.use(Cwj, {
        foo: () => bar
    })
    //       
    Cwj.install(Vue, {
        foo: () => bar
    })

    まとめ:Vue.use()の動作:プラグインのinstall()の方法を実行し、第1のパラメータはVueであり、残りのパラメータはVue.use()が受け入れる第2のパラメータおよび以降のパラメータである.
    また、uiコンポーネントのinstallメソッドの大部分はVue.component()を実行する、ハハ.
    統合エラーを回避する原理を分析するVue.use()が何をしたか知ったら、iViewのコードにinstall()の方法を探しに行きます.私がここで見たiViewのバージョンは2.5.0-betaです.1,src/index.jsでinstallメソッドが見つかりました.
    const install = function(Vue, opts = {}) {
        locale.use(opts.locale);
        locale.i18n(opts.i18n);
    
        Object.keys(iview).forEach(key => {
            Vue.component(key, iview[key]);
        });
    
        Vue.prototype.$Loading = LoadingBar;
        Vue.prototype.$Message = Message;
        Vue.prototype.$Modal = Modal;
        Vue.prototype.$Notice = Notice;
        Vue.prototype.$Spin = Spin;
    };

    2行目と3行目で2番目のパラメータの操作が行われていることは明らかですが、src/locale/index.jsを見てみましょう.
    export const use = function(l) {
        lang = l || lang;
    };
    
    export const i18n = function(fn) {
        i18nHandler = fn || i18nHandler;
    };

    わあ、なるほど、i18nメソッドが伝達すると、iViewコンポーネントに伝達メソッドが呼び出され、予め定義されたi 18 n処理メソッドではなく、文書の規定に従わなくてもエラーが報告されないのも無理はない.
    Vue.mixin
    では、私たちが伝えた方法は(key, value) => i18n.vm._t(key, value)です.ここのi18n.vm._tはどこから来たのか、私のプロジェクトで問題が発生したファイルがどのようにロードされているかを見てみましょう.
    Vue.use(VueI18n)
    
    const i18n = new VueI18n({
        locale: 'cn',
        messages
    })
    
    Vue.use(iView, {
        i18n: (key, value) => i18n.vm._t(key, value)
    })
    
    new Vue({
        components: {App},
        router,
        store,
        i18n,
        template: ''
    }).$mount('#app')

    なるほど、このi18nは、VueとコンポーネントのVueI18nに渡された例で、インスタンスには言語パッケージの情報が入っていて、翻訳を推定する際にもi18n.vm._tメソッドが呼び出されているので、vue-i18nのコードを見るのが我慢できません.私が見たvue-i 18 nのバージョンは7.3.1です.src/install.jsを見てみましょう.
    import { warn } from './util'
    import extend from './extend'
    import mixin from './mixin'
    import component from './component'
    import { bind, update } from './directive'
    
    export let Vue
    
    export function install (_Vue) {
      Vue = _Vue
      //             ,            
      const version = (Vue.version && Number(Vue.version.split('.')[0])) || -1
      /* istanbul ignore if */
      if (process.env.NODE_ENV !== 'production' && install.installed) {
        warn('already installed.')
        return
      }
      install.installed = true
    
      /* istanbul ignore if */
      if (process.env.NODE_ENV !== 'production' && version < 2) {
        warn(`vue-i18n (${install.version}) need to use Vue 2.0 or later (Vue: ${Vue.version}).`)
        return
      }
      //         ,    _i18n  Vue.$i18n
      Object.defineProperty(Vue.prototype, '$i18n', {
        get () { return this._i18n }
      })
      //   4      
      extend(Vue)
      Vue.mixin(mixin)
      Vue.directive('t', { bind, update })
      Vue.component(component.name, component)
      //      merge  
      // use object-based merge strategy
      const strats = Vue.config.optionMergeStrategies
      strats.i18n = strats.methods
    }

    同様に、解釈も注釈に書かれていますが、4つのinstallの核心には私のmixinの方法が詳しくありません.次に、Vue.mixin()の方法で何をしたのかを理解してみましょう.
    /* @flow */
    
    import { mergeOptions } from '../util/index'
    
    export function initMixin (Vue: GlobalAPI) {
      Vue.mixin = function (mixin: Object) {
        this.options = mergeOptions(this.options, mixin)
        return this
      }
    }

    文字通りmerge配置、optionsつまりnew Vue()のときに伝わるパラメータなので、mixinに伝わるのはすべてのVueのサブコンポーネントにoptionsとして扱われる.(このロジックはコードを見ていません.ドキュメントを見ています).
    $tがどのように動作するか
    ロードを行った後、domの補間表現で呼び出すだけで翻訳できます.$t('hello')のように、$tの方法はどのようにすべてのVueのサブコンポーネントにロードされますか.私たちはもう一度整理しなければなりません.
    以前の章ではいくつかのロード方法について理解していたが、vue-i18nのインストール時から分析を開始し、$tがどのように翻訳するかを検出することを目的としてvue-i18nのソースコードポケットについて一周する.
    ≪ロード|Load|emdw≫
    まずvue-i 18 nがどのようにロードされたかを見てみましょう.
    Vue.use(VueI18n)
    
    const i18n = new VueI18n({
        locale: 'cn',
        messages
    })
    
    new Vue({
        components: {App},
        router,
        store,
        i18n,
        template: ''
    }).$mount('#app')

    ここで2つに分けます.
  • Vue.use(VueI18n)、ここではinstallメソッド
  • が実行されている
  • new Vue({ i18n: new VueI18n(options)})、ここではvue-i18nのインスタンスをコンポーネントとのoptionsとして設定し、このインスタンスに何があるのか、どこでいつ呼び出されたのかを分析する必要があります.

  • install
    前述したように、installのコアの4つの方法は、
    Object.defineProperty(Vue.prototype, '$i18n', {
      get () { return this._i18n }
    })
    extend(Vue)
    Vue.mixin(mixin)
    Vue.directive('t', { bind, update })
    Vue.component(component.name, component)

    Directiveとcomponentはそれぞれ登録命令と登録コンポーネントであり、ここでは展開せず、$tを分析することを目標としている.
    見てみろjsの$tに関するコード:(ファイル内の他のコードは貼り付けられていません)
    /* @flow */
    
    export default function extend (Vue: any): void {
      Vue.prototype.$t = function (key: Path, ...values: any): TranslateResult {
        const i18n = this.$i18n
        return i18n._t(key, i18n.locale, i18n._getMessages(), this, ...values)
      }
    }

    なるほど、我々が呼び出す$t('hello')のソースはVue.$tであり、Vue.$i18n._tのメソッドが呼び出される.冒頭のi18n.vm._tと比較すると、i 18 nはVueI18nの例であり、Vueのoptionsのi18nというフィールドに登録されており、同じ_t()メソッドが呼び出されているが、現在浮上している問題は:
  • i18n.vm._tは、Vue.$i18n._tとなる
  • にどのようにロードするかである.
  • _tメソッドは、どこでVueにロードされるかを書く
  • 問題を抱えてmixinを見続けますjs. mixin.jsには2つの方法しかありません.beforeCreateとbeforeDestroyです.私は大体beforeCreateを見て、現在のcomponentのVueを構築する役割を果たしています.i 18 n変数、この変数はVue.$i 18 nのgetterの指向は、なぜgetterを書くのかという理由も出ているが、i 18 n-loaderは単一ファイルにローカル言語パッケージを書くことを許可しているので、mergeしてローカル言語環境を生成する.
    ではmixinではどのように初期言語パッケージを取得したのでしょうか.ソース:const options: any = this.$options、つまりVue.$optionsでは、次の章では、Vueインスタンスの構築時にvue-i 18 nインスタンスをVueインスタンスにロードする方法について説明する.
    Vueインスタンス構築中にロードされたVueI 18 nインスタンスsrc/core/instance/init.jsからのコードを切り取ります.
      Vue.prototype._init = function (options?: Object) {
        const vm: Component = this
        // a uid
        vm._uid = uid++
    
        let startTag, endTag
        /* istanbul ignore if */
        if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
          startTag = `vue-perf-start:${vm._uid}`
          endTag = `vue-perf-end:${vm._uid}`
          mark(startTag)
        }
    
        // a flag to avoid this being observed
        vm._isVue = true
        // merge options
        if (options && options._isComponent) {
          // optimize internal component instantiation
          // since dynamic options merging is pretty slow, and none of the
          // internal component options needs special treatment.
          initInternalComponent(vm, options)
        } else {
          vm.$options = mergeOptions(
            resolveConstructorOptions(vm.constructor),
            options || {},
            vm
          )
        }
        /* istanbul ignore else */
        if (process.env.NODE_ENV !== 'production') {
          initProxy(vm)
        } else {
          vm._renderProxy = vm
        }
        // expose real self
        vm._self = vm
        initLifecycle(vm)
        initEvents(vm)
        initRender(vm)
        callHook(vm, 'beforeCreate')
        initInjections(vm) // resolve injections before data/props
        initState(vm)
        initProvide(vm) // resolve provide after data/props
        callHook(vm, 'created')
    
        /* istanbul ignore if */
        if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
          vm._name = formatComponentName(vm, false)
          mark(endTag)
          measure(`vue ${vm._name} init`, startTag, endTag)
        }
    
        if (vm.$options.el) {
          vm.$mount(vm.$options.el)
        }
      }
    }

    (ざらざらしてみると)、Vueバーパラメータが判断して自分の.$options属性に詰め込む.すなわち、Vue.$options.i18nは現在、VueI 18 nの一例である.
    VueI 18 nの構造を見てみましょう.コードは600行ありますが、初期化時に実行されました
    const silent = Vue.config.silent
    Vue.config.silent = true
    this._vm = new Vue({ data })
    Vue.config.silent = silent

    vuexもそう書いてあるようですが、tメソッドはこのファイルに書かれていますが、どのようにロードするかはvueソースコードを見なければなりません.次回分解するしかありません.
    テキストアドレス