2017.08.28
New
Vue
Vue 适用于数据驱动开发的 Web应用程序。
数据绑定
Vue 实例
每个 Vue.js 应用的起步都是通过构造函数 Vue 创建一个 Vue 的根实例:
var vm = new Vue({
// 构造选项
el: '#app',
data: {
message: 'Hello Vue.js'
},
methods: {
greeting: function () {
alert('Hi, there.')
}
}
})
构造选项包含属性和方法,其中 data 对象属性包含了 Vue 实例内部可直接使用的数据属性,除非使用 Vue.js 扩充的 $set()
方法(列表渲染)或声明为计算属性,所有需要在 Vue 实例中使用的数据均需在 data 对象中提前声明。data 属性中的数据属性可通过 this 代理访问,比如:this.message
。
- Vue 模板
Vue 模板是包括特殊格式文本、 Vue.js 指令以及 Vue.js 特殊属性的 HTML 片段,这里的特殊格式文本指用于插值的文本内容,其中的文本内容称为绑定表达式,用于用户界面的呈现(即 view)。
<div id="app">
<!-- 插值 / 绑定表达式 -->
<div>{{ message }}</div>
<!-- 指令 -->
<div><span v-text="anotherMessage"></span></div>
<button v-on:click="greeting"> Say Hi </button>
</div>
Vue.js 的模板是基于 DOM 实现的,编译完成之后就是真实的 DOM 元素结构,而我们通常使用的 handlebar、ejs 和 arttemplate 等模板,编译完成之后生成的是字符串,然后需要通过 innerHTML 属性或者 jQuery.html()
方法插入到 DOM 结构中。
- 插件(绑定表达式)
Vue.js 的另一个特点是,除了 {{ msg }} {{{ HTMLSegment }}}
这样的插值方式之外,其他的数据绑定和指令都是直接写在 HTML 标签内,这一点和 AngularJS 相似,这样做的好处有以下几点:
- 没有额外的标签,不必像其他模板那样纠结于 `{{ if }}、{{ each }}、<% if %>` ……等额外标签是否需要缩进这样的问题;
- 指令作用于哪个 DOM 元素一目了然;
- 判断和循环这样的流程控制结构通过 DOM 元素天然“关闭”,不必担心额外标签的错配和漏配,结构检查和排错比较容易;
- 不用担心使用编辑器的代码格式化功能时出现代码混乱。
可以使用 Vue.config 全局配置对象的 delimiters 和 unsafeDelimiters 属性设置自定义的插值定界符,以避免与其他模板冲突,自定义插值定界符的语句应该写在 Vue 实例化之前。
// ES6 模板字符串
Vue.config.delimiters = ['${', '}']
// 使之看起来更危险
Vue.config.unsafeDelimiters = ['{!!', '!!}']
// 绑定表达式中 ++/-- 不可用(避免循环更新)
- 计算属性:适用于模版中不应出现过复杂逻辑而呈现的数据,如表单计算总价,数组排序等,避免模板难以维护。我们只需要编写一次计算逻辑,Vue.js 会自动建立该计算属性与 Vue 实例数据的依赖关系并追踪变化。(计算属性有两种声明语法,声明为一个函数时,该函数为计算属性的 getter,声明为含 get 和 set 方法的对象时,get 方法和 set 方法分别用作该计算属性的 getter 和 setter,可以在 setter 中进行其他操作和计算。)
Vue.js 提供了一个 $watch 方法用于观察 Vue 实例上的数据变动,这与 AngularJS 的做法类似。不过,通常更好的办法是使用计算属性而不是一个命令式的 $watch 回调。 一般情况下,使用计算属性比 $watch 实现简洁、维护方便,对于需要观察 Vue 实例数据变动的需求,如无特殊情况均应优先使用计算属性。const vm = new Vue({ el: 'root', data: () => ({ a: 5, b: 6 }), computed: { s: () => a * b; } })
根据 Vue.js 的 $watch API 文档,当调用 Vue 实例的 $watch 方法创建 $watch 时,返回一个 unwatch 函数,用于取消观察,因此在需要取消观察的场合,使用 $watch 为佳。 推荐使用专业的第三方类库 lodash 创建计算属性来实现列表内容的过滤和排序。
- 指令
特殊的带 v- 前缀的 HTML 元素属性,可带参数。插值语法不可用于 Vue.js 指令和特殊属性。
Vue.js 的双大括号插值和三大括号插值其实是语法糖,双大括号会被编译成一个 textNode,然后使用 v-text 指令插入插值内容,而三大括号插值则被编译成一个锚节点,然后使用 v-html 指令替换为插值内容,上述过程比直接在 DOM 元素中使用 v-text 或 v-html 在性能上略有降低。 Vue.js 使用了将插值内容直接赋值给 textNode 元素的 data 属性或其他元素的 textContent 属性这样一种精巧的方式进行 HTML 转义,充分利用了浏览器自身的处理能力。这种方式也会产生无伤大雅的副作用,如对 textNode 元素的 data 属性赋值其实是调用了该属性的 setter() 方法,实际生成的 DOM 元素的代码与绑定表达式的值有可能不完全相同。(参见源码)
v-pre 指令用于指示 Vue 编译器跳过含有该指令的元素及其子元素,该指令主要有如下两个用途:
- 显示原始插值标签
- 跳过大量没有指令的节点以降低编译时间
编写较复杂的 Vue.js 模板时可以适当使用 v-pre 指令,提升编译效率。(Vue.js 模板编译发生在使用 Vue 构造函数创建 Vue 实例时和使用 Vue.extend 方法定义组件构建器时)
- Vue.js数据绑定的注意事项
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 文档。
- 条件渲染
template 元素是 HTML5 中引入的新元素,天然具有 display:none 的样式且无法改变,因此v-if 指令使用 template 元素包装时,编译结果仅使用其所包装的内容而不保留 template 元素(脱壳)。
v-show 指令通过 display 样式来控制元素是否显示,若使用 template
元素包装,编译时同样需要经过“脱壳”的过程,无法实现一个父级元素设置多个子元素的 display 样式,因此不能使用 template
元素包装多个元素,若希望能在条件变化时单独设置多个元素的 display 样式,则会带来较大的实现复杂度。当希望控制多个元素显示/隐藏时,要么使用非 template
(如 div
)元素进行包装,并消除使用该包装元素对结构、样式带来的影响,要么分别对每个元素应用 v-show 指令,或者在切换性能消耗可接受的条件下,改为使用 v-if 指令。
- 列表渲染:
v-for="(key, val) in list
可以使用 $key 表示属性键名,若在对象属性遍历时使用 $index 特殊变量,则会返回表示属性序号的数字;方法是一种类型为 Function 的特殊属性。
使用 v-for 指令时,还可以指定一个整数,表示模板重复的数次。
<div>
<span v-for="n in items.length">
第 {{ n + 1 }} 个元素: {{ items[n] }}
</span>
</div>
- 绑定类与样式:可以采用 v-bind 或者 插值绑定的方式进行类绑定
表单控件绑定:
绑定 value 的表单控件种类
数据双向绑定有 text、checkbox、radio 以及 select 四种类型,其中的checkbox、radio 以及 select 的 options 可以进行使用 v-bind 指令绑定 value,唯独 text 类型没有绑定 value,这是为什么呢?
表单控件中,text 类型的数据双向绑定所涉及的表单控件如 text、number、range……等都是通过 value 来传递控件所包含的信息,双向绑定所绑定的其实就是控件的 value 属性。
而 checkbox、radio 以及 select 就不同了,就控件而言,checkbox 和 radio 控件通过 checked 属性来表示控件的状态,select 控件通过 option 子元素的 selected 属性来表示控件的状态,从表单层面来讲,需要结合 value 和 checked / selected 属性才能获取这三种表单控件的完整状态,也就是说,value 属性是这三种表单控件状态的一部分。
在 checkbox、radio控件及 select 控件的 option 子元素上绑定 value 可以实现动态的 value,如根据数组渲染一系列 checkbox、radio 控件或 select 控件的一系列 option 子元素,或者根据后端返回的数据插入或更新控件。
绑定 value 的优势
通常表单控件的 value 属性只能是普通的字符串。由于不能设置 value 属性为复杂数据类型,传统的视图驱动的 RIA (Rich Internet Application)前端开发中,获取上述三种表单控件的完整状态到进行业务处理之间可能还需要一个转换过程,如以获取的状态作为 index 来检索数组,或者作为键名来获取对象的键值数据,甚至还要结合控件的其他属性如 id 属性、class 属性……来进行加工处理。
在 Vue.js 中,绑定 value 可以绑定的数据不局限于字符串,也不局限于 JavaScript 原始数据类型,可以是任意数据类型如字符串、数值、boolean 值、对象、数组、函数方法……。通过数据双向绑定,用户交互时 Vue.js 直接将绑定的 value 赋予(单一数据)或插入(数组数据)双向绑定的数据,该数据无需进行额外的加工、转换,就可以直接用于业务逻辑的处理,这就是绑定 value 的优势所在。