成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

MVVM 中的動(dòng)態(tài)數(shù)據(jù)綁定

Meils / 2493人閱讀

摘要:要實(shí)現(xiàn)最小化刷新,我們要將模板中的每個(gè)綁定都收集起來。思考題在最后的實(shí)現(xiàn)下,我們把模板改為下面這樣雖然很少會(huì)有人這樣寫,就會(huì)出現(xiàn)重復(fù)的實(shí)例,該如何解決這個(gè)問題,參考早期源碼學(xué)習(xí)系列之四如何實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)綁定

上一篇文章我們了解了怎樣實(shí)現(xiàn)一個(gè)簡(jiǎn)單模板引擎。但這個(gè)模板引擎只適合靜態(tài)模板,因?yàn)樗菍⒛0逭w編譯成字符串進(jìn)行全量替換。如果每次數(shù)據(jù)改變都進(jìn)行一次替換,會(huì)有兩個(gè)最主要的問題:

性能差。DOM 操作本身就非常大的開銷,更別說每一次都替換這么大的量。

破壞事件綁定。這個(gè)是最麻煩的,如果我們沒有給解綁移除 DOM 綁定的事件,還會(huì)造成內(nèi)存泄露。而且每一次替換都要重新綁定事件。

因此,沒有人會(huì)將這種模板引擎用來編譯動(dòng)態(tài)模板。那我們?nèi)绾尉幾g動(dòng)態(tài)模板呢?

回答這個(gè)問題之前,我們先要了解前端的世界何時(shí)出現(xiàn)了動(dòng)態(tài)模板:它是由 MVVM 框架帶來的,動(dòng)態(tài)模板是 MVVM 框架的視圖層(view)。我們知道的 MVVM 框架有 knockout.js、angular.jsavalonvue。

對(duì)于這些框架,大部分人最熟悉的應(yīng)該就是 vue,所以我下面也是以 vue 1.0 作為參考,來實(shí)現(xiàn)一個(gè)功能更簡(jiǎn)單的動(dòng)態(tài)模板引擎。它是框架自帶的一個(gè)功能,讓框架能夠響應(yīng)數(shù)據(jù)的改變。從而刷新頁(yè)面。

MVVM 動(dòng)態(tài)模板的特點(diǎn)是能最小化刷新:哪個(gè)變量改變了,與之相關(guān)的節(jié)點(diǎn)才會(huì)更新。這樣我們就能避免上面提到的靜態(tài)模板的兩大問題。

要實(shí)現(xiàn)最小化刷新,我們要將模板中的每個(gè)綁定都收集起來。這個(gè)收集工作是框架在完成第一次渲染前就已經(jīng)完成了,每個(gè)綁定都會(huì)生成一個(gè) Directive 實(shí)例:

class Directive {
  constructor(vm, el, exp, update) {
    this.vm = vm
    this.el = el
    this.exp = exp
    this.update = update
    this.watchers = []
    this.get = getEvaluationFn(exp).bind(this, vm.$data)

    this.bind()
  }
}

function getEvaluationFn(exp) {
  return new Function("data", "with(data) { return " + exp + "}")
}

我們知道,每個(gè)綁定都由指令和指令值(指令值可能是表達(dá)式,可能是語(yǔ)句,也可能就是一個(gè)變量,還可能是框架自定義的語(yǔ)法)構(gòu)成,每種指令都有對(duì)應(yīng)的刷新函數(shù)(update)。如節(jié)點(diǎn)值的綁定的刷新函數(shù)是:

function updateTextNode() {
  const value = this.get()
  this.el.nodeValue = value
  console.log(this.exp + " updated: " + value)
}

有了刷新函數(shù),那如何做到在數(shù)據(jù)改變時(shí)調(diào)用刷新函數(shù)更新節(jié)點(diǎn)的值呢?我們就還要將每個(gè)指令里的相關(guān)變量都跟這個(gè) Directive 實(shí)例關(guān)聯(lián)起來。我們用一個(gè) $binding 對(duì)象來記錄,它的鍵是變量,值是 Binding 實(shí)例:

class Binding {
  constructor() {
    this.subs = []
  }

  addChild(key) {
    return this[key] || new Binding()
  }

  addSub(watcher) {
    this.subs.push(watcher)
  }
}

那上面的 subs 里添加的為什么不是 Directive 實(shí)例呢,而是 watcher 呢?它其實(shí)是 Watcher 的實(shí)例,這是為了以后能夠?qū)崿F(xiàn) $watch 方法提前引入的概念,Watcher 實(shí)例的 cb 既可以是指令的刷新函數(shù),也可以是 $watch 方法的回調(diào)函數(shù):

class Watcher {
  constructor(vm, path, cb, ctx) {
    this.id = ++uid
    this.vm = vm
    this.path = path
    this.cb = cb
    this.ctx = ctx || vm

    this.addDep()
  }
}
class Directive {
  bind() {
    this.watchers.push(new Watcher(this.vm, this.exp, this.update, this))
  }
}

我們先考慮最簡(jiǎn)單的情況,指令值就是一個(gè)變量,根據(jù)上面的思路,我們就可以寫出最簡(jiǎn)單的實(shí)現(xiàn)了,代碼就不貼了,有興趣的直接看源碼。

