Vue教程:指令與事件(二)

一.插值

v-once

經過使用 v-once 指令,你也能執行一次性地插值,當數據改變時,插值處的內容不會更新。但請留心這會影響到該節點上全部的數據綁定:javascript

span v-once>這個將不會改變: {{ msg }}</span>

v-html

雙大括號會將數據解釋爲普通文本,而非 HTML 代碼。爲了輸出真正的 HTML,你須要使用 v-html 指令:php

<p>Using mustaches: {{ rawHtml }}</p> <p>Using v-html directive: <span v-html="rawHtml"></span></p>

這個 span 的內容將會被替換成爲屬性值 rawHtml,直接做爲 HTML——會忽略解析屬性值中的數據綁定。css

你的站點上動態渲染的任意 HTML 可能會很是危險,由於它很容易致使 XSS 攻擊。請只對可信內容使用 HTML 插值,毫不要對用戶提供的內容使用插值。html

使用 JavaScript 表達式

Vue.js 都提供了徹底的 JavaScript 表達式支持。java

{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }} {{ message.split('').reverse().join('') }} <div v-bind:id="'list-' + id"></div>

 這些表達式會在所屬 Vue 實例的數據做用域下做爲 JavaScript 被解析。有個限制就是,每一個綁定都只能包含單個表達式,因此下面的例子都不會生效nginx

<!-- 這是語句,不是表達式 --> {{ var a = 1 }} <!-- 流控制也不會生效,請使用三元表達式 --> {{ if (ok) { return message } }}

二.v-bind與v-on的縮寫

v-bind 縮寫

<!-- 完整語法 --> <a v-bind:href="url"></a> <!-- 縮寫 --> <a :href="url"></a> <!-- 完整語法 --> <button v-bind:disabled="isButtonDisabled">Button</button> <!-- 縮寫 --> <button :disabled="isButtonDisabled">Button</button>

說明下:若是isButtonDisabled的值是 nullundefined 或 false,則 disabled 特性甚至不會被包含在渲染出來的 <button> 元素中。數組

v-on 縮寫

<!-- 完整語法 --> <a v-on:click="doSomething">...</a> <!-- 縮寫 --> <a @click="doSomething">...</a>

三.條件渲染

v-if

<h1 v-if="ok">Yes</h1>

在 <template> 元素上使用 v-if

<template v-if="ok"> <h1>Title</h1> <p>Paragraph 1</p> <p>Paragraph 2</p> </template>

v-else

你可使用 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 的元素的後面,不然它將不會被識別。ruby

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>

用 key 管理可複用的元素

Vue 會盡量高效地渲染元素,一般會複用已有元素而不是從頭開始渲染。這麼作除了使 Vue 變得很是快以外,還有其它一些好處。例如,若是你容許用戶在不一樣的登陸方式之間切換:dom

<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

這樣也不老是符合實際需求,因此 Vue 爲你提供了一種方式來表達「這兩個元素是徹底獨立的,不要複用它們」。只需添加一個具備惟一值的 key 屬性便可:

<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 屬性。

v-show

<h1 v-show="ok">Hello!</h1>

不一樣的是帶有 v-show 的元素始終會被渲染並保留在 DOM 中。v-show 只是簡單地切換元素的 CSS 屬性 display

注意,v-show 不支持 <template> 元素,也不支持 v-else。

v-if vs v-show

通常來講,v-if 有更高的切換開銷,而 v-show 有更高的初始渲染開銷。所以,若是須要很是頻繁地切換,則使用 v-show 較好;若是在運行時條件不多改變,則使用 v-if 較好。

v-if 與 v-for 一塊兒使用

當 v-if 與 v-for 一塊兒使用時,v-for 具備比 v-if 更高的優先級

四.列表渲染v-for

一個數組的v-for

<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>

一個對象的 v-for

<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 引擎下是一致的。

key

爲了給 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 }) } }

值域 v-for

<div> <span v-for="n in 10">{{ n }} </span> </div>

template-v-for

<ul> <template v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider"></li> </template> </ul>

一個組件的 v-for

<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-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) } }

事件修飾符

修飾符是由點開頭的指令後綴來表示的。

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
<!-- 阻止單擊事件繼續傳播 --> <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">

所有的按鍵別名:

  • .enter
  • .tab
  • .delete (捕獲「刪除」和「退格」鍵)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

能夠經過全局 config.keyCodes 對象自定義按鍵修飾符別名:

// 可使用 `v-on:keyup.f1` Vue.config.keyCodes.f1 = 112

自動匹配按鍵修飾符(2.5.0 新增)

你也可直接將 KeyboardEvent.key 暴露的任意有效按鍵名轉換爲 kebab-case 來做爲修飾符:

<input @keyup.page-down="onPageDown">

在上面的例子中,處理函數僅在 $event.key === 'PageDown' 時被調用。

有一些按鍵 (.esc 以及全部的方向鍵) 在 IE9 中有不一樣的 key 值, 若是你想支持 IE9,它們的內置別名應該是首選。

系統修飾鍵(2.1.0 新增)

能夠用以下修飾符來實現僅在按下相應按鍵時才觸發鼠標或鍵盤事件的監聽器。

  • .ctrl
  • .alt
  • .shift
  • .meta

注意:在 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 修飾符(2.5.0 新增)

.exact 修飾符容許你控制由精確的系統修飾符組合觸發的事件。

<!-- 即便 Alt 或 Shift 被一同按下時也會觸發 --> <button @click.ctrl="onClick">A</button> <!-- 有且只有 Ctrl 被按下的時候才觸發 --> <button @click.ctrl.exact="onCtrlClick">A</button> <!-- 沒有任何系統修飾符被按下的時候才觸發 --> <button @click.exact="onClick">A</button>

鼠標按鈕修飾符(2.1.0 新增)

  • .left
  • .right
  • .middle

這些修飾符會限制處理函數僅響應特定的鼠標按鈕。

六.表單輸入綁定v-model

你能夠用 v-model 指令在表單 <input> 及 <textarea> 元素上建立雙向數據綁定。

v-model 會忽略全部表單元素的 valuecheckedselected 特性的初始值而老是將 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' } ] } })

修飾符.lazy,.number,.trim

.lazy

在默認狀況下,v-model 在每次 input 事件觸發後將輸入框的值與數據進行同步 (除了上述輸入法組合文字時)。你能夠添加 lazy 修飾符,從而轉變爲使用 change 事件進行同步:

<!-- 在「change」時而非「input」時更新 --> <input v-model.lazy="msg" >

.number

若是想自動將用戶的輸入值轉爲數值類型,能夠給 v-model 添加 number 修飾符:

<input v-model.number="age" type="number">

這一般頗有用,由於即便在 type="number" 時,HTML 輸入元素的值也總會返回字符串。

.trim

<input v-model.trim="msg">
相關文章
相關標籤/搜索