JS原生数据双向绑定是实现MVVM(Model-View-ViewModel)框架的重要基础,该框架可以将数据和页面进行解耦,提高开发效率和代码可维护性。下面是JS原生数据双向绑定的实现代码攻略:
1. 实现数据绑定
数据绑定是指将数据与页面元素建立关联,当数据发生改变时,页面元素也会自动更新。我们可以使用Object.defineProperty()方法实现数据绑定,具体实现如下:
function bindData(obj, key, val) {
Object.defineProperty(obj, key, {
configurable: true,
enumerable: true,
get: function() {
console.log('get', key, val);
return val;
},
set: function(newVal) {
console.log('set', key, newVal);
if (val !== newVal) {
val = newVal;
updateValue(key, newVal);
}
}
});
}
function updateValue(key, newVal) {
var ele = document.querySelector('[v-model=' + key + ']');
ele.value = newVal;
}
上面的代码中,我们定义了一个bindData()函数来实现数据绑定,该函数接收三个参数,分别是对象obj、属性名key和属性值val。在函数体内,我们使用Object.defineProperty()方法来给obj对象的key属性赋值,并设置get和set方法获取和修改属性值。当属性值发生改变时,我们调用updateValue()函数来更新页面元素的值,这里我们假设页面元素使用v-model指令来关联对应的属性。
2. 实现模板编译
模板编译是指将页面元素中使用v-model指令的部分替换为对应的数据属性。我们可以使用正则表达式和DOM操作来实现模板编译,具体实现如下:
function compile(template) {
var reg = /\<input\s+v-model\=\"([\w\d]*)\"\>/g;
template = template.replace(reg, '<input v-model="$1" value="{{'+ '$1' +'}}">');
return template;
}
function render(tpl, data) {
var compiledTpl = compile(tpl);
for (var key in data) {
if (data.hasOwnProperty(key)) {
var reg = new RegExp('{{' + key + '}}', 'g');
compiledTpl = compiledTpl.replace(reg, data[key]);
}
}
return compiledTpl;
}
上面的代码中,我们定义了compile()函数来对模板中的v-model指令进行替换。该函数接收模板字符串作为参数,使用正则表达式查找所有包含v-model指令的input元素,并将其替换为<input v-model="$1" value="{{'+ '$1' +'}}">
字符串。其中$1表示v-model指令所绑定的属性名。
然后我们定义了render()函数来渲染模板。该函数接收两个参数,分别是模板字符串和数据对象。在函数体内,我们首先调用compile()函数对模板进行编译,然后使用for...in循环遍历数据对象,使用正则表达式和replace()方法将模板字符串中的{{key}}替换为对应的属性值。
示例说明
下面是两个使用JS原生数据双向绑定实现的示例:
示例1:实现简单计算器
我们使用JS原生数据双向绑定实现一个简单的计算器。该计算器包含两个输入框和一个结果框,用户可以输入两个数字,然后计算两数之和并显示在结果框中。
<div>
<input type="text" v-model="num1">
<input type="text" v-model="num2">
<input type="text" value="{{sum}}">
</div>
var data = {num1: 0, num2: 0, sum: 0};
var tpl = document.querySelector('#tpl').innerHTML;
tpl = render(tpl, data);
document.querySelector('#app').innerHTML = tpl;
bindData(data, 'num1', 0);
bindData(data, 'num2', 0);
bindData(data, 'sum', 0);
document.querySelector('[v-model=num1]').addEventListener('input', function(event){
data.num1 = event.target.value;
data.sum = parseFloat(data.num1) + parseFloat(data.num2);
});
document.querySelector('[v-model=num2]').addEventListener('input', function(event){
data.num2 = event.target.value;
data.sum = parseFloat(data.num1) + parseFloat(data.num2);
});
上面的代码中,我们首先定义了一个data对象来保存计算器的状态信息,包括num1表示第一个数字,num2表示第二个数字,sum表示计算结果。然后我们使用render()函数对模板字符串进行编译,使用bindData()函数实现数据绑定。当用户输入数字时,我们调用input事件的处理函数来更新数据对象的属性值,并计算两数之和来更新结果框的显示。
示例2:实现购物车
我们使用JS原生数据双向绑定实现一个简单的购物车应用。该应用包含一个商品列表和一个购物车列表,用户可以将商品添加到购物车中,并显示商品数量和总价。
<div id="app">
<h3>商品列表</h3>
<ul>
<li v-for="item in goods" :key="item.id">
{{item.name}}
<button @click="addToCart(item)">添加到购物车</button>
</li>
</ul>
<h3>购物车</h3>
<ul>
<li v-for="item in cart" :key="item.id">
{{item.name}} x {{item.num}} = {{item.price * item.num}}
</li>
</ul>
<p>总价格:{{totalPrice}}</p>
</div>
var data = {
goods: [
{id: 1, name: '商品1', price: 100},
{id: 2, name: '商品2', price: 200},
{id: 3, name: '商品3', price: 300}
],
cart: [],
totalPrice: 0
};
var tpl = document.querySelector('#tpl').innerHTML;
tpl = render(tpl, data);
document.querySelector('#app').innerHTML = tpl;
bindData(data, 'goods', data.goods);
bindData(data, 'cart', data.cart);
bindData(data, 'totalPrice', data.totalPrice);
Vue.component('my-component', {
template: '#my-component-template',
methods: {
addToCart: function(item) {
var cartItem = this.cart.find(function(cartItem) {
return cartItem.id === item.id;
});
if (cartItem) {
cartItem.num++;
} else {
this.cart.push({
id: item.id,
name: item.name,
price: item.price,
num: 1
});
}
}
}
});
new Vue({
el: '#app',
data: data,
methods: {
addToCart: function(item) {
var cartItem = this.cart.find(function(cartItem) {
return cartItem.id === item.id;
});
if (cartItem) {
cartItem.num++;
} else {
this.cart.push({
id: item.id,
name: item.name,
price: item.price,
num: 1
});
}
}
},
computed: {
totalPrice: function() {
var totalPrice = 0;
this.cart.forEach(function(cartItem) {
totalPrice += cartItem.price * cartItem.num;
});
return totalPrice;
}
}
});
上面的代码中,我们使用Vue.js框架的组件和响应式数据特性来实现购物车应用。我们首先定义了一个data对象来保存应用的状态信息,包括商品列表、购物车列表和总价格。然后我们使用render()函数对模板字符串进行编译,使用bindData()函数实现数据绑定。
在Vue.js中,我们通过定义一个自定义组件my-component来显示商品列表,并定义一个addToCart()方法来添加商品到购物车中。我们还需要在父组件中定义一个与该方法同名的函数并将其绑定到模板中的@click事件上,以便响应用户的点击事件。同时,我们使用computed属性来计算购物车中商品的总价格。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JS原生数据双向绑定实现代码 - Python技术站