美文网首页
vue-i18n部分源码解析

vue-i18n部分源码解析

作者: 回调的幸福时光 | 来源:发表于2018-12-13 20:49 被阅读28次

一、$i18n是如何挂载到vue.prototype上面的

挂载步骤.jpg
  1. main.js中执行
import i18n from './lang'
  1. lang/index.js 中执行
Vue.use(VueI18n)

vue.use() 触发的就是 install() 方法, 用来注册插件。

  1. 开始执行 vue-i18n 源码中的 install() 方法。
  extend(Vue)
  Vue.mixin(mixin)
  1. 执行extend()

  2. 执行extend中的以下代码

Object.defineProperty(Vue.prototype, '$i18n', {
      get () { return this._i18n }
    })

注意:

  • this 代表 vue.prototype
    在 get 和 set 方法中,this 指向某个被访问和修改属性的对象。
  • 这里首次,this._i18n 是没有值的, 但是 Object.defineProperty()可以监听属性的变化(赋值会触发getter、setter)。
    实际要到步骤 6 才会真正有值
  1. 执行Vue.mixin(mixin)
    mixin 中开始对 this._i18n 赋值
beforeCreate: function beforeCreate () {
  var options = this.$options;
  options.i18n = options.i18n || (options.__i18n ? {} : null);

  if (options.i18n) {
    
  } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
    // root i18n  根vue实例
    this._i18n = this.$root.$i18n;
    this._i18n.subscribeDataChanging(this);
    this._subscribing = true;
  } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
    // parent i18n 父实例
    this._i18n = options.parent.$i18n;
    this._i18n.subscribeDataChanging(this);
    this._subscribing = true;
  }
}

上述 mixin 的beforeCreate 方法中, 以 this.$options 为判断条件,在首次进入mixin中的时候,i18n是不存在的,为什么呢??

  • 因为 Vue.mixin() 是全局注册混入对象,影响之后创建的所有 vue 实例
  • 在创建 vue 实例时,并没有在选项中包含自定义属性 i18n 或者 __i18n, 所以在 this.$options 中是不存在属性 i18n 的。

但是在根 vue 实例 this.$root 中是有 i18n 的,因为在 main.js 中, 创建根 vue 实例时,是下面这样的 :

new Vue({
  el: '#app',
  router,
  store,
  i18n,  // 我在这里
  render: h => h(App)
})

所以通过 this.$root.$i18nthis.$i18n 赋值, 而这个赋值操作,又会触发 Object.defineProperty() 中的 get 方法,此时才真正的将 $i18n 挂载到 vue.prototype 上面。

二、动态切换语言选项后,vue-i18n是怎么起作用的?

vue-i18n切换语言选项时,在应用层面,只需要知道以下一行代码即可。

// 当前的语言
this.$i18n.locale = lang

那么底层在接收到最新的语言选项之后,是如何作用在页面上的呢???

在类 VueI18n 中,有以下方法 watchLocale() ,用来监听 locale 的变化。具体操作,看注释即可。

watchLocale (): ?Function {
    /* istanbul ignore if */
    if (!this._sync || !this._root) { return null }
    const target: any = this._vm // vue 实例
    return this._root.$i18n.vm.$watch('locale', (val) => {
      // 重新对 locale 赋值
      target.$set(target, 'locale', val) 
      // 迫使 Vue 实例重新渲染
      target.$forceUpdate() 
    }, { immediate: true })
  }

参考

大漠:JavaScript学习笔记: Object.defineProperty()

相关文章

网友评论

      本文标题:vue-i18n部分源码解析

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