每個 Vue 應(yīng)用都是通過用 Vue 函數(shù)創(chuàng)建一個新的 Vue 實例開始的:
<script>
// Vue實例
new Vue({ //創(chuàng)建一個Vue的實例
el: "#app", //掛載點(diǎn)是id="app"的地方
data: { //數(shù)據(jù)
ditu:true,
wangge:false
},
methods:{
toggleWangge:function(){
this.wangge = !this.wangge;
if(this.wangge == true){
this.wangText = "隱藏網(wǎng)格";
this.$refs.abc.style.backgroundColor = "#262C30";
this.$refs.abc.style.color = "red";
this.$refs.def.style.backgroundColor = "#D91A29";
this.$refs.def.style.color = "#fff";
this.$refs.ghi.style.backgroundColor = "#D91A29";
this.$refs.ghi.style.color = "#fff";
this.$refs.jkl.style.backgroundColor = "#D91A29";
this.$refs.jkl.style.color = "#fff";
this.allText = "顯示全部";
this.zhongText = "顯示中級物資";
this.gaoText = "顯示高級物資";
this.zongwuzi = false;
this.zhongjiwuzi = false;
this.gaojiwuzi = false;
}
if(this.wangge == false){
this.$refs.abc.style.backgroundColor = "#D91A29";
this.$refs.abc.style.color = "#fff";
this.wangText = "顯示網(wǎng)格";
}
}
實例生命周期鉤子
每個 Vue 實例在被創(chuàng)建時都要經(jīng)過一系列的初始化過程——例如,需要設(shè)置數(shù)據(jù)監(jiān)聽础爬、編譯模板甫贯、將實例掛載到 DOM 并在數(shù)據(jù)變化時更新 DOM 等。同時在這個過程中也會運(yùn)行一些叫做生命周期鉤子的函數(shù)看蚜,這給了用戶在不同階段添加自己的代碼的機(jī)會叫搁。
beforeCreate
在實例初始化之后,數(shù)據(jù)觀測(data observer) 和 event/watcher 事件配置之前被調(diào)用。
created
實例已經(jīng)創(chuàng)建完成之后被調(diào)用渴逻。在這一步疾党,實例已完成以下的配置:數(shù)據(jù)觀測(data observer),屬性和方法的運(yùn)算惨奕, watch/event 事件回調(diào)雪位。然而,掛載階段還沒開始梨撞,$el 屬性目前不可見雹洗。
beforeMount
在掛載開始之前被調(diào)用:相關(guān)的 render 函數(shù)首次被調(diào)用。
mounted
el 被新創(chuàng)建的 vm.$el 替換卧波,并掛載到實例上去之后調(diào)用該鉤子时肿。如果 root 實例掛載了一個文檔內(nèi)元素,當(dāng) mounted 被調(diào)用時 vm.$el 也在文檔內(nèi)港粱。
beforeUpdate
數(shù)據(jù)更新時調(diào)用螃成,發(fā)生在虛擬 DOM 重新渲染和打補(bǔ)丁之前。 你可以在這個鉤子中進(jìn)一步地更改狀態(tài)查坪,這不會觸發(fā)附加的重渲染過程寸宏。
updated
由于數(shù)據(jù)更改導(dǎo)致的虛擬 DOM 重新渲染和打補(bǔ)丁,在這之后會調(diào)用該鉤子偿曙。
當(dāng)這個鉤子被調(diào)用時击吱,組件 DOM 已經(jīng)更新,所以你現(xiàn)在可以執(zhí)行依賴于 DOM 的操作遥昧。然而在大多數(shù)情況下溃睹,你應(yīng)該避免在此期間更改狀態(tài)鸥诽,因為這可能會導(dǎo)致更新無限循環(huán)。
該鉤子在服務(wù)器端渲染期間不被調(diào)用敌呈。
beforeDestroy
實例銷毀之前調(diào)用袍辞。在這一步鞋仍,實例仍然完全可用。
destroyed
Vue 實例銷毀后調(diào)用搅吁。調(diào)用后威创,Vue 實例指示的所有東西都會解綁定,所有的事件監(jiān)聽器會被移除谎懦,所有的子實例也會被銷毀肚豺。 該鉤子在服務(wù)器端渲染期間不被調(diào)用。
看一下Vue中所有的生命周期怎么用的界拦。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue入門之生命周期</title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{ number }}</p>
<input type="text" name="btnSetNumber" v-model="number">
</div>
<script>
var app = new Vue({
el: '#app',
data: {
number: 1
},
beforeCreate: function () {
console.log('beforeCreate 鉤子執(zhí)行...');
console.log(this.number)
},
cteated: function () {
console.log('cteated 鉤子執(zhí)行...');
console.log(this.number)
},
beforeMount: function () {
console.log('beforeMount 鉤子執(zhí)行...');
console.log(this.number)
},
mounted: function () {
console.log('mounted 鉤子執(zhí)行...');
console.log(this.number);
console.log("后邊的鉤子函數(shù)都不會執(zhí)行");
},
beforeUpdate: function () {
console.log('beforeUpdate 鉤子執(zhí)行...');
console.log(this.number)
},
updated: function () {
console.log('updated 鉤子執(zhí)行...');
console.log(this.number)
},
beforeDestroy: function () {
console.log('beforeDestroy 鉤子執(zhí)行...');
console.log(this.number)
},
destroyed: function () {
console.log('destroyed 鉤子執(zhí)行...');
console.log(this.number)
},
});
</script>
</body>
</html>
再看一個綜合的實戰(zhàn)的例子吸申,可能涉及到ajax和組件,不過先看一下vue的生命周期的例子的用法:
import Axios from 'axios' // 這是一個輕量級的ajax庫,import是es6模塊導(dǎo)入的語法截碴。
export default { // 這是一個vue的模塊梳侨,后面講奧。
name: 'app',
components: {
},
data: function () {
return {
list: []
}
},
mounted: function () { // 掛在完成后的生命周期鉤子注冊日丹。
this.$nextTick(function () { // 等待下一次更新完成后執(zhí)行業(yè)務(wù)處理代碼走哺。
Axios.get('/api/menulist', {// 將回調(diào)延遲到下次 DOM 更新循環(huán)之后執(zhí)行。在修改數(shù)據(jù)之后立即使用它哲虾,然后等待 DOM 更新
params: {
}
}).then(function (res) {
this.list = res.data
}.bind(this))
})
}
}
全局 API
Vue.nextTick()
下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)丙躏。在修改數(shù)據(jù)之后立即使用這個方法,獲取更新后的 DOM妒牙。
官方文檔的這句話的側(cè)重點(diǎn)在最后那半句獲取更新后的DOM彼哼,獲取更新后的DOM言外之意就是什么操作需要用到了更新后的DOM而不能使用之前的DOM或者使用更新前的DOM或出問題,所以就衍生出了這個獲取更新后的DOM的Vue方法湘今。所以放在Vue.nextTick()回調(diào)函數(shù)中的執(zhí)行的應(yīng)該是會對DOM進(jìn)行操作的 js代碼
什么時候需要用的Vue.nextTick()
1.你在Vue生命周期的created()鉤子函數(shù)進(jìn)行的DOM操作一定要放在Vue.nextTick()的回調(diào)函數(shù)中敢朱。原因是什么呢,原因是在created()鉤子函數(shù)執(zhí)行的時候DOM 其實并未進(jìn)行任何渲染摩瞎,而此時進(jìn)行DOM操作無異于徒勞拴签,所以此處一定要將DOM操作的js代碼放進(jìn)Vue.nextTick()的回調(diào)函數(shù)中。與之對應(yīng)的就是mounted鉤子函數(shù)旗们,因為該鉤子函數(shù)執(zhí)行時所有的DOM掛載和渲染都已完成蚓哩,此時在該鉤子函數(shù)中進(jìn)行任何DOM操作都不會有問題 。
2.在數(shù)據(jù)變化后要執(zhí)行的某個操作上渴,而這個操作需要使用隨數(shù)據(jù)改變而改變的DOM結(jié)構(gòu)的時候岸梨,這個操作都應(yīng)該放進(jìn)Vue.nextTick()的回調(diào)函數(shù)中。
原因是稠氮,Vue是異步執(zhí)行dom更新的曹阔,一旦觀察到數(shù)據(jù)變化,Vue就會開啟一個隊列隔披,然后把在同一個事件循環(huán) (event loop) 當(dāng)中觀察到數(shù)據(jù)變化的 watcher 推送進(jìn)這個隊列赃份。如果這個watcher被觸發(fā)多次,只會被推送到隊列一次奢米。這種緩沖行為可以有效的去掉重復(fù)數(shù)據(jù)造成的不必要的計算和DOm操作抓韩。而在下一個事件循環(huán)時,Vue會清空隊列鬓长,并進(jìn)行必要的DOM更新谒拴。
當(dāng)你設(shè)置 vm.someData = 'new value',DOM 并不會馬上更新涉波,而是在異步隊列被清除彪薛,也就是下一個事件循環(huán)開始時執(zhí)行更新時才會進(jìn)行必要的DOM更新茂装。如果此時你想要根據(jù)更新的 DOM 狀態(tài)去做某些事情,就會出現(xiàn)問題善延。少态。為了在數(shù)據(jù)變化之后等待 Vue 完成更新 DOM ,可以在數(shù)據(jù)變化之后立即使用 Vue.nextTick(callback) 易遣。這樣回調(diào)函數(shù)在 DOM 更新完成后就會調(diào)用彼妻。
vue.directive( id, [definition] )
注冊或獲取全局指令。
例子:
Vue.directive('my-directive', {
bind: function(){
//做綁定的準(zhǔn)備工作
//比如添加事件監(jiān)聽器豆茫,或是其他只需要執(zhí)行一次的復(fù)雜操作
},
inserted: function(){
//...
},
update: function(){
//根據(jù)獲得的新值執(zhí)行對應(yīng)的更新
//對于初始值也會調(diào)用一次
},
componentUpdated: function(){
//...
},
unbind: function(){
//做清理操作
//比如移除bind時綁定的事件監(jiān)聽器
}
當(dāng)指令的定義對象中只使用update時侨歉,只需直接傳入函數(shù)即可,如下:
Vue.directive('my-directive', function(){
//...
})
應(yīng)用
我們往往自定義指令都是定義到全局揩魂,方式如下:
第一步:建立一個全局的命令文件例如:directive/directives.js.
第二步:利用Vue.directive()建立一個全局命令幽邓,并將它暴露出來,例如一個focus 讓表單自動聚焦.
directives.js
import Vue from 'vue';
Vue.directive('focus',{
//當(dāng)綁定元素插入到DOM中
inserted: function(el){
el.focus(); //元素聚焦
el.setAttribute('placeholder','自定義內(nèi)容');
}
})
Vue.directive('***',{
inserted: function(el){
//....
}
})
export {Vue}
第三步:在main.js(入口JS文件)中將它引入火脉,可以省略文件后綴.
import directive from './components/global/directives';
這樣任何一個Vue文件只要這樣v-focus(命令名)牵舵,就可以很方便的用到了
<el-input v-model="input" placeholder="" v-focus></el-input>
如果指令需要傳值或者多個值
<body id="example">
<div id="demo" v-demo="{color : 'white',text : 'hello!'}"></div>
</body>
<script>
Vue.directive('demo',function(value){
console.info(value.color); //white
console.info(value.text) // hello!
})
var demo = new Vue({
el : '#demo'
})
</script>
Vue.filter( id, [definition] )
2.0中已經(jīng)廢棄了過濾器,需要我們自定義
<div id="app">
{{message|uppercase}}
</div>
//過濾器
Vue.filter('uppercase', function(value) {
if (!value) { return ''}
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
var vm = new Vue({
el:'#app',
data: {
message: 'test'
}
})
Vue.component
組件 (Component) 是 Vue.js 最強(qiáng)大的功能之一倦挂。組件可以擴(kuò)展 HTML 元素畸颅,封裝可重用的代碼。在較高層面上方援,組件是自定義元素没炒,Vue.js 的編譯器為它添加特殊功能。在有些情況下犯戏,組件也可以表現(xiàn)為用 is 特性進(jìn)行了擴(kuò)展的原生 HTML 元素送火。
所有的 Vue 組件同時也都是 Vue 的實例,所以可接受相同的選項對象 (除了一些根級特有的選項) 并提供相同的生命周期鉤子
組件在注冊之后先匪,便可以作為自定義元素 <my-component></my-component> 在一個實例的模板中使用漾脂。注意確保在初始化根實例之前注冊組件:
<div id="example">
<my-component></my-component>
</div>
// 注冊
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
// 創(chuàng)建根實例
new Vue({
el: '#example'
})
基礎(chǔ)
- 通過使用 v-once 指令,你也能執(zhí)行一次性地插值胚鸯,當(dāng)數(shù)據(jù)改變時,插值處的內(nèi)容不會更新笨鸡。但請留心這會影響到該節(jié)點(diǎn)上的其它數(shù)據(jù)綁定:
<span v-once>這個將不會改變: {{ msg }}</span>
- 原始HTML
雙大括號會將數(shù)據(jù)解釋為普通文本姜钳,而非 HTML 代碼。為了輸出真正的 HTML形耗,你需要使用 v-html 指令:
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p> // 會將對應(yīng)的color屬性等解析出來哥桥,不再是純粹的字符串
這個 span 的內(nèi)容將會被替換成為屬性值 rawHtml,直接作為 HTML——會忽略解析屬性值中的數(shù)據(jù)綁定激涤。注意拟糕,你不能使用 v-html 來復(fù)合局部模板判呕,因為 Vue 不是基于字符串的模板引擎。反之送滞,對于用戶界面 (UI)侠草,組件更適合作為可重用和可組合的基本單位。
- 使用JavaScript表達(dá)式
迄今為止犁嗅,在我們的模板中边涕,我們一直都只綁定簡單的屬性鍵值。但實際上褂微,對于所有的數(shù)據(jù)綁定功蜓,Vue.js 都提供了完全的 JavaScript 表達(dá)式支持。
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>
這些表達(dá)式會在所屬 Vue 實例的數(shù)據(jù)作用域下作為 JavaScript 被解析宠蚂。有個限制就是式撼,每個綁定都只能包含單個表達(dá)式,所以下面的例子都不會生效求厕。
<!-- 這是語句著隆,不是表達(dá)式 -->
{{ var a = 1 }}
<!-- 流控制也不會生效,請使用三元表達(dá)式 -->
{{ if (ok) { return message } }}
- 指令
指令 (Directives) 是帶有 v- 前綴的特殊屬性甘改。指令屬性的值預(yù)期是單個 JavaScript 表達(dá)式 (v-for 是例外情況旅东,稍后我們再討論)。指令的職責(zé)是十艾,當(dāng)表達(dá)式的值改變時抵代,將其產(chǎn)生的連帶影響,響應(yīng)式地作用于 DOM忘嫉』珉梗回顧我們在介紹中看到的例子:
<p v-if="seen">現(xiàn)在你看到我了</p>
這里,v-if 指令將根據(jù)表達(dá)式 seen 的值的真假來插入/移除 <p> 元素庆冕。
參數(shù)
一些指令能夠接收一個“參數(shù)”康吵,在指令名稱之后以冒號表示。例如访递,v-bind 指令可以用于響應(yīng)式地更新 HTML 屬性:
<a v-bind:href="url">...</a>
在這里 href 是參數(shù)晦嵌,告知 v-bind 指令將該元素的 href 屬性與表達(dá)式 url 的值綁定。
另一個例子是 v-on 指令拷姿,它用于監(jiān)聽 DOM 事件:
<a v-on:click="doSomething">...</a>
修飾符
修飾符 (Modifiers) 是以半角句號 . 指明的特殊后綴惭载,用于指出一個指令應(yīng)該以特殊方式綁定。例如响巢,.prevent 修飾符告訴 v-on 指令對于觸發(fā)的事件調(diào)用 event.preventDefault():
<form v-on:submit.prevent="onSubmit">...</form>
- 縮寫
v-bind:
<!-- 完整語法 -->
<a v-bind:href="url">...</a>
<!-- 縮寫 -->
<a :href="url">...</a>
v-on:
<!-- 完整語法 -->
<a v-on:click="doSomething">...</a>
<!-- 縮寫 -->
<a @click="doSomething">...</a>
它們看起來可能與普通的 HTML 略有不同描滔,但 : 與 @ 對于特性名來說都是合法字符,在所有支持 Vue.js 的瀏覽器都能被正確地解析踪古。而且含长,它們不會出現(xiàn)在最終渲染的標(biāo)記中券腔。縮寫語法是完全可選的拘泞,但隨著你更深入地了解它們的作用纷纫,你會慶幸擁有它們。
-
計算屬性
的表達(dá)式非常便利田弥,但是設(shè)計它們的初衷是用于簡單運(yùn)算的涛酗。在模板中放入太多的邏輯會讓模板過重且難以維護(hù)。
計算屬性例子:
div id="app">
<p>{{ message }}</p>
<p>{{ reversedMessage }}</p> // olleH
<p>{{ reversedMessage2}}</p> // 579
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello'
},
computed: {
// 計算屬性的 getter
reversedMessage: function () {
// `this` 指向 vm 實例
return this.message.split('').reverse().join('')
},
reversedMessage2: function () {
// `this` 指向 vm 實例
return 123 + 456
}
}
});
</script>
你可能已經(jīng)注意到我們可以通過在表達(dá)式中調(diào)用方法來達(dá)到同樣的效果:
<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在組件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
結(jié)論:
我們可以將同一函數(shù)定義為一個方法而不是一個計算屬性偷厦。兩種方式的最終結(jié)果確實是完全相同的商叹。然而,不同的是計算屬性是基于它們的依賴進(jìn)行緩存的只泼。計算屬性只有在它的相關(guān)依賴發(fā)生改變時才會重新求值剖笙。這就意味著只要 message 還沒有發(fā)生改變,多次訪問 reversedMessage 計算屬性會立即返回之前的計算結(jié)果请唱,而不必再次執(zhí)行函數(shù)弥咪。
相比之下,每當(dāng)觸發(fā)重新渲染時十绑,調(diào)用方法將總會再次執(zhí)行函數(shù)聚至。
我們?yōu)槭裁葱枰彺妫考僭O(shè)我們有一個性能開銷比較大的的計算屬性 A本橙,它需要遍歷一個巨大的數(shù)組并做大量的計算扳躬。然后我們可能有其他的計算屬性依賴于 A 。如果沒有緩存甚亭,我們將不可避免的多次執(zhí)行 A 的 getter贷币!如果你不希望有緩存,請用方法來替代亏狰。
Vue 提供了一種更通用的方式來觀察和響應(yīng) Vue 實例上的數(shù)據(jù)變動:偵聽屬性役纹。當(dāng)你有一些數(shù)據(jù)需要隨著其它數(shù)據(jù)變動而變動時,你很容易濫用 watch——特別是如果你之前使用過 AngularJS暇唾。然而促脉,通常更好的做法是使用計算屬性而不是命令式的 watch 回調(diào)。細(xì)想一下這個例子:
<div id="demo">{{ fullName }}</div>
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
}
}
})
watch下邊的屬性值就是要檢測的變量
上面代碼是命令式且重復(fù)的策州。將它與計算屬性的版本進(jìn)行比較:
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
好得多了瘸味,不是嗎?
計算屬性默認(rèn)只有 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]
}
}
}
對象語法
數(shù)組語法
用在組件上
對象語法
數(shù)組語法
自動添加前綴
多重值
在 Vue 中,我們使用 v-if 指令實現(xiàn)同樣的功能
<h1 v-if="ok">Yes</h1>
也可以用 v-else 添加一個“else 塊”:
<h1 v-if="ok">Yes</h1>
<h1 v-else>No</h1>
-
在
<template>
元素上使用v-if
條件渲染分組
因為 v-if 是一個指令锰什,所以必須將它添加到一個元素上下硕。但是如果想切換多個元素呢丁逝?此時可以把一個 <template> 元素當(dāng)做不可見的包裹元素,并在上面使用 v-if梭姓。最終的渲染結(jié)果將不包含 <template> 元素霜幼。
<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 的元素的后面,否則它將不會被識別誉尖。
-
用
key
管理可復(fù)用的元素
Vue 會盡可能高效地渲染元素罪既,通常會復(fù)用已有元素而不是從頭開始渲染。這么做除了使 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>
這樣也不總是符合實際需求驹针,所以 Vue 為你提供了一種方式來表達(dá)“這兩個元素是完全獨(dú)立的,不要復(fù)用它們”诀艰。只需添加一個具有唯一值的 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>
現(xiàn)在,每次切換時其垄,輸入框都將被重新渲染苛蒲。請看:
意克懊,<label> 元素仍然會被高效地復(fù)用,因為它們沒有添加 key 屬性弄匕。
另一個用于根據(jù)條件展示元素的選項是 v-show 指令。用法大致一樣:
<h1 v-show="ok">Hello!</h1>
不同的是帶有 v-show 的元素始終會被渲染并保留在 DOM 中芙贫。v-show 只是簡單地切換元素的 CSS 屬性 display搂鲫。
v-if 是“真正”的條件渲染,因為它會確保在切換過程中條件塊內(nèi)的事件監(jiān)聽器和子組件適當(dāng)?shù)乇讳N毀和重建磺平。
v-if 也是惰性的:如果在初始渲染時條件為假魂仍,則什么也不做——直到條件第一次變?yōu)檎鏁r,才會開始渲染條件塊拣挪。
相比之下擦酌,v-show 就簡單得多——不管初始條件是什么,元素總是會被渲染菠劝,并且只是簡單地基于 CSS 進(jìn)行切換赊舶。
一般來說,v-if 有更高的切換開銷赶诊,而 v-show 有更高的初始渲染開銷笼平。因此,如果需要非常頻繁地切換舔痪,則使用 v-show 較好寓调;如果在運(yùn)行時條件很少改變,則使用 v-if 較好锄码。
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
</div>
父組件傳值到子組件:
組件實例的作用域是孤立的夺英。這意味著不能 (也不應(yīng)該) 在子組件的模板內(nèi)直接引用父組件的數(shù)據(jù)。父組件的數(shù)據(jù)需要通過 prop 才能下發(fā)到子組件中滋捶。
子組件要顯式地用 props
選項聲明它預(yù)期的數(shù)據(jù):
子組件的寫法:(props是用來接收數(shù)據(jù)的)
Vue.component('child', {
// 聲明 props
props: ['message'],
// 就像 data 一樣痛悯,prop 也可以在模板中使用
// 同樣也可以在 vm 實例中通過 this.message 來使用
template: '<span>{{ message }}</span>'
})
在父組件里邊引用子組件的寫法
<child message="hello!"></child>
結(jié)果:
hello!
-
自定義事件
子組件傳值到父組件
(https://cn.vuejs.org/v2/guide/components.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E4%BA%8B%E4%BB%B6 "自定義事件")
我們知道,父組件使用 prop 傳遞數(shù)據(jù)給子組件重窟。但子組件怎么跟父組件通信呢载萌?這個時候 Vue 的自定義事件系統(tǒng)就派得上用場了。
另外,父組件可以在使用子組件的地方直接用 v-on 來監(jiān)聽子組件觸發(fā)的事件(子組件傳值到父組件)
在子組件里邊
export default{
methods: {
onfilter(){
this.$emit("listenTochildEvent","browse");
},
}
}
在父組件:
<privateScoreTop :msg ="Widget" v-on:listenTochildEvent="showMessageFromChild"></privateScoreTop>
showMessageFromChild(data){
alert(data);
}
注意:不能用 $on 監(jiān)聽子組件釋放的事件扭仁,而必須在模板里直接用 v-on 綁定
有時候可缚,你可能想在某個組件的根元素上監(jiān)聽一個原生事件≌啵可以使用 v-on 的修飾符 .native。例如:
<my-component v-on:click.native="doTheThing"></my-component>
有時候知给,非父子關(guān)系的兩個組件之間也需要通信瓤帚。在簡單的場景下,可以使用一個空的 Vue 實例作為事件總線:
// 根組件(this.$root)
new Vue({
el: '#app',
router,
render: h => h(App),
data: {
// 空的實例放到根組件下涩赢,所有的子組件都能調(diào)用
Bus: new Vue()
}
})
// 觸發(fā)組件 A 中的事件
<button @click="submit">提交<button>
methods: {
submit() {
// 事件名字自定義戈次,用不同的名字區(qū)別事件
this.$root.Bus.$emit('eventName', 123)
}
}
// 在組件 B 創(chuàng)建的鉤子中監(jiān)聽事件
// 當(dāng)前實例創(chuàng)建完成就監(jiān)聽這個事件
created(){
this.$root.Bus.$on('eventName', value => {
this.print(value)
})
},
methods: {
print(value) {
console.log(value)
}
},
// 在組件銷毀時別忘了解除事件綁定
beforeDestroy() {
this.$root.Bus.$off('eventName')
},
例子:
在一個彈窗里邊修改了對應(yīng)的游戲詳情,修改成功之后筒扒,直接發(fā)送事件給游戲列表怯邪,讓游列表進(jìn)行刷新,達(dá)到適時修改的目的花墩。
<div id="app">
<h1>我是父組件的標(biāo)題</h1>
<childcomponent>
<!--如果組件里邊沒有值,slot就會插入進(jìn)來悬秉,如果有,就不會插入冰蘑,類似placeholder的占位符-->
<!--<p>我不是slot和泌,而是插值</p>-->
</childcomponent>
</div>
<script>
Vue.component('childcomponent',{
template:'<div><h2>我是子組件的標(biāo)題</h2><slot><div>我是子組件中slot值</div></slot></div>'
});
new Vue({
el:'#app'
})
</script>
結(jié)論:當(dāng)沒有插值時就解析slot中的代碼,有插值時就不解析slot中的代碼祠肥。最初在 <slot> 標(biāo)簽中的任何內(nèi)容都被視為備用內(nèi)容武氓。備用內(nèi)容在子組件的作用域內(nèi)編譯,并且只有在宿主元素為空仇箱,且沒有要插入的內(nèi)容時才顯示備用內(nèi)容县恕。
1.基本用法:vue2.0提供了一個keep-alive組件
用來緩存組件,避免多次加載相應(yīng)的組件,減少性能消耗
<keep-alive>
<component>
<!-- 組件將被緩存 -->
</component>
</keep-alive>
有時候 可能需要緩存整個站點(diǎn)的所有頁面,而頁面一般一進(jìn)去都要觸發(fā)請求的
在使用keep-alive的情況下
<keep-alive><router-view></router-view></keep-alive>
將首次觸發(fā)請求寫在created鉤子函數(shù)中,就能實現(xiàn)緩存,
比如列表頁,去了詳情頁 回來,還是在原來的頁面
2.緩存部分頁面或者組件
(1)使用router. meta屬性
// 這是目前用的比較多的方式
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
router設(shè)置:
routes: [
{ path: '/', redirect: '/index', component: Index, meta: { keepAlive: true }},
{
path: '/common',
component: TestParent,
children: [
{ path: '/test2', component: Test2, meta: { keepAlive: true } }
]
}
// 表示index和test2都使用keep-alive
(2).使用新增屬性inlcude/exclude
2.1.0后提供了include/exclude兩個屬性 可以針對性緩存相應(yīng)的組件
<!-- comma-delimited string -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- regex (use v-bind) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
//其中a,b是組件的name
注意:這種方法都是預(yù)先知道組件的名稱的
(2)動態(tài)判斷
<keep-alive :include="includedComponents">
<router-view></router-view>
</keep-alive>
includedComponents動態(tài)設(shè)置即可
-
自定義指令
除了核心功能默認(rèn)內(nèi)置的指令 (v-model 和 v-show),Vue 也允許注冊自定義指令剂桥。注意忠烛,在 Vue2.0 中,代碼復(fù)用和抽象的主要形式是組件渊额。然而况木,有的情況下,你仍然需要對普通 DOM 元素進(jìn)行底層操作旬迹,這時候就會用到自定義指令火惊。舉個聚焦輸入框的例子,如下:
當(dāng)頁面加載時奔垦,該元素將獲得焦點(diǎn) (注意:autofocus 在移動版 Safari 上不工作)屹耐。事實上,只要你在打開這個頁面后還沒點(diǎn)擊過任何內(nèi)容,這個輸入框就應(yīng)當(dāng)還是處于聚焦?fàn)顟B(tài)』塘耄現(xiàn)在讓我們用指令來實現(xiàn)這個功能:
// 注冊一個全局自定義指令 `v-focus`
Vue.directive('focus', {
// 當(dāng)被綁定的元素插入到 DOM 中時……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
如果想注冊局部指令寿弱,組件中也接受一個 directives 的選項:
directives: {
focus: {
// 指令的定義
inserted: function (el) {
el.focus()
}
}
}
然后你可以在模板中任何元素上使用新的 v-focus 屬性,如下:
<input v-focus>
在Vue 中可以把一系列復(fù)雜的操作包裝為一個指令按灶。
什么是復(fù)雜的操作症革?
我的理解是:復(fù)雜邏輯功能的包裝、違背數(shù)據(jù)驅(qū)動的 DOM 操作以及對一些 Hack 手段的掩蓋等鸯旁。我們總是期望以操作數(shù)據(jù)的形式來實現(xiàn)功能邏輯噪矛。
鉤子函數(shù)
對于自定義指令的定義,Vue2 有 5 個可選的鉤子函數(shù)铺罢。
bind: 只調(diào)用一次艇挨,指令第一次綁定到元素時調(diào)用,用這個鉤子函數(shù)可以定義一個在綁定時執(zhí)行一次的初始化動作韭赘。
inserted: 被綁定元素插入父節(jié)點(diǎn)時調(diào)用(父節(jié)點(diǎn)存在即可調(diào)用缩滨,不必存在于 document 中)。
update: 被綁定元素所在的模板更新時調(diào)用泉瞻,而不論綁定值是否變化脉漏。
componentUpdated: 被綁定元素所在模板完成一次更新周期時調(diào)用。
unbind: 只調(diào)用一次袖牙,指令與元素解綁時調(diào)用鸠删。
template
<div id="app">
<my-comp v-if="msg" :msg="msg"></my-comp>
<button @click="update">更新</button>
<button @click="uninstall">卸載</button>
<button @click="install">安裝</button>
</div>
script(通過輸出的結(jié)果判斷觸發(fā)的時機(jī))
Vue.directive('hello', {
bind: function (el) {
console.log('bind')
},
inserted: function (el) {
console.log('inserted')
},
update: function (el) {
console.log('update')
},
componentUpdated: function (el) {
console.log('componentUpdated')
},
unbind: function (el) {
console.log('unbind')
}
})
var myComp = {
template: '<h1 v-hello>{{msg}}</h1>',
// 傳遞數(shù)據(jù)
props: {
msg: String
}
}
new Vue({
el: '#app',
data: {
msg: 'Hello'
},
components: {
myComp: myComp
},
methods: {
update: function () {
this.msg = 'Hi'
},
uninstall: function () {
this.msg = ''
},
install: function () {
this.msg = 'Hello'
}
}
})
結(jié)論:
頁面加載時:bind inserted
點(diǎn)擊“更新”按鈕,更改數(shù)據(jù)觸發(fā)組件更新贼陶。
update
componentUpdated
卸載組件時
點(diǎn)擊“卸載”按鈕刃泡,數(shù)據(jù)置空否定判斷以觸發(fā)組件卸載。
unbind
卸載組件時
點(diǎn)擊“卸載”按鈕碉怔,數(shù)據(jù)置空否定判斷以觸發(fā)組件卸載烘贴。
unbind
重新安裝組件時
點(diǎn)擊“安裝”按鈕,數(shù)據(jù)賦值肯定判斷以觸發(fā)組件重新安裝撮胧。
bind
inserted
區(qū)別:
從案例的運(yùn)行中桨踪,對 5 個鉤子函數(shù)的觸發(fā)時機(jī)有了初步的認(rèn)識。存疑的也就是bind和inserted芹啥、update和componentUpdated的區(qū)別了锻离。
bind 和 inserted:
據(jù)文檔所說,插入父節(jié)點(diǎn)時調(diào)用 inserted墓怀,來個測試汽纠。
bind: function (el) {
console.log(el.parentNode) // null
console.log('bind')
},
inserted: function (el) {
console.log(el.parentNode) // <div id="app">...</div>
console.log('inserted')
}
分別在兩個鉤子函數(shù)中輸出父節(jié)點(diǎn):bind 時父節(jié)點(diǎn)為 null,inserted 時父節(jié)點(diǎn)存在傀履。
update 和 componentUpdated
關(guān)于這兩個的介紹虱朵,從字眼上看感覺是組件更新周期有關(guān)穷躁,繼續(xù)驗證僻焚。
update: function (el) {
console.log(el.innerHTML) // Hello
console.log('update')
},
componentUpdated: function (el) {
console.log(el.innerHTML) // Hi
console.log('componentUpdated')
}
沒毛病,update 和 componentUpdated 就是組件更新前和更新后的區(qū)別寞缝。
最佳實踐
根據(jù)需求的不同窜觉,我們要選擇恰當(dāng)?shù)臅r機(jī)去初始化指令科贬、更新指令調(diào)用參數(shù)以及釋放指令存在時的內(nèi)存占用等府适。
比較常見的場景是:用指令包裝一些無依賴的第三方庫以擴(kuò)展組件功能唯绍。而一個健壯的庫通常會包含:初始化實例、參數(shù)更新和釋放實例資源占用等操作偿荷。
Vue.directive('hello', {
bind: function (el, binding) {
// 在 bind 鉤子中初始化庫實例
// 如果需要使用父節(jié)點(diǎn)治专,也可以在 inserted 鉤子中執(zhí)行
el.__library__ = new Library(el, binding.value)
},
update: function (el, binding) {
// 模版更新意味著指令的參數(shù)可能被改變,這里可以對庫實例的參數(shù)作更新
// 酌情使用 update 或 componentUpdated 鉤子
el.__library__.setOptions(Object.assign(binding.oldValue, binding.value))
},
unbind: function (el) {
// 釋放實例
el.__library__.destory()
}
})
這是一個使用了這些屬性的自定義鉤子樣例:
<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
}
})
new Vue({
el: '#hook-arguments-example',
data: {
message: 'hello!'
}
})
函數(shù)簡寫
在很多時候遭顶,你可能想在 bind 和 update 時觸發(fā)相同行為,而不關(guān)心其它的鉤子泪蔫。比如這樣寫:
Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value
})
對象字面量
如果指令需要多個值棒旗,可以傳入一個 JavaScript 對象字面量。記住撩荣,指令函數(shù)能夠接受所有合法的 JavaScript 表達(dá)式铣揉。
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
Vue.directive('demo', function (el, binding) {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})
插件
開發(fā)插件
插件通常會為 Vue 添加全局功能。插件的范圍沒有限制——一般有下面幾種:
添加全局方法或者屬性餐曹,如: vue-custom-element
添加全局資源:指令/過濾器/過渡等逛拱,如 vue-touch
通過全局 mixin 方法添加一些組件選項,如: vue-router
添加 Vue 實例方法台猴,通過把它們添加到 Vue.prototype 上實現(xiàn)朽合。
一個庫,提供自己的 API饱狂,同時提供上面提到的一個或多個功能曹步,如 vue-router
Vue.js 的插件應(yīng)當(dāng)有一個公開方法 install
。這個方法的第一個參數(shù)是 Vue
構(gòu)造器休讳,第二個參數(shù)是一個可選的選項對象:
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或?qū)傩? Vue.myGlobalMethod = function () {
// 邏輯...
}
// 2. 添加全局資源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 邏輯...
}
...
})
// 3. 注入組件
Vue.mixin({
created: function () {
// 邏輯...
}
...
})
// 4. 添加實例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 邏輯...
}
}
使用插件
通過全局方法 Vue.use() 使用插件:
// 調(diào)用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)
也可以傳入一個選項對象:
Vue.use(MyPlugin, { someOption: true })
Vue.use 會自動阻止多次注冊相同插件讲婚,屆時只會注冊一次該插件。
Vue.js 官方提供的一些插件 (例如 vue-router) 在檢測到 Vue 是可訪問的全局變量時會自動調(diào)用 Vue.use()俊柔。然而在例如 CommonJS 的模塊環(huán)境中筹麸,你應(yīng)該始終顯式地調(diào)用 Vue.use():
// 用 Browserify 或 webpack 提供的 CommonJS 模塊環(huán)境時
var Vue = require('vue')
var VueRouter = require('vue-router')
// 不要忘了調(diào)用此方法
Vue.use(VueRouter)
awesome-vue 集合了來自社區(qū)貢獻(xiàn)的數(shù)以千計的插件和庫。