MVVM

My name is {{name.first}}-{{name.last }},{{age}} years old

上面實(shí)現(xiàn)的動(dòng)態(tài)模板是在我們假定了指令值是最簡(jiǎn)單的變量的情況下實(shí)現(xiàn)的。那要是把上面的模板改為下面這樣呢?

MVVM

My name is {{name.first}}-{{name.last }},{{"age: " + age}} years old

salary: {{ salary.toLocaleString() }}

那我們上面的實(shí)現(xiàn)有一些數(shù)據(jù)就不能動(dòng)態(tài)刷新了,原因很簡(jiǎn)單,就是我們是直接將 "age: " + ageDirective 實(shí)例關(guān)聯(lián),而我們修改的只是 age,自然就找不到對(duì)應(yīng)的實(shí)例了。那我們?nèi)绾谓鉀Q呢?

首先想到的肯定是按照現(xiàn)有的實(shí)現(xiàn)來擴(kuò)展,讓它支持模板插值是表達(dá)式的情況。已有的實(shí)現(xiàn)是直接解析得到變量,那我們就繼續(xù)想辦法直接解析表達(dá)式得到變量。像 "age: " + age 這種表達(dá)式直接解析出 age 其實(shí)不難。但 salary.toLocaleString() 這種就不好做了,要是 salary.toLocaleString().slice(1) 這種可以說是沒辦法解析了。

既然這條路行不通,其實(shí)我們是有更簡(jiǎn)單的方法。既然我們都已經(jīng)將 data 進(jìn)行了代理,那我們就可以在 get 獲取變量值時(shí)進(jìn)行依賴收集。因?yàn)槲覀儽緛砭蜁?huì)運(yùn)行 Directive 實(shí)例的求值函數(shù)進(jìn)行初始值的替換,這就會(huì)觸發(fā)變量的 get 。具體的代碼怎么寫就不說了,詳細(xì)的修改和支持表達(dá)式的源碼。

當(dāng)然現(xiàn)在只實(shí)現(xiàn)動(dòng)態(tài)模板最簡(jiǎn)單的插值指令。還有一些更復(fù)雜的指令如:iffor 的實(shí)現(xiàn)方式,下次有機(jī)會(huì)再分享。

思考題

在最后的實(shí)現(xiàn)下,我們把模板改為下面這樣(雖然很少會(huì)有人這樣寫),就會(huì)出現(xiàn)重復(fù)的 Watcher 實(shí)例,該如何解決這個(gè)問題?

MVVM

hello,My name is {{name.first + "-" + name.last }}

參考

vue早期源碼學(xué)習(xí)系列之四:如何實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)綁定

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/107754.html

相關(guān)文章

  • VUE - MVVM - part12 - props

    摘要:看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。而該組件實(shí)例的父實(shí)例卻并不固定,所以我們將這些在使用時(shí)才能確定的參數(shù)在組件實(shí)例化的時(shí)候傳入。系列文章地址優(yōu)化優(yōu)化總結(jié) 看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。 前言 在上一步,我們實(shí)現(xiàn) extend 方法,用于擴(kuò)展 Vue 類,而我們知道子組件需要通過 extend 方法來實(shí)現(xiàn),我們從測(cè)試?yán)?..

    bluesky 評(píng)論0 收藏0
  • MVC && MVVM

    摘要:面向?qū)ο笫亲约航M裝電腦,硬件已生產(chǎn)完畢。面向過程吃狗屎面向?qū)ο蠊烦允捍_切的講是一種軟件設(shè)計(jì)規(guī)范,早在年的理念就已經(jīng)誕生。后期的維護(hù)成本會(huì)減少很多。減輕了開發(fā)人員的負(fù)擔(dān),也減少了操作邏輯導(dǎo)致業(yè)務(wù)邏輯混亂的可能性。 什么是MVC,什么是MVVM? 面向過程 --> 面向?qū)ο?--> MVC --> MV* 面向過程: 開發(fā)人員按照需求邏輯順序開發(fā)代碼邏輯,主要思維模式在于如何實(shí)現(xiàn)。先細(xì)節(jié),...

    klinson 評(píng)論0 收藏0
  • 剖析Vue實(shí)現(xiàn)原理 - 如何實(shí)現(xiàn)雙向綁定mvvm(轉(zhuǎn)載)

    摘要:接下來要看看這個(gè)訂閱者的具體實(shí)現(xiàn)了實(shí)現(xiàn)訂閱者作為和之間通信的橋梁,主要做的事情是在自身實(shí)例化時(shí)往屬性訂閱器里面添加自己自身必須有一個(gè)方法待屬性變動(dòng)通知時(shí),能調(diào)用自身的方法,并觸發(fā)中綁定的回調(diào),則功成身退。 本文能幫你做什么?1、了解vue的雙向數(shù)據(jù)綁定原理以及核心代碼模塊2、緩解好奇心的同時(shí)了解如何實(shí)現(xiàn)雙向綁定為了便于說明原理與實(shí)現(xiàn),本文相關(guān)代碼主要摘自vue源碼, 并進(jìn)行了簡(jiǎn)化改造,...

    nemo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<