首頁 > 軟體

關於vue雙向繫結帶來的問題及解決

2022-09-26 14:02:23

vue雙向繫結帶來的問題

問題場景

查詢完表格資料後 通過作用域插槽,將該行資料傳到修改頁面(定義了個新物件儲存資料),但是由於資料雙向繫結,修改這個新物件的值,會影響到最初查詢表格獲取的值

如下

this.editForm = row

解決方案

方法1:通過json之間的解析,深拷貝建立一個與row無繫結關聯的臨時物件,再賦值給editForm

this.editForm = JSON.parse(JSON.stringify(row))

方法2:使用…展開運運算元

this.editForm = {...this.editForm,...row}

方法3:$set也不會影響原資料,但只能操作單個資料,在上述場景可能不太適用(屬性多久麻煩了)

this.$set(this.editForm,'roleName',row.roleName)
this.$set(this.editForm,'roleDesc',row.roleDesc)

這樣就不會影響到最初的row啦! 

vue雙向繫結的原理總結

MVVM

檢視模型雙向繫結,是Model-View-ViewModel的縮寫,也就是把MVC中的Controller演變成ViewModel。Model層代表資料模型,View代表UI元件,ViewModel是View和Model層的橋樑,資料會繫結到viewModel層並自動將資料渲染到頁面中,檢視變化的時候會通知viewModel層更新資料。以前是操作DOM結構更新檢視,現在是資料驅動檢視。

優點:

1.低耦合。檢視(View)可以獨立於Model變化和修改,一個Model可以繫結到不同的View上,當View變化的時候Model可以不變化,當Model變化的時候View也可以不變;

2.可重用性。你可以把一些檢視邏輯放在一個Model裡面,讓很多View重用這段檢視邏輯。

3.獨立開發。開發人員可以專注於業務邏輯和資料的開發(ViewModel),設計人員可以專注於頁面設計。

4.可測試。

資料(model)變化主動觸發ui(view)變化,同時ui(view)變化主動觸發資料(model)變化,當然這裡的ui變化指定表單中的使用者輸入,可通俗的理解為:在單向繫結的基礎上給可輸入元素(input、textarea等)新增change(input)事件,來動態修改model和view

vue當中的雙向繫結

vue.js是採用資料劫持結合釋出者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter和getter,在資料變動時釋出訊息給訂閱者,觸發相應的監聽回撥

使用 v-model / .sync 實現,v-model是 v-bind:value 和 v-on:input 的語法糖

  • v-bind:value 實現了 data ⇒ UI 的單向繫結
  • v-on:input 實現了 UI ⇒ data 的單向繫結

引申出這兩個單向繫結如何實現

v-bind的實現

通過 Object.defineProperty API 給 data 建立 getter 和 setter,用於監聽 data 的改變,data 一變就會安排改變 UI

v-on的實現

通過 template compiler 給 DOM 新增事件監聽,DOM input 的值變了就會去修改 data。

Compile(指令解析器)

Compile主要做的事情是解析模板指令,將模板中變數替換成資料,然後初始化渲染頁面檢視,並將每個指令對應的節點繫結更新函數,新增鑑定資料的訂閱者,一旦資料有變動,收到通知,更新檢視

Observer(資料監聽器)

Observer的核心是通過Object.defineProprtty()來監聽資料的變動,這個函數內部可以定義setter和getter,每當資料發生變化,就會觸發setter。這時候Observer就要通知訂閱者,訂閱者就是Watcher

Watcher(訂閱者)

Watcher訂閱者作為Observer和Compile之間通訊的橋樑,主要做的事情是:

  • 在自身範例化時往屬性訂閱器(dep)裡面新增自己
  • 自身必須有一個update()方法
  • 待屬性變動dep.notice()通知時,能呼叫自身的update()方法,並觸發Compile中繫結的回撥

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com