本章我们主要介绍一些 Vue 里常用的概念、语法和 API。
其实 Vue 以入门门槛低、对初学者友好而收获了一致的好评,在这种情况下,其实最新、最完整的语法和 API,当然是从官网上搜索最合适。而本章内容则配合一些对使用的理解和生动的实例,来让大家对 Vue 有更深刻的认知。
1. Vue 实例
讲 Vue 的基础,当然得先从实例说起。要怎么理解实例两个字?在 Vue 里,可以理解为每一个通过用 Vue 函数创建的,都是一个 Vue 实例:
// new Vue返回一个Vue实例 var vm = new Vue({ // 选项 });
Vue 实例和 Vue 应用是什么关系呢?官方介绍:一个 Vue 应用由一个通过new Vue()
创建的根 Vue 实例,以及可选的嵌套的、可复用的组件树组成。所以 Vue 实例是属于 Vue 应用的一部分,与组件树组成了 Vue 应用:
// 一个Vue应用,由根实例+组件树组成 根实例 └─ 根组件 // 此行开始,为组件树 ├─ 组件1 │ ├─ 组件1-1 │ └─ 组件1-2 └─ 组件2 ├─ 组件2-1 └─ 组件2-2
那组件又是什么呢?关于组件的介绍和使用,会在下一章介绍。
1.1 生命周期钩子
生命周期要怎么理解呢?结合前言中浏览器页面渲染的机制,以及第一节中 Vue 模板的解析和渲染的过程,我们知道在 Vue 中要渲染一块页面内容的时候,会有这么几个过程:
(1) 解析语法生成 AST。
(2) 根据 AST 结果,完成 data 数据初始化。
(3) 根据 AST 结果和 data 数据绑定情况,生成虚拟 DOM。
(4) 将虚拟 DOM 生成真正的 DOM 插入到页面中,此时页面会被渲染。
当我们绑定的数据进行更新的时候,又会产生以下这些过程:
(5) 框架接收到数据变更的事件,根据数据生成新的虚拟 DOM 树。比较新旧两棵虚拟 DOM 树,得到差异。
(6) 把差异应用到真正的 DOM 树上,即根据差异来更新页面内容。
当我们清空页面内容时,还有:
(7) 注销实例,清空页面内容,移除绑定事件、监听器等。
所以在整个页面或是某块页面内容(组件)中,Vue 提供了以下的一些关键的生命周期钩子:
表 3-1 Vue 生命周期说明
生命周期钩子 | 说明 | 对应上述步骤 |
---|---|---|
beforeCreate |
初始化实例前,data 、methods 等不可获取 |
1 之后,2 之前 |
created |
实例初始化完成,此时可获取data 里数据和methods 事件,无法获取 DOM |
2 之后,3 之前 |
beforeMount |
虚拟 DOM 创建完成,此时未挂载到页面中,vm.$el 可获取未挂载模板 |
3 之后,4 之前 |
mounted |
数据绑定完成,真实 DOM 已挂载到页面,vm.$el 可获取真实 DOM |
4 之后 |
beforeUpdate |
数据更新,DOM Diff 得到差异,未更新到页面 | 5 之后,6 之前 |
updated |
数据更新,页面也已更新 | 6 之后 |
beforeDestroy |
实例销毁前 | 7 之前 |
destroyed |
实例销毁完成 | 7 之后 |
我们可以更新官方的生命周期图如下:
图 3-1 Vue 生命周期说明补充前半部分
图 3-2 Vue 生命周期说明补充后半部分
生命周期钩子的使用方式也很简单,我们可以根据需要在特定的生命周期钩子里进行一些处理:
<div id="app"></div> <script> new Vue({ el: "#app", template: "<div>{{ message }}</div>", data() { return { message: "欢迎来到Vue的世界" }; }, methods: { test() {} }, beforeCreate: function() { // 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用 console.log("beforeCreate", this.message, this.test, this.$el); }, created: function() { // 在实例创建完成后被立即调用 // 在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调 // 挂载阶段还没开始,$el 属性目前不可见 console.log("created", this.message, this.test, this.$el); }, beforeMount: function() { // 在挂载开始之前被调用:相关的 render 函数首次被调用 console.log("beforeMount", this.message, this.test, this.$el); }, mounted: function() { // el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子 // 如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内 // mounted 不会承诺所有的子组件也都一起被挂载 // 如果希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted console.log("mounted", this.message, this.test, this.$el); this.$nextTick(function() { // 此处整个视图已渲染完毕 }); }, beforeUpdate: function() { // 数据更新时调用,发生在虚拟 DOM 打补丁之前 // 这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器 }, updated: function() { // 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子 // 当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作 }, beforeDestroy: function() { // 实例销毁之前调用。在这一步,实例仍然完全可用 }, destroyed: function() { // Vue 实例销毁后调用 // 调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁 } }); </script>
页面中我们可以看到输出结果,验证了几个生命周期的data
、methods
、DOM 挂载等情况:
图 3-3 生命周期测试输出
1.2 Vue 实例基本选项说明
Vue 实例提供了非常丰富的选项(new Vue()
时传入的选项),除了上面介绍的生命周期之外,最常见的大概是这几个了:
表 3-2 Vue 实例常用选项
选项名 | 说明 | 类型 |
---|---|---|
el |
通过 CSS 选择器或者 HTMLElement 实例的方式,提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标 |
string /Element
|
template |
字符串模板,将会替换挂载的元素 | string |
render |
字符串模板的代替方案,该渲染函数接收一个createElement 方法作为第一个参数用来创建 VNode |
(createElement: () => VNode) => VNode |
data |
Vue 实例的数据对象,用于数据绑定 |
Object /Function 组件只支持 Function
|
props |
用于接收来自父组件的数据 |
Array<string> /Object
|
methods |
Vue 实例的事件,可用于事件绑定 | { [key: string]: Function } |
computed |
计算属性,用于简化模板的复杂数据计算 | { [key: string]: Function or { get: Function, set: Function } } |
watch |
观察 Vue 实例变化的一个表达式或计算属性函数 | { [key: string]: string or Function or Object or Array } |
directives |
自定义指令 | Object |
filters |
过滤器 | Object |
components |
组件 | Object |
Vue 实例中的这些选项,大多数都可以作为全局实例属性来获取或者访问:
const vm = new Vue({ // ...一些选项 }); vm.$data; // 获取 data vm.$props; // 获取 props vm.$el; // 获取挂载元素 vm.$options; // 获取 Vue 实例的初始选项 vm.$parent; // 获取父实例 vm.$root; // 获取根实例 vm.$children; // 获取当前实例的直接子组件 vm.$refs; // 获取持有注册过 ref 特性 的所有 DOM 元素和组件实例 vm.$watch; // 观察 Vue 实例变化的一个表达式或计算属性函数 vm.$set; // 向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新 vm.$delete; // 删除对象的属性。如果对象是响应式的,确保删除能触发更新视图
这些内容,我们将在本章以及后面的几章里一一讲述。更完整的选项内容和 API,各位可以去官网查询。
1.3 DOM 相关选项
既然要讲 Vue 实例,那就从最基本的 DOM 渲染相关开始讲起。
el
Vue 实例中,el
选项提供一个页面中已存在的 DOM 元素作为实例的挂载目标。挂载的意思是,在选中的该元素所在的位置进行页面渲染,该元素会被替换成需要渲染的页面内容。我们可以传入一个 CSS 选择器,也可以传入一个 DOM 元素。例如,页面中有一个 id 为#app 的元素,如果我们希望以<div id="app"></div>
该元素作为 Vue 实例的挂载目标,以下方式都是可以的:
new Vue({ // 1. 传入 Element 元素方式一 el: document.getElementById("app"), // 2. 传入 Element 元素方式二 el: document.getElementsByTagName("div")[0], // 3. 传入 CSS 选择器方式一 el: "#app", // 4. 传入 CSS 选择器方式二 // 最好选择唯一的元素,不推荐该方式 el: "div" });
所谓挂载元素,在实例挂载之后,元素可以用vm.$el
访问。当然,前面生命周期中我们讲了,需要在mounted
之后才能获取到:
new Vue({ el: "#app", template: "<div>{{ message }}</div>", data() { return { message: "欢迎来到Vue的世界" }; }, mounted() { console.log(this.$el); } });
如果在实例化时存在这个选项,实例将立即进入编译过程,否则,需要显式调用vm.$mount()
手动开启编译,也就是这样:
const vm = new Vue({ template: "<div>{{ message }}</div>", data() { return { message: "欢迎来到Vue的世界" }; }, mounted() { console.log(this.$el); } }); // 需要的时候使用 vm.$mount("#app");
如果 render 函数和 template 属性都不存在,挂载 DOM 元素的 HTML 会被提取出来用作模板,此时,必须使用 Runtime + Compiler 构建的 Vue 库。我们来理解下这句话:
- 编译器(Compiler): 我们可以理解为用来将模板字符串编译成为 JavaScript 渲染函数的代码,也就是第1章内容中的 AST 解析部分
- 运行时(Runtime): 用来创建 Vue 实例、渲染并处理虚拟 DOM 等的代码,也就是第1章中 AST 以外的部分
一般来说,我们在部署生产代码的时候,已经将需要的代码解析编译好,这个时候我们只需要运行时的 Vue 库。在特殊情况下,有需要运行时解析编译的情况,如在线平台编写代码的时候,我们需要引入编译器的 Vue 库,该部分占完整版(Runtime + Compiler)的 30%。上面说到,如果我们需要使用挂载 DOM 元素的 HTML 作为模板,则需要运行时编译,也就需要编译器了。
那关于 render 函数和 template 属性的选项,我们来看一下。
template
给 Vue 实例提供字符串模板,该模板将会替换挂载的元素,我们来看一个简单的代码片段:
<body> <div id="app"></div> <script> new Vue({ el: "#app", template: "<p>{{ message }}</p>", data() { return { message: "欢迎来到Vue的世界" }; }, beforeMount() { console.log("beforeMount", this.$el); }, mounted: function() { console.log("mounted", this.$el); } }); </script> </body>
这里挂载的元素指的是<div id="app"></div>
,当我们使用了 template 选项之后,我们在页面中可以看到最终页面中的内容是 template 中的内容,此时<div id="app"></div>
已经被替换成 template 中的<p>{{ message }}</p>
,并将 message 中的内容替换成绑定的数据了:
图 3-4 挂载元素最终页面效果
我们也能看到,在beforeMount
生命周期中,vm.$el
获取的是挂载的元素模板,而在mounted
生命周期后则变成了 template 中的真实 DOM 元素:
图 3-5 挂载元素不同生命周期效果
如果 Vue 选项中包含 render 渲染函数,则 template 将被忽略,我们来看看渲染函数。
render
字符串模板 template 的代替方案,该渲染函数接收一个createElement
方法作为第一个参数用来创建 VNode。第1章中我们有讲到 Vue 里使用了虚拟 DOM,而createElement
创建的便是虚拟 DOM,在 Vue 里称为 VNode。要怎么用呢,例如我们可以实现一个v-if
的能力:
new Vue({ // 该段实现: // <p v-if="condition">condition work!</p> // <p v-else>condition not work!</p> render: function (createElement) { if (this.condition) { return createElement('p', "condition work!") } else { return createElement('p', 'condition not work!') } } // 该段实现: // <ul><li v-for="item in items">{{item}}</li></ul> render: function (createElement) { return createElement('ul', this.items.map(function (item) { return createElement('li', item) })) } });
一般来说,我们可以结合 JSX 来使用(需要添加 Babel 插件噢):
import MyComponent from "./MyComponent.vue"; new Vue({ render: function(h) { return ( <MyComponent> <p>Hello world!</p> </MyComponent> ); } });
2. 常用模板语法
关于 Vue 实例的选项,上面讲了最基本的生命周期钩子,以及 DOM 渲染相关的。而数据相关的,或许要结合模板语法来一起讲,会更好理解。
关于数据绑定、事件绑定,其实也是一种 Vue 提供的方便开发者使用的模板语法。在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。下面我们会结合对语法的理解,来介绍它们的使用。
2.1 数据绑定
数据绑定在 Vue 里有最基础的几种方式:
表 3-3 Vue 中数据绑定的常用方式
语法 | 说明 |
---|---|
插值语法{{}}
|
文本插值,可配合过 Javascript 表达式和过滤器使用 |
v-once |
一次性插值,数据改变时插值处的内容不会更新 |
v-html |
可输出真正的 HTML,不会被转义为普通文本 |
v-bind: (简写: ) |
可用于绑定 DOM 属性、或一个组件 prop 到表达式 |
插值
我们来简单看看插值相关的绑定语法:
<template> <div>{{ message }}</div> <div v-once>{{ message }}</div> <div v-html="message"></div> <div>{{ msgHtml }}</div> <div v-html="msgHtml"></div> </template> <script> export default { data() { return { message: "欢迎来到Vue的世界", msgHtml: "<p style='color: red'>欢迎来到红色Vue的世界</p>" }; }, created() { this.message = "啦啦啦啦啦啦"; }, mounted() { this.message = "略略略略略"; } }; </script>
虽然比较简单,但有意思的地方在于,你能猜到最终的真实 DOM 渲染是这样的吗:
图 3-5 Vue 中数据绑定渲染结果
我们知道,v-once
只渲染元素和组件一次,后面的所有重新渲染过程,被绑定的该元素/组件及其所有的子节点将被视为静态内容并跳过。但在这里,最终呈现的并不是我们初始data
中的“欢迎来到 Vue 的世界”,而是created
周期中设定的“啦啦啦啦啦啦”。
前面讲 Vue 生命周期钩子的时候我们知道,真实 DOM 挂载发生在beforeMount
之后、mounted
之前,也就是说,我们在mounted
之前的生命周期中更改data
中 message 的值,都是有效的。
所以关于插值,需要注意以下两点:
(1) v-once
在mounted
生命周期之后,不可再更改。
(2) v-html
请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值,因为它很容易导致 XSS 攻击(该内容在第1章有阐述)。
Javascript 表达式
Vue 中支持完全的 Javascript 表达式(请注意不是语句噢),因为我们可以直接在模板中做很多数据的处理和逻辑判断:
{{ price * 100 + 2000 }} {{ message.split('').reverse().join('') }} {{ type === 'group' ? '团队' : '个人' }} <div v-bind:class="isActived ? 'actived' : ''"></div> <div v-bind:index="'item-' + index"></div> <!-- 以下是语句,不是表达式 --> {{ var message = "123" }} {{ if(type === 'group') { return '团队' } }}
v-bind
其实v-bind
也是插值的一种,只不过它的使用方式更加灵活和多变,所以这里单独进行介绍,我们来看看以下的用法:
<!-- 绑定一个属性 --> <img v-bind:src="imageSrc" /> <!-- 缩写 --> <img :src="imageSrc" /> <!-- 最终会生成 `<img src="${imageSrc}">` 这样的模板 --> <!-- 动态特性名 (2.6.0+) --> <button v-bind:[key]="value"></button> <!-- 动态特性名缩写 (2.6.0+) --> <button :[key]="value"></button> <!-- 最终会生成 `<button ${key}="${value}">` 这样的模板 --> <!-- 内联字符串拼接 --> <img :src="'/path/to/images/' + fileName" /> <!-- class 绑定 --> <div :class="{ red: isRed }"></div> <div :class="[classA, classB]"></div> <div :class="[classA, { classB: isB, classC: isC }]"> <!-- style 绑定 --> <div :style="{ fontSize: size + 'px' }"></div> <div :style="[styleObjectA, styleObjectB]"></div> <!-- 绑定一个有属性的对象 --> <div v-bind="{ id: someProp, 'other-attr': otherProp }"></div> </div>
除了 style 绑定、class 绑定以及一些常用属性 src 等绑定在日常开发中会使用较多外,还有一个重要的 prop 绑定,用于向子组件传递数据,例如我们有这么一个组件:
Vue.component("my-text", { props: ["text"], template: "<p>{{ text }}</p>" });
则可以通过<my-text :text="myText"></my-text>
的方式使用。有关组件、子组件的内容,会在后面章节详细讲述,这里就不多再说了。
data
data
是 Vue 实例的数据对象,是上述所有数据绑定的数据来源。
var vm = new Vue({ // 1. 接受返回对象的函数 data() { return { message: "欢迎来到Vue的世界" }; }, // 2. 也可以直接棒对象 data: { message: "欢迎来到Vue的世界" } });
我们已经知道,Vue 里数据的变更检测是来自于 getter/setter,从而让data
的属性能够响应数据变化。前面我们也讲到,Vue 将遍历 data 选项的 JavaScript 对象所有的属性,并使用Object.defineProperty
把这些属性全部转为 getter/setter:
// 响应式的变更检测 Object.defineProperty(obj, key, { enumerable: true, configurable: true, // getter get: function reactiveGetter() { const value = getter ? getter.call(obj) : val; if (Dep.target) { // 依赖检测 dep.depend(); if (childOb) { childOb.dep.depend(); if (Array.isArray(value)) { dependArray(value); } } } return value; }, // setter,最终更新后会通知噢 set: function reactiveSetter(newVal) { const value = getter ? getter.call(obj) : val; if (newVal === value || (newVal !== newVal && value !== value)) { return; } if (process.env.NODE_ENV !== "production" && customSetter) { customSetter(); } if (getter && !setter) return; if (setter) { setter.call(obj, newVal); } else { val = newVal; } childOb = !shallow && observe(newVal); // 会通知噢 dep.notify(); } });
由于 Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的。换句话说,只有当实例被创建时就已经存在于data
中的属性才是响应式的(新增的属性等都不会触发视图的更新)。问题也是很显然,Vue 无法检测到对象属性的添加或删除,也无法检测一些特殊的数组变动:
// 只有这些操作会通知变更噢 const methodsToPatch = [ "push", "pop", "shift", "unshift", "splice", "sort", "reverse" ]; // 拦截上述这些操作方法,然后通知变更 methodsToPatch.forEach(function(method) { // cache original method const original = arrayProto[method]; def(arrayMethods, method, function mutator(...args) { const result = original.apply(this, args); const ob = this.__ob__; let inserted; switch (method) { case "push": case "unshift": inserted = args; break; case "splice": inserted = args.slice(2); break; } if (inserted) ob.observeArray(inserted); // notify change ob.dep.notify(); return result; }); });
所以在更新data
中绑定的对象或者数组的时候需要注意,除了使用可触发变更检测的特殊方法之外,也可以使用vm.$set
(Vue.set
)实例方法。vm.$set
(Vue.set
)用于向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新:
// 更新数组 vm.$set(vm.items, indexOfItem, newValue); // 更新对象 vm.$set(vm.someObject, keyOfObject, newValue);
2.2 过滤器
Vue 中可以自定义过滤器,可被用于一些常见的文本格式化,支持全局定义和组件中定义。
// 全局定义 // 千分位处理 Vue.filter('thousandth', function (value) { if (!value) return ''; return value && value.toString().replace(/^(-?\d+?)((?:\d{3})+)(?=\.\d+$|$)/, function (all, pre, groupOf3Digital) { return pre + groupOf3Digital.replace(/\d{3}/g, ',$&') }); }) // 局部定义 // 乘以倍数 filters: { multiply: function (value, times) { if (!value) return ''; return value * ( parseInt(times) || 1); } }
过滤器可以用在两个地方:双花括号插值和v-bind
表达式。
<!-- 在双花括号中 --> {{ number | thousandth }} <!-- 在 `v-bind` 中 --> <div v-bind:text="number | thousandth"></div> <!-- 支持串联,可接受传参 --> {{ number | multiply(1000) | thousandth }}
2.3 事件绑定
可以用v-on
指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码,可用@
缩写。
<template> <button v-on:click="addCounter">Add 1</button> <!-- 以下为缩写 --> <button @click="addCounter">Add 1</button> <p>The button above has been clicked {{ counter }} times.</p> </template> <script> export default { data() { return { counter: 0 }; }, methods: { addCounter() { this.counter += 1; } } }; </script>
事件修饰符
Vue 为v-on
提供了事件修饰符:
表 3-4 v-on
事件修饰符
修饰符 | 说明 |
---|---|
.stop |
event.stopPropagation() ,阻止事件继续传播 |
.prevent |
event.preventDefault() ,阻止默认事件 |
.capture |
添加事件监听器时使用事件捕获模式 |
.once |
只绑定一次 |
.enter /.tab /.esc /.space /.ctrl /.[keyCode]
|
按键修饰符 |
使用方式很简单,在绑定事件后面加上修饰符就可以:
<!-- 阻止单击事件继续传播 --> <a v-on:click.stop="doThis"></a> <!-- 提交事件不再重载页面 --> <form v-on:submit.prevent="onSubmit"></form> <!-- Alt + C --> <input @keyup.alt.67="clear" />
3. 计算属性和侦听器
computed
和watch
大概是 Vue 里除了data
、methods
、props
之外,用的最多的选项了。前面我们也讲了很多次,Vue 中数据变更之所以能更新到页面里,因为对data
执行 getter/setter 转化,然后进行侦听。而computed
和watch
属性都是基于此,我们看看一个Watcher
是怎样的:
export default class Watcher { vm: Component; expression: string; cb: Function; id: number; deep: boolean; user: boolean; lazy: boolean; sync: boolean; dirty: boolean; active: boolean; deps: Array<Dep>; newDeps: Array<Dep>; depIds: SimpleSet; newDepIds: SimpleSet; before: ?Function; getter: Function; value: any; constructor ( vm: Component, expOrFn: string | Function, cb: Function, options?: ?Object, isRenderWatcher?: boolean ) { // 初始化 } // 计算getter,重新收集依赖 get () { //... } // 添加依赖 addDep (dep: Dep) { //... } // 清理依赖集合 cleanupDeps () { //... } // 订阅接口,将在依赖项更新时调用 update () { //... } // 调用接口,将被调配者调用 run () { //... } // 该watcher的所有依赖 depend () { //... } // 从所有依赖项的订户列表中删除自己 teardown () { //... } }
计算属性和侦听器都离不开数据监听。
3.1 computed
有时候我们需要对绑定的数据进行一些处理,通常使用前面说过的插值的 Javascript 表达式、过滤器都可以处理完毕,但有些时候需要稍微复杂一点的逻辑计算,这种情况我们可以使用计算属性。计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算,计算属性支持读取设置:
var vm = new Vue({ data: { a: 1 }, computed: { // 仅读取 aDouble: function() { return this.a * 2; }, // 读取和设置 aPlus: { get: function() { return this.a + 1; }, set: function(v) { this.a = v - 1; } } } }); vm.aPlus; // => 2 vm.aPlus = 3; vm.a; // => 2 vm.aDouble; // => 4
3.2 watch
侦听器用来监听某些数据变化,观察 Vue 实例变化的一个表达式或计算属性函数。Vue 实例将会在实例化时调用$watch()
,遍历 watch 对象的每一个属性。watch
支持的方式有好几种,回调函数得到的参数为新值和旧值:
var vm = new Vue({ data: { a: 1, b: 2, c: 3, d: 4, e: { f: { g: 5 } } }, watch: { a: function(val, oldVal) { console.log("new: %s, old: %s", val, oldVal); }, // 方法名 b: "someMethod", // 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深 c: { handler: function(val, oldVal) { /* ... */ }, deep: true }, // 该回调将会在侦听开始之后被立即调用 d: { handler: "someMethod", immediate: true }, e: [ "handle1", function handle2(val, oldVal) { /* ... */ }, { handler: function handle3(val, oldVal) { /* ... */ } /* ... */ } ], // watch vm.e.f's value: {g: 5} "e.f": function(val, oldVal) { /* ... */ } }, methods: { someMethod() {} } }); vm.a = 2; // => new: 2, old: 1
本章内容主要介绍了 Vue 实例,以及一些常用的选项和模板语法,相信大家现在已经能理解一个 Vue 实例的生命周期,以及理解一些基本语法。后面我们会基于这些基础内容,来慢慢介绍组件、指令、动画相关,以及搭配一些其他开源库来完善项目,一步步走进 Vue 的世界里。