概览
核心
Reactive Components for Modern web interfaces.
数据驱动的组件,为现代化的web界面而生。
- 数据驱动
- 组件化
特点:
- 入侵性底
- 鼓励模块化
- 轻量,高性能
架构
MVC架构
- Model:模型,用来封装业务程序的逻辑相关的数据以及数据处理方法,可以直接访问业务数据。
- View:视图,实现数据的显示,为了相应数据的变化必需注册到他监视的数据模式上。视图具有一定的业务逻辑,当业务逻辑发生变化时,视图相应的发生变化。
- Controller:控制器,起到不同层次的组织作用。控制业务程序的流程,相应用户行为,创造用户模型。
MVC架构的缺点时由于三个部分耦合性比较高,使得单独拆出一个部分或接口拿出来测试会比较困难。
MVP
- Presenter:实现应用程序的业务逻辑,控制视图和数据模型中的同步
- View:变得轻量,不再需要注册并检测Model
MVP架构由于降低了耦合,各部分可以进行单元测试。
MVP的缺点是,Presenter还是要控制V和M的同步逻辑处理。
MVVM
- Model:应用程序数据的抽象和封装。
- ViewModel:显示在页面上的数据的抽象和封装
MVVM将各种同步处理的工作进行了进一步的抽象,ViewModel和View之间通过数据绑定,实现数据的同步。
以前由Presenter实现的数据同步操作,现在交给了数据绑定来实现。
只需要在View中使用数据绑定语法,证明View的显示内容和ViewModel的数据关系。
当ViewModel进行数据更新的时候,会将数据更新的内容实时在View上更新。
同时当用户对View进行操作的时候,数据绑定也会将View上的数据变化同步到数据模版上。
定位
vue 在MVVM中的定位是ViewModel层。
MVVM的View相当于页面的DOM树,而ViewModel层就由vue来实现,vue实例中的vm.$Data对页面或部分页面的数据进行抽象,映射页面的视图内容和状态。在Model层通过原生的JS来对业务逻辑进行抽象和封装。
在开发过程中,只需要关注如何合理地设置ViewModel的数据,来实现业务视图的封装和抽象,以及实现View和ViewModel的交互和同步。
开发
实现一个下拉选择列表
CSS
|
|
jquery实现方式
DOM
|
|
JS
|
|
使用vue
DOM
|
|
JS
|
|
数据绑定 与 计算属性
实例
每个 Vue.js 应用的起步都是通过构造函数 Vue 创建一个 Vue 的根实例:
|
|
构造选项包含属性和方法,其中 data 对象属性包含了 Vue 实例内部可直接使用的数据属性,除非使用 Vue.js 扩充的 $set() 方法(我们会在“列表渲染及其注意事项”中详细介绍)或声明为计算属性,所有需要在 Vue 实例中使用的数据均需在 data 对象中提前声明。
在上面的示例中,data 对象包含 message 数据属性,在 Vue 实例方法中,可以使用 this.message 访问,message 可使用数据绑定语法绑定到 Vue.js 模板中。
模版
Vue.js 模板是包括特殊格式文本、 Vue.js 指令以及 Vue.js 特殊属性的 HTML 片段,这里的特殊格式文本指用于插值的文本内容,其中的文本内容称为绑定表达式。
|
|
Vue.js 的模板是基于 DOM 实现的,编译完成之后就是真实的 DOM 元素结构。
我们通常使用的 handlebar、ejs 和 arttemplate 等模板,编译完成之后生成的是字符串,然后需要通过 innerHTML 属性或者 jQuery.html() 方法插入到 DOM 结构中。
Vue.js 的另一个特点是,除了
|
|
这样的插值方式之外,其他的数据绑定和指令都是直接写在 HTML 标签内,这样做的好处有以下几点:
- 没有额外的标签,不必像其他模板那样纠结于额外标签是否需要缩进这样的问题;
- 指令作用于哪个 DOM 元素一目了然;
- 判断和循环这样的流程控制结构通过 DOM 元素天然“关闭”,不必担心额外标签的错配和漏配,结构检查和排错比较容易;
- 不用担心使用编辑器的代码格式化功能时出现代码混乱。
数据绑定
Vue.js 通过插值和指令这两种方式来实现数据绑定,绑定的数据发生变化时,DOM 元素中的内容、属性会响应式地发生变化。
|
|
插值
使用Mustache语法:
|
|
插值类型:
- 文本
- 原始HTML
- HTML属性
Vue.js 的双大括号插值和三大括号插值其实是语法糖,双大括号会被编译成一个 textNode,然后使用 v-text 指令插入插值内容,而三大括号插值则被编译成一个锚节点,然后使用 v-html 指令替换为插值内容,上述过程比直接在 DOM 元素中使用 v-text 或 v-html 在性能上略有降低。
|
|
|
|
指令
带有v- 的特殊HTML属性:v-if 、v-text 、v-html 、v-bind 、v-on ……因为是HTML属性,所以在模版中是不能单独存在的,必需写在HTML标签中。
把某些特殊行为应用道DOM上,例如:
|
|
指令的缩写
|
|
绑定表达式
- 支持全功能JavaScript表达式
- 表达式将在其所在Vue实例的作用域内进行计算
- 不支持多于一个JavaScript表达式
- 不支持语句及流程控制
- 要避免循环更新
可选过滤器
Vue.js 2.0 版中将移除所有内置过滤器,过滤器的使用方式也将发生改变,在新版本中,过滤器后使用括号而非空格来添加参数,并只可应用于插值方式的数据绑定,其他使用过滤器的场景使用计算属性替代,并根据需要选择使用针对不同专业领域的第三方独立库,如针对日期时间处理使用 Moment.js,针对金融货币处理使用 Accounting.js,针对数组和对象处理使用 lodash。
计算属性
为什么要使用计算属性?
- 模版不宜过于复杂
- 绑定限定为一个表达式
- 如果获取绑定数据需要用刀多于一个表达式的逻辑,应使用计算属性
应用场景
- 电商网站中,购物车商品总重量及运费
- 电商网站中,购物车的总价
- 旅游网站中,飞机航班的航程时间、中转时间
- 旅游网站中,根据身份证号码获取乘客类型
声明方法:
- 创建Vue实例时,使用构造选项中的computed属性声明计算属性
- computed属性包含
- 用户获取计算属性的方法
- 带用get和set方法
栗子:
虽然Vue.js 提供了一个 $watch 方法用于观察 Vue 实例上的数据变动,这与 AngularJS 的做法类似。不过,通常更好的办法是使用计算属性而不是一个命令式的 $watch 回调。
以计算长方形面积为例,如果我们要观察长方形的长和宽的数据变动并计算其面积,需要分别设置长和宽的 $watch 回调。
模版
|
|
watch
|
|
computed
|
|
如果使用计算属性,我们只需要编写一次计算逻辑,Vue.js 会自动建立该计算属性与 Vue 实例数据 a、b 的依赖关系并追踪变化。
如果我们将长方形面积公式改为椭圆面积公式,则也只需要修改一次,维护工作量降低,不易出现遗漏的情况。
一般情况下,使用计算属性比 $watch 实现简洁、维护方便,对于需要观察 Vue 实例数据变动的需求,如无特殊情况均应优先使用计算属性。
根据 Vue.js 的 $watch API 文档,当调用 Vue 实例的 $watch 方法创建 $watch 时,返回一个 unwatch 函数,用于取消观察,因此在需要取消观察的场合,使用 $watch 为佳。
注意事项
Vue.js 应用从 Vue 实例起步,通过 Vue 构造函数构造 Vue 实例过程中对其模板进行编译,模板中含有插值标记或数据绑定指令,在编译过程中,Vue.js 将 DOM 元素的内容或属性与数据进行绑定,当数据发生变化时,DOM 元素的内容或属性响应式地发生改变。
在编写模板进行数据绑定时,需要注意如下几点:
- 插值语法可用于 DOM 元素内容和 HTML 普通属性,但插值语法和指令语法不可混用,注意不要在 Vue.js 指令中使用双大括号或三大括号插值语法;
- 不要不加限制地对用户提交的内容进行三大括号插值,防止 XSS 攻击;
- 绑定表达式可以是一个 Javascript 表达式,但不能是 Javascript 语句,也不能包含判断、循环之类的复杂的流程结构;
- 要注意避免循环更新;
- 绑定表达式支持过滤器,过滤器不是 Javascript 语法,不能用在表达式内部;
- 模板中的绑定表达式主要用于描述视图的结构,因此不建议使用复杂的逻辑,如果需要多于一个表达式的逻辑,应当使用计算属性;
- 使用 v-bind 和 v-on 指令进行数据绑定时,使用饰符表示指令应当以特殊方式绑定,修饰符的说明参见 Vue.js 的 v-bind 和 v-on 的 API 文档。
条件渲染
- Vue.js 条件渲染的作用是在不同条件下显示或隐藏某些元素,可以使用 v-if 和 v-show 指令实现不同的条件渲染。
- 这两个指令在作用、编译方式及使用方法上都各有不同,此外,还有一个 v-else 指令可以分别和 v-if、v-show 配合使用。
- v-if为true就在DOM中显示,为false则在DOM中移除。
- v-show为true在DOM中display为block,为false在DOM中display为none。
v-if例子:
|
|
|
|
v-show例子:
|
|
|
|
v-if 指令的切换性能消耗较高,当条件切换时,v-if 指令会根据条件创建或删除 DOM 元素,在条件满足时编译生成相应的元素并插入 DOM 结构,在条件不满足时将元素从 DOM 结构中删除;当使用 template元素包装多个元素时,最终的渲染结果仅包含 template 元素的内容。
v-show 指令的初始性能消耗较高,v-show 指令会在初始编译时创建元素并插入 DOM 结构,同时根据条件决定该元素是否显示;v-show 指令不能使用 template 元素包装多个元素;v-if 和 v-show 指令后面都可以紧跟一个 v-else 指令表示当条件不满足时渲染/显示的内容。
扩展:
template 元素是 HTML5 中引入的新元素,天然具有 display:none 的样式且无法改变,因此v-if 指令使用 template元素包装时,编译结果仅使用其所包装的内容而不保留 template 元素(脱壳)。
v-show 指令通过 display 样式来控制元素是否显示,若使用 template 元素包装,编译时同样需要经过“脱壳”的过程,无法实现一个父级元素设置多个子元素的 display 样式,因此不能使用 template 元素包装多个元素,若希望能在条件变化时单独设置多个元素的 display 样式,则会带来较大的实现复杂度。当希望控制多个元素显示/隐藏时,要么使用非 template(如 div )元素进行包装,并消除使用该包装元素对结构、样式带来的影响,要么分别对每个元素应用 v-show 指令,或者在切换性能消耗可接受的条件下,改为使用 v-if 指令。
注意事项:
- 多于一个元素的 v-if 需要使用 template
- v-show 不支持 template
- v-else 必须紧跟在 v-if/v-show 指令后面
- 组件条件下不能使用 v-else
当 v-if 用于多个元素时,若随意在元素外面使用 div> 元素包装,当在 css 文件中使用了元素结构较为明确的选择子时(如.nav > span),则有可能会导致元素的样式发生变化;
v-if 和 v-show 指令编译时,会查找紧跟其后的元素是否带有 v-else 指令,因此带 v-else 指令的元素与带 v-if/v-show 指令的元素之间不能间隔其他元素;
组件条件下,由于指令优先级的不同,会导致 v-else 出现问题,因此只能通过使用相反条件的 v-if 指令来实现 v-else 的效果。
比较:
v-if 指令是惰性的,只有条件为真时才开始局部编译(编译后缓存),当条件变化时将编译生成的元素从 DOM 结构中插入/删除;
v-show 是非惰性的,初始编译时编译和渲染元素,并根据条件设置 display 样式来控制其显示/隐藏;v-if 指令切换消耗较高,v-show 指令初始渲染消耗较高。
选择 v-if 还是 v-show 指令主要考虑条件变化是否频繁及当条件切换时对性能的消耗。
列表渲染
指令与索引:
可以使用 v-for 指令基于一个数组渲染一个列表。这个指令使用特殊的语法,形式为 item in items,items 是数据数组,item 是当前数组元素的别名。
从1.0.17版开始,为兼容 Javascript 写法,也可以使用 item of items 语法;
在 v-for 块内我们能完全访问父组件作用域内的属性,另有一个特殊变量 $index,正如你猜到的,它是当前数组元素的索引:
|
|
|
|
嵌套:
类似于 template v-if,也可以将 v-for 用在 标签上,以渲染一个包含多个元素的块。
对象属性:
除了 $index 之外,作用域内还可以访问另外一个特殊变量 $key。
在遍历对象时,是按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下是一致的。
|
|
|
|
值域:
v-for 也可以接收一个整数,此时它将重复模板数次。
|
|
检测:
受ES5限制,vue不能监测到数据元素的或对象属性的添加或者删除。所以Vue.js 包装了被观察数组的变异方法,故它们能触发视图更新。被包装的方法有:
变异方法:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
非变异方法
不会修改原始数组而是返回一个新数组:
- concat()
- slice()
- filter()
重新赋值
在使用非变异方法时,可以直接用新数组替换旧数组:
|
|
对象扩充方法:
因为 JavaScript 的限制,Vue.js 不能检测到下面数组变化:
直接用索引设置元素,如 vm.items[0] = {};
修改数据的长度,如 vm.items.length = 0。
所以,Vue.js 扩展了观察数组:
- $set 添加数据
- $remove 删除数据12example1.items.$set(0, { childMsg: 'Changed!'})this.items.$remove(item)
track-by:
当对数组重新赋值时,如果不加特殊设置,vue会重新渲染所有列表上的DOM元素。
为了提升性能,所以提供了track-by属性,对v-for指令的元素设置这个属性,可以提示vue在什么情况下可以复用已有的DOM元素。
使用 track-by 可以增加复用,提升数据变动时的渲染性能;
可以 track-by 数组中的唯一键值来指示当键值一致时复用使用域和 DOM 元素;
若数组没有唯一键值,可以使用 track-by=”$index” 指示 v-for 指令进行原位更新模式,该模式也可用于处理数组中的重复值。
http://cn.vuejs.org/guide/list.html#track-by