1. 生命周期
我們先來(lái)看下圖:

我們來(lái)解釋一下上圖的各個(gè)階段:
beforeCreate: vue實(shí)例進(jìn)行基礎(chǔ)初始化時(shí)
created:實(shí)例初始化完成時(shí)
beforeMount:模板與數(shù)據(jù)結(jié)合掛載到頁(yè)面之前
beforeUpdate:數(shù)據(jù)發(fā)生改變,但并未渲染之前
updated:數(shù)據(jù)發(fā)生改變,并渲染之后
mounted:頁(yè)面掛載之后
beforeDestroy:組件銷毀之前
destroyed:銷毀組件之后
activated: keep-alive 組件激活時(shí)調(diào)用。該鉤子在服務(wù)器端渲染期間不被調(diào)用。
deactivated:keep-alive 組件停用時(shí)調(diào)用。該鉤子在服務(wù)器端渲染期間不被調(diào)用。
errorCaptured:2.5.0+ 新增,當(dāng)捕獲一個(gè)來(lái)自子孫組件的錯(cuò)誤時(shí)被調(diào)用。此鉤子會(huì)收到三個(gè)參數(shù):錯(cuò)誤對(duì)象、發(fā)生錯(cuò)誤的組件實(shí)例以及一個(gè)包含錯(cuò)誤來(lái)源信息的字符串。此鉤子可以返回 false 以阻止該錯(cuò)誤繼續(xù)向上傳播。
2. computed計(jì)算屬性
計(jì)算屬性在computed:{}中聲明,不需要在data中聲明,當(dāng)data中沒(méi)有時(shí)會(huì)自動(dòng)來(lái)計(jì)算屬性中找。寫法取下:
computer: {
aaa: {
get:function() {
// 讀取該方法內(nèi)容時(shí)
},
set:function(value) {
// 設(shè)置該方法時(shí),即給該方法重新賦值時(shí)
}
}
3. 偵聽(tīng)屬性
來(lái)看下watch的作用,當(dāng)需要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開(kāi)銷較大的操作時(shí),這個(gè)方式是最有用的。來(lái)看演示代碼:
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 發(fā)生改變,這個(gè)函數(shù)就會(huì)運(yùn)行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
4. 樣式綁定
方法1: 對(duì)象形式
// 當(dāng)isactive為true時(shí)存在active類名
<div v-bind:class="{ active: isActive }"></div>
// 傳入多個(gè)class
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
data: {
isActive: true,
hasError: false
}
// 綁定的數(shù)據(jù)對(duì)象不必內(nèi)聯(lián)定義在模板里:
<div v-bind:class="classObject"></div>
data: {
classObject: {
active: true,
'text-danger': false
}
}
// 也可以在這里綁定一個(gè)返回對(duì)象的計(jì)算屬性。
<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'
}
}
}
方法2: 數(shù)組形式
<div v-bind:class="[isactive]"></div>
data{
isactive:"active"
}
// 動(dòng)態(tài)切換
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
// 在數(shù)組中加入對(duì)象語(yǔ)法
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
方法3: 綁定style樣式
<div v-bind:style="styleObj"></div>
data{
styleObj:{
color:"black"
}
}
<div v-bind:style="[styleObj,{fontSize:'20px'}]"></div>
data{
styleObj:{
color:"black"
}
}
// 綁定多個(gè)值的數(shù)組,這樣寫只會(huì)渲染數(shù)組中最后一個(gè)被瀏覽器支持的值
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
5. 條件渲染
5.1 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>
如果想切換多個(gè)元素,我們使用template包裹即可
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
vue會(huì)復(fù)用v-if中相同的組件,如果要避免,可設(shè)置key,如下:
<div v-if=“show”>
<input key=“username” />
</div>
<div v-else>
<input key=“password” />
</div>
5.2 v-show與v-if區(qū)別
- v-show 的元素始終會(huì)被渲染并保留在 DOM 中。v-show 只是簡(jiǎn)單地切換元素的 CSS 屬性 display。
- v-show 不支持 <template> 元素,也不支持 v-else。
- v-if 是“真正”的條件渲染,因?yàn)樗鼤?huì)確保在切換過(guò)程中條件塊內(nèi)的事件監(jiān)聽(tīng)器和子組件適當(dāng)?shù)乇讳N毀和重建。
- v-if 也是惰性的:如果在初始渲染時(shí)條件為假,則什么也不做——直到條件第一次變?yōu)檎鏁r(shí),才會(huì)開(kāi)始渲染條件塊。v-show 就簡(jiǎn)單得多——不管初始條件是什么,元素總是會(huì)被渲染,并且只是簡(jiǎn)單地基于 CSS 進(jìn)行切換。
- 一般來(lái)說(shuō),v-if 有更高的切換開(kāi)銷,而 v-show 有更高的初始渲染開(kāi)銷。因此,如果需要非常頻繁地切換,則使用 v-show 較好;如果在運(yùn)行時(shí)條件很少改變,則使用 v-if 較好。
5.3 v-show與v-for一起使用
不推薦同時(shí)使用 v-if 和 v-for。當(dāng) v-if 與 v-for 一起使用時(shí),v-for 具有比 v-if 更高的優(yōu)先級(jí)。
6. 列表渲染
6.1 數(shù)組的v-for
<ul id="example-2">
<li v-for="(item, index) in items" :key="item.id">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
可以用 of 替代 in 作為分隔符,因?yàn)樗亲罱咏?JavaScript 迭代器的語(yǔ)法,遍歷沒(méi)有in深,節(jié)省性能
6.2 對(duì)象的v-for
// 第二個(gè)參數(shù)為鍵名,第三個(gè)參數(shù)為索引
<ul id="v-for-object" class="demo">
<li v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</li>
</ul>
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
在遍歷對(duì)象時(shí),是按 Object.keys() 的結(jié)果遍歷,但是不能保證它的結(jié)果在不同的 JavaScript 引擎下是一致的。
6.3 注意事項(xiàng)
由于 JavaScript 的限制,Vue 不能檢測(cè)以下變動(dòng)的數(shù)組:
- 當(dāng)你利用索引直接設(shè)置一個(gè)項(xiàng)時(shí),例如:
vm.items[indexOfItem] = newValue - 當(dāng)你修改數(shù)組的長(zhǎng)度時(shí),例如:
vm.items.length = newLength
舉個(gè)例子:
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是響應(yīng)性的
vm.items.length = 2 // 不是響應(yīng)性的
為了解決第一類問(wèn)題,以下兩種方式都可以實(shí)現(xiàn)和 vm.items[indexOfItem] = newValue 相同的效果,同時(shí)也將觸發(fā)狀態(tài)更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
你也可以使用 vm.$set 實(shí)例方法,該方法是全局方法 Vue.set 的一個(gè)別名:
vm.$set(vm.items, indexOfItem, newValue)
為了解決第二類問(wèn)題,你可以使用 splice:
vm.items.splice(newLength)
還有如下方法:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
6.4 對(duì)象更改檢測(cè)注意事項(xiàng)
還是由于 JavaScript 的限制,Vue 不能檢測(cè)對(duì)象屬性的添加或刪除:
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 現(xiàn)在是響應(yīng)式的
vm.b = 2
// `vm.b` 不是響應(yīng)式的
對(duì)于已經(jīng)創(chuàng)建的實(shí)例,Vue 不能動(dòng)態(tài)添加根級(jí)別的響應(yīng)式屬性。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套對(duì)象添加響應(yīng)式屬性。例如,對(duì)于:
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
你可以添加一個(gè)新的 age 屬性到嵌套的 userProfile 對(duì)象:
Vue.set(vm.userProfile, 'age', 27)
你還可以使用 vm.$set 實(shí)例方法,它只是全局 Vue.set 的別名:
vm.$set(vm.userProfile, 'age', 27)
有時(shí)你可能需要為已有對(duì)象賦予多個(gè)新屬性,比如使用 Object.assign() 或 _.extend()。在這種情況下,你應(yīng)該用兩個(gè)對(duì)象的屬性創(chuàng)建一個(gè)新的對(duì)象。所以,如果你想添加新的響應(yīng)式屬性,不要像這樣:
Object.assign(vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
你應(yīng)該這樣做:
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
6.5 顯示過(guò)濾/排序結(jié)果
有時(shí),我們想要顯示一個(gè)數(shù)組的過(guò)濾或排序副本,而不實(shí)際改變或重置原始數(shù)據(jù)。在這種情況下,可以創(chuàng)建返回過(guò)濾或排序數(shù)組的計(jì)算屬性。
例如:
<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
})
}
}
在計(jì)算屬性不適用的情況下 (例如,在嵌套 v-for 循環(huán)中) 你可以使用一個(gè) 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
})
}
}
6.6 一段取值范圍的 v-for
v-for 也可以取整數(shù)。在這種情況下,它將重復(fù)多次模板。
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
結(jié)果:
1 2 3 4 5 6 7 8 9 10
6.7 v-for on a <template>
類似于 v-if,你也可以利用帶有 v-for 的 <template> 渲染多個(gè)元素。比如:
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
6.8 v-for with v-if
不推薦同時(shí)使用 v-if 和 v-for。當(dāng)它們處于同一節(jié)點(diǎn),v-for 的優(yōu)先級(jí)比 v-if 更高,這意味著 v-if 將分別重復(fù)運(yùn)行于每個(gè) v-for 循環(huán)中。當(dāng)你想為僅有的一些項(xiàng)渲染節(jié)點(diǎn)時(shí),這種優(yōu)先級(jí)的機(jī)制會(huì)十分有用,如下:
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
上面的代碼只傳遞了未完成的 todos。
而如果你的目的是有條件地跳過(guò)循環(huán)的執(zhí)行,那么可以將 v-if 置于外層元素 (或 <template>)上。如:
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
6.9 一個(gè)組件的 v-for
在自定義組件里,你可以像任何普通元素一樣用 v-for 。
<my-component v-for="item in items" :key="item.id"></my-component>
2.2.0+ 的版本里,當(dāng)在組件中使用
v-for時(shí),key現(xiàn)在是必須的。
然而,任何數(shù)據(jù)都不會(huì)被自動(dòng)傳遞到組件里,因?yàn)榻M件有自己獨(dú)立的作用域。為了把迭代數(shù)據(jù)傳遞到組件里,我們要用 props :
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>
不自動(dòng)將 item 注入到組件里的原因是,這會(huì)使得組件與 v-for 的運(yùn)作緊密耦合。明確組件數(shù)據(jù)的來(lái)源能夠使組件在其他場(chǎng)合重復(fù)使用。
下面是一個(gè)簡(jiǎn)單的 todo list 的完整例子:
<div id="todo-list-example">
<form v-on:submit.prevent="addNewTodo">
<label for="new-todo">Add a todo</label>
<input
v-model="newTodoText"
id="new-todo"
placeholder="E.g. Feed the cat"
>
<button>Add</button>
</form>
<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 模板時(shí)是十分必要的,因?yàn)樵?<ul> 元素內(nèi)只有 <li> 元素會(huì)被看作有效內(nèi)容。這樣做實(shí)現(xiàn)的效果與 <todo-item> 相同,但是可以避開(kāi)一些潛在的瀏覽器解析錯(cuò)誤。查看
Vue.component('todo-item', {
template: '
<li>
{{ title }}
<button v-on:click="$emit(\'remove\')">Remove</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 = ''
}
}
})
7. 事件處理
7.1 ## 內(nèi)聯(lián)處理器中的方法
如果需要在內(nèi)聯(lián)語(yǔ)句處理器中訪問(wèn)原始的 DOM 事件??梢杂锰厥庾兞?$event 把它傳入方法:
<button v-on:click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
// ...
methods: {
warn: function (message, event) {
// 現(xiàn)在我們可以訪問(wèn)原生事件對(duì)象
if (event) event.preventDefault()
alert(message)
}
}
7.2 事件修飾符
<!-- 阻止單擊事件繼續(xù)傳播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重載頁(yè)面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修飾符可以串聯(lián) -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修飾符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件監(jiān)聽(tīng)器時(shí)使用事件捕獲模式 -->
<!-- 即元素自身觸發(fā)的事件先在此處理,然后才交由內(nèi)部元素進(jìn)行處理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只當(dāng)在 event.target 是當(dāng)前元素自身時(shí)觸發(fā)處理函數(shù) -->
<!-- 即事件不是從內(nèi)部元素觸發(fā)的 -->
<div v-on:click.self="doThat">...</div>
<!-- 點(diǎn)擊事件將只會(huì)觸發(fā)一次 -->
<a v-on:click.once="doThis"></a>
<!-- 滾動(dòng)事件的默認(rèn)行為 (即滾動(dòng)行為) 將會(huì)立即觸發(fā) -->
<!-- 而不會(huì)等待 `onScroll` 完成 -->
<!-- 這其中包含 `event.preventDefault()` 的情況 -->
<div v-on:scroll.passive="onScroll">...</div>
使用修飾符時(shí),順序很重要;相應(yīng)的代碼會(huì)以同樣的順序產(chǎn)生。因此,用
v-on:click.prevent.self 會(huì)阻止所有的點(diǎn)擊,而
v-on:click.self.prevent 只會(huì)阻止對(duì)元素自身的點(diǎn)擊。
不要把 .passive 和 .prevent 一起使用,因?yàn)?.prevent 將會(huì)被忽略,同時(shí)瀏覽器可能會(huì)向你展示一個(gè)警告。請(qǐng)記住,.passive 會(huì)告訴瀏覽器你不想阻止事件的默認(rèn)行為。
7.3 按鍵修飾符
<!-- 只有在 `key` 是 `Enter` 時(shí)調(diào)用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
你可以直接將 KeyboardEvent.key暴露的任意有效按鍵名轉(zhuǎn)換為 kebab-case 來(lái)作為修飾符。
<input v-on:keyup.page-down="onPageDown">
在上述示例中,處理函數(shù)只會(huì)在 $event.key 等于 PageDown 時(shí)被調(diào)用。
使用 keyCode 特性也是允許的:
<input v-on:keyup.13="submit">
為了在必要的情況下支持舊瀏覽器,Vue 提供了絕大多數(shù)常用的按鍵碼的別名:
.enter.tab-
.delete(捕獲“刪除”和“退格”鍵) .esc.space.up.down.left.right
有一些按鍵 (.esc 以及所有的方向鍵) 在 IE9 中有不同的 key 值, 如果你想支持 IE9,這些內(nèi)置的別名應(yīng)該是首選。
你還可以通過(guò)全局 config.keyCodes 對(duì)象自定義按鍵修飾符別名:
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
系統(tǒng)修飾鍵
2.1.0 新增
可以用如下修飾符來(lái)實(shí)現(xiàn)僅在按下相應(yīng)按鍵時(shí)才觸發(fā)鼠標(biāo)或鍵盤事件的監(jiān)聽(tīng)器。
.ctrl.alt.shift.meta
注意:在 Mac 系統(tǒng)鍵盤上,meta 對(duì)應(yīng) command 鍵 (?)。在 Windows 系統(tǒng)鍵盤 meta 對(duì)應(yīng) Windows 徽標(biāo)鍵 (?)。在 Sun 操作系統(tǒng)鍵盤上,meta 對(duì)應(yīng)實(shí)心寶石鍵 (◆)。在其他特定鍵盤上,尤其在 MIT 和 Lisp 機(jī)器的鍵盤、以及其后繼產(chǎn)品,比如 Knight 鍵盤、space-cadet 鍵盤,meta 被標(biāo)記為“META”。在 Symbolics 鍵盤上,meta 被標(biāo)記為“META”或者“Meta”。
例如:
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
請(qǐng)注意修飾鍵與常規(guī)按鍵不同,在和 keyup 事件一起用時(shí),事件觸發(fā)時(shí)修飾鍵必須處于按下?tīng)顟B(tài)。換句話說(shuō),只有在按住 ctrl 的情況下釋放其它按鍵,才能觸發(fā) keyup.ctrl。而單單釋放 ctrl 也不會(huì)觸發(fā)事件。如果你想要這樣的行為,請(qǐng)為 ctrl 換用 keyCode:keyup.17。
.exact 修飾符
2.5.0 新增
.exact 修飾符允許你控制由精確的系統(tǒng)修飾符組合觸發(fā)的事件。
<!-- 即使 Alt 或 Shift 被一同按下時(shí)也會(huì)觸發(fā) -->
<button @click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的時(shí)候才觸發(fā) -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 沒(méi)有任何系統(tǒng)修飾符被按下的時(shí)候才觸發(fā) -->
<button @click.exact="onClick">A</button>
鼠標(biāo)按鈕修飾符
2.2.0 新增
.left.right.middle
這些修飾符會(huì)限制處理函數(shù)僅響應(yīng)特定的鼠標(biāo)按鈕。
8. 組件
8.1
<table>
<tbody>
<tr is=“row”></tr>
<tr is=“row”></tr>
<tr is=“row”></tr>
</tbody>
</table>
vue.components('row',{
template:'<tr><td>this os a row</td></tr>'
})
因?yàn)閔5有規(guī)定<tbody>內(nèi)只能寫<tr>,所以這里不能直接引用組件<row>,要通過(guò)以上方式引用,<ul>,<select>同理,建議用is=“”寫法
8.2 組件參數(shù)校驗(yàn)與非props特性
props:{
content:{
type: [String,Number],
required:true // 調(diào)用本組件的必傳的屬性
default: 123 // 默認(rèn)值
validator: function(value) {
return value.length > 5 // 傳入的內(nèi)容長(zhǎng)度必須大于5
}
}
}
非props特性,即父組件傳遞給子組件的參數(shù)并沒(méi)有在子組件props中聲明,此時(shí)該傳遞會(huì)出現(xiàn)該子組件最外層dom標(biāo)簽中,(如果是props特性,則dom中不顯示 )如下:
<div content="hell">hello</div>
8.3 將原生事件綁定到組件
你可能有很多次想要在一個(gè)組件的根元素上直接監(jiān)聽(tīng)一個(gè)原生事件。這時(shí),你可以使用 v-on 的 .native 修飾符:
<base-input v-on:focus.native="onFocus"></base-input>
在有的時(shí)候這是很有用的,不過(guò)在你嘗試監(jiān)聽(tīng)一個(gè)類似 <input> 的非常特定的元素時(shí),這并不是個(gè)好主意。比如上述 <base-input> 組件可能做了如下重構(gòu),所以根元素實(shí)際上是一個(gè) <label> 元素:
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
這時(shí),父級(jí)的 .native 監(jiān)聽(tīng)器將靜默失敗。它不會(huì)產(chǎn)生任何報(bào)錯(cuò),但是 onFocus 處理函數(shù)不會(huì)如你預(yù)期地被調(diào)用。
為了解決這個(gè)問(wèn)題,Vue 提供了一個(gè) $listeners 屬性,它是一個(gè)對(duì)象,里面包含了作用在這個(gè)組件上的所有監(jiān)聽(tīng)器。例如:
{
focus: function (event) { /* ... */ }
input: function (value) { /* ... */ },
}
有了這個(gè) $listeners 屬性,你就可以配合 v-on="$listeners" 將所有的事件監(jiān)聽(tīng)器指向這個(gè)組件的某個(gè)特定的子元素。對(duì)于類似 <input> 的你希望它也可以配合 v-model 工作的組件來(lái)說(shuō),為這些監(jiān)聽(tīng)器創(chuàng)建一個(gè)類似下述 inputListeners 的計(jì)算屬性通常是非常有用的:
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
computed: {
inputListeners: function () {
var vm = this
// `Object.assign` 將所有的對(duì)象合并為一個(gè)新對(duì)象
return Object.assign({},
// 我們從父級(jí)添加所有的監(jiān)聽(tīng)器
this.$listeners,
// 然后我們添加自定義監(jiān)聽(tīng)器,
// 或覆寫一些監(jiān)聽(tīng)器的行為
{
// 這里確保組件配合 `v-model` 的工作
input: function (event) {
vm.$emit('input', event.target.value)
}
}
)
}
},
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on="inputListeners"
>
</label>
`
})
現(xiàn)在 <base-input> 組件是一個(gè)完全透明的包裹器了,也就是說(shuō)它可以完全像一個(gè)普通的 <input> 元素一樣使用了:所有跟它相同的特性和監(jiān)聽(tīng)器的都可以工作。
8.4 非父子組件間傳值(bus/總線/觀察者模式/發(fā)布訂閱模式)
<div id="root">
<child content="Dell"></child>
<child content="Lee"></child>
</div>
<script type="text/javascript">
Vue.protopyte.bus = new Vue()
Vue.component('child', {
props: {
content:String
},
template: '<div @click="childClick">{{content}}</div>',
methods:{
childClick: function() {
this.bus.$emit('change',this.content)
}
},
mounted: function() {
var self = this;
this.bus.$on('change',function(msg) { // 監(jiān)聽(tīng)bus事件
})
}
})
</script>
8.5 在vue中使用插槽(slot)
// 父:
<child>
<p>內(nèi)容</p>
</child>
// 子:
<div>
<slot>默認(rèn)內(nèi)容</slot>
</div>
// 父:
<child>
<div class=“header” slot=“header”></div>
<div class=“header” slot=“header”></div>
</child>
// 子:
<div>
<slot name=“header”></slot>
<div class=“content”>content</div>
<slot name=“footer”></slot>
</div>
// vue中的作用域插槽
<child>
<template slot-scope=“props”> /*template必須要加上,props為接收的子組件數(shù)據(jù),名字可自定義*/
<li>{{props.item}}</li>
</template>
</child>
// 子組件
data: function(){
return {
list:[1,2,3,4]
}
}
<div>
<ul>
<slot v-for=“item of list” :item=item></slot>
</ul>
</div>
8.6 動(dòng)態(tài)組件 & 異步組件
我們之前曾經(jīng)在一個(gè)多標(biāo)簽的界面中使用 is 特性來(lái)切換不同的組件:
<component v-bind:is="currentTabComponent"></component>
當(dāng)在這些組件之間切換的時(shí)候,你有時(shí)會(huì)想保持這些組件的狀態(tài),以避免反復(fù)重渲染導(dǎo)致的性能問(wèn)題。例如我們來(lái)展開(kāi)說(shuō)一說(shuō)這個(gè)多標(biāo)簽界面:
Posts Archive
- Cat Ipsum
- Hipster Ipsum
- Cupcake Ipsum
Click on a blog title to the left to view it.
你會(huì)注意到,如果你選擇了一篇文章,切換到 Archive 標(biāo)簽,然后再切換回 Posts,是不會(huì)繼續(xù)展示你之前選擇的文章的。這是因?yàn)槟忝看吻袚Q新標(biāo)簽的時(shí)候,Vue 都創(chuàng)建了一個(gè)新的 currentTabComponent 實(shí)例。
重新創(chuàng)建動(dòng)態(tài)組件的行為通常是非常有用的,但是在這個(gè)案例中,我們更希望那些標(biāo)簽的組件實(shí)例能夠被在它們第一次被創(chuàng)建的時(shí)候緩存下來(lái)。為了解決這個(gè)問(wèn)題,我們可以用一個(gè) <keep-alive> 元素將其動(dòng)態(tài)組件包裹起來(lái)。
<!-- 失活的組件將會(huì)被緩存!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
來(lái)看看修改后的結(jié)果:
Posts Archive
- Cat Ipsum
- Hipster Ipsum
- Cupcake Ipsum
Click on a blog title to the left to view it.
現(xiàn)在這個(gè) Posts 標(biāo)簽保持了它的狀態(tài) (被選中的文章) 甚至當(dāng)它未被渲染時(shí)也是如此。你可以在這個(gè) fiddle 查閱到完整的代碼。
注意這個(gè) <keep-alive> 要求被切換到的組件都有自己的名字,不論是通過(guò)組件的 name 選項(xiàng)還是局部/全局注冊(cè)。
你可以在 API 參考文檔 查閱更多關(guān)于 <keep-alive> 的細(xì)節(jié)。
加上exclude表示哪個(gè)組件不會(huì)被緩存
異步組件
在大型應(yīng)用中,我們可能需要將應(yīng)用分割成小一些的代碼塊,并且只在需要的時(shí)候才從服務(wù)器加載一個(gè)模塊。為了簡(jiǎn)化,Vue 允許你以一個(gè)工廠函數(shù)的方式定義你的組件,這個(gè)工廠函數(shù)會(huì)異步解析你的組件定義。Vue 只有在這個(gè)組件需要被渲染的時(shí)候才會(huì)觸發(fā)該工廠函數(shù),且會(huì)把結(jié)果緩存起來(lái)供未來(lái)重渲染。例如:
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 向 `resolve` 回調(diào)傳遞組件定義
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
如你所見(jiàn),這個(gè)工廠函數(shù)會(huì)收到一個(gè) resolve 回調(diào),這個(gè)回調(diào)函數(shù)會(huì)在你從服務(wù)器得到組件定義的時(shí)候被調(diào)用。你也可以調(diào)用 reject(reason) 來(lái)表示加載失敗。這里的 setTimeout 是為了演示用的,如何獲取組件取決于你自己。一個(gè)推薦的做法是將異步組件和 webpack 的 code-splitting 功能一起配合使用:
Vue.component('async-webpack-example', function (resolve) {
// 這個(gè)特殊的 `require` 語(yǔ)法將會(huì)告訴 webpack
// 自動(dòng)將你的構(gòu)建代碼切割成多個(gè)包,這些包
// 會(huì)通過(guò) Ajax 請(qǐng)求加載
require(['./my-async-component'], resolve)
})
你也可以在工廠函數(shù)中返回一個(gè) Promise,所以把 webpack 2 和 ES2015 語(yǔ)法加在一起,我們可以寫成這樣:
Vue.component(
'async-webpack-example',
// 這個(gè) `import` 函數(shù)會(huì)返回一個(gè) `Promise` 對(duì)象。
() => import('./my-async-component')
)
當(dāng)使用局部注冊(cè)的時(shí)候,你也可以直接提供一個(gè)返回 Promise 的函數(shù):
new Vue({
// ...
components: {
'my-component': () => import('./my-async-component')
}
})
如果你是一個(gè) Browserify 用戶同時(shí)喜歡使用異步組件,很不幸這個(gè)工具的作者明確表示異步加載“并不會(huì)被 Browserify 支持”,至少官方不會(huì)。Browserify 社區(qū)已經(jīng)找到了一些變通方案,這些方案可能會(huì)對(duì)已存在的復(fù)雜應(yīng)用有幫助。對(duì)于其它的場(chǎng)景,我們推薦直接使用 webpack,以擁有內(nèi)置的頭等異步支持。
處理加載狀態(tài)
2.3.0+ 新增
這里的異步組件工廠函數(shù)也可以返回一個(gè)如下格式的對(duì)象:
const AsyncComponent = () => ({
// 需要加載的組件 (應(yīng)該是一個(gè) `Promise` 對(duì)象)
component: import('./MyComponent.vue'),
// 異步組件加載時(shí)使用的組件
loading: LoadingComponent,
// 加載失敗時(shí)使用的組件
error: ErrorComponent,
// 展示加載時(shí)組件的延時(shí)時(shí)間。默認(rèn)值是 200 (毫秒)
delay: 200,
// 如果提供了超時(shí)時(shí)間且組件加載也超時(shí)了,
// 則使用加載失敗時(shí)使用的組件。默認(rèn)值是:`Infinity`
timeout: 3000
})
注意如果你希望在 Vue Router 的路由組件中使用上述語(yǔ)法的話,你必須使用 Vue Router 2.4.0+ 版本。
9. 動(dòng)畫
transition標(biāo)簽中不寫name屬性時(shí)默認(rèn)類名前綴為v,否則為name定義的名字
9.2. 幀動(dòng)畫
自定義類名
通過(guò)自定義類名方式可使用animate.css庫(kù),如果想要使頁(yè)面進(jìn)入時(shí)也具有動(dòng)畫,需加入如下紅框中的自定義類名
既有keyframe動(dòng)畫,又有transition動(dòng)畫,當(dāng)兩者動(dòng)畫時(shí)長(zhǎng)不同時(shí),通過(guò)設(shè)置type來(lái)規(guī)定用誰(shuí)的動(dòng)畫時(shí)長(zhǎng),或自己設(shè)置。:duration=“1000”
也可以分別給入場(chǎng),出場(chǎng)動(dòng)畫設(shè)置時(shí)長(zhǎng)
:duration=“{enter:5000,leave:10000}”
9.3 vue引入velocity.js
入場(chǎng)動(dòng)畫
第一個(gè)是事件觸發(fā)前
第二個(gè)是運(yùn)行動(dòng)畫效果時(shí)
最后是動(dòng)畫完成后
動(dòng)畫完成后要執(zhí)行done()函數(shù),一定要調(diào)用
出場(chǎng)動(dòng)畫
多個(gè)元素時(shí),同之前的組件復(fù)用,要想讓其顯示,需要加key
先顯示,再隱藏
先隱藏,在顯示,mode = “out-in”
動(dòng)態(tài)組件除了用以上多個(gè)元素的方式還可用以下方式
列表過(guò)渡
transition-group相當(dāng)于如下
9.4 動(dòng)畫封裝
以下為用js,不用css的情況
9.5 引入swiper插件 vue-awesome-swiper
如果很多地方都需要用,就全局引入
因?yàn)閟tyle設(shè)置了scoped,所以在這里修改swiper內(nèi)的樣式是無(wú)效的,這時(shí)需要按以下設(shè)置來(lái)突破scoped
.wrapper >>> .swiper-pagination-bullet-active
background: #fff
窗口改變時(shí)swiper窗口重新計(jì)算
在Google 應(yīng)用商店下載vue.js devtools插件工具
當(dāng)圖標(biāo)超過(guò)8個(gè)時(shí)可以輪播,用計(jì)算屬性處理數(shù)據(jù)
computed: {
pages () {
const pages = []
this.list.forEach((item, index) => {
const page = Math.floor(index / 8)
if (!pages[page]) {
pages[page] = []
}
pages[page].push(item)
})
return pages
}
}
10. 常用知識(shí)點(diǎn)
10.1. 路由跳轉(zhuǎn)后頁(yè)面滾動(dòng)位置
10.2. 如果需要用ip地址訪問(wèn),需要在pack.json文件的npm run dev中加上如下:
10.3. vue在atom中配置emmet
https://github.com/emmetio/emmet-atom/issues/364
點(diǎn)擊文件 - 用戶鍵盤映射打開(kāi)配置文件
在配置文件的最后添加
'atom-text-editor[data-grammar~="vue"]:not([mini])':
'tab':'emmet:expand-abbreviation-with-tab'
注意: 如果配置文件中已經(jīng)有'atom-text-editor[data-grammar~="vue"]:not([mini])':的其他配置, 那么要在其他配置的下面直接添加'tab': 'emmet:expand-abbreviation-with-tab', 而不能直接添加上面的兩行, 不然會(huì)報(bào)錯(cuò)
重啟編輯器
這樣就可以愉快的玩耍了...
10.4 vue 使用clipboard實(shí)現(xiàn)復(fù)制功能
https://blog.csdn.net/guxuehua/article/details/79169190
10.5. vue星星評(píng)論插件
https://github.com/shengxinjing/vue-tiny-rate
原理:將一行有顏色的星星定位覆蓋到無(wú)顏色的星星上,通過(guò)改變上層星星的width值來(lái)達(dá)到效果
10.6. promise封裝jsonp
// 引入jsonp插件
import originJsonp from 'jsonp'
export default function jsonp(url, data, option) {
url += (url.indexOf('?') < 0 ? '?' : '&') + param(data) // 如果沒(méi)有問(wèn)號(hào)加問(wèn)號(hào),否則加&
return new Promise((resolve, reject) => {
originJsonp(url, option, (err, data) => {
if (!err) {
resolve(data)
} else {
reject(err)
}
})
})
}
export function param(data) {
let url = ''
for (var k in data) {
let value = data[k] !== undefined ? data[k] : ''
url += `&${k}=${encodeURIComponent(value)}` // encodeURIComponent 把字符串作為url組件進(jìn)行編碼
}
return url ? url.substring(1) : '' // 有data時(shí)刪掉第一個(gè)&
}
10.7. Object.assign
// commonParams是一個(gè)對(duì)象
const data = Object.assign({}, commonParams, {// Object.assign 合并javascript對(duì)象
platform: 'h5', // h5平臺(tái)
uin: 0, // qq號(hào),默認(rèn)0
needNewCode: 1
})
10.8 代理
在build目錄下的webpack.dev.conf.js文件中,加入如下代碼
const axios = require('axios')
const express = require('express')
const app = express()
var apiRoutes = express.Router()
app.use('/api', apiRoutes)
在devServer中加入
before(app) {
app.get('/api/getDiscList', function (req, res) {
var url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg'
axios.get(url, {
headers: {
referer: 'https://c.y.qq.com/',
host: 'c.y.qq.com'
},
params: req.query //將參數(shù)返回給后端
}).then((response) => {
res.json(response.data)
}).catch((e) => {
console.log(e)
})
})
}
10.9 vue-lazyload插件
https://github.com/hilongjw/vue-lazyload
// 在main.js中引入
import VueLazyLoad from 'vue-lazyload'
Vue.use(VueLazyLoad, {
loading: require('common/image/default.png')
})
// 使用方法,將需要的地方的 :src改為v-lazy即可
<img v-lazy="img.src" >
10.10 常用樣式插件
import './assets/styles/reset.css' // 重置樣式表
import './assets/styles/border.css' // 移動(dòng)端1px像素問(wèn)題
import FastClick from 'fastclick' //移動(dòng)端點(diǎn)擊300ms延遲問(wèn)題
FastClick.attach(document.body);
10.11 建分支
在碼云上建index-swiper分支,然后在本地
git pull
git checkout index-swiper
// 合并分支
git checkout master
git merge origin/index-swiper
git push
10.12 圖片寬高自適應(yīng)
overflow:hidden
width:100%
height:0
padding-bottom: 31.25%