vue 2.0ソースコード分析の理解応答式アーキテクチャ
11862 ワード
分かち合う前に
以前に紹介したのですが、どうやって
この文章は何を共有しますか
vue 2.0の応答式アーキテクチャを理解すると、次の図です.
ちなみに彼がレイクより速い理由の一つを紹介します.
本分は何を実現しますか
第一歩は、dataの下の全ての属性をobservableに変更します.
コードを見てみましょう.
第二歩、第一歩はなぜ正確ではないかを詳しく述べます.
たとえば、下記のコードを考慮します.
以前に紹介したのですが、どうやって
observer
とwatcher
を実現しますか?続けて書きたいですが、vue 2.0は空から出てきますので、直接vue 2.0を見てください.この文章は会社でシェアして、やっと書きました.私たちは最も洗練されたコードを使って、vue 2.0応答式のアーキテクチャを復元し、以前書いたvueソースの分析を実現するために、どうやってobserverとwatchを実現するかを今回の共有の参考にすることができます.見なくてもいいですが、Object.definePropertyを知っておいたほうがいいです.この文章は何を共有しますか
vue 2.0の応答式アーキテクチャを理解すると、次の図です.
ちなみに彼がレイクより速い理由の一つを紹介します.
本分は何を実現しますか
const demo = new Vue({
data: {
text: "before",
},
// template {{text}}
render(h){
return h('div', {}, [
h('span', {}, [this.__toString__(this.text)])
])
}
})
setTimeout(function(){
demo.text = "after"
}, 3000)
対応する仮想domは
before
からafter
に変えられます.始めましょう.第一歩は、dataの下の全ての属性をobservableに変更します.
コードを見てみましょう.
class Vue {
constructor(options) {
this.$options = options
this._data = options.data
observer(options.data, this._update)
this._update()
}
_update(){
this.$options.render()
}
}
function observer(value, cb){
Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
}
function defineReactive(obj, key, val, cb) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: ()=>{},
set:newVal=> {
cb()
}
})
}
var demo = new Vue({
el: '#demo',
data: {
text: 123,
},
render(){
console.log(" render ")
}
})
setTimeout(function(){
demo._data.text = 444
}, 3000)
デモのために、私たちは最も簡単な状況だけを考えています.vueのソースコードの分析を見たら、どうやってobserverとwatchを実現すればいいのかよく分かります. var demo = new Vue({
el: '#demo',
data: {
text: 123,
},
render(){
console.log(" render ")
}
})
data
の中のすべての属性をobserverに置いて、data
の中の属性、例えばtext
を変えて、_update()
の関数を呼び出して再レンダリングします.これはどのようにしてできますか?私達は実際には値が賦課されていると知っています.data
の下のtext
に値を与えたらset
関数がトリガされます.このとき_update
を呼んだらOKですが、 setTimeout(function(){
demo._data.text = 444
}, 3000)
demo._data.text
はdemo.text
を使っていません.大丈夫です.代理店を追加します. _proxy(key) {
const self = this
Object.defineProperty(self, key, {
configurable: true,
enumerable: true,
get: function proxyGetter () {
return self._data[key]
},
set: function proxySetter (val) {
self._data[key] = val
}
})
}
次に、Vue
のconstructor
に次のような文を加えます. Object.keys(options.data).forEach(key => this._proxy(key))
第1のステップは、まずここで述べてください.data
のいずれかの属性の値が変更され、_update
のトリガを引き起こして再レンダリングされます.属性は明らかに正確ではありません.第二歩、第一歩はなぜ正確ではないかを詳しく述べます.
たとえば、下記のコードを考慮します.
new Vue({
template: `
name: {{name}}
age: {{age}}
`,
data: {
name: 'js',
age: 24,
height: 180
}
})
setTimeout(function(){
demo.height = 181
}, 3000)
template
data
name
age
, height
, , ? !, , !!
,
DOM
,template render ( , , ), render DOM, DOM
function VNode(tag, data, children, text) {
return {
tag: tag,
data: data,
children: children,
text: text
}
}
class Vue {
constructor(options) {
this.$options = options
const vdom = this._update()
console.log(vdom)
}
_update() {
return this._render.call(this)
}
_render() {
const vnode = this.$options.render.call(this)
return vnode
}
__h__(tag, attr, children) {
return VNode(tag, attr, children.map((child)=>{
if(typeof child === 'string'){
return VNode(undefined, undefined, undefined, child)
}else{
return child
}
}))
}
__toString__(val) {
return val == null ? '' : typeof val === 'object' ? JSON.stringify(val, null, 2) : String(val);
}
}
var demo = new Vue({
el: '#demo',
data: {
text: "before",
},
render(){
return this.__h__('div', {}, [
this.__h__('span', {}, [this.__toString__(this.text)])
])
}
})
が したら、 が します. {
tag: 'div',
data: {},
children:[
{
tag: 'span',
data: {},
children: [
{
children: undefined,
data: undefined,
tag: undefined,
text: '' // before, ,
}
]
}
]
}
これは の も な DOM
であり、tag
はhtml
タグ であり、data
はclass
およびstyle
などのラベル の を み、childen
はサブノードであり、 DOMに しては しない. の に ります.つまり、render
の でvueインスタンスに している が かります. はちょっと いにくいですが、コードを ます. var demo = new Vue({
el: '#demo',
data: {
text: "before",
name: "123",
age: 23
},
render(){
return this.__h__('div', {}, [
this.__h__('span', {}, [this.__toString__(this.text)])
])
}
})
このコードのように、render
はtext
だけに しています.name
とage
に していません.ですから、text
が したら、 たちは にrender
をトリガして、 DOM
を させてもいいです.( りはこの DOMと の DOM
とのマッチングです.その 、 の はDOM
です.あとで うしかないです.)どうすればいいかを に えてみます.
、'touch'は を る.
の に ります.data
の defineReactive
を っています.data の を するとset
がトリガされます.data
の を るとget
がトリガされます.そうです. で を ってもいいです.render
を に してみます.data
のどの がトリガされたかを てみます. たちはget
をトリガしました.render
がdata
のどの に しているかを ることができます.その 、これらの を にしてもいいです.これらの が わるたびに、render
をトリガします. のステップは に4つのサブ で された です.( には、render
だけではなく、いずれかの の は、 の の によって き こされ、 の 、つまりcomputed
とwatch
の でもmobxのコアでもある)
、
たちは に するクラスを いています. data
のオブジェクトはrender
に する がありますので、 はdefineReactive
の に されます. class Dep {
constructor() {
this.subs = []
}
add(cb) {
this.subs.push(cb)
}
notify() {
console.log(this.subs);
this.subs.forEach((cb) => cb())
}
}
function defineReactive(obj, key, val, cb) {
const dep = new Dep()
Object.defineProperty(obj, key, {
//
})
}
そして、render
を してtouchに すると、 getが され、render
の をsubs
の に することができます.set
の は、notify
のすべてのsubs の を します.render
の が まれます.これで します. は、すべてのコードを します. function VNode(tag, data, children, text) {
return {
tag: tag,
data: data,
children: children,
text: text
}
}
class Vue {
constructor(options) {
this.$options = options
this._data = options.data
Object.keys(options.data).forEach(key => this._proxy(key))
observer(options.data)
const vdom = watch(this, this._render.bind(this), this._update.bind(this))
console.log(vdom)
}
_proxy(key) {
const self = this
Object.defineProperty(self, key, {
configurable: true,
enumerable: true,
get: function proxyGetter () {
return self._data[key]
},
set: function proxySetter (val) {
self._data.text = val
}
})
}
_update() {
console.log(" ");
const vdom = this._render.call(this)
console.log(vdom);
}
_render() {
return this.$options.render.call(this)
}
__h__(tag, attr, children) {
return VNode(tag, attr, children.map((child)=>{
if(typeof child === 'string'){
return VNode(undefined, undefined, undefined, child)
}else{
return child
}
}))
}
__toString__(val) {
return val == null ? '' : typeof val === 'object' ? JSON.stringify(val, null, 2) : String(val);
}
}
function observer(value, cb){
Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
}
function defineReactive(obj, key, val, cb) {
const dep = new Dep()
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: ()=>{
if(Dep.target){
dep.add(Dep.target)
}
return val
},
set: newVal => {
if(newVal === val)
return
val = newVal
dep.notify()
}
})
}
function watch(vm, exp, cb){
Dep.target = cb
return exp()
}
class Dep {
constructor() {
this.subs = []
}
add(cb) {
this.subs.push(cb)
}
notify() {
this.subs.forEach((cb) => cb())
}
}
Dep.target = null
var demo = new Vue({
el: '#demo',
data: {
text: "before",
},
render(){
return this.__h__('div', {}, [
this.__h__('span', {}, [this.__toString__(this.text)])
])
}
})
setTimeout(function(){
demo.text = "after"
}, 3000)
を てみます.
たちはDep.target
を します. のget
ですか?それとも を す のget
ですか? function watch(vm, exp, cb){
Dep.target = cb
return exp()
}
Dep.target
の は、フラグに し、get
の get: () => {
if (Dep.target) {
dep.add(Dep.target)
}
return val
},
すればいいです. までその を たらよく かりますか?
め りをつける
はとても きです.Vue 2.0 のコードは をよくするために、 な で れます.でも、コード の はVue 2.0と じようにreact、vue 2.0 で してくれます. に レンダリングします.reactは の を します. の をします. えば、 したreactはどのように が いですか? ( )、 びreactはなぜimmutble.js reactを してpure renderを しなければならない 、bind(this) れた です.vue 2.0 がベストを くしてくれました.また、ラベルのような のclass
に して、vue 2.0は レンダリング にdiffをする は しません.vue 2.0は が したreactよりも い です.ここで、 きなのはstarにあげるように えています. があれば、コメントエリアにコメントしてもいいですよ.
<div class=「col-md-3」>
<div class=「row」id=「ad」>
<div id=「right-1」class=「col-lg-12 col-sm-4 col-xs-4 ad」
<div id=「right-2」class=「col-lg-12 col-sm-4 col-xs-4 ad」
<div id=「right-3」class=「col-lg-12 col-sm-4 col-xs-4 ad」