前言
記錄平時學到的知識氛堕,標題寫的大氣一點枪芒,也算是給自己一點鼓勵,希望在技術這條路可以遠走越遠挺庞,路越走越寬~
PS:如果對你有一點幫助,請順手給個小星星哦稼病,鼓勵我繼續(xù)寫下去~
引入的文件文件說明
vue.js——開發(fā)版本:包含完整的警告和調試模式
vue.min.js——生產(chǎn)版本:刪除了警告选侨,進行了壓縮
1、全局api
全局API并不在構造器里然走,而是先聲明全局變量或者直接在Vue上定義一些新功能援制,Vue內置了一些全局API。說的簡單些就是芍瑞,在構造器外部用Vue提供給我們的API函數(shù)來定義新的功能晨仑。
1.1 Vue.directive
除了Vue提供的內部指令,還可以根據(jù)Vue提供的全局api來定義一些屬于自己的指令。比如定義一個change指令洪己,作用就是讓文字顏色變成紅色妥凳。
demo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue.directive 自定義指令</title>
<script type="text/javascript" src="../assets/js/vue.js"></script>
</head>
<body>
<h1>Vue.directive 自定義指令</h1>
<hr>
<div id="app">
<div v-change="color">{{num}}</div>
<p><button @click="add">ADD</button></p>
</div>
<script type="text/javascript">
var app = new Vue({
el: '#app',
data: {
num: 10
},
methods: {
add: function() {
this.num++
}
}
})
</script>
</body>
</html>
接下來定義一個全局指令change讓文字變色,這里使用Vue.directive();來定義全局指令:
//如果在 bind 和 update 時觸發(fā)相同行為答捕,而不關心其它的鉤子逝钥,可以簡寫成這種形式
Vue.directive('change',function(el,binding,vnode, oldVnode){
el.style='color:'+binding.value;
});
使用聲明周期鉤子:
Vue.directive("change", {
bind:function(el, binding) {//被綁定
console.log('1 - bind')
el.style="color:"+binding.value
},
inserted: function() {//綁定到節(jié)點
console.log('2 - inserted')
},
update:function(){//組件更新
console.log('3 - update');
},
componentUpdated:function(){//組件更新完成
console.log('4 - componentUpdated');
},
unbind:function(){//解綁
console.log('5 - unbind');
}
})
寫完之后可以看到數(shù)字已經(jīng)變成了綠色,說明自定義指令起到了作用拱镐。
自定義指令中傳遞的四個個參數(shù):
el: 指令所綁定的元素艘款,可以用來直接操作DOM。
binding: 一個對象沃琅,包含指令的很多信息哗咆。
vnode:Vue 編譯生成的虛擬節(jié)點。
oldVnode:上一個虛擬節(jié)點益眉,僅在 update 和 componentUpdated 鉤子中可用晌柬。
自定義指令的生命周期:
自定義指令有五個生命周期(也叫鉤子函數(shù)),分別是 bind,inserted,update,componentUpdated,unbind
- bind:只調用一次呜叫,指令第一次綁定到元素時調用空繁,用這個鉤子函數(shù)可以定義一個綁定時執(zhí)行一次的初始化動作。
- inserted:被綁定元素插入父節(jié)點時調用(父節(jié)點存在即可調用朱庆,不必存在于document中)盛泡。
- update:被綁定于元素所在的模板更新時調用,而無論綁定值是否變化娱颊。通過比較更新前后的綁定值傲诵,可以忽略不必要的模板更新。
- componentUpdated:被綁定元素所在模板完成一次更新周期時調用箱硕。
- unbind:只調用一次拴竹,指令與元素解綁時調用。
bind:function(){//被綁定
console.log('1 - bind');
},
inserted:function(){//綁定到節(jié)點
console.log('2 - inserted');
},
update:function(){//組件更新
console.log('3 - update');
},
componentUpdated:function(){//組件更新完成
console.log('4 - componentUpdated');
},
unbind:function(){//解綁
console.log('5 - unbind');
}
1.2 Vue.extend
Vue.extend 返回的是一個“擴展實例構造器”,也就是預設了部分選項的Vue實例構造器剧罩。經(jīng)常服務于Vue.component用來生成組件栓拜,可以簡單理解為當在模板中遇到該組件名稱作為標簽的自定義元素時,會自動調用“擴展實例構造器”來生產(chǎn)組件實例惠昔,并掛載到自定義元素上幕与。
Vue 的構造函數(shù)可接收的大部分選項都能在 Vue.extend() 中使用,不過也有兩個特例:data 和 el镇防。由于每個 Vue 的實例都應該有自己的 $data
和$el
啦鸣,我們顯然不希望傳遞給 Vue.extend() 的值被所有通過這個構造函數(shù)創(chuàng)建的實例所共享。因此如果要定義組件初始化默認數(shù)據(jù)和元素的方式来氧,應該傳入一個函數(shù):
搭配Vue.component使用:
// 擴展 Vue 得到一個可復用的構造函數(shù)
var MyComponent = Vue.extend({
template: '<p>{{title}} a custom component!</p>',
data: function () {
return {
title: 'Hello!'
}
}
})
接下來诫给,就可以用 Vue.component() 來注冊這個構造函數(shù):
// 注冊組件香拉,傳入擴展構造器
Vue.component('my-component', MyComponent)
擴展實例demo:
//Vue.extend 返回的是一個“擴展實例構造器”,也就是一個預設了部分選項的 Vue 實例構造器
var authorExtend = Vue.extend({
template: "<p><a :href='authorUrl'>{{authorName}}</a></p>",
data: function() {
return {
authorName: 'zaishuiyixia',
authorUrl: 'http://www.reibang.com/u/6d5f3f6492f8'
}
}
});
想要展示在頁面上中狂,還需要把擴展實例掛載到元素上凫碌。
new authorExtend().$mount('#author');
還可以通過HTML標簽或者標簽的class來生成擴展實例構造器,Vue.extend里的代碼是一樣的吃型,只是在掛載的時候证鸥,我們用類似jquery的選擇器的方法,來進行掛載就可以了勤晚。
new authorExtend().$mount('.extend');
完整代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue.extend 擴展實例構造器</title>
<script type="text/javascript" src="../assets/js/vue.js"></script>
</head>
<body>
<h1>Vue.extend 擴展實例構造器</h1>
<hr>
<div id="author" class="extend"></div>
<script type="text/javascript">
//Vue.extend 返回的是一個“擴展實例構造器”枉层,也就是一個預設了部分選項的 Vue 實例構造器
var authorExtend = Vue.extend({
template: "<p><a :href='authorUrl'>{{authorName}}</a></p>",
data: function() {
return {
authorName: 'zaishuiyixia',
authorUrl: 'http://www.reibang.com/u/6d5f3f6492f8'
}
}
});
//調用 new authorExtend 構造函數(shù)來生成組件實例,并掛載到元素上
new authorExtend().$mount('#author');
//調用 new authorExtend 構造函數(shù)來生成組件實例赐写,并掛載到元素上
// var vm = new authorExtend({
// el: '#author'
// })
</script>
</body>
</html>
1.3 Vue.set
當一個 Vue 實例被創(chuàng)建時鸟蜡,它向 Vue 的響應式系統(tǒng)中加入了其 data 對象中能找到的所有的屬性。當這些屬性的值發(fā)生改變時挺邀,視圖將會產(chǎn)生“響應”揉忘,即匹配更新為新的值。
// 我們的數(shù)據(jù)對象
var data = { a: 1 }
// 該對象被加入到一個 Vue 實例中
var vm = new Vue({
data: data
})
// 獲得這個實例上的屬性
// 返回源數(shù)據(jù)中對應的字段
vm.a == data.a // => true
// 設置屬性也會影響到原始數(shù)據(jù)
vm.a = 2
data.a // => 2
// ……反之亦然
data.a = 3
vm.a // => 3
當這些數(shù)據(jù)改變時端铛,視圖會進行重渲染泣矛。值得注意的是只有當實例被創(chuàng)建時 data 中存在的屬性才是響應式的。也就是說如果你添加一個新的屬性禾蚕,比如:
vm.b = 'hi'
那么對 b 的改動將不會觸發(fā)任何視圖的更新您朽。
如果我就是希望新添加的屬性也是響應式的,應該怎么辦呢换淆?
Vue.set就是來解決這個問題的哗总。
Vue.set 的作用就是向響應式對象中添加一個屬性,并確保這個新屬性同樣是響應式的倍试,且觸發(fā)視圖更新讯屈。它主要用于向響應式對象上添加新屬性,因為 Vue 無法探測普通的新增屬性 县习。也可以通過Vue.set在構造器外部操作構造器內部的數(shù)據(jù)涮母、屬性或者方法。
什么是外部數(shù)據(jù)躁愿,就是不在Vue構造器里里的data處聲明哈蝇,而是在構造器外部聲明,然后在data處引用就可以了攘已。外部數(shù)據(jù)的加入讓程序更加靈活,我們可以在外部獲取任何想要的數(shù)據(jù)形式怜跑,然后讓data引用:
//在構造器外部聲明數(shù)據(jù)
var outData={
count:1,
goodName:'zaishuiyixia'
};
var app=new Vue({
el:'#app',
//引用外部數(shù)據(jù)
data:outData
})
在外部改變數(shù)據(jù)的三種方法:
1样勃、用Vue.set改變
function add(){
Vue.set(outData,'count',4);
}
2吠勘、用Vue對象的方法添加
app.count++;
3、直接操作外部數(shù)據(jù)
outData.count++;
Vue.set存在的意義:
由于Javascript的限制峡眶,Vue不能自動檢測以下變動的數(shù)組剧防。
- 當你利用索引直接設置一個項時,vue不會為我們自動更新辫樱。
- 當你修改數(shù)組的長度時峭拘,vue不會為我們自動更新。
example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>Vue.set 全局api</title>
</head>
<body>
<h1>Vue.set 全局api</h1>
<hr>
<div id="app">
<ul>
<li v-for=" aa in arr">{{aa}}</li>
</ul>
</div>
<button onclick="add()">外部添加</button>
<script type="text/javascript">
function add(){
console.log("我已經(jīng)執(zhí)行了");
app.arr[1]='ddd';
//Vue.set(app.arr,1,'ddd');
}
var outData={
arr:['aaa','bbb','ccc']
};
var app=new Vue({
el:'#app',
data:outData
})
</script>
</body>
</html>
這時我們的界面是不會自動跟新數(shù)組的狮暑,我們需要用Vue.set(app.arr,1,’ddd’)來設置改變鸡挠,vue才會給我們自動更新,這就是Vue.set存在的意義搬男。
另一個代碼例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>Vue.set 全局api</title>
</head>
<body>
<h1>Vue.set 全局api</h1>
<hr>
<div id="app">
<ul>
<li v-for=" aa in arr">{{aa}}</li>
</ul>
<hr>
<p v-for="item in items" :key="item.id">
{{item.message}}
</p>
<!--@click等價于v-on:click-->
<button class="btn" @click="btn1Click()">點我試試</button>
<br/>
</div>
<button onclick="add()">外部添加</button>
<script type="text/javascript">
function add(){
console.log("我已經(jīng)執(zhí)行了");
app.arr[1]='ddd';
//Vue.set(app.arr,1,'ddd');
}
var outData={
arr:['aaa','bbb','ccc'],
items:[
{message:"Test one",id:"1"},
{message:"Test two",id:"2"},
{message:"Test three",id:"3"}
]
};
var app=new Vue({
el:'#app',
data:outData,
methods:{
btn1Click:function(){
//為data中的items動態(tài)新增一條數(shù)據(jù)
this.items.push({message:"動態(tài)新增"});
}
}
})
</script>
</body>
</html>
點擊之后試圖更新拣展,列表新增了一條數(shù)據(jù),通過數(shù)組的變異方法( Vue數(shù)組變異方法:push()缔逛、pop()备埃、shift()、unshift()褐奴、splice()按脚、sort()、reverse() )我們可以動態(tài)控制數(shù)據(jù)的增減敦冬,但是卻無法做到對某一條數(shù)據(jù)的修改辅搬。這時候就也會用到Vue的內置方法Vue.set。
Vue.set( target, key, value ) 響應式新增與修改數(shù)據(jù):
- target:{Object | Array} 要更改的數(shù)據(jù)源(可以是對象或者數(shù)組)
- key:{Object | Array} 要更改的具體數(shù)據(jù)
- value :重新賦的值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>Vue.set 全局api</title>
</head>
<body>
<h1>Vue.set 全局api</h1>
<hr>
<div id="app">
<ul>
<li v-for=" aa in arr">{{aa}}</li>
</ul>
<button onclick="add()">外部添加</button>
<br/>
<hr>
<p v-for="item in items" :key="item.id">
{{item.message}}
</p>
<!--@click等價于v-on:click-->
<button class="btn" @click="btn1Click()">點我試試</button>
<br/>
<br/>
<button class="btn" @click="btn2Click()">動態(tài)賦值</button>
<br/>
<br/>
<button class="btn" @click="btn3Click()">為data新增屬性</button>
<br/>
<br/>
<button class="btn" @click="btn4Click()">通過數(shù)組下表修改數(shù)據(jù)</button>
</div>
<script type="text/javascript">
function add(){
console.log("我已經(jīng)執(zhí)行了");
app.arr[1]='ddd';
//Vue.set(app.arr,1,'ddd');
}
var outData={
arr:['aaa','bbb','ccc'],
items:[
{message:"Test one",id:"1"},
{message:"Test two",id:"2"},
{message:"Test three",id:"3"}
]
};
var app=new Vue({
el:'#app',
data:outData,
methods:{
btn1Click:function(){
//為data中的items動態(tài)新增一條數(shù)據(jù)
this.items.push({message:"動態(tài)新增"});
console.log('btn1Click', this.items)
},
btn2Click:function(){
//Vue methods中的this 指向的是Vue的實例,這里可以直接在this中找到items
Vue.set(this.items,0,{message:"Change Test",id:'10'});
console.log('btn2Click', this.items)
},
btn3Click:function(){
var itemLen=this.items.length;
Vue.set(this.items,itemLen,{message:"Test add attr",id:itemLen});
console.log('btn3Click', this.items)
},
btn4Click:function(){
this.items[0]={message:"Change Test",id:'10'},
console.log('btn4Click', this.items)
}
}
})
</script>
</body>
</html>
點擊第一個按鈕后新增了一條數(shù)據(jù)虹统,此時點擊第二個按鈕將Test one更改為Change Test币绩。
可以看到列表中第一列的Test one已經(jīng)變成了Change Test。
當寫慣了JS之后蚤氏,有可能想改數(shù)組中某個下標的中的數(shù)據(jù)我直接this.items[XX]就改了,如:
btn4Click:function(){
this.items[0]={message:"Change Test",id:'10'}
}
點擊btn4Click按鈕時踊兜,通過打印出的數(shù)據(jù)可以看到竿滨,雖然數(shù)據(jù)已經(jīng)改變了,但是視圖沒有更新捏境。這是因為由于 JavaScript 的限制于游,當通過數(shù)組下標直接修改數(shù)據(jù)時,Vue 不能檢測出數(shù)據(jù)的改變垫言,所以當我們需要動態(tài)改變數(shù)據(jù)的時候贰剥,可以使用Vue.set()。
btn3Click:function(){
var itemLen=this.items.length;
Vue.set(this.items,itemLen,{message:"Test add attr",id:itemLen});
console.log('btn3Click', this.items)
}
點擊btn3Click按鈕可以看到視圖更新并且新增了一條數(shù)據(jù)筷频。
Vue.set()不光能修改數(shù)據(jù)蚌成,還能添加數(shù)據(jù)前痘,彌補了Vue數(shù)組變異方法的不足。
Vue.set()在methods中也可以寫成this.$set()
1.4 Vue的生命周期
Vue實例有一個完整的生命周期担忧,也就是從開始創(chuàng)建芹缔、初始化數(shù)據(jù)、編譯模板瓶盛、掛載Dom最欠、渲染→更新→渲染、銷毀等一系列過程惩猫,我們稱這是Vue的生命周期芝硬。通俗說就是Vue實例從創(chuàng)建到銷毀的過程,就是生命周期帆锋。
每一個組件或者實例都會經(jīng)歷一個完整的生命周期吵取,可以大致分為三個階段:初始化、運行中锯厢、銷毀皮官。
Vue一共有10個生命周期函數(shù),我們可以利用這些函數(shù)在vue的每個階段執(zhí)行一些操作实辑,例如操作數(shù)據(jù)或者改變內容捺氢。
beforeCreate:實例、組件通過new Vue() 創(chuàng)建出來之后會初始化生命周期剪撬,然后就會執(zhí)行beforeCreate鉤子函數(shù)摄乒,這個時候,數(shù)據(jù)還沒有掛載呢残黑,只是一個空殼馍佑,無法訪問到數(shù)據(jù)和真實的dom,一般不做操作梨水。
created:接下來初始化數(shù)據(jù)data拭荤,綁定事件(methods里面定義的方法),然后執(zhí)行created函數(shù)疫诽,這個時候已經(jīng)可以使用到數(shù)據(jù)舅世,也可以更改數(shù)據(jù),在這里更改數(shù)據(jù)不會觸發(fā)updated函數(shù),在這里可以在渲染前倒數(shù)第二次更改數(shù)據(jù)的機會奇徒,不會觸發(fā)其他的鉤子函數(shù)雏亚,一般可以在這里做(請求數(shù)據(jù))初始數(shù)據(jù)的獲取。
beforeMount: 接下來開始找實例或者組件對應的模板摩钙,編譯模板為虛擬dom放入到render函數(shù)中準備渲染罢低,然后執(zhí)行beforeMount鉤子函數(shù),在這個函數(shù)中虛擬dom已經(jīng)創(chuàng)建完成胖笛,馬上就要渲染,在這里也可以更改數(shù)據(jù)奕短,不會觸發(fā)updated宜肉,在這里可以在渲染前最后一次更改數(shù)據(jù)的機會,不會觸發(fā)其他的鉤子函數(shù)翎碑,在這里做初始數(shù)據(jù)的更改,也可以做初始數(shù)據(jù)的獲取之斯。
mounted:接下來開始render日杈,渲染出真實dom,然后執(zhí)行mounted鉤子函數(shù)佑刷,此時莉擒,組件已經(jīng)出現(xiàn)在頁面中,數(shù)據(jù)瘫絮、真實dom都已經(jīng)處理好了,事件都已經(jīng)掛載好了涨冀,可以在這里操作真實dom等事情...
beforeUpdate:當組件或實例的數(shù)據(jù)更改之后,會立即執(zhí)行beforeUpdate麦萤,然后vue的虛擬dom機制會重新構建虛擬dom與上一次的虛擬dom樹利用diff算法進行對比之后重新渲染鹿鳖,一般不做什么事兒。
updated:當數(shù)據(jù)更新完成壮莹,重新渲染完成后翅帜,執(zhí)行updated,這是數(shù)據(jù)已經(jīng)更改完成命满,dom也重新render完成涝滴,可以操作更新后的真實dom。
activated:搭配keep-alive使用胶台。keep-alive是Vue的內置組件歼疮,能在組件切換過程中將狀態(tài)保留在內存中,防止切換回組件后重復渲染DOM诈唬。一般搭配路由或者組件使用韩脏,作用是路由或組件的內容被加載過一次之后,放到內存之中讯榕,下一此再進這個路由或者切換回這個組件的時候就不用重新渲染這個組件了骤素,繼而也就不會重新執(zhí)行鉤子函數(shù),也不會有像發(fā)送請求再次獲取數(shù)據(jù)這樣的操作了愚屁,只有當數(shù)據(jù)變化時济竹,才使用VirtualDOM進行diff更新。它會把以前的內容(數(shù)據(jù))從內存里拿出來顯示霎槐,繼而不用從新發(fā)請求渲染數(shù)據(jù)了送浊。包裹動態(tài)組件時,會緩組件實例丘跌,而不是銷毀它們袭景。
和<transition>
相似唁桩,<keep-alive>
是一個抽象組件:它自身不會渲染一個 DOM 元素,也不會出現(xiàn)在父組件鏈中耸棒。當?shù)谝淮芜M入keep-alive 頁面的時候荒澡,鉤子函數(shù)的觸發(fā)順序是:beforeCreate>created-> mounted-> activated,退出時觸發(fā)deactivated与殃。當再次進入時单山,只觸發(fā)activated。deactivated:與activated生命周期函數(shù)相對應的就是deactivated生命周期函數(shù)幅疼。它會在組件被替換米奸、頁面被隱藏(如跳到其他頁面)的時候執(zhí)行。
beforeDestroy:當經(jīng)過某種途徑調用$destroy方法后爽篷,立即執(zhí)行beforeDestroy悴晰,在組件或實例銷毀前執(zhí)行。一般在這里做一些善后工作逐工,例如清除計時器铡溪、清除非指令綁定的事件等等...
destroyed:在組件或實例銷毀后執(zhí)行,這時已經(jīng)解除了組件的數(shù)據(jù)綁定钻弄、指令綁定的事件監(jiān)聽...去掉后只剩下dom空殼佃却,在這里做善后工作也可以。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>vue的生命周期</title>
<script type="text/javascript" src="../assets/js/vue.js"></script>
</head>
<body>
<h1>vue的聲明周期</h1>
<hr>
<div id="app">
<p>{{ message }}</p>
<button @click="add">增加內容</button>
</div>
<br>
<button onclick="app.$destroy()">銷毀</button>
<script type="text/javascript">
var app = new Vue({
el: '#app',
data: {
message : "zaishuiyixia is boy"
},
methods: {
alert: function () {
console.log('events')
},
add:function () {
this.message += '!'
}
},
//beforeCreate:剛剛創(chuàng)建vue實例窘俺,這個時候饲帅,數(shù)據(jù)還沒有掛載,只是一個空殼
beforeCreate: function () {
console.group('beforeCreate 創(chuàng)建前狀態(tài)===============》');
console.log("%c%s", "color:red" , "el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //undefined
console.log("%c%s", "color:red","message: " + this.message) //undefined
console.log('beforeCreate: 剛剛new Vue()之后瘤泪,這個時候灶泵,數(shù)據(jù)還沒有掛載,只是一個空殼')
console.log('this.$methods',this.$methods) //undefined
// console.log(this.alert()) // 會報錯 this.alert is not a function
},
//created:掛載數(shù)據(jù)对途,綁定事件(methods里面定義的事件)赦邻,這個時候已經(jīng)可以使用到數(shù)據(jù),也可以更改數(shù)據(jù),在這里更改數(shù)據(jù)不會觸發(fā)updated函數(shù)
created: function () {
console.group('created 創(chuàng)建完畢狀態(tài)===============》');
console.log("%c%s", "color:red","el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
console.log(this.alert()) //可以執(zhí)行methods里定義的函數(shù)了 初始化事件
this.message = 'zaishuiyixia is a pretty handsome boy!'
console.log('更改數(shù)據(jù)',this.$data.message)
console.log('在這里可以在渲染前倒數(shù)第二次更改數(shù)據(jù)的機會实檀,不會觸發(fā)其他的鉤子函數(shù)惶洲,一般可以在這里做初始數(shù)據(jù)的獲取')
console.log('接下來開始找實例或者組件對應的模板,編譯模板為虛擬dom放入到render函數(shù)中準備渲染')
},
//beforeMount:虛擬dom已經(jīng)創(chuàng)建完成膳犹,馬上就要渲染,在這里也可以更改數(shù)據(jù)恬吕,不會觸發(fā)updated
beforeMount: function () {
console.group('beforeMount 掛載前狀態(tài)===============》');
console.log("%c%s", "color:red","el : " + (this.$el)); //已被初始化
console.log(this.$el); //el已被初始化,是虛擬dom,數(shù)據(jù)message還沒有渲染上去
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
this.message = 'The last change to change data!'
console.log('最后一次改變數(shù)據(jù)的機會', this.$data.message)
console.log('在這里可以在渲染前最后一次更改數(shù)據(jù)的機會须床,不會觸發(fā)其他的鉤子函數(shù)铐料,一般可以在這里做初始數(shù)據(jù)的獲取')
console.log('接下來開始render,渲染出真實dom')
},
//mounted:此時,數(shù)據(jù)钠惩、真實dom都已經(jīng)處理好了,dom上的事件也都已經(jīng)掛載好了
mounted: function () {
console.group('mounted 掛載結束狀態(tài)===============》');
console.log("%c%s", "color:red","el : " + this.$el); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
console.log('可以在這里操作真實dom等事情...')
},
//beforeUpdate:重新渲染之前觸發(fā),當組件或實例的數(shù)據(jù)更改之后柒凉,會立即執(zhí)行beforeUpdate
beforeUpdate: function () {
console.group('beforeUpdate 更新前狀態(tài)===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
console.log('在這里不能更改數(shù)據(jù),否則會陷入死循環(huán)')
console.log('組件或實例的數(shù)據(jù)更改之后篓跛,會立即執(zhí)行beforeUpdate膝捞,然后vue的虛擬dom機制會重新構建虛擬dom并與上一次的虛擬dom樹利用diff算法進行對比之后重新渲染')
},
//當更新完成后,執(zhí)行updated愧沟,數(shù)據(jù)已經(jīng)更改完成绑警,dom也重新render完成,可以操作更新后的虛擬dom
updated: function () {
console.group('updated 更新完成狀態(tài)===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
console.log('在這里不能更改數(shù)據(jù)央渣,否則會陷入死循環(huán)')
console.log('當數(shù)據(jù)更新完成后,執(zhí)行updated渴频,這時候數(shù)據(jù)已經(jīng)更改完成芽丹,dom也重新render完成,可以操作更新后的虛擬dom')
},
//beforeDestory:銷毀前執(zhí)行($destroy方法被調用的時候就會執(zhí)行),一般在這里做善后處理:清除計時器卜朗、清除非指令綁定的事件等等...
beforeDestroy: function () {
console.group('beforeDestroy 銷毀前狀態(tài)===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
console.log('beforeDestory:組件或實例銷毀前執(zhí)行($destroy方法被調用的時候就會立刻執(zhí)行),一般在這里做善后處理:清除計時器拔第、清除非指令綁定的事件等等...')
},
//destroyed:組件的數(shù)據(jù)綁定、監(jiān)聽...都去掉了,只剩下dom空殼场钉,這里也可以用來做善后處理
destroyed: function () {
console.group('destroyed 銷毀完成狀態(tài)===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message)
console.log('在組件或實例銷毀后執(zhí)行蚊俺,這是已經(jīng)解除了組件的數(shù)據(jù)綁定、指令綁定的事件監(jiān)聽...去掉后只剩下dom空殼逛万,在這里做善后工作也可以')
}
})
</script>
</body>
</html>
打開控制臺泳猬,可以看到剛進入頁面的時候會執(zhí)行beforeCreate、created宇植、beforeMount得封、mounted這四個生命周期函數(shù):
可以看到在beforeMount階段打印出的實例的掛載點是虛擬dom,數(shù)據(jù)還沒有掛載上去指郁;在mounted階段數(shù)據(jù)才被掛載上去忙上,這時才可以操作真實的dom。
點擊增加內容按鈕后可以看到執(zhí)行了beforeUpdate闲坎、和updated這兩個聲明周期函數(shù):
最后點擊銷毀按鈕可以看到執(zhí)行了beforeDestroy和destroyed這兩個生命周期函數(shù):
PS:activated和deactivated生命周期函數(shù)將會在之后做專門的講解疫粥。
1.5 template模板標簽
一個字符串模板作為 Vue 實例的標識使用。模板將會替換 掛載的元素腰懂。掛載元素的內容都將被忽略梗逮,除非模板的內容有分發(fā)插槽。
這是官網(wǎng)給出的template模板標簽的作用描述悯恍,感覺不是很詳細库糠,寫幾個例子看看它都能做什么。
把template寫在掛載元素外面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>Vue模板標簽templete</title>
</head>
<body>
<h1>Vue模板標簽templete</h1>
<hr>
<div id="app"></div>
<template>
<h1 style="color:red">我是Template</h1>
</template>
<script type="text/javascript">
var app=new Vue({
el:'#app',
data:{
message:'hello Vue!'
},
})
</script>
</body>
</html>
當把template寫在掛載點外面的時候,打開瀏覽器可以看到在瀏覽器上并沒有渲染出任何信息瞬欧,這是因為template標簽內容天生不可見贷屎,設置了display:none;屬性:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>Vue模板標簽templete</title>
</head>
<body>
<h1>Vue模板標簽templete</h1>
<hr>
<div id="app">
<template>
<h1 style="color:red">我是Template</h1>
</template>
</div>
<script type="text/javascript">
var app=new Vue({
el:'#app',
data:{
message:'hello Vue!'
},
})
</script>
</body>
</html>
當把template寫在掛載點里面的時候艘虎,打開瀏覽器可以看到在瀏覽器上渲染出了模板唉侄,并且最終的渲染結果并沒有包含 <template> 元素。
根據(jù)渲染結果并沒有包含 <template> 元素的這個特性野建,它可以用來:
- 把template元素當做一個不可見的包裹元素属划,用于分組的條件判斷:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>Vue模板標簽templete</title>
</head>
<body>
<h1>Vue模板標簽templete</h1>
<hr>
<div id="app">
<template v-if="show">
<h1 style="color:red">我是Template</h1>
</template>
<template v-else>
<h1 style="color:blue">我是Template2</h1>
</template>
</div>
<script type="text/javascript">
var app=new Vue({
el:'#app',
data:{
message:'hello Vue!',
show: false
},
})
</script>
</body>
</html>
利用渲染結果將不包含 <template> 元素的這個特性,可以結合指令v-if進行條件渲染候生。因為 v-if 是一個指令同眯,所以必須將它添加到一個元素上,所以可以把它和template搭配使用來進行元素間的切換唯鸭。
注意:Vue中另一個用于根據(jù)條件展示元素的選項是 v-show 指令须蜗。但是v-show 不支持 <template> 元素。
- 把template元素當做一個不可見的包裹元素目溉,用于列表渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>Vue模板標簽templete</title>
<style>
.divider {
font-size: 16px;
color: red;
}
</style>
</head>
<body>
<h1>Vue模板標簽templete</h1>
<hr>
<div id="app">
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider">{{message}}</li>
</template>
</ul>
</div>
<script type="text/javascript">
var app=new Vue({
el:'#app',
data:{
message:'hello Vue!',
items: [{
msg: 'list1'
}, {
msg: 'list2'
}, {
msg: 'list3'
}, {
msg: 'list4'
}, {
msg: 'list5'
}]
},
})
</script>
</body>
</html>
- 用于制作模板明肮,最后將寫好的模板掛載到指定元素上展示內容。有四種寫法:
第一種:直接在構造器里的template選項后邊編寫缭付。這種寫法比較直觀柿估,但是如果模板html代碼多的話,不建議這么寫陷猫。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>Template</title>
</head>
<body>
<h1>Template</h1>
<hr>
<div id="app">我是掛載的內容</div>
<script type="text/javascript">
var app=new Vue({
el:'#app',
data:{
message:'hello Vue!'
},
template:`
<h1 style="color:red">我是選項模板</h1>
`
})
</script>
</body>
</html>
可以看到模板替換了掛載的元素秫舌。掛載元素的內容都被忽略了。template元素最終也沒有渲染出來烙丛。
這里需要注意的是:模板的標識不是單引號和雙引號舅巷,而是`,就是Tab上面的鍵河咽。
第二種:寫在template標簽里的模板钠右,并且template元素寫在掛載元素外面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>Template</title>
</head>
<body>
<h1>Template</h1>
<hr>
<div id="app">我是掛載的內容</div>
<template id="demo2">
<h2 style="color:red">我是template標簽模板</h2>
</template>
<script type="text/javascript">
var app=new Vue({
el:'#app',
data:{
message:'hello Vue!'
},
template:'#demo2'
})
</script>
</body>
</html>
可以看到寫在掛載點外面的template是不會顯示的忘蟹,這種寫法更像是在寫HTML代碼飒房,就算不會寫Vue的人,也可以制作頁面媚值,比較直觀狠毯。
第三種:寫在script標簽里的模板。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>Template</title>
</head>
<body>
<h1>Template</h1>
<hr>
<div id="app">我是掛載的內容</div>
<script type="x-template" id="demo3">
<h2 style="color:red">我是script標簽模板</h2>
</script>
<script type="text/javascript">
var app=new Vue({
el:'#app',
data:{
message:'hello Vue!'
},
template:'#demo3'
})
</script>
</body>
</html>
第四種:使用Vue官方腳手架vue-cli褥芒,xxx.vue單文件組件的寫法
<template>
<div>
我是第四種template寫法
</div>
</template>
<script type="text/javascript">
......
</script>
<style scoped>
</style>
1.6 component組件
組件可以理解成就是制作自定義的標簽嚼松,這些標簽在HTML中是沒有的嫡良。
一、全局注冊組件:
全局就是在構造器的外部用Vue.component來注冊組件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>Component-1</title>
</head>
<body>
<h1>component-1</h1>
<hr>
<div id="app">
<hello></hello>
</div>
<script type="text/javascript">
//Vue.component全局注冊組件献酗,一次只能定義一個組件
Vue.component('hello',{
template:`<div>全局化注冊的:<hello>標簽寝受,在構造器外部定義的</div>`
});
var app = new Vue({
el:'#app',
data: {
}
})
</script>
</body>
</html>
上面的例子在javascript里注冊了一個組件,在HTML中調用了這個組件罕偎。這就是最簡單的一個組件的編寫方法很澄,并且它可以放到多個構造器的作用域里。
二颜及、局部注冊組件:
局部注冊組件和全局注冊組件是相對應的甩苛,局部注冊的組件只能在組件注冊的作用域里進行使用,其他作用域使用無效俏站。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>Component-1</title>
</head>
<body>
<h1>component-1</h1>
<hr>
<div id="app">
<helloworld></helloworld>
<sayhi></sayhi>
</div>
<script type="text/javascript">
var helloworld = { template:`<div>局部注冊的:<helloworld>標簽讯蒲,在構造器里面定義的</div>`}
var app = new Vue({
el:'#app',
data: {
},
//components足部注冊組件,一次能定義多個組件
components: {
"helloworld": helloworld,
"sayhi": {
template: `<div>你好肄扎,再睡一夏~</div>`
}
}
})
</script>
</body>
</html>
從代碼中你可以看出局部注冊其實就是寫在構造器里爱葵,但是需要注意的是,構造器里的components 是加s的反浓,而全局注冊是不加s的。
1.7 component props 組件屬性
props選項就是獲取標簽上的屬性值的赞哗。props 可以是數(shù)組或對象雷则,用于接收傳入組件的數(shù)據(jù)。props 可以是簡單的數(shù)組肪笋,或者使用對象作為替代月劈,對象允許配置高級選項,如類型檢測藤乙、自定義校驗和設置默認值猜揪。
一、定義屬性并獲取屬性值:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>component-2 props 組件屬性</title>
</head>
<body>
<h1>component-2 props 組件屬性</h1>
<hr>
<div id="app">
<date week="Monday"></date>
</div>
<script type="text/javascript">
var date = {
template: `<div>Today is {{week}}!</div>`,
props: ['week']
}
var app=new Vue({
el:'#app',
data:{
},
components:{
"date": date
}
})
</script>
</body>
</html>
二坛梁、屬性中帶'-'的處理方式:
有時在寫屬性時會加入'-'來進行分詞而姐,比如:在props里如果寫成props:['form-here']是錯誤的,必須用小駝峰式寫法props:['formHere']:
html文件:
<hometown from-here="China"></hometown>
javascript文件:
var app=new Vue({
el:'#app',
components:{
"hometown":{
template:`<div style="color:red;">I'm from {{ here }}.</div>`,
props:['fromHere']
}
}
})
三划咐、在構造器里向組件中傳值:
把構造器中data的值傳遞給組件拴念,只要進行綁定就可以了。使用指令v-bind:xxx.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>component-2 props 組件屬性</title>
</head>
<body>
<h1>component-2 props 組件屬性</h1>
<hr>
<div id="app">
<helloworld :here="message"></helloworld>
</div>
<script type="text/javascript">
var helloworld = {
template: `<div>My here is {{here}}!</div>`,
props: ['here']
}
var app=new Vue({
el:'#app',
data:{
message:'GuangZhou'
},
components:{
"helloworld": helloworld
}
})
</script>
</body>
</html>
1.8 component 父子組件
在實際開發(fā)中我們經(jīng)常會遇到在一個自定義組件中要使用其他自定義組件褐缠,這就需要一個父子組件
關系政鼠。
一、構造器外部寫局部注冊組件:
如果都把局部組件的編寫放到構造器內部队魏,那么當組件代碼量很大時公般,會影響構造器的可讀性,造成拖拉和錯誤。
所以應該把組件編寫的代碼放到構造器外部或者放到單獨的文件里官帘。
需要先聲明一個對象,對象里就是組件的內容:
var world={
template:`<div><p>局部注冊的- <world>組件</p></div>`
}
聲明好對象后在構造器里引用就可以了:
components:{
"world": world
}
html中引用:
<world></world>
二瞬雹、父子組件的嵌套:
先聲明一個父組件,叫world遏佣,然后里邊加入一個city組件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>component-3 父子組件</title>
</head>
<body>
<h1>component-3 父子組件</h1>
<hr>
<div id="app">
<world></world>
</div>
<script type="text/javascript">
var city={
template:`<div>this is city!</div>`
}
var world={
template:`<div>
<p>局部注冊的- <world>組件</p>
<city></city>
</div>`,
//父組件中引用子組件挖炬,要先在父組件中注冊子組件
components:{
"city":city
}
}
var app=new Vue({
el:'#app',
data:{
message:'hello Vue!'
},
components:{
"world":world
}
})
</script>
</body>
</html>
1.9 component標簽,動態(tài)組件
component標簽是Vue框架自定義的標簽状婶,它的用途就是可以動態(tài)綁定組件意敛,根據(jù)數(shù)據(jù)的不同更換不同的組件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../assets/js/vue.js"></script>
<title>component-4膛虫,使用component標簽生成動態(tài)組件</title>
</head>
<body>
<h1>component-4草姻,使用component標簽生成動態(tài)組件</h1>
<hr>
<div id="app">
<component v-bind:is="who"></component>
<br>
<button @click="changeComponent">changeComponent</button>
</div>
<script type="text/javascript">
var componentA={
template:`<div style="color:red;">I'm componentA</div>`
}
var componentB={
template:`<div style="color:green;">I'm componentB</div>`
}
var componentC={
template:`<div style="color:pink;">I'm componentC</div>`
}
var app=new Vue({
el:'#app',
data:{
who:'componentA'
},
components:{
"componentA":componentA,
"componentB":componentB,
"componentC":componentC,
},
methods:{
changeComponent:function(){
if(this.who=='componentA'){
this.who='componentB';
}else if(this.who=='componentB'){
this.who='componentC';
}else{
this.who='componentA';
}
}
}
})
</script>
</body>
</html>