经过使用 v-once
指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上全部的数据绑定:html
span v-once>这个将不会改变: {{ msg }}</span>
双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你须要使用 v-html 指令:数组
<p>Using mustaches: {{ rawHtml }}</p> <p>Using v-html directive: <span v-html="rawHtml"></span></p>
这个 span 的内容将会被替换成为属性值 rawHtml,直接做为 HTML——会忽略解析属性值中的数据绑定。浏览器
你的站点上动态渲染的任意 HTML 可能会很是危险,由于它很容易致使
XSS
攻击。请只对可信内容使用 HTML 插值,毫不要对用户提供的内容使用插值。
Vue.js 都提供了彻底的 JavaScript 表达式支持。dom
{{ number + 1 }} {{ ok ? 'YES' : 'NO' }} {{ message.split('').reverse().join('') }} <div v-bind:id="'list-' + id"></div>
这些表达式会在所属 Vue 实例的数据做用域下做为 JavaScript 被解析。有个限制就是,每一个绑定都只能包含单个表达式
,因此下面的例子都不会生效
。ide
<!-- 这是语句,不是表达式 --> {{ var a = 1 }} <!-- 流控制也不会生效,请使用三元表达式 --> {{ if (ok) { return message } }}
<!-- 完整语法 --> <a v-bind:href="url"></a> <!-- 缩写 --> <a :href="url"></a> <!-- 完整语法 --> <button v-bind:disabled="isButtonDisabled">Button</button> <!-- 缩写 --> <button :disabled="isButtonDisabled">Button</button>
说明下:若是isButtonDisabled
的值是null
、undefined
或false
,则disabled
特性甚至不会被包含在渲染出来的<button>
元素中。
<!-- 完整语法 --> <a v-on:click="doSomething">...</a> <!-- 缩写 --> <a @click="doSomething">...</a>
<h1 v-if="ok">Yes</h1>
<template v-if="ok"> <h1>Title</h1> <p>Paragraph 1</p> <p>Paragraph 2</p> </template>
你可使用 v-else 指令来表示 v-if 的“else 块”:函数
<div v-if="Math.random() > 0.5"> Now you see me </div> <div v-else> Now you don't </div>
v-else 元素必须紧跟在带 v-if 或者 v-else-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>
Vue 会尽量高效地渲染元素,一般会复用已有元素而不是从头开始渲染。这么作除了使 Vue 变得很是快以外,还有其它一些好处。例如,若是你容许用户在不一样的登陆方式之间切换:性能
<template v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username"> </template> <template v-else> <label>Email</label> <input placeholder="Enter your email address"> </template>
那么在上面的代码中切换 loginType
将不会清除用户已经输入的内容。由于两个模板使用了相同的元素,<input>
不会被替换掉——仅仅是替换了它的 placeholder
。this
这样也不老是符合实际需求,因此 Vue 为你提供了一种方式来表达“这两个元素是彻底独立的,不要复用它们
”。只需添加一个具备惟一值的 key
属性便可:url
<template v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username" key="username-input"> </template> <template v-else> <label>Email</label> <input placeholder="Enter your email address" key="email-input"> </template>
如今,每次切换时,输入框都将被从新渲染
。注意,<label>
元素仍然会被高效地复用,由于它们没有添加 key
属性。spa
<h1 v-show="ok">Hello!</h1>
不一样的是带有 v-show
的元素始终会被渲染并保留在 DOM
中。v-show
只是简单地切换元素的 CSS
属性 display
。
注意,v-show 不支持 <template> 元素,也不支持 v-else。
通常来讲,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。所以,若是须要很是频繁地切换,则使用 v-show
较好;若是在运行时条件不多改变,则使用 v-if
较好。
当 v-if
与 v-for
一块儿使用时,v-for 具备比 v-if 更高的优先级
。
<ul id="example-1"> <li v-for="item in items"> {{ item.message }} </li> </ul> var example1 = new Vue({ el: '#example-1', data: { items: [ { message: 'Foo' }, { message: 'Bar' } ] } })
在 v-for 块中,咱们拥有对父做用域属性的彻底访问权限。v-for
还支持一个可选的第二个参数为当前项的索引。
<ul id="example-2"> <li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} </li> </ul> var example2 = new Vue({ el: '#example-2', data: { parentMessage: 'Parent', items: [ { message: 'Foo' }, { message: 'Bar' } ] } })
结果:
Parent - 0 - Foo Parent - 1 - Bar
你也能够用 of 替代 in 做为分隔符,由于它是最接近 JavaScript 迭代器的语法:
<div v-for="item of items"></div>
<ul id="v-for-object" class="demo"> <li v-for="value in object"> {{ value }} </li> </ul> new Vue({ el: '#v-for-object', data: { object: { firstName: 'John', lastName: 'Doe', age: 30 } } })
结果:
John Doe 30
你也能够提供第二个的参数为键名:
<div v-for="(value, key) in object"> {{ key }}: {{ value }} </div>
结果:
firstName: John lastName: Doe age: 30
第三个参数为索引:
<div v-for="(value, key, index) in object"> {{ index }}. {{ key }}: {{ value }} </div>
在遍历对象时,是按 Object.keys() 的结果遍历,可是不能保证它的结果在不一样的 JavaScript 引擎下是一致的。
为了给 Vue 一个提示,以便它能跟踪每一个节点的身份,从而重用和从新排序现有元素,你须要为每项提供一个惟一 key 属性。理想的 key 值是每项都有的且惟一的 id。
<div v-for="item in items" :key="item.id"> <!-- 内容 --> </div>
建议尽量在使用 v-for 时提供 key,除非遍历输出的 DOM 内容很是简单,或者是刻意依赖默认行为以获取性能上的提高。
Vue.js 包装了被观察数组的变异方法,故它们能触发视图更新。被包装的方法有: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/) })
因为 JavaScript 的限制,Vue 不能检测如下变更的数组:
vm.items[indexOfItem] = newValue
vm.items.length = newLength
为了解决第一类问题,如下两种方式均可以实现和 vm.items[indexOfItem] = newValue
相同的效果,同时也将触发状态更新:
// Vue.set Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice example1.items.splice(indexOfItem, 1, newValue)
为了解决第二类问题,你可使用 splice:
example1.items.splice(newLength)
仍是因为 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:
var vm = new Vue({ data: { a: 1 } }) // `vm.a` 如今是响应式的 vm.b = 2 // `vm.b` 不是响应式的
对于已经建立的实例,Vue 不能动态添加根级别的响应式属性。可是,可使用 Vue.set(object, key, value)
方法向嵌套对象添加响应式属性。例如,对于:
ar vm = new Vue({ data: { userProfile: { name: 'Anika' } } })
你能够添加一个新的 age
属性到嵌套的 userProfile
对象:
Vue.set(vm.userProfile, 'age', 27)
你还可使用 vm.$set
实例方法,它只是全局 Vue.set
的别名:
vm.$set(this.userProfile, 'age', 27)
有时你可能须要为已有对象赋予多个新属性,好比使用 Object.assign()
或 _.extend()
。在这种状况下,你应该用两个对象的属性建立一个新的对象。因此,若是你想添加新的响应式属性,不要像这样:
Object.assign(this.userProfile, { age: 27, favoriteColor: 'Vue Green' })
你应该这样作:
this.userProfile = Object.assign({}, this.userProfile, { age: 27, favoriteColor: 'Vue Green' })
有时,咱们想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。在这种状况下,能够建立返回过滤或排序数组的计算属性。
<li v-for="n in evenNumbers">{{ n }}</li> data: { numbers: [ 1, 2, 3, 4, 5 ] }, computed: { evenNumbers: function () { return this.numbers.filter(function (number) { return number % 2 === 0 }) } }
在计算属性不适用的状况下 (例如,在嵌套 v-for 循环中) 你可使用一个 method 方法:
<li v-for="n in even(numbers)">{{ n }}</li> data: { numbers: [ 1, 2, 3, 4, 5 ] }, methods: { even: function (numbers) { return numbers.filter(function (number) { return number % 2 === 0 }) } }
<div> <span v-for="n in 10">{{ n }} </span> </div>
<ul> <template v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider"></li> </template> </ul>
<my-component v-for="item in items" :key="item.id"></my-component>
2.2.0+ 的版本里,当在组件中使用v-for
时,key
如今是必须的。
然而,任何数据都不会被自动传递到组件里,由于组件有本身独立的做用域。为了把迭代数据传递到组件里,咱们要用 props
:
<my-component v-for="(item, index) in items" v-bind:item="item" v-bind:index="index" v-bind:key="item.id" ></my-component>
不自动将 item 注入到组件里的缘由是,这会使得组件与 v-for 的运做紧密耦合。明确组件数据的来源可以使组件在其余场合重复使用。
<div id="todo-list-example"> <input v-model="newTodoText" v-on:keyup.enter="addNewTodo" placeholder="Add a todo" > <ul> <li is="todo-item" v-for="(todo, index) in todos" v-bind:key="todo.id" v-bind:title="todo.title" v-on:remove="todos.splice(index, 1)" ></li> </ul> </div>
注意这里的is="todo-item"
属性。这种作法在使用 DOM 模板时是十分必要的,由于在 <ul> 元素内只有 <li> 元素会被看做有效内容。这样作实现的效果与<todo-item>
相同,可是能够避开一些潜在的浏览器解析错误。
Vue.component('todo-item', { template: '\ <li>\ {{ title }}\ <button v-on:click="$emit(\'remove\')">X</button>\ </li>\ ', props: ['title'] }) new Vue({ el: '#todo-list-example', data: { newTodoText: '', todos: [ { id: 1, title: 'Do the dishes', }, { id: 2, title: 'Take out the trash', }, { id: 3, title: 'Mow the lawn' } ], nextTodoId: 4 }, methods: { addNewTodo: function () { this.todos.push({ id: this.nextTodoId++, title: this.newTodoText }) this.newTodoText = '' } } })
当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每一个 v-for 循环中。当你想为仅有的一些项渲染节点时,这种优先级的机制会十分有用,以下:
<li v-for="todo in todos" v-if="!todo.isComplete"> {{ todo }} </li>
上面的代码只传递了未完成的 todos。
而若是你的目的是有条件地跳过循环的执行,那么能够将 v-if 置于外层元素 (或 <template>)上。如:
<ul v-if="todos.length"> <li v-for="todo in todos"> {{ todo }} </li> </ul> <p v-else>No todos left!</p>
<div id="example-2"> <!-- `greet` 是在下面定义的方法名 --> <button v-on:click="greet">Greet</button> </div>
var example2 = new Vue({ el: '#example-2', data: { name: 'Vue.js' }, // 在 `methods` 对象中定义方法 methods: { greet: function (event) { // `this` 在方法里指向当前 Vue 实例 alert('Hello ' + this.name + '!') // `event` 是原生 DOM 事件 if (event) { alert(event.target.tagName) } } } }) // 也能够用 JavaScript 直接调用方法 example2.greet() // => 'Hello Vue.js!'
<div id="example-3"> <button v-on:click="say('hi')">Say hi</button> <button v-on:click="say('what')">Say what</button> </div> new Vue({ el: '#example-3', methods: { say: function (message) { alert(message) } } })
有时也须要在内联语句处理器中访问原始的 DOM 事件。能够用特殊变量 $event
把它传入方法:
<button v-on:click="warn('Form cannot be submitted yet.', $event)"> Submit </button> // ... methods: { warn: function (message, event) { // 如今咱们能够访问原生事件对象 if (event) event.preventDefault() alert(message) } }
修饰符是由点开头的指令后缀来表示的。
<!-- 阻止单击事件继续传播 --> <a v-on:click.stop="doThis"></a> <!-- 提交事件再也不重载页面 --> <form v-on:submit.prevent="onSubmit"></form> <!-- 修饰符能够串联 --> <a v-on:click.stop.prevent="doThat"></a> <!-- 只有修饰符 --> <form v-on:submit.prevent></form> <!-- 添加事件监听器时使用事件捕获模式 --> <!-- 即元素自身触发的事件先在此到处理,而后才交由内部元素进行处理 --> <div v-on:click.capture="doThis">...</div> <!-- 只当在 event.target 是当前元素自身时触发处理函数 --> <!-- 即事件不是从内部元素触发的 --> <div v-on:click.self="doThat">...</div>
使用修饰符时,顺序很重要;相应的代码会以一样的顺序产生。所以,用@click.prevent.self
会阻止全部的点击,而@click.self.prevent
只会阻止对元素自身的点击。
<!-- 点击事件将只会触发一次 2.1.4 新增--> <a v-on:click.once="doThis"></a>
不像其它只能对原生的 DOM 事件起做用的修饰符,.once 修饰符还能被用到自定义的组件事件上。
<!-- the scroll event will not cancel the default scroll behavior 2.3.0 新增 --> <div v-on:scroll.passive="onScroll">...</div>
Vue 为这些修饰符额外提供了 .passive
修饰符来提高移动端的性能。举个例子,在滚动的时候,浏览器会在整个事件处理完毕以后再触发滚动,由于浏览器并不知道这个事件是否在其处理函数中被调用了 event.preventDefault()
。.passive
修饰符用来进一步告诉浏览器这个事件的默认行为不会被取消。
不要把 .passive 和 .prevent 一块儿使用。被动处理函数没法阻止默认的事件行为。
<!-- 只有在 keyCode 是 13 时调用 vm.submit() --> <input v-on:keyup.13="submit"> <!-- 同上 --> <input v-on:keyup.enter="submit"> <!-- 缩写语法 --> <input @keyup.enter="submit">
所有的按键别名:
能够经过全局 config.keyCodes
对象自定义按键修饰符别名:
// 可使用 `v-on:keyup.f1` Vue.config.keyCodes.f1 = 112
你也可直接将 KeyboardEvent.key
暴露的任意有效按键名转换为 kebab-case
来做为修饰符:
<input @keyup.page-down="onPageDown">
在上面的例子中,处理函数仅在 $event.key === 'PageDown'
时被调用。
有一些按键 (.esc
以及全部的方向键) 在 IE9 中有不一样的key
值, 若是你想支持 IE9,它们的内置别名应该是首选。
能够用以下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
注意:在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。在 Sun 操做系统键盘上,meta 对应实心宝石键 (◆)。在其余特定键盘上,尤为在 MIT 和 Lisp 机器的键盘、以及其后继产品,好比 Knight 键盘、space-cadet 键盘,meta 被标记为“META”。在 Symbolics 键盘上,meta 被标记为“META”或者“Meta”。
<!-- Alt + C --> <input @keyup.alt.67="clear"> <!-- Ctrl + Click --> <div @click.ctrl="doSomething">Do something</div>
请注意修饰键与常规按键不一样,在和keyup
事件一块儿用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住ctrl
的状况下释放其它按键,才能触发keyup.ctrl
。而单单释放ctrl
也不会触发事件。
.exact 修饰符容许你控制由精确的系统修饰符组合触发的事件。
<!-- 即便 Alt 或 Shift 被一同按下时也会触发 --> <button @click.ctrl="onClick">A</button> <!-- 有且只有 Ctrl 被按下的时候才触发 --> <button @click.ctrl.exact="onCtrlClick">A</button> <!-- 没有任何系统修饰符被按下的时候才触发 --> <button @click.exact="onClick">A</button>
这些修饰符会限制处理函数仅响应特定的鼠标按钮。
你能够用 v-model
指令在表单 <input>
及 <textarea>
元素上建立双向数据绑定。
v-model
会忽略全部表单元素的 value
、checked
、selected
特性的初始值而老是将 Vue 实例的数据做为数据来源。你应该经过 JavaScript 在组件的 data
选项中声明初始值。
对于须要使用输入法
(如中文、日文、韩文等) 的语言,你会发现v-model
不会在输入法组合文字过程当中获得更新。若是你也想处理这个过程,请使用input
事件。
<input v-model="message" placeholder="edit me"> <p>Message is: {{ message }}</p>
<span>Multiline message is:</span> <p style="white-space: pre-line;">{{ message }}</p> <br> <textarea v-model="message" placeholder="add multiple lines"></textarea>
在文本区域插值 (<textarea></textarea>
) 并不会生效,应用v-model
来代替。
单个复选框,绑定到布尔值:
<input type="checkbox" id="checkbox" v-model="checked"> <label for="checkbox">{{ checked }}</label>
多个复选框,绑定到同一个数组:
<div id='example-3'> <input type="checkbox" id="jack" value="Jack" v-model="checkedNames"> <label for="jack">Jack</label> <input type="checkbox" id="john" value="John" v-model="checkedNames"> <label for="john">John</label> <input type="checkbox" id="mike" value="Mike" v-model="checkedNames"> <label for="mike">Mike</label> <br> <span>Checked names: {{ checkedNames }}</span> </div>
new Vue({ el: '#example-3', data: { checkedNames: [] } })
看下面一个例子:
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" >
// 当选中时 vm.toggle === 'yes' // 当没有选中时 vm.toggle === 'no'
这里的true-value
和false-value
特性并不会影响输入控件的value
特性,由于浏览器在提交表单时并不会包含未被选中的复选框。若是要确保表单中这两个值中的一个可以被提交,(好比“yes”或“no”),请换用单选按钮。
<div id="example-4"> <input type="radio" id="one" value="One" v-model="picked"> <label for="one">One</label> <br> <input type="radio" id="two" value="Two" v-model="picked"> <label for="two">Two</label> <br> <span>Picked: {{ picked }}</span> </div>
new Vue({ el: '#example-4', data: { picked: '' } })
单选时:
<div id="example-5"> <select v-model="selected"> <option disabled value="">请选择</option> <option>A</option> <option>B</option> <option>C</option> </select> <span>Selected: {{ selected }}</span> </div>
new Vue({ el: '...', data: { selected: '' } })
若是v-model
表达式的初始值未能匹配任何选项,<select>
元素将被渲染为“未选中”状态。在iOS
中,这会使用户没法选择第一个选项。由于这样的状况下,iOS
不会触发change
事件。所以,更推荐像上面这样提供一个值为空的禁用选项。
多选时 (绑定到一个数组):
<div id="example-6"> <select v-model="selected" multiple style="width: 50px;"> <option>A</option> <option>B</option> <option>C</option> </select> <br> <span>Selected: {{ selected }}</span> </div> new Vue({ el: '#example-6', data: { selected: [] } })
用 v-for
渲染的动态选项:
<select v-model="selected"> <option v-for="option in options" v-bind:value="option.value"> {{ option.text }} </option> </select> <span>Selected: {{ selected }}</span> new Vue({ el: '...', data: { selected: 'A', options: [ { text: 'One', value: 'A' }, { text: 'Two', value: 'B' }, { text: 'Three', value: 'C' } ] } })
在默认状况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你能够添加 lazy 修饰符,从而转变为使用 change 事件进行同步:
<!-- 在“change”时而非“input”时更新 --> <input v-model.lazy="msg" >
若是想自动将用户的输入值转为数值类型,能够给 v-model 添加 number 修饰符:
<input v-model.number="age" type="number">
这一般颇有用,由于即便在 type="number"
时,HTML 输入元素的值也总会返回字符串。
<input v-model.trim="msg">