日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

html或原生js是单一对应绑定的,原生js数据绑定

發布時間:2024/9/27 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 html或原生js是单一对应绑定的,原生js数据绑定 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

雙向數據綁定是非常重要的特性 —— 將JS模型與HTML視圖對應,能減少模板編譯時間同時提高用戶體驗。我們將學習在不使用框架的情況下,使用原生JS實現雙向綁定 —— 一種為Object.observe_(譯注:現已廢棄,作者寫博客時為14年11月),另一種為覆蓋get / set。PS: 第二種更好,詳情請參閱底部的TL;DR(譯注:too long;don't read. 直譯為“太長,不想看”,意譯為“簡單粗暴來吧”)_。

1: Object.observe 和 DOM.onChange

Object.observe()是一種新特性,其在ES7中實現,但在最新的Chrome中已可用 —— 允許對JS對象進行響應式更新。簡單說就是 —— 只要對象(的屬性)發生變化就調用回調函數。

一般用法為:

log = console.log

user = {}

Object.observe(user, function(changes){

changes.forEach(function(change) {

user.fullName = user.firstName + " " + user.lastName;

});

});

user.firstName = 'Bill';

user.lastName = 'Clinton';

user.fullName // 'Bill Clinton'

復制代碼

這很方便,且能實現響應式編程 —— 保證所有內容都是最新的。

如下:

//

user = {};

div = $("#foo");

Object.observe(user, function(changes){

changes.forEach(function(change) {

var fullName = (user.firstName || "") + " " + (user.lastName || "");

div.text(fullName);

});

});

user.firstName = 'Bill';

user.lastName = 'Clinton';

div.text() //Bill Clinton

復制代碼

如上,我們自己實現了模型到數據的綁定!封裝一下(譯注:此處原文為Let’s DRY ourselves with a helper function. DRY即 don't repeat yourself):

//

function bindObjPropToDomElem(obj, property, domElem) {

Object.observe(obj, function(changes){

changes.forEach(function(change) {

$(domElem).text(obj[property]);

});

});

}

user = {};

bindObjPropToDomElem(user,'name',$("#foo"));

user.name = 'William'

$("#foo").text() //'William'

復制代碼

換一種方式 —— 將DOM元素與JS值綁定起來。簡單的方法是使用jQuery.change

//

$("#foo").val("");

function bindDomElemToObjProp(domElem, obj, propertyName) {

$(domElem).change(function() {

obj[propertyName] = $(domElem).val();

alert("user.name is now "+user.name);

});

}

user = {}

bindDomElemToObjProp($("#foo"), user, 'name');

//enter 'obama' into input

user.name //Obama.

復制代碼

簡直不要太方便,在實際開發時,可以將兩者結合,通過函數來創建一個雙向數據綁定:

function bindObjPropToDomElem(obj, property, domElem) {

Object.observe(obj, function(changes){

changes.forEach(function(change) {

$(domElem).text(obj[property]);

});

});

}

function bindDomElemToObjProp(obj, propertyName, domElem) {

$(domElem).change(function() {

obj[propertyName] = $(domElem).val();

console.log("obj is", obj);

});

}

function bindModelView(obj, property, domElem) {

bindObjPropToDomElem(obj, property, domElem)

bindDomElemToObjProp(obj, propertyName, domElem)

}

復制代碼

注意:在雙向綁定時,需正確進行DOM操作,因為不同的DOM元素(input,div,textarea,select)有不同的取值方式(text,val)。同時注意:雙向數據綁定并不是必須的 —— “輸出型”元素一般不需要視圖到模型的綁定,而“輸入型”元素一般不需要模型到視圖的綁定。

下面為第二種方式:

2: 深入'get'和'set'屬性

上面的解決方法并不完美。比如直接的修改并不會自動觸發jQuery的“change”事件 —— 例如,直接通過代碼對DOM進行修改,比如以下代碼不起作用:

$("#foo").val('Putin')

user.name //still Obama. Oops.

復制代碼

現在,我們來用一種更激進的方式實現 —— 重寫getter和setter。因為我們不僅要監測變化,我們將重寫JS最底層的功能,即get/setting變量的能力,所以不那么“安全”。后面我們將會看到,這種元編程的方式有多強大。

那么,如果我們可以重寫get和set對象值的方法會怎么樣呢?這也是數據綁定的實質。用 Object.defineProperty() 即可實現.

其實,以前就有已廢棄且非標準實現方式,但通過Object.defineProperty的實現方式更好(最重要的是標準),如下所示:

user = {}

nameValue = 'Joe';

Object.defineProperty(user, 'name', {

get: function() { return nameValue },

set: function(newValue) { nameValue = newValue; },

configurable: true //to enable redefining the property later

});

user.name //Joe

user.name = 'Bob'

user.name //Bob

nameValue //Bob

復制代碼

現在user.name是nameValue的別名。但可做的不僅僅是創建新的變量名 - 我們可以通過它來保證模型和視圖的一致。如下:

//

Object.defineProperty(user, 'name', {

get: function() { return document.getElementById("foo").value },

set: function(newValue) { document.getElementById("foo").value = newValue; },

configurable: true //to enable redefining the property later

});

復制代碼

user.name現在綁定到#foo元素。這種底層的方式非常簡潔 —— 通過定義(或擴展)變量屬性的get / set實現。由于實現非常簡潔,因此可以根據情況輕松擴展/修改代碼 —— 僅綁定或擴展get / set中的一個,比如綁定其他數據類型。

可封裝如下:

function bindModelInput(obj, property, domElem) {

Object.defineProperty(obj, property, {

get: function() { return domElem.value; },

set: function(newValue) { domElem.value = newValue; },

configurable: true

});

}

復制代碼

使用:

user = {};

inputElem = document.getElementById("foo");

bindModelInput(user,'name',inputElem);

user.name = "Joe";

alert("input value is now "+inputElem.value) //input is now 'Joe';

inputElem.value = 'Bob';

alert("user.name is now "+user.name) //model is now 'Bob';

復制代碼

注意:上面的domElem.value只對input元素有效。(可在bindModelInput中擴展,對不同的DOM類型使用對應的方法來設置它的值)。

思考:

注意:上面的實現中,在某些場景下,視圖可認為是符合SPOT (single point of truth )原則的,但該原則常常被忽視(因為雙向數據綁定也就意味著等價)。然而,深究下去可能就會發現問題了,在實際開發中也會遇到。 —— 比如,當刪除DOM元素時,關聯的模型會自動注銷么?答案是不會。bindModelInput函數在domElem元素上創建了一個閉包,使DOM元素常駐在內存中

—— 并保持模型與模型的綁定關系 —— 即使DOM元素被移除。即使視圖被移除了,但模型依舊存在。反之一樣 —— 若模型被移除了,視圖依然能夠正常顯示。在某些刷新視圖和模型無效的情況下,理解這些內部原理就能找到原因了。

(譯注:SPOT簡單翻譯為“單點原則”,即引起變化最好的是由單一入口引起的,而不是由多個入口引起的,比如一個函數,其返回結果最好僅由參數決定,這樣輸入和輸出才能一致,而不會由于其他變化導致用一個輸入會出現不同的輸出)

這種自己實現的數據綁定方法與Knockout或Angular等框架的數據綁定相比,有一些優點,例如:

理解:一旦掌握數據綁定的源碼,不僅理解更深入,而且也能對其進行擴展和修改。

性能:不要將所有東西都綁定在一起,只綁定所需的,避免監測過多對象

避免鎖定:若所用的框架不支持數據綁定,則自行實現的數據綁定更強大

缺點是由于不是真正的綁定(沒有臟檢查),有些情況會失敗 —— 視圖更新時不會觸發模型中的數據,所以當試著同步視圖中的兩個DOM元素時將會失敗。也就是說,將兩個元素綁定到同一個模型上時,只有更新模型,則兩個元素才會被正確更新。可以通過自定義一個更新函數來實現:

//

//

input1 = document.getElementById('input1')

input2 = document.getElementById('input2')

user = {}

Object.defineProperty(user, 'name', {

get: function() { return input1.value; },

set: function(newValue) { input1.value = newValue; input2.value = newValue; },

configurable: true

});

input1.onchange = function() { user.name = user.name } //sync both inputs.

復制代碼

TL;DR:

當需要使用原生JS創建模型和視圖的雙向數據綁定時,如下:

function bindModelInput(obj, property, domElem) {

Object.defineProperty(obj, property, {

get: function() { return domElem.value; },

set: function(newValue) { domElem.value = newValue; },

configurable: true

});

}

//

user = {}

bindModelInput(user,'name',document.getElementById('foo')); //hey presto, we now have two-way data binding.

復制代碼

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的html或原生js是单一对应绑定的,原生js数据绑定的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。