一个 Vue 应用由一个通过 new Vue 创建的根 Vue 实例,以及可选的嵌套的、可复用的组件树组成。demo
当一个 Vue 实例被创建时,它向 Vue 的响应式系统中加入了其 data 对象中能找到的所有的属性。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。(注意的是只有当实例被创建时 data 中存在的属性才是响应式的。)
使用 Object.freeze(),这会阻止修改现有的属性,也意味着响应系统无法再追踪变化。demo
除了数据属性,Vue 实例还暴露了一些有用的实例属性与方法。它们都有前缀 $,以便与用户定义的属性区分开来。demo
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
beforeCreate created beforeMount mounted beforeUpdate updated beforeDestroy destroyed 8个声明周期
生命周期钩子的 this 上下文指向调用它的 Vue 实例。注意:不要在选项属性或回调上使用箭头函数,会改变this指向。
使用“Mustache”语法 (双大括号) 的文本插值demo, 一次性插值,当数据改变时,插值处的内容不会更新demo。
输出真正的 HTML,你需要使用 v-html 指令demo注意:你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。
Mustache 语法不能作用在 HTML 特性上,遇到这种情况应该使用 v-bind 指令demo当绑定属性值为null、undefined 或 false特性甚至不会被包含在渲染出来的元素中demo
对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持demo。限制,每个绑定都只能包含单个表达式,语句不生效。注意:模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如 Math 和 Date 。你不应该在模板表达式中试图访问用户定义的全局变量。
指令 (Directives) 是带有 v- 前缀的特殊特性。指令特性的值预期是单个 JavaScript 表达式(v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。
参数 一些指令能够接收一个“参数”,在指令名称之后以冒号表示。例如,v-bind 指令可以用于响应式地更新 HTML 特性demo
修饰符 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。如.prevent组织form提交默认行为demo
缩写 v-bind缩写 : , v-on缩写 @
在模版中使用表达式,不易于观察,可使用计算属性代替。对于任何复杂逻辑,你都应当使用计算属性。
一个基础的例子demo,你可以像绑定普通属性一样在模板中绑定计算属性。
demo两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。
我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。
侦听属性:观察和响应 Vue 实例上的数据变动。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。watch的例子 改成计算属性后
计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter。demo
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。demo 除了 watch 选项之外,您还可以使用命令式的 vm.$watch API。
操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是属性,所以我们可以用 v-bind 处理它们:只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将 v-bind 用于 class 和 style 时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
传给 v-bind:class 一个对象,以动态地切换 class demo , v-bind:class 指令也可以与普通的 class 属性共存demo
绑定的数据对象不必内联定义在模板里demo,绑定一个返回对象的计算属性。这是一个常用且强大的模式demo
我们可以把一个数组传给 v-bind:class,以应用一个 class 列表demo,根据条件切换列表中的 class,可以用三元表达式demo当有多个条件 class 时这样写有些繁琐。所以在数组语法中也可以使用对象语法demo
当在一个自定义组件上使用 class 属性时,这些类将被添加到该组件的根元素上面。这个元素上已经存在的类不会被覆盖。demo
对于带数据绑定 class 也同样适用demo。
v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) 来命名demo。,直接绑定到一个样式对象通常更好,这会让模板更清晰demo,同样的,对象语法常常结合返回对象的计算属性使用。
v-bind:style 的数组语法可以将多个样式对象应用到同一个元素上 demo
当 v-bind:style 使用需要添加浏览器引擎前缀的 CSS 属性时,如 transform,Vue.js 会自动侦测并添加相应的前缀。
从 2.3.0 ,可以为 style 绑定中的属性提供一个包含多个值的数组,常用于提供多个带前缀的值。demo
元素上使用 v-if 条件渲染分组v-if 指令必须添加到一个元素上,如果想切换元素,可以把一个 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含
元素。demo
使用 v-else 指令来表示 v-if 的“else 块”demo
v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
v-else-if,顾名思义,充当 v-if 的“else-if 块”,可以连续使用demo
类似于 v-else,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换demo,代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,不会被替换掉——仅仅是替换了它的 placeholder。
这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key 属性即可demo,注意, 元素仍然会被高效地复用,因为它们没有添加 key 属性。
另一个用于根据条件展示元素的选项是 v-show 指令。用法大致一样demo, 不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display。注意,v-show 不支持 元素,也不支持 v-else。
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。
我们用 v-for 指令根据一组数组的选项列表进行渲染。v-for 指令需要使用 item in items 形式的特殊语法,items 是源数据数组并且 item 是数组元素迭代的别名demo 。在 v-for 块中,我们拥有对父作用域属性的完全访问权限。v-for 还支持一个可选的第二个参数为当前项的索引demo。你也可以用 of 替代 in 作为分隔符,因为它是最接近 JavaScript 迭代器的语法demo。
你也可以用 v-for 通过一个对象的属性来迭代demo。你也可以提供第二个的参数为键名 demo。第三个参数为索引demo。 注意,在遍历对象时,是按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下是一致的。
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。理想的 key 值是每项都有的且唯一的 id。
<div v-for="item in items" :key="item.id">
div>
建议尽可能在使用 v-for 时提供 key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
因为它是 Vue 识别节点的一个通用机制,key 并不与 v-for 特别关联,key 还具有其他用途。
Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下:
push()pop()shift()unshift()splice()sort()reverse()
你打开控制台,然后用前面例子的 items 数组调用变异方法:example1.items.push({ message: ‘Baz’ }) 。
变异方法 (mutation method),顾名思义,会改变被这些方法调用的原始数组。相比之下,也有非变异 (non-mutating method) 方法,例如:filter(), concat() 和 slice() 。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的、启发式的方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
由于 JavaScript 的限制,Vue 不能检测以下变动的数组:
当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength
举个例子:
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
你也可以使用 vm.$set 实例方法,该方法是全局方法 Vue.set 的一个别名:
vm.$set(vm.items, indexOfItem, newValue)
为了解决第二类问题,你可以使用 splice:
vm.items.splice(newLength)
还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除demo。对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性。你还可以使用 vm.$set 实例方法,它只是全局 Vue.set 的别名demo。有时你可能需要为已有对象赋予多个新属性,比如使用 Object.assign() 或 _.extend()。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性,不要这样做demo你应该这样做demo。
有时,我们想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。在这种情况下,可以创建返回过滤或排序数组的计算属性demo。在计算属性不适用的情况下 (例如,在嵌套 v-for 循环中) 你可以使用一个 method 方法demo。
v-for 也可以取整数。在这种情况下,它将重复多次模板demo。
类似于 v-if,你也可以利用带有 v-for 的 渲染多个元素demo。
当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。当你想为仅有的一些项渲染节点时,这种优先级的机制会十分有用demo。而如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或 )上demo。
在自定义组件里,你可以像任何普通元素一样用 v-for 。然而,任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要用 props。demo
可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。demo
然而许多事件处理逻辑会更为复杂,所以直接把 JavaScript 代码写在 v-on 指令中是不可行的。因此 v-on 还可以接收一个需要调用的方法名称。demo
除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法demo
有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法demo
在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
.stop .prevent .capture .self .once .passive demo
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
Vue 还对应 addEventListener 中的 passive 选项提供了 .passive 修饰符 demo。这个 .passive 修饰符尤其能够提升移动端的性能。
注意,不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive 会告诉浏览器你不想阻止事件的默认行为。
在监听键盘事件时,我们经常需要检查常见的键值。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符demo,记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名,如.enter demo。
全部的按键别名:.enter .tab .delete (捕获“删除”和“退格”键) .esc .space .up .down .left .right
可以通过全局 config.keyCodes 对象自定义按键修饰符别名demo。
你也可直接将 KeyboardEvent.key 暴露的任意有效按键名转换为 kebab-case 来作为修饰符
@keyup.page-down="onPageDown">
在上面的例子中,处理函数仅在 $event.key === ‘PageDown’ 时被调用。
注意,有一些按键 (.esc 以及所有的方向键) 在 IE9 中有不同的 key 值, 如果你想支持 IE9,它们的内置别名应该是首选。
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
.ctrl .alt .shift .meta demo
2.2.0 新增 .left .right .middle 这些修饰符会限制处理函数仅响应特定的鼠标按钮。
你可能注意到这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。但不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用 v-on 有几个好处:
扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何自己清理它们。
用 v-model 指令在表单 及
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。 v-model 本质上是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
v-model 会忽略所有表单元素的 value、checked、selected 特性的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。
对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组合文字过程中得到更新。如果你也想处理这个过程,请使用 input 事件。
文本demo
多行文本demo 在文本区域插值 () 并不会生效,应用 v-model 来代替。
复选框 单个复选框,绑定到布尔值单个复选框,绑定到布尔值demo。多个复选框,绑定到同一个数组demo
单选按钮demo
选择框 单选时demo 多选时 (绑定到一个数组)demo 用 v-for 渲染的动态选项demo
如果 v-model 表达式的初始值未能匹配任何选项, 元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
复选框demo
这里的 true-value 和 false-value 特性并不会影响输入控件的 value 特性,因为浏览器在提交表单时并不会包含未被选中的复选框。如果要确保表单中这两个值中的一个能够被提交,(比如“yes”或“no”),请换用单选按钮。
单选按钮 demo
选择框的选项demo
.lazy 添加 lazy 修饰符,是v-model转变为使用 change 事件进行同步demo实时更新
.number 自动将用户的输入值转为数值类型demo
.trim 自动过滤用户输入的首尾空白字符demo
阅读指南 自定义输入组件
Vue 组件的示例demo
组件的复用
组件进行任意次数的复用,每用一次组件,就会有一个它的新实例被创建。demo 注意:组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。
组件的组织
应用会以一棵嵌套的组件树的形式来组织。组件使用前必须先注册以便Vue能够识别。注册分为全局注册demo和局部注册
通过 Prop 向子组件传递数据demo 博文的例子
单个根元素 每个组件必须只有一个根元素
通过事件向父级组件发送消息
调用内建的 $emit
方法并传入事件的名字,来向父级组件触发一个事件demo
使用事件抛出一个值 使用 $emit
的第二个参数来提供这个值,父级组件监听时通过$event访问这个值demo,如果这个事件处理函数是一个方法,这个值将会作为第一个参数传入这个方法demo
组件上使用 v-model demo
通过插槽分发内容 在需要的地方加入插槽slot demo
动态组件
在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里demo
解析 DOM 模板时的注意事项