目标
指定一个Vue实例,可以渲染出对应的HTML,并且当数据变动时重新渲染。
例如:
let app = new Vue({
el: '#app',
data: {
user: {
name: 'youngwind',
age: 25,
location: {
province: 'GD',
city: 'GZ'
},
school: 'bupt',
major: 'computer'
}
}
})
<div id="app">
<p>姓名:{{user.name}}</p>
<p>年龄:{{user.age}}</p>
<div>
<p>省份:{{user.location.province}}</p>
<p>城市:{{user.location.city}}</p>
</div>
</div>
结果如下:
结果思路
- 根据
el
属性找到对应的根元素 - 记录原HTML。
- 使用正则表达式找到需要替换的部分,然后根据
data
属性对{{}}
内的字符串进行求值。把修改后的HTML赋值回去。 - 监视数据的变动,如果数据有改变,就重复上一步。
其中前几步实现都不难,最主要的部分就是第四步。
这里需要实现一个Observer
类,它接受一个对象作为监视的值。然后当对象产生变化时,需要发出消息。
怎么发出消息?
- 实现一个
EventHandler
类,有一个属性$listeners
,2个函数$on
和$emit
,前者对于某个事件把指定的函数存入对应的监听器中,后者对于某个事件调用其对应的所有监听器。(发布-订阅模式)
怎么监视属性的修改?
- 遍历对象的每个属性,使用
Object.defineProperty
设置属性的getter
,如果值改变了就调用$emit
方法。
如果对象内还嵌套对象怎么办?
- 使用递归的方法,遍历每个对象的每个属性(实际做的时候没考虑继承的),如果属性是一个对象则继续
new Observer
。
如果属性修改后的值是对象怎么办?
- 检测属性修改后的类型,如果是对象则也要
new Observer
。
内层属性的修改如何传递到上层?
- 例如
user.location
是一个对象,为location
的每个属性$on
一个函数,内容是在user
里$emit location
,这样就实现了层层上传。
样例地址
https://github.com/huhk-sysu/ife-study/blob/master/vue/hw5/hw5.js
网友评论