1.最も俗っぽい学習の-Vueソース学習-導入編(上)

27425 ワード

ソースアドレス
前方高エネルギー!!!
これはただの個人学習です.jsソースのノートは、教程ではありません.个人のレベルが限られているため、间违いがある可能性があります.また、各道の大神が文章の内容が极度に下品であることを指导してください.
Vue.jsバージョン–2.1.7
これを選んだのは、この大神の分析を見て、同じバージョンを採用することにしたためで、現在Vueはすでに2.5を発表している.xここではぜひ皆さんにお勧めします.この大神の2つのソース分析はユーゴスラーのお勧めだそうですよ.本文は第1編としても大神の文章を参考にして冒頭に、大きな部分を参考にして自分の理解を加えて書いたものです
Vue2.1.7ソース学習
JavaScriptがMVVMを実現した私は、一般的なオブジェクトの変化を監視したいと思っています.
src/core/instance/index.js
これはvue全体のエントリファイルで、まずvueを導入した後、私たちは構造関数を導入しただけなので、一般的に初期化するときはnew Vueで起動します.つまり、次のVue関数で、this.Init(options)、このoptionsは私たちが伝えた様々なパラメータです.

new Vue({
  el: '#app',
  data: {
    name: 'zhang san',
    age: 18
  }
})

以下はsrc/core/instance/indexです.jsのソースコードで、vueを導入するとすぐにmixinが5個初期化されます

import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'

function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue


依存を導入し,Vueコンストラクション関数を定義し,次にVueコンストラクション関数をパラメータとして5つの方法を呼び出し,最後にVueを導出した.この5つの方法はそれぞれ5つのファイルから来ています:init.js state.js render.js events.jsおよびlifecycle.js. この5つのファイルを開くと、対応する方法が見つかります.これらの方法の役割は、Vueのプロトタイプprototypeにメソッドまたはプロパティをマウントすることです.この5つの方法を経験したVueは次のようになります.

// initMixin(Vue)    src/core/instance/init.js **************************************************
Vue.prototype._init = function (options?: Object) {}

// stateMixin(Vue)    src/core/instance/state.js **************************************************
Vue.prototype.$data
Vue.prototype.$set = set
Vue.prototype.$delete = del
Vue.prototype.$watch = function(){}

// renderMixin(Vue)    src/core/instance/render.js **************************************************
Vue.prototype.$nextTick = function (fn: Function) {}
Vue.prototype._render = function (): VNode {}
Vue.prototype._s = _toString
Vue.prototype._v = createTextVNode
Vue.prototype._n = toNumber
Vue.prototype._e = createEmptyVNode
Vue.prototype._q = looseEqual
Vue.prototype._i = looseIndexOf
Vue.prototype._m = function(){}
Vue.prototype._o = function(){}
Vue.prototype._f = function resolveFilter (id) {}
Vue.prototype._l = function(){}
Vue.prototype._t = function(){}
Vue.prototype._b = function(){}
Vue.prototype._k = function(){}

// eventsMixin(Vue)    src/core/instance/events.js **************************************************
Vue.prototype.$on = function (event: string, fn: Function): Component {}
Vue.prototype.$once = function (event: string, fn: Function): Component {}
Vue.prototype.$off = function (event?: string, fn?: Function): Component {}
Vue.prototype.$emit = function (event: string): Component {}

// lifecycleMixin(Vue)    src/core/instance/lifecycle.js **************************************************
Vue.prototype._mount = function(){}
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {}
Vue.prototype._updateFromParent = function(){}
Vue.prototype.$forceUpdate = function () {}
Vue.prototype.$destroy = function () {}

これで終わりですか?いいえ、私たちが前にVueを探していたルートによると、これは始まったばかりで、ルートを遡って戻ります.では、次のVue構造関数を処理するのはsrc/core/indexです.jsファイルを開きます.

import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'

initGlobalAPI(Vue)

Object.defineProperty(Vue.prototype, '$isServer', {
  get: isServerRendering
})

Vue.version = '__VERSION__'

export default Vue

私たちはここから出発点として
まずここでこのisServer Renderingを言って、このenvファイルを見つけて、中に方法があります

export const inBrowser = typeof window !== 'undefined'

let _isServer
export const isServerRendering = () => {
  if (_isServer === undefined) {
    /* istanbul ignore if */
    if (!inBrowser && typeof global !== 'undefined') {
      // detect presence of vue-server-renderer and avoid
      // Webpack shimming the process
      _isServer = global['process'].env.VUE_ENV === 'server'
    } else {
      _isServer = false
    }
  }
  return _isServer
}

このコードはサービス側かどうかを判断し、const inBrowser=typeof window!="undefinedというコードはだいたい分かります
次に、コンストラクション関数のプロトタイプのプロパティ$isServerにバインドします.

