視訊教程
由於掘金不支援視訊連結 視訊請移步 www.henrongyi.top
你能學到什麼
二檔視訊當然要比一檔視訊難一點,如果前面的內容還沒有消化完畢的話,還是建議大家繼續消化前面的內容,然後再看接下來的部分。這一部分是VUE的核心,講到元件化開發的基礎部分,多學,多練。
生命週期
Vue官網給出的生命週期圖
這張圖裡包含了基本的生命週期,實際上生命週期鉤子函式還有兩個不在圖內(activated,deactivated),這兩個生命週期函式這裡不給大家講,如果大家有興趣可以自行到VUE官網看文件,工作中用到他們的機會不多,這邊講也會擾亂大家的學習程式。這裡我們通過程式碼來講解Vue的生命週期 ```html<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
num:1
},
methods:{
add(){
this.num++
},
minus(){
this.num--
}
},
beforeCreate:function(){
console.log('頁面初始化之後立刻執行');
},
created:function(){
console.log('頁面初始化完成之後created,這裡模板還沒有渲染呢!');
},
beforeMount:function(){
console.log('元件掛載之前beforeMount');
},
mounted:function(){
console.log('元件掛載之後mounted');
},
beforeUpdate:function(){
console.log('元件更新前beforeUpdate');
},
updated:function(){
console.log('元件更新後updated');
},
// activated:function(){
// console.log('activated');
// },
// deactivated:function(){
// console.log('deactivated');
// }, 你只需要知道這兩個生命週期是在這個位置進行就好了,別的可以不要想太多。
beforeDestroy:function(){
console.log('元件銷燬之前beforeDestroy');
},
destroyed:function(){
console.log('元件銷燬後destroyed')
}
})
</script>
複製程式碼
```
這些生命週期函式大體就演示到這裡,剩下的兩個沒能給大家展示的請大家牢記,我們開始學元件的時候,就可以體會到這兩個鉤子函式的用法了。
元件建立
Vue.component 註冊全域性元件 Vue.component("元件名",{ 元件的各種屬性(模板啊,data啊,方法啊,生命週期啊之類的。) }), (視訊裡有一句口誤,應該是小駝峰。手動捂臉)
這個全域性API看過以後,我們來實現一個元件的hello world
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<shuai-qm></shuai-qm>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component("shuai-qm",{
data(){
return{
hello:'hello world'
}
},
template:'<h1>{{hello}}</h1>'
})
var app = new Vue({
el:"#app",
data:{
message:'Hello Word',
isTrue:true,
},
})
</script>
</body>
</html>
複製程式碼
一個全域性元件的hello world就完成了,但是大家是不是覺得全域性元件非常不踏實?隨時可能一個變動摧毀我們的專案? 那沒關係,接下來是區域性組建的註冊方法。
Vue的components屬性
我們在註冊區域性組建的時候,需要把區域性組建掛載到Vue構造器的components內,注意:全域性api不帶s,而這個屬性帶s。不說廢話,我們先來構造一個。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
{{message}}
<shuai-qm></shuai-qm>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
message:'Hello World',
isTrue:true,
},
components:{
"shuaiQm":{
data(){
return{
hello:"hello world"
}
},
template:'<h1>{{hello}}</h1>'
}
}
})
</script>
</body>
</html>
複製程式碼
這樣我們就得到了一個可以hello world的區域性元件,但是,一堆組建都這個樣子羅列出來的話,會將我們的專案弄得體無完膚? 所以我們抽離一下程式碼。變成這樣
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
{{message}}
<shuai-qm></shuai-qm>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var shuaiQm = {
data(){
return{
hello:"hello world"
}
},
template:'<h1>{{hello}}</h1>'
}
var app = new Vue({
el:"#app",
data:{
message:'Hello World',
isTrue:true,
},
components:{
"shuaiQm":shuaiQm,
}
})
</script>
</body>
</html>
複製程式碼
是不是用vue-cli開發過的同學就比較眼熟了?那麼問題又來了,元件裡面的html全都是寫的字串,都這麼玩下去,要亂死啊,沒問題,我們繼續抽離。
這裡介紹的就是vue的template用法了,馬上又是一個cli黨眼熟的東西
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<template id="shuaiQm">
<h1>{{hello}}</h1>
</template>
<!-- 上面是html模板的用法,下面是script模板的用法,使用<script>標籤時,type指定為text/x-template,意在告訴瀏覽器這不是一段js指令碼,瀏覽器在解析HTML文件時會忽略<script>標籤內定義的內容。-->
<!-- 推薦 -->
<script type="x-template" id="shuaiQm2"></script>
<body>
<div id="app">
{{message}}
<shuai-qm></shuai-qm>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var shuaiQm = {
data(){
return{
hello:"hello world"
}
},
template:"#shuaiQm2"
}
var app = new Vue({
el:"#app",
data:{
message:'Hello World',
isTrue:true,
},
components:{
"shuaiQm":shuaiQm,
}
})
</script>
</body>
</html>
複製程式碼
拆出來以後是不是莫名其妙引起了極度舒適?當然後面我們學到使用vue-cli的時候 我們還會用到新的書寫方法 .vue 檔案的方法,這裡就先不給大家多說了。
元件裡面套元件(父子元件)
可能由同學會問了,元件裡面還可以巢狀元件嗎?我可以很負責任地告訴你,完全沒問題!怎麼寫呢?你如果會在Vue例項的構造器裡引用元件,你就會在別的元件內部引用元件,他們其實是一個寫法。這邊我使用我們的第三種模板寫法來給大家書寫。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<script type="x-template" id="father"></script>
<script type="x-template" id="childer"></script>
<body>
<div id="app">
{{message}}
<shuai-qm></shuai-qm>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var childer = {
data(){
return{
hello:"hello i'm dawangraoming"
}
},
template:"#childer"
}
var father = {
data(){
return{
hello:"hello world"
}
},
template:"#father",
components:{
"childer":childer
}
}
var app = new Vue({
el:"#app",
data:{
message:'Hello World',
isTrue:true,
},
components:{
"shuaiQm":father,
}
})
</script>
</body>
</html>
複製程式碼
這裡大家也可以看到,我們在 app內部只引用了 shuaiQm這一個元件, shuaiQm又包含他的子元件 childer,因此父子都被渲染出來了。這就是父子元件的寫法。
插槽slot
這時候又有朋友要問了,如果我想在元件裡面繼續書寫html怎麼辦呢? slot插槽就是個很好的東西了,這裡我用程式碼給大家演示一下slot插槽的用法。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<script type="x-template" id="shuaiQm2"></script>
<body>
<div id="app">
{{message}}
<shuai-qm>
<span slot="solt1">hello world</span>
</shuai-qm>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var shuaiQm = {
data(){
return{
hello:"hello world"
}
},
template:"#shuaiQm2"
}
var app = new Vue({
el:"#app",
data:{
message:'Hello World',
isTrue:true,
},
components:{
"shuaiQm":shuaiQm,
}
})
</script>
</body>
</html>
複製程式碼
插槽只有這一個作用嗎?不,那你就太小看插槽了,接下來要介紹一下插槽的作用域插槽用法。
作用域插槽,聽不懂可跳過,後面還會詳細講解
使用時候子元件標籤Child中要有 template scope=”scopeName” 標籤,再通過scopeName.childProp就可以呼叫子元件模板中的childProp繫結的資料,所以作用域插槽是一種子傳父傳參的方式,解決了普通slot在parent中無法訪問child資料的去問題; 這麼說太複雜了,直接上個例子顯而易見。 如果這裡聽不懂可以暫時跳過,只需要會用slot插槽的基礎用法即可,在後面講Element專案的時候,我會結合例項給大家講解這個作用域插槽。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<script type="x-template" id="shuaiQm2"></script>
<body>
<div id="app">
{{message}}
<shuai-qm>
<template slot="item" scope="props">
<li>{{props.myname}}</li>
<li>{{props.text}}</li>
</template>
</shuai-qm>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var shuaiQm = {
data(){
return{
hello:"hello world",
items:[{
text:"我在子元件內,通過插槽展示在父元件",
myname:"Qm",
},{
text:"我在子元件內,通過插槽展示在父元件",
myname:"奇淼",
}]
}
},
template:"#shuaiQm2"
}
var app = new Vue({
el:"#app",
data:{
message:'Hello World',
isTrue:true,
},
components:{
"shuaiQm":shuaiQm,
}
})
</script>
</body>
</html>
複製程式碼
prop 傳遞引數給元件(父傳值給子)
講到這裡,已經到了VUE一個需要理解的地方了,父子傳值,我們先講解一下,如何將值傳遞給子元件,這個整體來說還是比較簡單。引用我們的元件的標籤上寫上屬性,並且把引數傳入,這樣我們在元件內部使用props就可以獲得傳過來的值了,我們還是以上面的程式碼為例。
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<script type="x-template" id="father"></script>
<script type="x-template" id="childer"></script>
<body>
<div id="app">
<shuai-qm apptoshuaiqm="我是app傳過來的值" ></shuai-qm>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var childer = {
props:['shuaiQmtochilder'],
data(){
return{
hello:"hello i'm dawangraoming",
}
},
template:"#childer"
}
var father = {
props:["apptoshuaiqm"],// 這裡大家一定要注意,請完全使用小寫傳參
data(){
return{
hello:"hello world",
shuaiQmGiveMe:"我是從shuaiQm傳過來的值"
}
},
template:"#father",
components:{
"childer":childer
}
}
var app = new Vue({
el:"#app",
data:{
message:'Hello World',
isTrue:true,
},
components:{
"shuaiQm":father,
}
})
</script>
</body>
</html>
複製程式碼
這一段程式碼注意,再給html上面新增屬性的時候,我們是不可以直接新增駝峰命名的,因為html不會區分大小寫,所以我們建議屬性的命名方式是完全小寫或者橫線命名的方式。如果我們使用橫線命名來傳遞引數的話,在接收的時候,橫線後面的首字母大寫,變成小駝峰來接受,否則使用的時候它會被渲染成NaN,這是為什麼呢?別忘了我們一檔講過的,在插值表示式內,是支援簡單計算的,- 會被當作減號處理,這裡我會在視訊中給大家詳細講解。
子元件傳值給父元件
學到這裡,如果大家已經有些迷茫,現在請先停下,喘口氣,這裡難度已經慢慢加大。我也會放慢講解的速度。 如果我們想要獲取到子元件內部的值,該怎麼辦呢?有什麼辦法能夠讓我們回去到內部的值呢?在這裡,先給大家插播一個JS寫法,我覺得這有助於理解子傳父值。
function thief (gold) {
console.log(gold)
}
function richMan (){
var money = 1000086
thief(money)
}
richMan()
複製程式碼
我們想要在vue中做到子傳參給父,那我們的父元件就要像子元件伸出小偷之手。我在程式碼中為大家書寫一下
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<script type="x-template" id="shuaiQm">
<div>
</div>
</script>
<body>
<div id="app">
{{qmGold}}
<shuai-qm :father="thief"></shuai-qm>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var shuaiQm = {
props:["father"],
data(){
return{
money:"10000",
}
},
template:"#shuaiQm",
created() {
this.father(this.money)
},
}
var app = new Vue({
el:"#app",
data:{
qmGold:0,
},
components:{
"shuaiQm":shuaiQm,
},
methods:{
thief(gold){
this.qmGold = gold
}
}
})
</script>
</body>
</html>
複製程式碼
這樣 你理解子傳參給父了嗎?
其餘會用到的全域性API
Vue.directivet Vue.directive 我們用來編寫全域性指令,它也有自己的生命週期
// 註冊
Vue.directive('my-directive', {
bind: function () {},
inserted: function () {},
update: function () {},
componentUpdated: function () {},
unbind: function () {}
})
/*
bind:只呼叫一次,指令第一次繫結到元素時呼叫。在這裡可以進行一次性的初始化設定。
inserted:被繫結元素插入父節點時呼叫 (僅保證父節點存在,但不一定已被插入文件中)。
update:所在元件的 VNode 更新時呼叫,但是可能發生在其子 VNode 更新之前。指令的值可能發生了改變,也可能沒有。但是你可以通過比較更新前後的值來忽略不必要的模板更新 (詳細的鉤子函式引數見下)。
componentUpdated:指令所在元件的 VNode 及其子 VNode 全部更新後呼叫。
unbind:只呼叫一次,指令與元素解綁時呼叫。
接下來我們來看一下鉤子函式的引數 (即 el、binding、vnode 和 oldVnode)。
在這些鉤子函式內部,都可以接受三個引數,我們來看看文件中的寫法。
el:指令所繫結的元素,可以用來直接操作 DOM 。
binding:一個物件,包含以下屬性:
name:指令名,不包括 v- 字首。
value:指令的繫結值,例如:v-my-directive="1 + 1" 中,繫結值為 2。
oldValue:指令繫結的前一個值,僅在 update 和 componentUpdated 鉤子中可用。無論值是否改變都可用。
expression:字串形式的指令表示式。例如 v-my-directive="1 + 1" 中,表示式為 "1 + 1"。
arg:傳給指令的引數,可選。例如 v-my-directive:foo 中,引數為 "foo"。
modifiers:一個包含修飾符的物件。例如:v-my-directive.foo.bar 中,修飾符物件為 { foo: true, bar: true }。
vnode:Vue 編譯生成的虛擬節點。
oldVnode:上一個虛擬節點,僅在 update 和 componentUpdated 鉤子中可用。
這裡我會在視訊中結合官方樣例講解
*/
複製程式碼
上面我們羅列了這麼多它的特性,不過真正開發中,我們最常用的只有 bind 和 update 這兩個時期 我們可以簡寫為
Vue.directive('color', function (el, binding) {
el.style.backgroundColor = binding.value
})
複製程式碼
下面我們來舉個例子
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<script type="x-template" id="shuaiQm">
<div>
</div>
</script>
<body>
<div id="app">
<div v-color="color">
我來測試測試directive
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.directive("color",function(el,binding){
el.style.color = binding.value
})
var app = new Vue({
el:"#app",
data:{
color:"red"
}
})
</script>
</body>
</html>
複製程式碼
好了我們可以看到加上v-color的這個div內部的文字變紅了
Vue.set
Vue.set官網給出的用法是 Vue.set( target, key, value ) 向響應式物件中新增一個屬性,並確保這個新屬性同樣是響應式的,且觸發檢視更新。它必須用於向響應式物件上新增新屬性,因為 Vue 無法探測普通的新增屬性 這麼聽起來是有些籠統的,我給大家用程式碼展示一下它在我們日常開發中經常出現的場景。
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item,ket) in list" :key="key">{{item.hello}}</li>
</ul>
<button @click="addList">+</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
list:[{hello:"hello world"},{hello:"hello two"}]
},
methods:{
addList(){
this.list[0] = {hello:"ttt"}
console.log(this.list)
}
}
})
</script>
</body>
</html>
複製程式碼
在上述程式碼中,我們通過this.list[0]直接修改了陣列中的第0專案物件,那麼檢視是沒有更新的,但是資料確實變更了,這是為什麼呢?因為Vue是通過Object.defineProperty()來進行資料的監聽,它的機制導致了它無法直接檢測出陣列中這種情況的變化。這時候我們就需要使用Vue.set了
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item,ket) in list" :key="key">{{item.hello}}</li>
</ul>
<button @click="addList">+</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
list:[{hello:"hello world"},{hello:"hello two"}]
},
methods:{
addList(){
this.list[0] = {hello:"ttt"}
console.log(this.list)
}
}
})
</script>
</body>
</html>
複製程式碼
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item,ket) in list" :key="key">{{item.hello}}</li>
</ul>
<button @click="addList">+</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
list:[{hello:"hello world"},{hello:"hello two"}]
},
methods:{
addList(){
// this.list[0] = {hello:"ttt"}
Vue.set(this.list,0, {hello:"我強制改變了!"})
// this.$set(this.list,0,{hello:"我強制改變了!"}) 在methods 中可以寫成 this.$set
console.log(this.list)
}
}
})
</script>
</body>
</html>
複製程式碼
看 是不是強制將它改變了呢? 有了Vue.set 資料就都不再得瑟了