lanbos'blog

js的mvvm(1)

通过vue框架的简单学习来了解js的mvvm思想。

mvvm雏形

都在说jq的黄金时代已过,但是jq在当前很多项目中也仍在发挥着重要的作用。个人觉得jq+模板引擎+各种插件的开发模式是当下非常流行的mvvm的雏形。
各种模板引擎充当view的角色,同样使用js的对象充当model,同样通过修改赋值给模板引擎的数据来实现view层的改变。(模板引擎的使用不在这里赘述,详情参见《新一代 javascript 模板引擎:artTemplate-3.0》
这套方法可以基本实现mvvm中的单向数据绑定(双向数据绑定择需要配合jq的事件监听,或其他复杂方法),jq在其中起到的作用只是简单的dom节点获取,然后把模板生成的html格式字符串再输出到指定位置,这种简单的dom操作甚至完全可以通过原生的js代替。而jq的插件多用来在view层进行更改,若是要配合数据输出的话只需简单的在html中套用模板引擎并稍加修改就可以。在小型项目,页面较少、表单较少、非SPA等情况下,这种开发方式具有高度的灵活性和便利性,学习成本非常低。当然随着前端代码的复杂性不断提升,ajax数据交互的更频繁,SPA更加流行等趋势,一套完整的、体系化的mvvm框架能帮助开发者更快,更舒适的开发。mvvm框架有很多,最知名的angular和react的大战持续了一段时间,但是angular2.0的断层兼容与react的jsx语法都有颠覆式的学习成本,国内大神的vue在2016年渐渐的积攒人气正在迎头赶上,而且和之前所说的jq+模板引擎的雏形开发方式相像处不少,通过对vue的学习可以较为系统的理解js的mvvm。

vue的安装

安装Vue有很多方法,可以用npm或者webpack。但是我们现在的目标是尽快用起来,所以最简单的方法是直接在HTML代码中像引用jQuery一样引用Vue。可以直接使用CDN的地址,例如:

1
<script src="https://unpkg.com/vue@2.0.1/dist/vue.js"></script>

vue和随后路由组件(vue-router),ajax请求组件(vue-resource),表单验证组件(vue-validator)等最好由自动化工具webpack来配合使用,自动化工具选择的灵活性是mvvm框架与jq+模板引擎无法比拟的地方,当然强大的webpack对组件式开发带来的便利性也是非常有利的。

vue的单向数据绑定

用js的对象实现一个model:

1
2
3
4
{
name:'Robot',
age: 15
}

而view层的dom节点用类似于模板引擎的{ {name} }{ {age} }来引用model的属性:

1
2
3
4
<div id="vm">
<p>Hello, {{ name }}!</p>
<p>You are {{ age }} years old!</p>
</div>

最后一步是用Vue把两者关联起来。要特别注意的是,在< head >内部编写的JavaScript代码,需要用jQuery把MVVM的初始化代码推迟到页面加载完毕后执行,否则,直接在< head >内执行MVVM代码时,DOM节点尚未被浏览器加载,初始化将失败。正确的写法如下:

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
<html>
<head>

<!-- 引用jQuery -->
<script src="/static/js/jquery.min.js"></script>

<!-- 引用Vue -->
<script src="/static/js/vue.js"></script>

<script>
// 初始化代码:
$(function () {
var vm = new Vue({
el: '#vm',
data: {
name: 'Robot',
age: 15
}
});
window.vm = vm;
});
</script>

</head>

<body>

<div id="vm">
<p>Hello, {{ name }}!</p>
<p>You are {{ age }} years old!</p>
</div>

</body>
<html>

我们创建一个VM的核心代码如下:

1
2
3
4
5
6
7
var vm = new Vue({
el: '#vm',
data: {
name: 'Robot',
age: 15
}
});

其中,el指定了要把Model绑定到哪个DOM根节点上,语法和jQuery类似。这里的‘#vm’对应ID为vm的一个

节点:
1
2
3
<div id="vm">
...
</div>

该节点以及该节点内部,就是vue可以操作的view。Vue可以自动把Model的状态映射到View上,但是不能操作View范围之外的其他DOM节点。实际操作过程中若是页面不复杂可以类似于angular一样直接把body整个选中当做可操作的view。然后,data属性指定了Model,我们初始化了Model的两个属性nameage,在View内部的< p >节点上,可以直接用 name 引用Model的某个属性。
用浏览器打开html,显示

1
2
Hello, Robot!
You are 15 years old!

然后可以直接用js代码

1
window.vm.name = 'Bob'

来进行单向数据绑定操作,页面输出为

1
2
Hello, Bob!
You are 15 years old!

原来的Hello, Robot!自动变成了Hello, Bob!。Vue作为MVVM框架会自动监听Model的任何变化,在Model数据变化时,更新View的显示。这种Model到View的绑定我们称为单向绑定。
在Vue中,可以直接写 name 绑定某个属性。如果属性关联的是对象,还可以用多个.引用,例如,{ { address.zipcode } }。另一种单向绑定的方法是使用Vue的指令v-text,写法如下:

1
<p>Hello, <span v-text="name"></span>!</p>

这种写法是把指令写在HTML节点的属性上,它会被Vue解析,该节点的文本内容会被绑定为Model的指定属性,注意不能再写双花括号。

vue的双向数据绑定

单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新。
有单向绑定,就有双向绑定。如果用户更新了View,Model的数据也自动被更新了,这种情况就是双向绑定。
什么情况下用户可以更新View呢?填写表单就是一个最直接的例子。当用户填写表单时,View的状态就被更新了,如果此时MVVM框架可以自动更新Model的状态,那就相当于我们把Model和View做了双向绑定,在浏览器中,当用户修改了表单的内容时,我们绑定的Model会自动更新。

在Vue中,使用双向绑定非常容易,我们仍然先创建一个VM实例:

1
2
3
4
5
6
7
8
var vm = new Vue({
el: '#vm',
data: {
email: '',
name: ''
}
});
window.vm = vm;

然后,编写一个HTML FORM表单,并用v-model指令把某个< input >和Model的某个属性作双向绑定:

1
2
3
4
<form id="vm" action="#">
<p><input v-model="email"></p>
<p><input v-model="name"></p>
</form>

我们可以在表单中输入内容,然后在浏览器console中用window.vm.$data查看Model的内容,也可以用window.vm.name查看Model的name属性,它的值和FORM表单对应的< input >是一致的。
如果在浏览器console中用JavaScript更新Model,例如,执行window.vm.name=’Bob’,表单对应的< input >内容就会立刻更新。

参照:廖雪峰的官方网站javascript教程部分