Object.defineProperty(Vue.prototype, '$isServer', {
  get: isServerRendering
})


それからinitGlobalAPIメソッドの実行について話します
src\core\global-api\index.js
このファイルは、パラメータとしてVueコンストラクション関数を受け入れる関数をエクスポートします.

export function initGlobalAPI (Vue: GlobalAPI) {
  // config
  const configDef = {}
  configDef.get = () => config
  if (process.env.NODE_ENV !== 'production') {
    configDef.set = () => {
      util.warn(
        'Do not replace the Vue.config object, set individual fields instead.'
      )
    }
  }
  Object.defineProperty(Vue, 'config', configDef)
  Vue.util = util
  Vue.set = set
  Vue.delete = del
  Vue.nextTick = util.nextTick

  Vue.options = Object.create(null)
  config._assetTypes.forEach(type => {
    Vue.options[type + 's'] = Object.create(null)
  })

  // this is used to identify the "base" constructor to extend all plain-object
  // components with in Weex's multi-instance scenarios.
  Vue.options._base = Vue

  util.extend(Vue.options.components, builtInComponents)

  initUse(Vue)
  initMixin(Vue)
  initExtend(Vue)
  initAssetRegisters(Vue)
}

まずオブジェクトconfigDef,configDefを定義.getはconfigに関連付けられ、srccoreconfigを開く.js
中は実は1つのオブジェクトを書き出して、オブジェクトの中には多くの属性があって、その中には

_assetTypes: [
    'component',
    'directive',
    'filter'
  ],

  _lifecycleHooks: [
    'beforeCreate',
    'created',
    'beforeMount',
    'mounted',
    'beforeUpdate',
    'updated',
    'beforeDestroy',
    'destroyed',
    'activated',
    'deactivated'
  ],


この2つが一般的な属性とライフサイクルであり,開発環境で提示のためのsetメソッドの最後のObjectがあると判断する.defineProperty(Vue,‘config’,configDef)は、構造関数の静的属性configを定義し、getとsetの方法があり、util,set,delete,nexttickをVue構造関数の上にバインドし、options空のオブジェクトを作成し、configの_assetTypes、つまり上記の3つの属性に、それらの名前をs複素数、すなわちcomponents,directives,filtersバインド再optionsの下の属性に加え、3つとも空のオブジェクトで、もう1つ_base=Vueは自身の付与値であるが,ここではなぜそうするのか,キャッシュのためかもしれない,utilを実行する.extend(Vue.options.components,builtInComponents)は、自身のデフォルトコンポーネントKeepAliveをoptionsにバインドします.
Vue.config
Vue.util = util
Vue.set = set
Vue.delete = del
Vue.nextTick = util.nextTick

Vue.options = {
    components: {
        KeepAlive
    },
    directives: {},
    filters: {},
    _base: Vue
}

最後に4つのメソッドを実行

initUse(Vue)
initMixin(Vue)
initExtend(Vue)
initAssetRegisters(Vue)

この4つの方法は、現在のディレクトリの4つのjsファイルに対応する、まずuseである.js、ここではVueに静的な方法をマウントしています.プロトタイプではありません.私たちはプラグインをインストールするために使用しています.例えばVueです.use(VueRouter)ルーティングプラグインはこのようにして、ここではまずinstalledがインストールされているかどうかを判断し、toArrayメソッドを実行し、配列を返し、toArrayメソッドはmethods realizesディレクトリの下で対応する名前フォルダを見つけ、argsを解釈する.unshift(this)この返される配列ヘッダにVueコンストラクション関数を追加し、このinstallメソッドを実行します.一般的なプラグインのinstallメソッド形式は公式ドキュメントに書かれています.

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) {
    //   ...
  }
}

Vue.use(MyPlugin)

ここではこのinstallメソッドを実行します.すなわち、Vueを呼び出すグローバルメソッド、登録命令、prototypeにメソッドをマウントしたり、グローバルmixinを使用したりします.ここにはelse文、つまりinstallが関数ではない場合があります.この場合、functionが直接入ってくるはずです.以下のようになりますが、最後にこのメソッドを起動します.Vueコンストラクション関数の上でいくつかの操作をします

Vue.use(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) {
    //   ...
  }
})


