Vueにおけるrenderの流れ
5817 ワード
私の前の2つの文章からVueのデータ応答について話しましたが、どのようにrenderとre-renderがありますか?私が見たのは2.1.10というバージョンで、
実は
スタンドアロンコンストラクションとランタイムコンストラクション
独立した構築と実行時の構築の違いは、前者はテンプレートコンパイルを含み、後者は含まれていないことです.テンプレートコンパイルは、テンプレート文字列をレンダリング関数にコンパイルします.Vueのレンダリングには、文字列テンプレートをrender関数にコンパイルする2つのステップがあります.第2の実行プロセスは、render関数を実行することです.独立したコンストラクションはtemplateからrender関数を実行し、templateオプションをサポートしますが、ブラウザインタフェースに依存するため、サーバ側レンダリングとして使用できません.実行時構築にはコンパイル部分は含まれず、render関数を直接実行するためtemplateオプションはサポートされていませんが、コンパイルプロセスがないため、フレームワークをより軽量化できます.実行時にtemplateオプションを書くことはできませんが、単一ファイルコンポーネントにはテンプレートを書くことができます.通常、コンパイラをパッケージ化することなく、vue-loaderとvueifyでテンプレートをプリコンパイルします.
今戻ってコードを見て
一度分析:まずキャッシュした
最終的に呼び出される
ええ...上の注釈ははっきり書いてあると思います.ここではこの一言を重点的に述べる
これまでのデータ応答部で述べたように
まずわかりやすいです.render()メソッドは、
まず、この関数の中の
init.js
中initMixin()
の初期化コードはこう書いてあります initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initState(vm)
callHook(vm, 'created')
//
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
実は
initRender(vm)
関数でレンダリングの初期化作業をしていますが、後で詳しくお話しします.Vueには2箇所定義されているVue.prototype.$mount
.一つはweb-runtime.js
一つはweb-runtime-with-compile.js
で、ここではVueの2つの構築方式について言及する.独立した構築と実行時に構築します.スタンドアロンコンストラクションとランタイムコンストラクション
独立した構築と実行時の構築の違いは、前者はテンプレートコンパイルを含み、後者は含まれていないことです.テンプレートコンパイルは、テンプレート文字列をレンダリング関数にコンパイルします.Vueのレンダリングには、文字列テンプレートをrender関数にコンパイルする2つのステップがあります.第2の実行プロセスは、render関数を実行することです.独立したコンストラクションはtemplateからrender関数を実行し、templateオプションをサポートしますが、ブラウザインタフェースに依存するため、サーバ側レンダリングとして使用できません.実行時構築にはコンパイル部分は含まれず、render関数を直接実行するためtemplateオプションはサポートされていませんが、コンパイルプロセスがないため、フレームワークをより軽量化できます.実行時にtemplateオプションを書くことはできませんが、単一ファイルコンポーネントにはテンプレートを書くことができます.通常、コンパイラをパッケージ化することなく、vue-loaderとvueifyでテンプレートをプリコンパイルします.
今戻ってコードを見て
web-runtime-with-compile.js
中// './web-runtime' Vue.prototype.$mount
const mount = Vue.prototype.$mount
// Vue.prototype.$mount
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
// el dom
el = el && query(el)
const options = this.$options
// resolve template/el and convert to render function
// render template render
if (!options.render) {
let template = options.template
if (template) {
template = idToTemplate(template)
} else if (template.nodeType) {
template = template.innerHTML
} else {
return this
}
} else if (el) {
// el template
template = getOuterHTML(el)
}
// template
if (template) {
const { render, staticRenderFns } =compileToFunctions(template, {
warn: msg => warn(msg, this),
shouldDecodeNewlines,
delimiters: options.delimiters
}, this)
// compileToFunctions render this.$options
options.render = render
}
}
// './web-runtime' Vue.prototype.$mount
// './web-runtime' Vue.prototype.$mount' lifecycle.js _mount
return mount.call(this, el, hydrating)
}
一度分析:まずキャッシュした
./web-runtime
つまりランタイム構築で定義したVue.prototype.$mount
メソッドを再定義し、そのメソッドを再定義し、renderオプションのある直接キャッシュを呼び出す$mount()
renderメソッドがなければtemplate
オプションがあるかどうかをチェックし、あればtemplateをrenderにコンパイルし、なければel
のコードを文字列に変換し、コンパイルしてrenderを生成します.最終的にはrender関数を生成し、キャッシュされたmount関数を呼び出すことがわかります.次にmount関数を見ます.web-runtime.js
中Vue.prototwype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
/**
* query => el ,
* create div,
* , document.querySelector(el)
*/
el = el && inBrowser ? query(el) : undefined
// _mount lifecycle.js
return this._mount(el, hydrating)
}
最終的に呼び出される
lifecycle.js
で定義されている_mount()
であることがわかりますが、この方法を続けてみましょうVue.prototype._mount = function (
el?: Element | void,
hydrating?: boolean
): Component {
const vm: Component = this
// $el
vm.$el = el
// beforeMount
callHook(vm, 'beforeMount')
vm._watcher = new Watcher(vm, function updateComponent () {
vm._update(vm._render(), hydrating)
}, noop)
hydrating = false
// manually mounted instance, call mounted on self
// mounted is called for render-created child components in its inserted hook
// mount mounted
if (vm.$vnode == null) {
vm._isMounted = true
callHook(vm, 'mounted')
}
return vm
}
ええ...上の注釈ははっきり書いてあると思います.ここではこの一言を重点的に述べる
vm._watcher = new Watcher(vm, function updateComponent () {
vm._update(vm._render(), hydrating)
}, noop)
これまでのデータ応答部で述べたように
Watcher
このコンストラクション関数.Watcher
インスタンス作成時にトリガーされるget()
、ここでgetが実行updateComponent ()
=>vm._update()
=>vm.render()
、最初に実行されたのはvm.render()
であることがわかる.Vue.prototype._render = function (): VNode {
const vm: Component = this
// $options render
//$options.render compileToFunctions template el
const {
render,
staticRenderFns,
_parentVnode
} = vm.$options
vm.$vnode = _parentVnode
// render self
let vnode
try {
vnode = render.call(vm._renderProxy, vm.$createElement)
...
} catch (e) {
...
vnode = vm._vnode
}
return vnode
}
vm._renderProxy = vm
まずわかりやすいです.render()メソッドは、
render
を呼び出すvnodeを返します.render
印刷してみるとこんな関数function anonymous() {
with(this){
return _c('div',{attrs:{"id":"app"} },
[ _v("
"+_s(sum)+"
")]
)}
}
まず、この関数の中の
this
がvm
そのものを指していることがわかります._c
,_v
,_s
,sum
いずれもvm
の方法と属性です.取得this.sum
でトリガーdefinePropery()
のget()
.よし、これでrender
データ応答に関連付けることができます.new Watcher(updateComponent())
を実行すると依存を収集し、依存の値が変化するとwatcherのupdateComponentをトリガーして依存を再収集する.実はtemplateがrenderに変換されると,中間は先に生成された抽象構文ツリー(AST)が静的ノードを抽出し,その後renderに変換する.さらにvnodeのpatchアルゴリズムもあり,この文章ではまだ述べていない.もし后ろのコードがまだ読めたら、私はまた书きます....