接上一篇文章《js實現數據單向綁定》
上篇文章中用原生js實現了數據的單向綁定。本篇文章繼續介紹如何用js實現數據的雙向綁定。綁定的方式模仿vue中的v-model指令。
創建標籤
<div id="div1">
<input type="text" v-model="name">
<br> 姓名:{{name}}
</div>
創建一個輸入框,使用v-model屬性綁定變量name,注意這裏只是模仿vue綁定的形式,代碼中並沒有引入任何vue依賴。完全靠原生js實現。
單向綁定
let el = document.getElementById('app');
let template = el.innerHTML;
let _data = {
name: '_BuzzLy'
};
let data = new Proxy(_data, {
set(obj, name, value) {
obj[name] = value;
render();
}
});
render();
function render() {
el.innerHTML = template.replace(/\{\{\w+\}\}/g, str => {
str = str.substring(2, str.length - 2);
return _data[str];
});
}
到這我們又實現了一遍單向綁定,想要實現數據的雙向綁定其實很簡單,只需稍微修改我們的render函數。
雙向綁定
function render() {
el.innerHTML = template.replace(/\{\{\w+\}\}/g, str => {
str = str.substring(2, str.length - 2);
return _data[str];
});
// 找到所有input標籤
Array.from(el.getElementsByTagName('input'))
// 過濾得到其中帶有v-model屬性的標籤
.filter(ele => ele.getAttribute('v-model'))
// 遍歷這些input標籤
.forEach(input => {
// 獲取到v-model中綁定的key,從數據中找到key對應的value賦給input
// 這一步就相當於數據=>視圖的綁定
let name = input.getAttribute('v-model');
input.value = _data[name];
// 為input綁定輸入事件
input.oninput = function () {
// 當input修改時,將修改後的值賦給暴露在外的data對象
// 這一步就實現了視圖=>數據的綁定
data[name] = this.value;
};
});
}
修改後的render函數通過過濾、遍歷得到每一個擁有v-model屬性的input標籤,然後將數據綁定到視圖上,並且視圖修改也會觸發數據的更新,這樣就實現了數據的雙向綁定。
看似複雜的綁定機制其實就是通過我們熟悉的js一些基礎的操作來實現的。
完整代碼
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="div1">
<input type="text" v-model="name">
<br> 姓名:{{name}}
</div>
</body>
<script>
let el = document.getElementById('div1');
let template = el.innerHTML;
let _data = {
name: '_BuzzLy'
};
let data = new Proxy(_data, {
set(obj, name, value) {
obj[name] = value;
render();
}
});
render();
function render() {
el.innerHTML = template.replace(/\{\{\w+\}\}/g, str => {
str = str.substring(2, str.length - 2);
return _data[str];
});
Array.from(el.getElementsByTagName('input'))
.filter(ele => ele.getAttribute('v-model'))
.forEach(input => {
let name = input.getAttribute('v-model');
input.value = _data[name];
input.oninput = function () {
data[name] = this.value;
};
});
}
</script>
</html>