Vue – 如何使用作用域插槽 (Scoped Slots) 分割元件版面並餵入不同資料

這次我們示範要如何使用 slot 去製作分割組件。我希望呈現
- <header> + <main>
- <main> 包含了標題與三篇文章
- 三篇文章是從伺服器取得資料
影片教學
文字教學如下
1、建立 container 並加入第一個整體架構的組件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!-- 先建立父組件,形成整體框架 --> <template id="container"> <div class="container"> <header> <ul> <li>Home</li> <li>About</li> </ul> </header> </div> </template> <div class="app"> <c-container></c-container> </div> |
1 2 3 4 5 6 7 8 9 10 11 |
// 建立第一個父組件 Vue.component('c-container', { template: '#container' }) // 先初始化後 var vm = new Vue({ el: '.app' }) |
2、在父組件中,建立一個子組件,子組件有自己的樣式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<!-- 模版使用 main 包圍 --> <template id="content"> <main> <h1>瀏覽器</h1> <p>文字摘要介紹</p> </main> </template> <template id="container"> <div class="container"> <header> <ul> <li>Home</li> <li>About</li> </ul> </header> <!-- 加入子組件,放來放置主內容 --> <c-content></c-content> </div> </template> <div class="app"> <c-container></c-container> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 加入子組件 Vue.component('c-content', { template: '#content' }) Vue.component('c-container', { template: '#container' }) var vm = new Vue({ el: '.app' }) |
這是父組件的框架 + 子組件的內容樣式
3、父組件,建立準備分派到子組件的內容,也就是一個模版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<template id="content"> <main> <h1>瀏覽器</h1> <p>文字摘要介紹</p> </main> </template> <template id="container"> <div class="container"> <header> <ul> <li>Home</li> <li>About</li> </ul> </header> <!-- 1.加入子組件,放來放置主內容 --> <c-content> <!-- 2.使用 template 包圍,加入 scope 範圍屬性,指定一個暫時參數叫做屬性 props --> <template scope="props"> <!-- 3.準備批次顯示的模版樣式 --> <article> <h1>Title</h1> <p>Content</p> </article> </template> </c-content> </div> </template> <div class="app"> <c-container></c-container> </div> |
4. 在子組件,建立插槽 slot 的擺放位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<template id="content"> <main> <h1>瀏覽器</h1> <p>文字摘要介紹</p> <!-- 1.放置插槽,命名為 slot-content --> <slot name="slot-content"></slot> </main> </template> <template id="container"> <div class="container"> <header> <ul> <li>Home</li> <li>About</li> </ul> </header> <c-content> <!-- 2. 替模版指定對應的插槽為 slot-content --> <template scope="props" slot="slot-content"> <article> <h1>Title</h1> <p>Content</p> </article> </template> </c-content> </div> </template> <div class="app"> <c-container></c-container> </div> |
5. 在子組件建立 JSON 資料,例如透過 AJAX 遠端取得。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Vue.component('c-content', { template: '#content', // 假設從遠端取得了物件,使用 artlist 包裝 data: function (){ return { artlist: [ {title: 'Chrome', description: 'Chrome 描述...'}, {title: 'IE', description: 'IE 描述...'}, {title: 'Firefox', description: 'Firefox 描述...'}, ] } } }) Vue.component('c-container', { template: '#container' }) var vm = new Vue({ el: '.app' }) |
6. 修改子組件,讓插槽使用 for loop 逐一取出每筆資料
- :item 也就是 v-bind:item 的綁定自訂屬性的縮寫
- 可以參考
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<template id="content"> <main> <h1>瀏覽器</h1> <p>文字摘要介紹</p> <!-- 1. 每筆資料從 artlist 物件逐一取出,每筆用 val 承接 --> <!-- 將 val 放入自訂參數 item --> <slot name="slot-content" :item="val" v-for="val in artlist"></slot> </main> </template> <template id="container"> <div class="container"> <header> <ul> <li>Home</li> <li>About</li> </ul> </header> <c-content> <template scope="props" slot="slot-content"> <!-- 2. 範圍使用了自訂參數名稱叫做 props--> <!-- 所以子組件模版中的 item 會被放到 props 底下 --> <article> <h1>{{ props.item.title }}</h1> <p>{{ props.item.description }}</p> </article> </template> </c-content> </div> </template> <div class="app"> <c-container></c-container> </div> |
7、最後完成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<template id="content"> <main> <h1>瀏覽器</h1> <p>文字摘要介紹</p> <slot name="slot-content" :item="val" v-for="val in artlist"></slot> </main> </template> <template id="container"> <div class="container"> <header> <ul> <li>Home</li> <li>About</li> </ul> </header> <c-content> <template scope="props" slot="slot-content"> <article> <h1>{{ props.item.title }}</h1> <p>{{ props.item.description }}</p> </article> </template> </c-content> </div> </template> <div class="app"> <c-container></c-container> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Vue.component('c-content', { template: '#content', data: function (){ return { artlist: [ {title: 'Chrome', description: 'Chrome 描述...'}, {title: 'IE', description: 'IE 描述...'}, {title: 'Firefox', description: 'Firefox 描述...'}, ] } } }) Vue.component('c-container', { template: '#container' }) var vm = new Vue({ el: '.app' }) |