1. 程式人生 > 實用技巧 >詳解Vue大護法——元件

詳解Vue大護法——元件

1.什麼是元件化

人面對複雜問題的處理方式:

  1. 任何一個人處理資訊的邏輯能力都是有限的

  2. 所以,當面對一個非常複雜的問題時,我們不太可能一次性搞定一大堆的內容。

  3. 但是,我們人有一種天生的能力,就是將問題進行拆解。

  4. 如果將一個複雜的問題,拆分成很多個可以處理的小問題,再將其放在整體當中,你會發現大的問題也會迎刃而解。

元件化也是類似的思想:

如果我們將一個頁面中所有的處理邏輯全部放在一起,處理起來就會變得非常複雜,而且不利於後續的管理以及擴充套件。但如果,我們講一個頁面拆分成一個個小的功能塊,每個功能塊完成屬於自己這部分獨立的功能,那麼之後整個頁面的管理和維護就變得非常容易了。

2.vue元件化思想

元件化是Vue.js中的重要思想

  • 它提供了一種抽象,讓我們可以開發出一個個獨立可複用的小元件來構造我們的應用。

  • 任何的應用都會被抽象成一顆元件樹。

元件化思想的應用:

有了元件化的思想,我們在之後的開發中就要充分的利用它。儘可能的將頁面拆分成一個個小的、可複用的元件。這樣讓我們的程式碼更加方便組織和管理,並且擴充套件性也更強。

3.註冊元件

3.1案例引入

元件的使用分成三個步驟:

  • 建立元件構造器

  • 註冊元件

  • 使用元件

下面我們通過程式碼來看看如何註冊元件

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 使用元件-->
<my-cpn></my-cpn>
</div>
</body>
<script type="text/javascript"> //1、建立元件構造器
const myComponent = Vue.extend({
template:`
<div>
<h2>元件標題</h2>
<p>我是元件中的一個段落</p>
</div
`
}) //2、註冊元件,並定義元件標籤的名稱
Vue.component('my-cpn',myComponent) let app=new Vue({
el: '#app',
data: {
message: '你好呀'
}
})
</script>
</html>

3.2註冊元件步驟解析

上面我們通過程式碼使用了元件,那麼這段程式碼表示什麼含義呢?

1.Vue.extend():

呼叫Vue.extend()建立的是一個元件構造器。 通常在建立元件構造器時,傳入template代表我們自定義元件的模板。該模板就是在使用到元件的地方,要顯示的HTML程式碼。事實上,這種寫法在Vue2.x的檔案中幾乎已經看不到了,它會直接使用下面我們會講到的語法糖,但是在很多資料還是會提到這種方式,而且這種方式是學習後面方式的基礎。

2.Vue.component():

  • 呼叫Vue.component()是將剛才的元件構造器註冊為一個元件,並且給它起一個元件的標籤名稱。

  • 所以需要傳遞兩個引數:1、註冊元件的標籤名 2、元件構造器

3.元件必須掛載在某個Vue例項下,否則它不會生效。

4.全域性父子元件

4.1全域性元件和區域性元件

當我們通過Vue.component()註冊元件時,元件的註冊是全域性的,這意味著該元件可以在任意Vue例項下使用。

如果我們註冊的元件是掛載在某個例項中, 那麼就是一個區域性元件

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<my-cpn></my-cpn>
</div> <div id="app2">
<my-cpn></my-cpn>
</div>
</body>
<script type="text/javascript">
//1、建立元件構造器
const myComponent = Vue.extend({
template: `
<div>
<h2>元件標題</h2>
<p>我是元件中的一個段落</p>
</div
`
}) let app = new Vue({
el: '#app',
components: {
'my-cpn': myComponent
}
}) let app2 = new Vue({
el: '#app2'
})
</script>
</html>

從頁面顯示結果我們可以看出app2中的元件沒有顯示出來,因為這段程式碼註冊的是區域性元件,只能在app中使用

4.2父子元件

