- 直接用
<script>
引入
CDN
<!-- 最新版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!-- 生产环境推荐链接到一个明确的版本号和构建文件 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.7/dist/vue.js"></script>
<!-- 原生 ES Modules -->
<script type="module">
import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.7/dist/vue.esm.browser.js'
</script>
- NPM
# 最新稳定版
$ npm install --save-dev vue
# 最新稳定版
$ npm install --save-dev vue-cli
- Vue 的生命周期
beforeCreate/created、beforeMount/mounted、beforeUpdate/updated、beforeDestory/destoryed
所有的生命周期钩子自动绑定
this
上下文到实例中,因此你可以访问数据,对属性和方法进行运算。这意味着你不能使用箭头函数来定义一个生命周期方法 (例如created: () => this.fetchTodos()
)。这是因为箭头函数绑定了父上下文,因此this
与你期待的Vue
实例不同,this.fetchTodos
的行为未定义。
-
v-text
更新元素的textContent
<span v-text="msg"></span> <!-- 和下面的一样 --> <span>{{msg}}</span>
v-html
更新元素的innerHTML
<div v-html="html"></div>
v-show
根据表达式之真假值,切换元素的 display CSS 属性(总是渲染)。条件渲染(伪物) v-show
v-show
不支持<template>
元素,也不支持v-else
v-if
的切换开销大,v-show
则是初始渲染开销大,频繁切换使用v-show
,运行时经常改变则使用v-if
<h1 v-show="ok">Hello!</h1>
v-if
,v-else-if
(Vue2.1.0+),v-else
根据表达式的值的真假条件渲染元素(v-if
是惰性的,初始为假)。在切换时元素及它的数据绑定/组件被销毁并重建。如果元素是<template>
,将提出它的内容作为条件块。条件渲染
当和
v-if
一起使用时,v-for
的优先级比v-if
更高。详见列表渲染教程<div v-if="type === 'A'"> A </div> <div v-else-if="type === 'B'"> B </div> <div v-else-if="type === 'C'"> C </div> <div v-else> Not A/B/C </div>
用 key 管理可复用的元素: Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染,使用
key
来表达元素是完全独立的,不要复用。-
v-for
基于源数据多次渲染元素或模板块。此指令之值,必须使用特定语法alias in expression
,为当前遍历的元素提供别名- 从 Vue 2.6 起,
v-for
也可以在实现了可迭代协议的值上使用,包括原生的Map
和Set
。不过应该注意的是 Vue 2.x 目前并不支持可响应的Map
和Set
值,所以无法自动探测变更。 v-for
和<template>
搭配可减少渲染次数v-for
和自定义组件使用时,需要使用props
来传递值- 当 Vue.js 用
v-for
正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。建议尽可能在使用v-for
时提供key
,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
- 从 Vue 2.6 起,
<div v-for="item in items"> {{ item.text }} </div> <!-- 或 --> <div v-for="(item, index) in items"></div> <div v-for="(val, key) in object"></div> <div v-for="(val, key, index) in object"></div> <!-- v-for 默认行为试着不改变整体,而是替换元素。迫使其重新排序的元素,你需要提供一个 key 的特殊属性: --> <div v-for="item in items" :key="item.id"> {{ item.text }} </div>
-
v-on
缩写
@
绑定事件 监听器。事件类型由参数指定。表达式可以是一个方法的名字或一个内联语句,如果没有修饰符也可以省略。用在普通元素上时,只能监听原生 DOM 事件。用在自定义元素组件上时,也可以监听子组件触发的自定义事件。在监听原生 DOM 事件时,方法以事件为唯一的参数。如果使用内联语句,语句可以访问一个$event
属性:v-on:click="handle('ok', $event)"
。 修饰符.stop
调用event.stopPropagation()
。.prevent
调用event.preventDefault()
。.capture
添加事件侦听器时使用capture
模式。.self
只当事件是从侦听器绑定的元素本身触发时才触发回调。.{keyCode | keyAlias}
只当事件是从特定键触发时才触发回调。.native
监听组件根元素的原生事件。.once
(2.1.4+) 只触发一次回调。.left
(2.2.0+) 只当点击鼠标左键时触发。.right
(2.2.0+) 只当点击鼠标右键时触发。.middle
(2.2.0+) 只当点击鼠标中键时触发。.passive
(2.3.0+) 以{ passive: true }
模式添加侦听器。
<!-- 方法处理器 --> <button v-on:click="doThis"></button> <!-- 动态事件 (2.6.0+) --> <button v-on:[event]="doThis"></button> <!-- 内联语句 --> <button v-on:click="doThat('hello', $event)"></button> <!-- 缩写 --> <button @click="doThis"></button> <!-- 动态事件缩写 (2.6.0+) --> <button @[event]="doThis"></button> <!-- 停止冒泡 --> <button @click.stop="doThis"></button> <!-- 阻止默认行为 --> <button @click.prevent="doThis"></button> <!-- 阻止默认行为,没有表达式 --> <form @submit.prevent></form> <!-- 串联修饰符 --> <button @click.stop.prevent="doThis"></button> <!-- 键修饰符,键别名 --> <!-- 有一些按键 (.esc 以及所有的方向键) 在 IE9 中有不同的 key 值, 如果你想支持 IE9,这些内置的别名应该是首选。 --> <input @keyup.enter="onEnter"> <!-- 键修饰符,键代码 --> <!-- keyCode 的事件用法已经被废弃了并可能不会被最新的浏览器支持 --> <input @keyup.13="onEnter"> <!-- 点击回调只会触发一次 --> <button v-on:click.once="doThis"></button> <!-- 对象语法 (2.4.0+) --> <button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
-
v-bind
缩写::
. 动态地绑定一个或多个特性,或一个组件prop
到表达式。修饰符:
<!-- 绑定一个属性 --> <img v-bind:src="imageSrc"> <!-- 动态特性名 (2.6.0+) --> <button v-bind:[key]="value"></button> <!-- 缩写 --> <img :src="imageSrc"> <!-- 动态特性名缩写 (2.6.0+) --> <button :[key]="value"></button> <!-- 内联字符串拼接 --> <img :src="'/path/to/images/' + fileName"> <!-- class 绑定 --> <div :class="{ red: isRed }"></div> <div :class="definedObject"></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> <!-- v-bind:style可以使用多重值的形式 --> <div :style="display:['-webkit-box','-ms-flexbox', 'flex']"></div> <!-- 绑定一个有属性的对象 --> <div v-bind="{ id: someProp, 'other-attr': otherProp }"></div> <!-- 通过 prop 修饰符绑定 DOM 属性 --> <div v-bind:text-content.prop="text"></div> <!-- prop 绑定。“prop”必须在 my-component 中声明。--> <my-component :prop="someThing"></my-component> <!-- 通过 $props 将父组件的 props 一起传给子组件 --> <child-component v-bind="$props"></child-component> <!-- XLink --> <svg><a :xlink:special="foo"></a></svg>
-
v-model
在表单控件或者组件上创建双向绑定。 仅限于以下使用:<input>
<select>
<textarea>
- components
修饰符:
<input v-model="message" placeholder="edit me"> <p>Message is: {{ message }}</p>
Notice:
v-model
会忽略所有表单元素的value
、checked
、selected
特性的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的data
选项中声明初始值。v-slot
(2.6.0+) 缩写:#
,提供具名插槽或需要接收prop
的插槽。 限用于<template>
- 组件 (对于一个单独的带
prop
的默认插槽)
<!-- 具名插槽 --> <foo> <template v-slot:header> <div class="header"></div> </template> <template v-slot:body> <div class="body"></div> </template> <template v-slot:footer> <div class="footer"></div> </template> </foo> <!-- 接收 prop 的具名插槽 --> <infinite-scroll> <template v-slot:item="slotProps"> <div class="item"> {{ slotProps.item.text }} </div> </template> </infinite-scroll> <!-- 接收 prop 的默认插槽,使用了解构 --> <mouse-position v-slot="{ x, y }"> Mouse position: {{ x }}, {{ y }} </mouse-position>
v-pre
跳过这个元素和它的子元素的编译过程。可以用来显示原始Mustache
标签。跳过大量没有指令的节点会加快编译。
<span v-pre>{{ this will not be compiled }}</span>
v-cloak
这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如[v-cloak] { display: none }
一起用时,这个指令可以隐藏未编译的Mustache
标签直到实例准备完毕。
<div v-cloak> {{ message }} </div>
[v-cloak] { display: none; }
v-once
只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。
<!-- 单个元素 --> <span v-once>This will never change: {{msg}}</span> <!-- 有子元素 --> <div v-once> <h1>comment</h1> <p>{{msg}}</p> </div> <!-- 组件 --> <my-component v-once :comment="msg"></my-component> <!-- `v-for` 指令--> <ul> <li v-for="i in list" v-once>{{i}}</li> </ul>
is
值:string | Object (组件的选项对象)
用于动态组件且基于 DOM 内模板的限制来工作。
<!-- 当 `currentView` 改变时,组件也跟着改变 -->
<component v-bind:is="currentView"></component>
<!-- 这样做是有必要的,因为 `<my-row>` 需要放在一个`<table>` 内才会被挂载,类似的还有 `li` 元素需要放在 `<ul>` 中才能生效,这样可以避开一些潜在的浏览器解析错误 -->
<table>
<tr is="my-row"></tr>
</table>
组件声明格式:组件名大小写使用
kebab-case
或PascalCase
。每个组件必须只有一个根元素,否则 Vue 会显示错误every component must have a single root element
// 全局注册
// 通过 Vue.component() 全局注册的组件可在其被注册后的任何通过 new Vue() 创建的实例所使用,包含其组件树中的所有组件
Vue.component('ComponentName',{
data: function() {
return {
name: 'yuko',
};
},
props:['p1','p2'],
template: '<li>{{ name }} {{ p1 }}</li>'
});
// 局部注册
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
});
注意:
data
必须是一个函数,以实现每个实例可以维护一份被返回对象的独立的拷贝- 局部注册的组件在其子组件中不可用
Prop
- 当你使用 DOM 中的模板时,
camelCase
(驼峰命名法) 的prop
名需要使用其等价的kebab-case
(短横线分隔命名) 命名。(使用字符串模板,不存在此限制) - 为了定制
prop
的验证方式,你可以为props
中的值提供一个带有验证需求的对象,而不是一个字符串数组
// 数组形式
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
// 对象形式
// Prop 验证
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
- 传递静态或动态 Prop
传递 Prop 的值类型可以是任何类型的值,如 String
, Number
, Boolean
, Array
. Object
等
<!-- 静态赋值 -->
<blog-post title="My journey with Vue"></blog-post>
<!-- 动态赋予一个变量的值 -->
<blog-post v-bind:title="post.title"></blog-post>
<!-- 动态赋予一个复杂表达式的值 -->
<blog-post
v-bind:title="post.title + ' by ' + post.author.name"
></blog-post>
当需要使用对象的多个属性时,单独传参显得比较复杂时可以重构如下:
<!-- 需要使用对象的多个属性 -->
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title"
v-bind:content="post.content"
v-bind:publishedAt="post.publishedAt"
v-bind:comments="post.comments"
></blog-post>
<!-- 接受一个单独的 post prop -->
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
// 需要使用对象的多个属性
Vue.component('blog-post', {
props: ['title', 'content'],
template: `
<div class="blog-post">
<h3>{{ title }}</h3>
<div v-html="content"></div>
</div>
`
})
// 接受一个单独的 post prop
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content"></div>
</div>
`
})
-
单向数据流 所有的
prop
都使得其父子prop
之间形成了一个单向下行绑定:父级prop
的更新会向下流动到子组件中,但是反过来则不行。每次父级组件发生更新时,子组件中所有的prop
都将会刷新为最新的值。这意味着 不应该 在一个子组件内部改变prop
。以下是两种常见的试图改变一个prop
的情形:- 这个
prop
用来传递一个初始值;这个子组件接下来希望将其作为一个本地的prop
数据来使用。
// 最好定义一个本地的 data 属性并将这个 prop 用作其初始值 props: ['initialCounter'], data: function () { return { counter: this.initialCounter } }
- 这个 prop 以一种原始的值传入且需要进行转换。
// 最好使用这个 prop 的值来定义一个计算属性 props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
- 这个
监听子组件事件
<blog-post
...
v-on:enlarge-text="postFontSize += 0.1"
></blog-post>
<button v-on:click="$emit('enlarge-text')">
Enlarge text
</button>
<!-- 使用事件抛出一个值 -->
<button v-on:click="$emit('enlarge-text', 0.1)">
Enlarge text
</button>
<blog-post
...
v-on:enlarge-text="postFontSize += $event"
></blog-post>
<!-- OR -->
<blog-post
...
v-on:enlarge-text="onEnlargeText"
></blog-post>
<!-- 在组件上使用 v-model -->
<custom-input v-model="searchText"></custom-input>
// 使用事件抛出一个值
...
methods: {
onEnlargeText: function (enlargeAmount) {
this.postFontSize += enlargeAmount
}
}
// 在组件上使用 v-model
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
动态组件|异步组件
- 在动态组件上使用
<keep-alive>
<keep-alive>
要求被切换到的组件都有自己的名字,不论是通过组件的 name 选项还是局部/全局注册。
<!-- 根据 is 每次切换时 Vue 都创建了一个新的 currentTabComponent 实例 -->
<component v-bind:is="currentTabComponent"></component>
<!-- 失活的组件将会被缓存!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
- 异步组件 Vue 允许以一个工厂函数的方式定义组件,这个工厂函数会异步解析组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。
Vue.component('async-example', function (resolve, reject) {
// 向 `resolve` 回调传递组件定义
resolve({
template: '<div>I am async!</div>'
})
})
-
data/vm.$data
Vue 实例的数据对象。Vue 将会递归将
data
的属性转换为getter/setter
,从而让data
的属性能够响应数据变化。对象必须是纯粹的对象 (含有零个或多个的key/value
对)。实例创建之后,可以通过vm.$data
访问原始数据对象。Vue 实例也代理了data
对象上所有的属性,因此访问vm.a
等价于访问vm.$data.a
(以_
或$
开头的属性不会被代理)。 -
vm.$props
当前组件接收到的
props
对象。Vue 实例代理了对其props
对象属性的访问。 -
vm.$el
Vue 实例使用的根 DOM 元素
-
vm.$options
用于当前 Vue 实例的初始化选项,一般在选项中包含自定义属性时使用。
new Vue({ customOption: 'foo', created: function () { console.log(this.$options.customOption) // => 'foo' } })
-
vm.$parent
当前实例的父实例。
-
vm.$root
当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。
-
vm.$children
Vue 实例数组
Array<Vue instance>
,当前实例的直接子组件(非响应且无法保证顺序)。 -
vm.$slots
只读,类型:
{ [name: string]: ?Array<VNode> }
。用来访问被插槽分发的内容。每个具名插槽有其相应的属性 (例如:
slot="foo"
中的内容将会在vm.$slots.foo
中被找到)。default
属性包括了所有没有被包含在具名插槽中的节点。一般在渲染函数书写一个组件时使用。Vue.component('blog-post', { render: function (createElement) { var header = this.$slots.header var body = this.$slots.default var footer = this.$slots.footer return createElement('div', [ createElement('header', header), createElement('main', body), createElement('footer', footer) ]) } })
-
vm.$scopedSlots
只读,类型
{ [name: string]: props => Array<VNode> | undefined }
用来访问作用域插槽。对于包括
默认 slot
在内的每一个插槽,该对象都包含一个返回相应 VNode 的函数。一般在渲染函数书写一个组件时使用。Vue2.6.0+,所有的
$slots
现在都会作为函数暴露在$scopedSlots
中。如果你在使用渲染函数,不论当前插槽是否带有作用域,我们都推荐始终通过$scopedSlots
访问它们。 -
vm.$refs
持有注册过
ref
特性 的所有 DOM 元素和组件实例(如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例)。$refs
只会在组件渲染完成之后生效且不是响应式的。常用于在 JavaScript 里直接访问一个子组件。当
ref
和v-for
一起使用的时候,vm.$refs
将会是一个包含了对应数据源的这些子组件的数组。<!-- `vm.$refs.p` will be the DOM node --> <p ref="p">hello</p> <!-- `vm.$refs.child` will be the child component instance --> <child-component ref="child"></child-component>
// <input ref="input"> methods: { // 用来从父级组件聚焦输入框 focus: function () { this.$refs.input.focus() } }
-
vm.$isServer
当前 Vue 实例是否运行于服务器。
-
vm.$attrs
包含了父作用域中不作为
prop
被识别 (且获取) 的特性绑定 (class
和style
除外)。当一个组件没有声明任何prop
时,这里会包含所有父作用域的绑定 (class
和style
除外),并且可以通过v-bind="$attrs"
传入内部组件——在创建高级别的组件时非常有用。 -
vm.$listeners
包含了父作用域中的 (不含
.native
修饰器的)v-on
事件监听器。它可以通过v-on="$listeners"
传入内部组件——在创建更高层次的组件时非常有用。
-
vm.$watch
:语法vm.$watch( expOrFn, callback, [options] )
{string | Function} expOrFn
{Function | Object} callback
{Object} [options]
{boolean} deep
为了发现对象内部值的变化,可以在选项参数中指定deep: true
(监听数组的变动不需要){boolean} immediate
在选项参数中指定immediate: true
将立即以表达式的当前值触发回调
观察 Vue 实例变化的一个表达式或计算属性函数。回调函数得到的参数为新值和旧值(在变异 (不是替换) 对象或数组时,旧值将与新值相同,因为它们的引用指向同一个对象/数组。Vue 不会保留变异之前值的副本。)。表达式只接受监督的键路径。对于更复杂的表达式,用一个函数取代。
vm.$watch
返回一个取消观察函数,用来停止触发回调。// 键路径 vm.$watch('a.b.c', function (newVal, oldVal) { // 做点什么 }) // 函数 var unwatch = vm.$watch( function () { // 表达式 `this.a + this.b` 每次得出一个不同的结果时 // 处理函数都会被调用。 // 这就像监听一个未被定义的计算属性 return this.a + this.b }, function (newVal, oldVal) { // 做点什么 } ); // vm.$watch 返回一个取消观察函数,用来停止触发回调 unwatch();
-
vm.$set
:语法vm.$set( target, key, value )
{Object | Array} target
{string | number} key
{any} value
全局
Vue.set
的别名,向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。对象不能是 Vue 实例,或者 Vue 实例的根数据对象。 -
vm.$delete
:语法vm.$delete( target, key )
{Object | Array} target
{string | number} key
全局
Vue.delete
的别名。删除对象的属性。如果对象是响应式的,确保删除能触发更新视图。这个方法主要用于避开 Vue 不能检测到属性被删除的限制。目标对象不能是一个 Vue 实例或 Vue 实例的根数据对象。
-
vm.$on
:语法vm.$on( event, callback )
{string | Array<string>} event
(数组只在 2.2.0+ 中支持){Function} callback
监听当前实例上的自定义事件。事件可以由
vm.$emit
触发。回调函数会接收所有传入事件触发函数的额外参数。vm.$on('test', function (msg) { console.log(msg) }) vm.$emit('test', 'hi') // => "hi"
-
vm.$once
:语法vm.$once( event, callback )
{string} event
{Function} callback
监听一个自定义事件,但是只触发一次,在第一次触发之后移除监听器。
-
vm.$off
:语法vm.$off( [event, callback] )
{string | Array<string>} event
(只在 2.2.2+ 支持数组){Function} [callback]
移除自定义事件监听器。如果没有提供参数,则移除所有的事件监听器;如果只提供了事件,则移除该事件所有的监听器;如果同时提供了事件与回调,则只移除这个回调的监听器。
-
vm.$emit
:语法vm.$emit( eventName, […args] )
触发当前实例上的事件。附加参数都会传给监听器回调。
-
vm.$mount
:语法vm.$mount( [elementOrSelector] )
如果 Vue 实例在实例化时没有收到
el
选项,则它处于“未挂载”状态,没有关联的 DOM 元素。可以使用vm.$mount()
手动地挂载一个未挂载的实例。如果elementOrSelector
参数缺失,模板将被渲染为文档之外的的元素,需要使用原生 DOM API 插入文档。方法返回实例vm
自身。var MyComponent = Vue.extend({ template: '<div>Hello!</div>' }) // 创建并挂载到 #app (会替换 #app) new MyComponent().$mount('#app') // 同上 new MyComponent({ el: '#app' }) // 或者,在文档之外渲染并且随后挂载 var component = new MyComponent().$mount() document.getElementById('app').appendChild(component.$el)
-
vm.$forceUpdate()
迫使 Vue 实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
-
vm.$nextTick( [callback] )
将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法
Vue.nextTick
一样,不同的是回调的this
自动绑定到调用它的实例上。new Vue({ // ... methods: { // ... example: function () { // 修改数据 this.message = 'changed' // DOM 还没有更新 this.$nextTick(function () { // DOM 现在更新了 // `this` 绑定到当前实例 this.doSomethingElse() }) } } })
-
vm.$destroy
完全销毁一个实例。清理它与其它实例的连接,解绑它的全部指令及事件监听器。触发
beforeDestroy
和destroyed
的钩子。在大多数场景中你不应该调用这个方法。最好使用v-if
和v-for
指令以数据驱动的方式(修改涉及到的对象)控制子组件的生命周期。
**计算属性是基于它们的依赖进行缓存的。**只在相关依赖发生改变时它们才会重新求值。这就意味着下面代码中,只要 message
还没有发生改变,多次访问 reversedMessage
计算属性会立即返回之前的计算结果,而不必再次执行函数。(相比之下,每当触发重新渲染时,调用方法 methods
将总会再次执行函数。)
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
计算属性默认只有 getter
,不过在需要时你也可以提供一个 setter
:
// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// ...
Vue 通过 watch
选项提供了一个方法来来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
</div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer: function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
}
}
})
</script>
-
变异方法
Vue 包含一组观察数组的变异方法,调用以下数组方法将会触发视图更新
push()
,pop()
,shift()
,unshift()
,splice()
,sort()
,reverse()
-
非变异方法
调用数组的非变异方法返回一个新数组,不会改变原始数组。当使用非变异方法时,可以用新数组替换旧数组。
-
由于 JavaScript 的限制,Vue 不能检测到数组索引赋值(使用
Vue.set()
/vm.$set()
解决)和修改length
长度赋值(使用Array.prototype.splice()
解决)的情况
Vue.set(vm.items, indexOfItem, newValue)
vm.items.splice(indexOfItem, 1, newValue)
Vue 可以检测对象属性的修改,但由于 JavaScript 的限制,不能检测对象属性的添加或删除(使用 Vue.set(object, key, value)
/vm.$set()
或 Object.assign
解决)
Vue.set(vm.userProfile, 'age', 27)
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
- 事件修饰符,它们可串联使用:
.stop
、.prevent
、.capture
、.self
、.once
、.passive
(尤其适合移动端).passive
同时和.prevent
使用时,后者会被忽略 - 按键修饰符:
.enter
、.tab
、.delete
、.esc
、.space
、.up
、.down
、.left
、.right
- 系统按键修饰符:
.ctrl
、.alt
、.shift
、.meta(⌘|⊞|◆)
、.exact
(允许精确控制系统修饰符组合键触发) - 鼠标修饰符:
.left
、.right
、.middle