示例代码请访问我的GitHub:
以06课双向绑定为基础实现双向绑定对象属性
代码参考/lesson09/01. watch监听对象属性.html
在06课中,实现了对数据的监听,当然Proxy对象同时也可以监听对象类型的数据,我们需要做的只是将相应的变化渲染到页面中。
首先,我们先将_data中的值修改为
// 用_data保存数据let _data = { userInfo: { name: 'lee', age: 18 }}复制代码
HTML修改为:
姓名:{ {userInfo.name}} 年龄:{ {userInfo.age}}复制代码
因此需要将render方法中查找模板中要写入值的正则从
/\{\{\w+\}\}/g复制代码
替换为:
/\{\{[\w\.]+\}\}/g复制代码
这样就可以匹配到HTML模板中的{
{ }},但我们从对象中获取数据必须使用data["userInfo"]["name"],而不能直接用data[],因此接下来需要拼接出相应的格式查找到数据,就可以将数据渲染到页面中。完整代码如下:
// 将模板中{ {}}内部的内容,用数据替换el.innerHTML = template.replace(/\{\{[\w\.]+\}\}/g, str => { str = str.substring(2, str.length - 2); // 将userInfo.name拼接为["userInfo"]["name"],以便查找对象中的属性。 return eval('_data["' + str.split('.').join('"]["') + '"]')})复制代码
这样一来我们就实现了将对象中的属性数据渲染到页面中。 当然同理,我们就可以实现对象中属性的双向绑定,完整代码如下:
JavaScript:
const el = document.querySelector('#app')// 获取标签内容作为页面模板let template = el.innerHTML// 用_data保存数据let _data = { userInfo: { name: 'lee', age: 18 }}// 为_data设置拦截,通过修改data中属性的值,来修改let data = new Proxy(_data, { // 当数据修改时,会被set方法拦截,从而得知数据被修改的值value,之后可以将value渲染到页面中,obj为_data set(obj, key, value) { console.log(`设置${key}属性为${value}`) eval('_data["' + key.split('.').join('"]["') + '"] = value') // 将数据渲染到页面中 render() }})// 初始化时渲染页面render()function render() { // 将模板中{ {}}内部的内容,用数据替换 el.innerHTML = template.replace(/\{\{[\w\.]+\}\}/g, str => { str = str.substring(2, str.length - 2); // 将userInfo.name拼接为["userInfo"]["name"],以便查找对象中的属性。 return eval('_data["' + str.split('.').join('"]["') + '"]') }) // 但检测到数据改变时,将input的值同步 Array.from(document.getElementsByTagName('input')) // 查找含有v-model属性,即设置了双向绑定的input .filter((ele) => ele.getAttribute('v-model')) .forEach((input, index) => { const name = input.getAttribute('v-model') eval('input.value = data["' + name.split('.').join('"]["') + '"]') // 输入框的值变化时,将data中相应属性的值改变 input.oninput = function () { data[name] = input.value eval('data["' + name.split('.').join('"]["') + '"] = input.value') } })}复制代码
HTML:
姓名:{ {userInfo.name}} 年龄:{ {userInfo.age}}复制代码