在前面我們看到了元件樹,元件和元件之間存在層級關係,而其中一種非常重要的關係就是父子元件的關係。我們來看通過程式碼如何組成的這種層級關係:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 使用元件-->
<parent-cpn></parent-cpn>
</div>
</body>
<script type="text/javascript">
//1 建立一個子元件構造器 注意template的最外層必須用div包裹起來
const childComponent = Vue.extend({
template: `
<div>我是子元件的內容,我是child哦</div>
`
}) //2 建立一個父元件構造器 注意template的最外層必須用div包裹起來
const parentComponet = Vue.extend({
template: `
<div>
<p>我是父元件的內容,我是parent哦</p>
<h2>我是父元件的標題</h2>
<child-cpn></child-cpn>
</div>
`,
components: {
'child-cpn': childComponent
}
}) let app = new Vue({
el: '#app',
components: {
'parent-cpn': parentComponet
}
})
</script>
</html>

注意:

這裡不能直接在Vue例項中使用,這樣使用瀏覽器不識別

因為當子元件註冊到父元件的components時,Vue會編譯好父元件的模組,該模板的內容已經決定了父元件將要渲染的HTML(相當於父元件中已經有了子元件中的內容了),是隻能在父元件中被識別的。類似這種用法,是會被瀏覽器忽略的。

註冊元件的語法糖

上面的註冊元件的方式有點繁瑣,Vue為了簡化註冊元件的過程,提供了註冊元件的語法糖

4.3模板的分離寫法

剛才,我們通過語法糖簡化了Vue元件的註冊過程,另外還有一個地方的寫法比較麻煩,就是template模組寫法。如果我們能將其中的HTML分離出來寫,然後掛載到對應的元件上,必然結構會變得非常清晰。Vue提供了兩種方案來定義HTML模組內容:

  • 使用標籤

  • 使用標籤

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 使用元件-->
<my-cpn></my-cpn>
</div>
</body> <!-- 使用template標籤 -->
<template id="myCpn">
<div>
<h2>元件標題</h2>
<p>我是元件中的一個段落</p>
</div>
</template>
<script type="text/javascript"> let app=new Vue({
el: '#app',
components: {
'my-cpn': {
template: '#myCpn'
}
}
})
</script>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 使用元件-->
<my-cpn></my-cpn>
</div>
</body> <!-- 使用script標籤 -->
<script type="text/x-template" id="myCpn">
<div>
<h2>元件標題</h2>
<p>我是元件中的一個段落</p>
</div>
</script>
<script type="text/javascript"> let app=new Vue({
el: '#app',
components: {
'my-cpn': {
template: '#myCpn'
}
}
})
</script>
</html>

5.元件資料

上面我們介紹瞭如何使用Vue元件,但是愛思考的同學就產生問題了,Vue元件中可以訪問Vue例項資料嗎?

元件是一個單獨功能模組的封裝,這個模組有屬於自己的HTML模板,也應該有屬性自己的資料data。

元件中的資料是儲存在哪裡呢?頂層的Vue例項中嗎?我們先來測試一下,元件中能不能直接訪問Vue例項中的data

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<my-cpn></my-cpn>
</div>
</body>
<template id="myCpn">
<div>
訊息:{{message}}
</div>
</template>
<script type="text/javascript">
let app=new Vue({
el: '#app',
data: {
message: '你好呀'
},
components: {
'my-cpn': {
template: '#myCpn'
}
}
})
</script>
</html>

從頁面效果可以看出,元件時訪問不到message的。那麼元件中的資料該存放在哪裡呢

5.1元件資料存放

元件物件也有一個data屬性(也可以有methods等屬性,下面我們有用到),只是這個data屬性必須是一個函式,而且這個函式返回一個物件,物件內部儲存著資料。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<my-cpn></my-cpn>
</div>
</body>
<template id="myCpn">
<div>
訊息:{{message}}
</div>
</template>
<script type="text/javascript">
let app=new Vue({
el: '#app',
components: {
'my-cpn': {
template: '#myCpn',
// 存放元件資料的地方
data() {
return {
message: '我是元件的資料'
}
}
}
}
})
</script>
</html>