最後にplugin.installed=trueは、既にインストールされているように設定されており、プラグインの再インストールは行われません.
着いたjsファイル、つまり2番目の方法initMixin(Vue)がextendに到着しました.jsファイル、すなわち2番目のメソッドinitExtend(Vue)
この2つのファイルは比較的多くの問題に関連しており、個人のレベルが限られているため、しばらく残っているが、ここではmixinファイルが主にVueをバインドしている.mixinメソッドは、よく使われるグローバルブレンドであり、mergeOptionsマージポリシーが呼び出されていることが重要であり、後述するextendファイルはVueをバインドしている.extendメソッド、これが一般的なvueコンストラクタであり、サブコンポーネントを作成すると理解できるでしょう.属性Vueも追加されています.cid = 0.
ここでは4つ目の方法を直接見て、assetsを見つけます.jsファイル
ここはまたこの配列を巡る_assetTypes、ここは上の話と少し似ていますが、最初見たときは少しぼんやりしていましたが、実はそうでした.

//          , Vue.options     

Vue.options = {
    components: {
        KeepAlive
    },
    directives: {},
    filters: {}
}

//          

Vue.component = function(id, definition){

}

Vue.directive = function(id, definition){

}

Vue.filter = function(id, definition){

}

//    Vue options   ,       Vue ,        s,    

この3つの方法はいずれも同じ関数操作であり,2つのパラメータを受け入れ,1つ目はstr,すなわち命令名,2つ目はfunまたはobjであり,2つ目のパラメータがなければ対応する命令,例えば

var directiveData = Vue.directive('show')

console.log(directiveData)

//       v-show     ,        

Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

var filterData = Vue.filter('capitalize')

console.log(filterData)

//             capitalize   ,             ,     undefined

//                    ,     

//              

1.

Vue.directive('demo', {
  bind: function (el, binding, vnode) {
    var s = JSON.stringify
    el.innerHTML =
      'name: '       + s(binding.name) + '
'
+ 'value: ' + s(binding.value) + '
'
+ 'expression: ' + s(binding.expression) + '
'
+ 'argument: ' + s(binding.arg) + '
'
+ 'modifiers: ' + s(binding.modifiers) + '
'
+ 'vnode keys: ' + Object.keys(vnode).join(', ') } }) 2. Vue.directive('color-swatch', function (el, binding) { el.style.backgroundColor = binding.value }) // , 2 if (type === 'directive' && typeof definition === 'function') { definition = { bind: definition, update: definition } } // if, 1 { bind: function (el, binding) { el.style.backgroundColor = binding.value }, update: function (el, binding) { el.style.backgroundColor = binding.value } } // Vue this.options[type + 's'][id] = definition // return , // Vue.options Vue.options = { components: { KeepAlive }, directives: { // Vue , , , model: { }, show: { }, // , demo: { bind: function () { // some methods } } }, filters: {} }

もちろん、カスタムコマンドを登録するには、他のライフサイクルフックやパラメータもあります.ドキュメントのカスタムコマンドを参照してください.

//         ,       ,     if   
//    this.options[type + 's'][id] = definition
//       

Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

var filterData = Vue.filter('capitalize')

console.log(filterData)

//              

//      component   ,         ,        

Vue.component('my-component', {
  name: 'my-name',
  template: '{{ message }}',
  data () {
    return {
      message: 'hello'
    }
  }
})

//     1 if,    config.isReservedTag(id)  ,     methods realizes  
//          config.isReservedTag        no  ,        
// platforms\web\util\element.js    ,             
//              html              ,     2 if  ,    
//   isPlainObject,     methods realizes  ,       obj,      name
//     id            name,  name my-name,     name  my-component
//     definition = this.options._base.extend(definition),             
// initExtend(Vue)   ,     this.options._base  Vue    ,  
// console.log(this.options._base === Vue)  // => true
//      this.options  ,      

//    Vue.options       

Vue.options = {
    components: {
      KeepAlive: {

      },
      //     Vue   ,          ,          ,        
      Transition: {

      },
      TransitionGroup: {

      },
      my-component: {

      }
    },
    directives: {
      //     Vue   ,          ,          ,        
      model: {

      },
      show: {

      },
      //               ,           
      demo: {
        bind: function () {
          // some methods
        }
      }
    },
    filters: {}
}

残りのいくつかの問題

Vue.set = set                       //    Vue        ,   
Vue.delete = del                    //    Vue        ,   
Vue.nextTick = util.nextTick        //     ,    - -#
initMixin(Vue)                      //       
initExtend(Vue)                     //     ,    - -#

以上より、
InitGlobalAPIの役割は、Vueコンストラクション関数に静的属性とメソッドをマウントすることです.VueはinitGlobalAPIを通過すると、次のようになります.

Vue.config
Vue.util = util
Vue.set = set
Vue.delete = del
Vue.nextTick = util.nextTick

Vue.options = {
    components: {
        KeepAlive
    },
    directives: {},
    filters: {},
    _base: Vue
}

Vue.use
Vue.mixin
Vue.cid = 0
Vue.extend
Vue.component = function(){}
Vue.directive = function(){}
Vue.filter = function(){}

Vue.prototype.$isServer

Vue.version = '__VERSION__'