持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
上一篇我们已经可以实现简版Vue的大部分功能:
- 将data数据转换为响应式数据
- 能够解析插值和一些表达式,如h-text、h-html
- 改变数据能够将页面更新 现在我们要实现数组的响应式,@click点击事件和h-model双向绑定,接下来开始吧。
代码实现
数组响应式
- 找到数组的原型
- 覆盖那些能够修改数组的更新方法,使其通知更新。
- 将改造好的数组原型设置到数组实例原型上
具体代码实现等我学习完相关源码再更新。
事件绑定
首先我们要给页面绑定点击事件。为了不影响观看,我们把sum去掉。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>简版vue的实现</title>
</head>
<body>
<div id="app">
<p>{{counter}}</p>
<p h-text="counter"></p>
<p h-html="htmlText" @click="doubleCounter"></p>
</div>
</body>
<!-- <script src="../node_modules/vue/dist/vue.js"></script> -->
<script src="./hvue.js"></script>
<script>
const app = new Hvue({
el:'#app',
data:{
counter:1,
htmlText:'<span style="color:red">我成功啦</span>'
},
methonds:{
doubleCounter(){
this.counter = this.counter * 2;
}
}
})
</script>
</html>
此刻的页面,我们绑定了个方法,当我们点击“我成功啦”的时候,counter的值会变双倍。
我们实现点击事件绑定的解析。回到hvue.js文件。首先要解析绑定,看代码。之前在解析插值和h-xxx表达式的时候,有一个compileElement的编译函数,我们就要在这里判断是否为@xxx形式的事件绑定,然后进行处理。
// 处理指令 编译
compileElement(n){
const attrs = n.attributes;
Array.from(attrs).forEach(attr=>{
const attrName = attr.name;
const exp = attr.value;
// 判断是否为特定的属性指令 h-
if(this.isDir(attrName)){
this.commandHandler(n,attrName,exp);
}
//事件绑定处理 @xxxx
if(this.isEvent(attrName)){
//@click
const dir = attrName.substring(1); //click
//事件监听
this.eventHandler(n,exp,dir);
}
})
}
//是否为事件绑定
isEvent(attrName){
return attrName&&attrName.startsWith('@');
}
//事件处理
eventHandler(node,exp,dir){ //exp就是方法名doubleCounter
const fn = this.$vm.$options.methods&&this.$vm.$options.methods[exp];//拿到绑定的事件方法
node.addEventListener(dir,fn.bind(this.$vm));//进行事件绑定
}
现在我们的页面已经可以进行点击操作,并且页面也会更新了
数据的双向绑定
双向绑定其实要实现两件事,一件是value的设定,另一件是事件的监听。这里只是简单实现input的元素
//hvue.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>简版vue的实现</title>
</head>
<body>
<div id="app">
<p>{{counter}}</p>
<p h-text="counter"></p>
<p h-html="htmlText" @click="doubleCounter"></p>
<input type="text" h-model="htmlText"/>
</div>
</body>
<!-- <script src="../node_modules/vue/dist/vue.js"></script> -->
<script src="./hvue.js"></script>
<script>
const app = new Hvue({
el:'#app',
data:{
counter:1,
htmlText:'<span style="color:red">我成功啦</span>',
array:['一','二','三','四']
},
methods:{
doubleCounter(){
this.counter = this.counter * 2;
}
}
})
</script>
</html>
此时页面的输入框内还是空白,数据并没有填充到里面。一下的功能的实现代码,h-model也是个指令属性,所以我们可以像h-text和h-html一样,再添加个modelCommandHandler的处理函数就可以了。只是要实现两件事,一个是赋值更新,另一件事是事件监听。
//h-model
modelCommandHandler(node,exp){
//赋值更新
node.value = this[exp];
//
node.addEventListener('input',e=>{
this[exp]=e.target.value
})
}
现在我们可以看到输入框已经有值了,将red改为blue,页面中的文字颜色也发生了变化。