前端双向数据绑定的优势

双向数据绑定是现在前端框架中很流行的一种技术,当前最流行的三大前端框架AngularJS、React、Vue均对其做了实现。通过 View <-> ViewModal <=> Modal的mvvm模型,使View的变化能触发Model的修改,Model的变化也能触发View的修改。本文不讨论双向数据绑定的功能实现,仅仅从最简单的层面分析其优势。

业务逻辑

假设有如下业务场景:

  • 有3个INPUT,需要三者的值始终保持一致

事件驱动

在未实现双向数据绑定时,我们的所有前端操作都属于事件驱动型,也就是为不同的DOM附加各种EventLIstener,当事件触发时,对页面和数据进行操作。

下面以jquery为例对上述逻辑进行实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<input id="A"/>
<input id="B"/>
<input id="C"/>

<script>
$("#A").on("keydown", function() {
$("#B").val($(this).val())
$("#C").val($(this).val())
})
$("#B").on("keydown", function() {
$("#A").val($(this).val())
$("#C").val($(this).val())
})
$("#C").on("keydown", function() {
$("#A").val($(this).val())
$("#B").val($(this).val())
})
</script>

可见上述逻辑看起来非常简单,但实际业务场景复杂度远远超过这个,当一个DOM发生变化时,也许要操作多个DOM,所以,双向数据绑定诞生了。

数据驱动

双向数据绑定后,所有的变化都是由数据的变化来驱动的,所以称为数据驱动型。同样来解决上面提到的业务需求,这里以vue为例来写代码,angular和react的代码逻辑类似。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<input id="A" v-bind:value="inputVal"/>
<input id="B" v-bind:value="inputVal"/>
<input id="C" v-bind:value="inputVal"/>

<script>
export default {
data() {
return {
inputVal: ''
}
}
}
</script>

可以看到上面的代码非常简单,没有任何事件的监听,其中v-bind:value='inputVal'里的v-bind:表示将input的属性value与下面数据集中的inputVal属性绑定,甚至可以更简单的写成:value="inputVal"。与事件驱动型的代码比较起来,仅仅看代码的行数就少了50%。

更复杂的例子

我们下面看一个更复杂的例子,来比较事件驱动和数据驱动的开发工作量。

例如:一个任务卡片有4个状态(未提交、运行、完成、错误),显示在任务卡的状态栏中,还有5个功能按钮(运行、删除、编辑、详情、日志),需要根据任务卡的状态来修改状态栏文本,以及判断5个功能按钮是否应该显示。

  • 事件驱动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<div class="card">
<div id="status">未提交</div>
<button id="run">运行</button>
<button id="delete">删除</button>
<button id="edit">编辑</button>
<button id="reset">重置</button>
<button id="log">日志</button>
</div>

<script>
var changeWithStatus = function (status) {
$("#status").html(status)
switch(status) {
case "未提交":
$("#run").show();
$("#delete").show();
$("#edit").show();
$("#reset").show();
$("#log").hide();
break;
case "运行":
$("#run").hide();
$("#delete").hide();
$("#edit").hide();
$("#reset").hide();
$("#log").hide();
break;
case "完成":
$("#run").hide();
$("#delete").hide();
$("#edit").hide();
$("#reset").show();
$("#log").show();
break;
case "错误":
$("#run").show();
$("#delete").show();
$("#edit").show();
$("#reset").hide();
$("#log").show();
break;
}
}
</script>
  • 数据驱动

    其中,v-show表示将元素是否显示,绑定到相应的属性或方法,根据属性值或方法的返回值来判断元素是否显示,在下面这种场景下,如果我要在另一个地方改变卡片的状态,例如this.status = '错误'这时所有设置了v-show绑定的button,都会根据status变化成的状态”错误”,来重新渲染其是否显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div class="card">
<div>{{ status }}</div>
<button v-show="canOperater">运行</button>
<button v-show="canOperater">删除</button>
<button v-show="canOperater">编辑</button>
<button v-show="status == '完成'">重置</button>
<button v-show="status == '完成' || status == '错误'">日志</button>
</div>
<script>
export default {
data() {
return {
status: ''
}
},
methods: {
canOperate: function() {
return this.status == '未提交' || status =='错误'"
}
}
}
</script>

综合上面的例子来看,实现了双向数据绑定的框架,代码逻辑更加清晰,代码量少了一半左右,开发效率更高。

分享到