成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

Meils / 2457人閱讀

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

上一篇文章我們了解了怎樣實現(xiàn)一個簡單模板引擎。但這個模板引擎只適合靜態(tài)模板,因為它是將模板整體編譯成字符串進行全量替換。如果每次數(shù)據(jù)改變都進行一次替換,會有兩個最主要的問題:

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

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

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

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

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

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

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

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òu)成,每種指令都有對應的刷新函數(shù)(update)。如節(jié)點值的綁定的刷新函數(shù)是:

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

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

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

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

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

那上面的 subs 里添加的為什么不是 Directive 實例呢,而是 watcher 呢?它其實是 Watcher 的實例,這是為了以后能夠?qū)崿F(xiàn) $watch 方法提前引入的概念,Watcher 實例的 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))
  }
}

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

MVVM

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

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

MVVM

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

salary: {{ salary.toLocaleString() }}

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

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

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

當然現(xiàn)在只實現(xiàn)動態(tài)模板最簡單的插值指令。還有一些更復雜的指令如:iffor 的實現(xiàn)方式,下次有機會再分享。

思考題

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

MVVM

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

參考

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

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107754.html

相關文章

  • VUE - MVVM - part12 - props

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

    bluesky 評論0 收藏0
  • MVC && MVVM

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

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

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

    nemo 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<