我們可以看到data()是一個函式,為什麼data是一個函式呢?可不可以是物件或者陣列呢?答案是不可以,data必須是函式。

  • 首先,如果不是一個函式,Vue直接就會報錯。

  • 其次,原因是在於Vue讓每個元件物件都返回一個新的物件,因為如果是同一個物件的,元件在多次使用後會相互影響。

下面我們通過一個案例來看data如果每次都返回一個新物件會有什麼效果

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
</body>
<template id="myCpn">
<div>
<button type="button" @click="btnClick">點選按鈕</button>
<span>當前數量:{{count}}</span>
</div>
</template>
<script type="text/javascript">
const obj = {
count: 0
} let app = new Vue({
el: '#app',
components: {
'my-cpn': {
template: '#myCpn',
// 存放元件資料的地方
data() {
return obj;
},
methods: {
btnClick() {
this.count++
}
}
}
}
})
</script>
</html>

6.元件間通訊

在上一個小節中,我們提到了子元件是不能引用父元件或者Vue例項的資料的。但是,在開發中,往往一些資料確實需要從上層傳遞到下層。比如在一個頁面中,我們從伺服器請求到了很多的資料。其中一部分資料,並非是我們整個頁面的大元件來展示的,而是需要下面的子元件進行展示。這個時候,並不會讓子元件再次傳送一個網路請求,而是直接讓大元件(父元件)將資料傳遞給小元件(子元件)。

Vue官方提供了兩種方式用於元件間的通訊

  • 通過props向子元件傳遞資料
  • 通過事件向父元件傳送訊息

6.1父級向子級傳遞

在元件中,使用選項props來宣告需要從父級接收到的資料。props的值有兩種方式:

  • 方式一:字串陣列,陣列中的字串就是傳遞時的名稱。

  • 方式二:物件,物件可以設定傳遞時的型別,也可以設定預設值等。

