<div id="app"> {{ message }} </div> var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } })
<div id="app-2"> <span v-bind:title="message"> 鼠標懸停幾秒鐘查看此處動態綁定的提示信息! </span> </div> var app2 = new Vue({ el: '#app-2', data: { message: '頁面加載於 ' + new Date().toLocaleString() } })
<div id="app-3"> <p v-if="seen">如今你看到我了</p> </div> var app3 = new Vue({ el: '#app-3', data: { seen: true } })
<div id="app-4"> <ol> <li v-for="todo in todos"> {{ todo.text }} </li> </ol> </div> var app4 = new Vue({ el: '#app-4', data: { todos: [ { text: '學習 JavaScript' }, { text: '學習 Vue' }, { text: '整個牛項目' } ] } })
<div id="app-5"> <p>{{ message }}</p> <button v-on:click="reverseMessage">逆轉消息</button> </div> var app5 = new Vue({ el: '#app-5', data: { message: 'Hello Vue.js!' }, methods: { reverseMessage: function () { this.message = this.message.split('').reverse().join('') } } })
Vue 還提供了 v-model 指令,它能輕鬆實現表單輸入和應用狀態之間的雙向綁定。javascript
<div id="app-6"> <p>{{ message }}</p> <input v-model="message"> </div> var app6 = new Vue({ el: '#app-6', data: { message: 'Hello Vue!' } })
當一個 Vue 實例被建立時,它向 Vue 的響應式系統中加入了其 data 對象中能找到的全部的屬性。當這些屬性的值發生改變時,視圖將會產生「響應」,即匹配更新爲新的值。html
// 咱們的數據對象 var data = { a: 1 } // 該對象被加入到一個 Vue 實例中 var vm = new Vue({ data: data }) // 它們引用相同的對象! vm.a === data.a // => true // 設置屬性也會影響到原始數據 vm.a = 2 data.a // => 2 // ……反之亦然 data.a = 3 vm.a // => 3
當這些數據改變時,視圖會進行重渲染。值得注意的是只有當實例被建立時 data 中存在的屬性纔是響應式的。vue
若是你知道你會在晚些時候須要一個屬性,可是一開始它爲空或不存在,那麼你僅須要設置一些初始值。java
$data、$el、$watch
除了數據屬性,Vue 實例還暴露了一些有用的實例屬性與方法。它們都有前綴 $,以便與用戶定義的屬性區分開來ios
能夠在 API 參考中查閱到完整的實例屬性和方法的列表。web
好比 created 鉤子能夠用來在一個實例被建立以後執行代碼:axios
new Vue({ data: { a: 1 }, created: function () { // `this` 指向 vm 實例 console.log('a is: ' + this.a) } }) // => "a is: 1"
也有一些其它的鉤子,在實例生命週期的不一樣階段被調用,如 mounted、updated 和 destroyed。生命週期鉤子的 this 上下文指向調用它的 Vue 實例。api
beforeCreate、created、beforeMount、mounted、BeforeUpdate、updated、beforeDestroy、destroyed
注意:數組
不要在選項屬性或回調上使用箭頭函數,好比 created: () => console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。由於箭頭函數是和父級上下文綁定在一塊兒的,this 不會是如你所預期的 Vue 實例,常常致使 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之類的錯誤。瀏覽器
在底層的實現上,Vue 將模板編譯成虛擬 DOM 渲染函數。結合響應系統,Vue 可以智能地計算出最少須要從新渲染多少組件,並把 DOM 操做次數減到最少。
若是你熟悉虛擬 DOM 而且偏心 JavaScript 的原始力量,你也能夠不用模板,直接寫渲染 (render) 函數,使用可選的 JSX 語法。
經過使用 v-once 指令,你也能執行一次性地插值,當數據改變時,插值處的內容不會更新。但請留心這會影響到該節點上的其它數據綁定:
<span>Message: {{ msg }}</span> <span v-once>這個將不會改變: {{ msg }}</span>
<p>{{ rawHtml }}</p> <p><span v-html="rawHtml"></span></p>
注意,你不能使用 v-html 來複合局部模板,由於 Vue 不是基於字符串的模板引擎。反之,對於用戶界面 (UI),組件更適合做爲可重用和可組合的基本單位。
注意:
你的站點上動態渲染的任意 HTML 可能會很是危險,由於它很容易致使 XSS 攻擊。請只對可信內容使用 HTML 插值,毫不要對用戶提供的內容使用插值。
Mustache 語法不能做用在 HTML 特性上,遇到這種狀況應該使用 v-bind 指令
<div v-bind:id="dynamicId"></div> <button v-bind:disabled="isButtonDisabled">Button</button>
{{ number + 1 }} {{ ok ? 'YES' : 'NO' }} {{ message.split('').reverse().join('') }} <div v-bind:id="'list-' + id"></div>
指令 (Directives) 是帶有 v- 前綴的特殊屬性。指令屬性的值預期是單個 JavaScript 表達式 (v-for 是例外狀況,稍後咱們再討論)。指令的職責是,當表達式的值改變時,將其產生的連帶影響,響應式地做用於 DOM。回顧咱們在介紹中看到的例子:
<p v-if="seen">如今你看到我了</p>
這裏,v-if 指令將根據表達式 seen 的值的真假來插入/移除
元素。
一些指令可以接收一個「參數」,在指令名稱以後以冒號表示。
<a v-bind:href="url">...</a> <a v-on:click="doSomething">...</a>
修飾符 (Modifiers) 是以半角句號 . 指明的特殊後綴,用於指出一個指令應該以特殊方式綁定。例如,.prevent 修飾符告訴 v-on 指令對於觸發的事件調用 event.preventDefault():
<form v-on:submit.prevent="onSubmit">...</form>
<div id="example"> <p>Original message: "{{ message }}"</p> <p>Computed reversed message: "{{ reversedMessage }}"</p> </div> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { // 計算屬性的 getter reversedMessage: function () { // `this` 指向 vm 實例 return this.message.split('').reverse().join('') } } })
你能夠像綁定普通屬性同樣在模板中綁定計算屬性。Vue 知道 vm.reversedMessage 依賴於 vm.message,所以當 vm.message 發生改變時,全部依賴 vm.reversedMessage 的綁定也會更新。
計算屬性只有在它的相關依賴發生改變時纔會從新求值。這就意味着只要 message 尚未發生改變,屢次訪問 reversedMessage 計算屬性會當即返回以前的計算結果,而沒必要再次執行函數。
var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { firstName: function (val) { this.fullName = val + ' ' + this.lastName }, lastName: function (val) { this.fullName = this.firstName + ' ' + val } } }) var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar' }, computed: { fullName: function () { return this.firstName + ' ' + this.lastName } } })
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] } } }
如今再運行 vm.fullName = 'John Doe' 時,setter 會被調用,vm.firstName 和 vm.lastName 也會相應地被更新。
雖然計算屬性在大多數狀況下更合適,但有時也須要一個自定義的偵聽器。這就是爲何 Vue 經過 watch 選項提供了一個更通用的方法,來響應數據的變化。
當須要在數據變化時 執行異步 或開銷較大的操做時,這個方式是最有用的。
<div id="watch-example"> <p> Ask a yes/no question: <input v-model="question"> </p> <p>{{ answer }}</p> </div> <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.getAnswer() } }, methods: { // `_.debounce` 是一個經過 Lodash 限制操做頻率的函數。 // 在這個例子中,咱們但願限制訪問 yesno.wtf/api 的頻率 // AJAX 請求直到用戶輸入完畢纔會發出。想要了解更多關於 // `_.debounce` 函數 (及其近親 `_.throttle`) 的知識, // 請參考:https://lodash.com/docs#debounce getAnswer: _.debounce( 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 }) }, // 這是咱們爲斷定用戶中止輸入等待的毫秒數 500 ) } }) </script>
除了 watch 選項以外,您還可使用命令式的 vm.$watch API。
直接綁對象
<div v-bind:class="{ active: isActive }"></div>
上面的語法表示 active 這個 class 存在與否將取決於數據屬性 isActive
綁定多個class
<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"> </div> data: { isActive: true, hasError: false }
綁定的數據對象沒必要內聯定義在模板裏:
<div v-bind:class="classObject"></div> data: { classObject: { active: true, 'text-danger': false } }
返回對象的計算屬性。這是一個經常使用且強大的模式:
<div v-bind:class="classObject"></div> data: { isActive: true, error: null }, computed: { classObject: function () { return { active: this.isActive && !this.error, 'text-danger': this.error && this.error.type === 'fatal' } } }
數組語法
咱們能夠把一個數組傳給 v-bind:class,以應用一個 class 列表:
<div v-bind:class="[activeClass, errorClass]"></div> data: { activeClass: 'active', errorClass: 'text-danger' }
若是你也想根據條件切換列表中的 class,能夠用三元表達式:
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
不過,當有多個條件 class 時這樣寫有些繁瑣。因此在數組語法中也可使用對象語法:
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
綁定內聯
v-bind:style 的對象語法十分直觀——看着很是像 CSS,但實際上是一個 JavaScript 對象。CSS 屬性名能夠用駝峯式 (camelCase) 或短橫線分隔 (kebab-case,記得用單引號括起來) 來命名:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> data: { activeColor: 'red', fontSize: 30 }
直接綁定到一個樣式對象一般更好,這會讓模板更清晰:
<div v-bind:style="styleObject"></div> data: { styleObject: { color: 'red', fontSize: '13px' } }
當 v-bind:style 使用須要添加瀏覽器引擎前綴的 CSS 屬性時,如 transform,Vue.js 會自動偵測並添加相應的前綴。
多重值
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
<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就能夠從新渲染,不然會複用
<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>
<h1 v-show="ok">Hello!</h1>
不一樣的是帶有 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 更高的優先級。
<ul id="example-1"> <li v-for="item in items"> //用of代替in也能夠 {{ item.message }} </li> </ul> var example1 = new Vue({ el: '#example-1', data: { items: [ { message: 'Foo' }, { message: 'Bar' } ] } })
v-for中第二個參數index
<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' } ] } })
能夠用v-for來遍歷一個對象
<div v-for="(value, key, index) in object"> {{ index }}. {{ key }}: {{ value }} </div> new Vue({ el: '#v-for-object', data: { object: { firstName: 'John', lastName: 'Doe', age: 30 } } })
建議儘量在使用 v-for 時提供 key,除非遍歷輸出的 DOM 內容很是簡單,或者是刻意依賴默認行爲以獲取性能上的提高。
Vue 包含一組觀察數組的變異方法,因此它們也將會觸發視圖更新。這些方法以下:
push() pop() shift() unshift() splice() sort() reverse()
例如:filter(), concat() 和 slice() 。這些不會改變原始數組,但老是返回一個新數組。當使用非變異方法時,能夠用新數組替換舊數組:
example1.items = example1.items.filter(function (item) { return item.message.match(/Foo/) })
注意:
當你利用索引直接設置一個項時,例如:vm.items[indexOfItem] = newValue
當你修改數組的長度時,例如:vm.items.length = newLength
vue都不能識別數組的變更
// Vue.set Vue.set(example1.items, indexOfItem, newValue) // Array.prototype.splice example1.items.splice(indexOfItem, 1, newValue) example1.items.splice(newLength)
能夠用以上方法解決
有時,咱們想要顯示一個數組的過濾或排序副本,而不實際改變或重置原始數據。在這種狀況下,能夠建立返回過濾或排序數組的計算屬性。
<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 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!'
能夠用event做形參,能夠傳$event
事件修飾符
.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> <!-- 點擊事件將只會觸發一次 --> <a v-on:click.once="doThis"></a>
使用修飾符時,順序很重要;相應的代碼會以一樣的順序產生。所以,用 @click.prevent.self 會阻止全部的點擊,而 @click.self.prevent 只會阻止對元素自身的點擊。
Vue 還對應 addEventListener 中的 passive 選項提供了 .passive 修飾符。
<!-- 滾動事件的默認行爲 (即滾動行爲) 將會當即觸發 --> <!-- 而不會等待 `onScroll` 完成 --> <!-- 這其中包含 `event.preventDefault()` 的狀況 --> <div v-on:scroll.passive="onScroll">...</div>
這個 .passive 修飾符尤爲可以提高移動端的性能。
.enter .tab .delete (捕獲「刪除」和「退格」鍵) .esc .space .up .down .left .right <!-- 只有在 `keyCode` 是 13 時調用 `vm.submit()` --> <input v-on:keyup.13="submit">
.ctrl .alt .shift .meta <!-- Alt + C --> <input @keyup.alt.67="clear"> <!-- Ctrl + Click --> <div @click.ctrl="doSomething">Do something</div>
.exact 修飾符容許你控制由精確的系統修飾符組合觸發的事件。
<!-- 即便 Alt 或 Shift 被一同按下時也會觸發 --> <button @click.ctrl="onClick">A</button> <!-- 有且只有 Ctrl 被按下的時候才觸發 --> <button @click.ctrl.exact="onCtrlClick">A</button> <!-- 沒有任何系統修飾符被按下的時候才觸發 --> <button @click.exact="onClick">A</button>
.left .right .middle
<input v-model="message" placeholder="edit me"> <p>Message is: {{ message }}</p>
複選按鈕
<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: [] } })
單選按鈕
<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: '' } })
多選
<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: [] } })
在自定義組件中使用這些受限制的元素時會致使一些問題,例如:
<table> <my-row>...</my-row> </table>
自定義組件
<table> <tr is="my-row"></tr> </table>
應當注意,若是使用來自如下來源之一的字符串模板,則沒有這些限制:
<script type="text/x-template"> JavaScript 內聯模板字符串 .vue 組件
父傳子,子經過props來接收
Vue.component('child', { // 聲明 props props: ['message'], //經過駝峯xxSs // 就像 data 同樣,prop 也能夠在模板中使用 // 一樣也能夠在 vm 實例中經過 this.message 來使用 template: '<span>{{ message }}</span>' })
而後咱們能夠這樣向它傳入一個普通字符串:
<child message="hello!"></child> //可使用xx-ss
若是你想把一個對象的全部屬性做爲 prop 進行傳遞,可使用不帶任何參數的 v-bind (即用 v-bind 而不是 v-bind:prop-name)。例如,已知一個 todo 對象:
todo: { text: 'Learn Vue', isComplete: false }
而後:
<todo-item v-bind="todo"></todo-item>
將等價於:
<todo-item v-bind:text="todo.text" v-bind:is-complete="todo.isComplete" ></todo-item>
注意在 JavaScript 中對象和數組是引用類型,指向同一個內存空間,若是 prop 是一個對象或數組,在子組件內部改變它會影響父組件的狀態。
Vue.component('example', { props: { // 基礎類型檢測 (`null` 指容許任何類型) 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 value > 10 } } } })
type 能夠是下面原生構造器:
String Number Boolean Function Object Array Symbol
注意 prop 會在組件實例建立以前進行校驗,因此在 default 或 validator 函數裏,諸如 data、computed 或 methods 等實例屬性還沒法使用。
每一個 Vue 實例都實現了事件接口,即:
使用 $on(eventName) 監聽事件 使用 $emit(eventName) 觸發事件
下面是一個例子:
<div id="counter-event-example"> <p>{{ total }}</p> <button-counter v-on:increment="incrementTotal"></button-counter> <button-counter v-on:increment="incrementTotal"></button-counter> </div> Vue.component('button-counter', { template: '<button v-on:click="incrementCounter">{{ counter }}</button>', data: function () { return { counter: 0 } }, methods: { incrementCounter: function () { this.counter += 1 this.$emit('increment') } }, }) new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal: function () { this.total += 1 } } })
以下代碼
<comp :foo.sync="bar"></comp>
會被擴展爲:
<comp :foo="bar" @update:foo="val => bar = val"></comp>
當子組件須要更新 foo 的值時,它須要顯式地觸發一個更新事件:
this.$emit('update:foo', newValue)
var bus = new Vue() // 觸發組件 A 中的事件 bus.$emit('id-selected', 1) // 在組件 B 建立的鉤子中監聽事件 bus.$on('id-selected', function (id) { // ... })
另外一種定義模板的方式是在 JavaScript 標籤裏使用 text/x-template 類型,而且指定一個 id。例如:
<script type="text/x-template" id="hello-world-template"> <p>Hello hello hello</p> </script> Vue.component('hello-world', { template: '#hello-world-template' })
這在有不少大模板的演示應用或者特別小的應用中可能有用,其它場合應該避免使用,由於這將模板和組件的其它定義分離了。