我們先來看一個最簡單的props傳遞:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 3 通過:message="message"將data中的資料傳遞給了props -->
<child-cpn :message='message'></child-cpn>
</div>
</body> <template id="childCpn">
<div>
顯示的資訊:{{message}}
</div>
</template>
<script type="text/javascript">
let app=new Vue({
el: '#app',
data: {
message: '我是父元件的內容' //1 Vue例項中的data
},
components: {
'child-cpn': {
template: '#childCpn',
props: ['message'] // 2 元件中的props }
}
})
</script>
</html>

在上面的案例中,我們的props選項是使用一個陣列。除了陣列props還可以使用物件的方式。我們來看一下具體如何使用。

6.2子級向父級傳遞資料

props用於父元件向子元件傳遞資料,還有一種比較常見的是子元件傳遞資料或事件到父元件中。我們應該如何處理呢?這個時候,我們需要使用自定義事件來完成。

什麼時候需要自定義事件呢?當子元件需要向父元件傳遞資料時,就要用到自定義事件了。我們之前學習的v-on不僅僅可以用於監聽DOM事件,也可以用於元件間的自定義事件。

自定義事件的流程:

  1. 在子元件中,通過$emit()來觸發事件。

  2. 在父元件中,通過v-on來監聽子元件事件。

我們來看一個簡單的例子:

我們之前做過一個兩個按鈕+1和-1,點選後修改counter。我們整個操作的過程還是在子元件中完成,但是之後的展示交給父元件。這樣,我們就需要將子元件中的counter,傳給父元件的某個屬性,比如total。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 通過@increment和@decrement監聽事件 -->
<child-cpn @increment="changeTotal" @decrement="changeTotal"></child-cpn>
<h2>count: {{total}}</h2>
</div>
</body>
<template id="childCpn">
<div>
<button type="button" @click="increment">+1</button>
<button type="button" @click="decrement">-1</button>
</div>
</template>
<script type="text/javascript">
let app=new Vue({
el: '#app',
data: {
total: 0
},
methods: {
changeTotal(counter){
this.total = counter
}
},
components: {
'child-cpn': {
template: '#childCpn',
data() {
return {
counter: 0
}
},
methods: {
increment() {
this.counter++;
this.$emit('increment',this.counter)
},
decrement() {
this.counter--;
this.$emit('decrement',this.counter)
}
} }
}
})
</script>
</html>

6.3父子元件的訪問

有時候我們需要父元件直接訪問子元件,子元件直接訪問父元件,或者是子元件訪問根元件。父元件訪問子元件:使用$children或$refs子元件訪問父元件:使用$parent

6.3.1$children

我們先來看下$children的訪問,this.$children是一個陣列型別,它包含所有子元件物件。我們這裡通過一個遍歷,取出所有子元件的message內容。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 在Vue例項中使用父元件 -->
<parent-cpn></parent-cpn>
</div>
</body> <!-- 父元件 -->
<template id="parentCpn">
<div>
<!-- 在父元件中使用子元件 -->
<child-cpn1></child-cpn1>
<child-cpn2></child-cpn2>
<button type="button" @click="showChildCpn()">顯示所有子元件的資訊</button>
</div>
</template> <!-- 第一個子元件 -->
<template id="childCpn1">
<div>
<h2>我是子元件1,哈哈哈</h2>
</div>
</template>
<!-- 第二個子元件 -->
<template id="childCpn2">
<div>
<h2>我是子元件2,啊啊啊</h2>
</div>
</template> <script type="text/javascript"> // 註冊父元件
Vue.component('parent-cpn',{
template: '#parentCpn',
methods: {
showChildCpn() {
for(let i=0; i<this.$children.length;i++){
console.log(this.$children[i].message);
}
}
},
//註冊子元件
components: {
'child-cpn1': {
template: '#childCpn1',
data() {
return {
message: '我是子元件1'
}
}
},
'child-cpn2': {
template: '#childCpn2',
data() {
return {
message: '我是子元件2'
}
}
} }
}); let app=new Vue({
el: '#app' })
</script>
</html>

6.3.2$refs

$children的缺陷:

通過$children訪問子元件時,是一個陣列型別,訪問其中的子元件必須通過索引值。但是當子元件過多,我們需要拿到其中一個時,往往不能確定它的索引值,甚至還可能會發生變化。有時候,我們想明確獲取其中一個特定的元件,這個時候就可以使用$refs

$refs的使用:

$refs和ref指令通常是一起使用的。首先,我們通過ref給某一個子元件繫結一個特定的ID。其次,通過this.$refs.ID就可以訪問到該元件了。

將上面的程式碼修改成

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 在Vue例項中使用父元件 -->
<parent-cpn></parent-cpn>
</div>
</body> <!-- 父元件 -->
<template id="parentCpn">
<div>
<!-- 在父元件中使用子元件 -->
<child-cpn1 ref="child1"></child-cpn1>
<child-cpn2 ref="child2"></child-cpn2>
<button type="button" @click="showChildCpn()">顯示所有子元件的資訊</button>
</div>
</template> <!-- 第一個子元件 -->
<template id="childCpn1">
<div>
<h2>我是子元件1,哈哈哈</h2>
</div>
</template>
<!-- 第二個子元件 -->
<template id="childCpn2">
<div>
<h2>我是子元件2,啊啊啊</h2>
</div>
</template> <script type="text/javascript"> // 註冊父元件
Vue.component('parent-cpn',{
template: '#parentCpn',
methods: {
showChildCpn() {
// 這裡通過child1 child2來訪問子元件
console.log("refs"+this.$refs.child1.message);
console.log("refs"+this.$refs.child2.message);
}
},
//註冊子元件
components: {
'child-cpn1': {
template: '#childCpn1',
data() {
return {
message: '我是子元件1'
}
}
},
'child-cpn2': {
template: '#childCpn2',
data() {
return {
message: '我是子元件2'
}
}
} }
}); let app=new Vue({
el: '#app' })
</script>
</html>

6.3.3$parent

如果我們想在子元件中直接訪問父元件,可以通過$parent

注意事項:

儘管在Vue開發中,我們允許通過$parent來訪問父元件,但是在真實開發中儘量不要這樣做。子元件應該儘量避免直接訪問父元件的資料,因為這樣耦合度太高了。如果我們將子元件放在另外一個元件之內,很可能該父元件沒有對應的屬性,往往會引起問題。另外,更不好做的是通過$parent直接修改父元件的狀態,那麼父元件中的狀態將變得飄忽不定,很不利於我的除錯和維護。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 在Vue例項中使用父元件 -->
<parent-cpn></parent-cpn>
</div>
</body> <!-- 父元件 -->
<template id="parentCpn">
<div>
<!-- 在父元件中使用子元件 -->
<child-cpn></child-cpn>
</div>
</template> <!-- 子元件 -->
<template id="childCpn">
<div>
<h2>我是子元件,哈哈哈</h2>
<button type="button" @click="showParent">顯示父元件的資訊</button>
</div>
</template> <script type="text/javascript"> // 註冊父元件
Vue.component('parent-cpn',{
template: '#parentCpn',
data() {
return {
message: '我是父元件'
}
},
//註冊子元件
components: {
'child-cpn': {
template: '#childCpn',
methods: {
showParent() {
console.log(this.$parent.message)
}
}
} }
}); let app=new Vue({
el: '#app' })
</script>
</html>

6.3.4非父子元件通訊

剛才我們討論的都是父子元件間的通訊,那如果是非父子關係呢?非父子元件關係包括多個層級的元件,也包括兄弟元件的關係。在Vue1.x的時候,可以通過$dispatch和$broadcast完成。$dispatch用於向上級派發事件,$broadcast用於向下級廣播事件。但是在Vue2.x都被取消了,在Vue2.x中,有一種方案是通過中央事件匯流排,也就是一箇中介來完成。但是這種方案和直接使用Vuex的狀態管理方案還是遜色很多。並且Vuex提供了更多好用的功能,所以這裡我們暫且不討論這種方案,後續我們專門學習Vuex的狀態管理。

7.插槽slot

7.1編譯作用域

在真正學習插槽之前,我們需要先理解一個概念:編譯作用域。官方對於編譯的作用域解析比較簡單,我們自己來通過一個例子來理解這個概念:我們來考慮下面的程式碼是否最終是可以渲染出來的:

<my-cpn v-show="isShow"></my-cpn>這段程式碼中,我們使用了isShow屬性。isShow屬性包含在元件中,也包含在Vue例項中。

答案:最終可以渲染出來,也就是使用的是Vue例項的屬性。為什麼呢?

官方給出了一條準則:父元件模板的所有東西都會在父級作用域內編譯;子元件模板的所有東西都會在子級作用域內編譯。而我們在使用<my-cpn v-show="isShow"></my-cpn>的時候,整個元件的使用過程是相當於在父元件中出現的。那麼他的作用域就是父元件,使用的屬性也是屬於父元件的屬性。因此,isShow使用的是Vue例項中的屬性,而不是子元件的屬性。

7.2為什麼使用插槽(slot)

slot翻譯為插槽,在生活中很多地方都有插槽,電腦的USB插槽,插板當中的電源插槽。插槽的目的是讓我們原來的裝置具備更多的擴充套件性。比如電腦的USB我們可以插入U盤、硬碟、手機、音響、鍵盤、滑鼠等等。

元件的插槽:

元件的插槽也是為了讓我們封裝的元件更加具有擴充套件性。讓使用者可以決定元件內部的一些內容到底展示什麼。

栗子:移動網站中的導航欄

移動開發中,幾乎每個頁面都有導航欄。導航欄我們必然會封裝成一個外掛,比如nav-bar元件。一旦有了這個元件,我們就可以在多個頁面中複用了。例如京東的導航

7.3如何使用slot

如何去封裝這類的元件呢?

它們也很多區別,但是也有很多共性。如果,我們每一個單獨去封裝一個元件,顯然不合適:比如每個頁面都返回,這部分內容我們就要重複去封裝。但是,如果我們封裝成一個,好像也不合理:有些左側是選單,有些是返回,有些中間是搜尋,有些是文字,等等。

如何封裝合適呢?抽取共性,保留不同

最好的封裝方式就是將共性抽取到元件中,將不同暴露為插槽。一旦我們預留了插槽,就可以讓使用者根據自己的需求,決定插槽中插入什麼內容。是搜尋框,還是文字,還是選單。由呼叫者自己來決定。這就是為什麼我們要學習元件中的插槽slot的原因

7.4slot基本使用

瞭解了為什麼用slot,我們再來談談如何使用slot?在子元件中,使用特殊的元素<slot>就可以為子元件開啟一個插槽。該插槽插入什麼內容取決於父元件如何使用。

我們通過一個簡單的例子,來給子元件定義一個插槽:<slot>中的內容表示,如果沒有在該元件中插入任何其他內容,就預設顯示該內容

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 如果元件中沒有替換,則使用預設顯示內容 -->
<child-cpn></child-cpn>
<br/>
<child-cpn>
<!-- 使用自己的內容替換插槽的內容 -->
<h2>我是插槽的替換內容1</h2>
<p>我是插槽的替換內容2</p>
</child-cpn>
</div>
</body> <template id="childCpn">
<div>
<!-- 定義一個插槽 裡面有預設內容 -->
<slot>我是一個插槽中的預設內容</slot>
</div>
</template> <script type="text/javascript"> let app=new Vue({
el: '#app',
components: {
'child-cpn': {
template: '#childCpn'
}
}
})
</script>
</html>

7.5具名插槽slot

當子元件的功能複雜時,子元件的插槽可能並非是一個。比如我們封裝一個導航欄的子元件,可能就需要三個插槽,分別代表左邊、中間、右邊。那麼,外面在給插槽插入內容時,如何區分插入的是哪一個呢?這個時候,我們就需要給插槽起一個名字

如何使用具名插槽呢?非常簡單,只要給slot元素一個name屬性即可<slot name='myslot'></slot>

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 沒有傳入任何內容 -->
<child-cpn></child-cpn>
<br/>
<!-- 傳入某一個內容 -->
<child-cpn>
<span slot="left">我是返回</span>
</child-cpn>
<br/>
<!-- 傳入所有內容 -->
<child-cpn>
<span slot="left">我是返回</span>
<span slot="center">我是標題</span>
<span slot="right">我是選單</span>
</child-cpn>
</div>
</body> <template id="childCpn">
<div>
<slot name="left">左邊</slot>
<slot name="center">中間</slot>
<slot name="right">右邊</slot>
</div>
</template> <script type="text/javascript"> let app=new Vue({
el: '#app',
components: {
'child-cpn': {
template: '#childCpn'
}
}
})
</script>
</html>

7.6作用域插槽

作用域插槽是slot一個比較難理解的點,而且官方檔案說的又有點不清晰。這裡,我們用一句話對其做一個總結,然後我們在後續的案例中來體會:父元件替換插槽的標籤,但是內容由子元件來提供

我們先提一個需求:

子元件中包括一組資料,比如:pLanguages: ['JavaScript', 'Python', 'Swift', 'Go', 'C++'],需要在多個介面進行展示。某些介面是以水平方向一一展示的,某些介面是以列表形式展示的,某些介面直接展示一個陣列。內容在子元件,希望父元件告訴我們如何展示,怎麼辦呢?利用slot作用域插槽就可以了。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<my-cpn>
<!-- 通過<template slot-scope="slotProps">獲取到slotProps屬性 -->
<template slot-scope="slotProps">
<!-- 列表展示 -->
<ul>
<!-- 通過slotProps.data就可以獲取到剛才我們傳入的data -->
<li v-for="info in slotProps.data">{{info}}</li>
</ul>
</template>
</my-cpn> <my-cpn>
<template slot-scope="slotProps">
<!-- 水平展示 -->
<span v-for="info in slotProps.data">{{info}} </span>
</template>
</my-cpn>
</div>
</body> <template id="myCpn">
<div>
<slot :data="pLanguages"></slot>
</div>
</template> <script type="text/javascript"> let app=new Vue({
el: '#app',
components: {
'my-cpn': {
template: '#myCpn',
data() {
return {
pLanguages: [
'JavaScript', 'Python', 'Swift', 'Go', 'C++'
]
}
}
}
}
})
</script>
</html>