插槽的作用
相信看過前一篇元件化開發後,你對元件化開發有了新的認識。
插槽是幹什麼的呢?它其實是配合元件一起使用的,讓一個元件能夠更加的靈活多變,如下圖所示,你可以將元件當作一塊電腦主機板,將插槽當作主機板上的插槽,你可以隨意的更換該主機板上的零件。
常見的應用場景,如淘寶的導航條:
其實他們大體框架都是一樣的,只是內容不同罷了。我們就可以將這個導航條定義為一個元件,而內容不同的地方都定義為一個插槽,到了不同的場景更換不同插槽即可。
匿名插槽
使用<slot>
定義插槽,當父元件模板中引用子元件時,可向該插槽插入內容,如下所示:
- 一個元件中最多隻能擁有一個匿名插槽,它其實也叫預設插槽
- 每個插槽都可以有預設值
<body>
<div id="app">
<navigation>
<span>這是導航</span>
</navigation>
</div>
<template id="navigation">
<main>
<slot>沒有內容時顯示我</slot>
</main>
</template>
<script src="./vue.js"></script>
<script>
Vue.component("navigation", {
template: "#navigation",
})
const app = new Vue({
el: "#app",
})
</script>
</body>
具名插槽
實際開發中使用最多的還是具名插槽,給每個<slot>
新增一個name
屬性。
在插入內容時,指定slot
屬性為<slot>
的name
屬性進行一一插入即可。
如下所示,定義了三種不同的搜尋框,都是用的同一個元件:
<style>
@font-face {
font-family: 'iconfont'; /* project id 1953712 */
src: url('//at.alicdn.com/t/font_1953712_uiyayrse2ul.eot');
src: url('//at.alicdn.com/t/font_1953712_uiyayrse2ul.eot?#iefix') format('embedded-opentype'),
url('//at.alicdn.com/t/font_1953712_uiyayrse2ul.woff2') format('woff2'),
url('//at.alicdn.com/t/font_1953712_uiyayrse2ul.woff') format('woff'),
url('//at.alicdn.com/t/font_1953712_uiyayrse2ul.ttf') format('truetype'),
url('//at.alicdn.com/t/font_1953712_uiyayrse2ul.svg#iconfont') format('svg');
}
.iconfont {
font-family: "iconfont";
font-size: 16px;
font-style: normal;
}
i {
flex-grow: 2;
text-align: center;
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
nav {
width: 100%;
background-color: rgba(255, 162, 109, 0.8);
padding: 10px;
margin-bottom: 20px;
}
.navigation {
display: inline-flex;
justify-content: space-around;
align-items: center;
width: 100%;
}
input {
flex-grow: 6;
border-radius: 3rem;
text-align: center;
outline: none;
}
</style>
<body>
<div id="app">
<!-- 第一個個導航條,中間用預設的input框 -->
<nav>
<navigation class="navigation">
<!-- 插入時,指定slot屬性 -->
<i class="iconfont" slot="left" :style="{fontSize:'2rem'}"></i>
<i class="iconfont" slot="right" :style="{fontSize:'2rem'}"></i>
</navigation>
</nav>
<!-- 第二個導航條,不需要預設的input框,所以用div填充 -->
<nav style="background-color: aliceblue">
<navigation class="navigation">
<i class="iconfont" slot="left" :style="{fontSize:'2rem'}"></i>
<div slot="mid" style="width: 70%;text-align: center">雙十一狂歡夜</div>
<i class="iconfont" slot="right" :style="{fontSize:'2rem'}"></i>
</navigation>
</nav>
<!-- 第三個導航條,不需要預設的input框,所以用div填充 -->
<nav style="background-color: #ffaad8">
<navigation class="navigation">
<i class="iconfont" slot="left" :style="{fontSize:'2rem'}"></i>
<div slot="mid" style="width: 70%;text-align: center">我的資料</div>
<i class="iconfont" slot="right" :style="{fontSize:'2rem'}"></i>
</navigation>
</nav>
</div>
<template id="navigation">
<main>
<!-- 給插槽取名 name屬性-->
<slot name="left"></slot>
<slot name="mid"><input type="text" placeholder="輸入你的搜尋項" :style="{height:'2rem'}"></slot>
<slot name="right"></slot>
</main>
</template>
<script src="./vue.js"></script>
<script>
Vue.component("navigation", {
template: "#navigation",
})
const app = new Vue({
el: "#app",
})
</script>
</body>
編譯作用域
編譯作用域的意思是,在那個元件的模板中,渲染時的資料就查詢那個元件。
如下所示,父元件和子元件都有一個變數show
,同時子元件中擁有一個插槽,將插槽插入子元件時用了v-show
指令,那麼這個被插入的元素會去找子元件的show
還是找父元件的show
呢?
答案是父元件,因為插入插槽的元素是書寫在父元件中的。
<body>
<div id="app">
<cpn>
<span slot="cpn-slot" v-show="show">引用父元件的show</span>
</cpn>
</div>
<!-- 子元件模板 -->
<template id="cpn-template">
<div>
<span v-show="show">引用子元件的show</span>
<slot name="cpn-slot"></slot>
</div>
</template>
<script src="./vue.js"></script>
<script>
var cpn = {
template: "#cpn-template",
data() {
return {
show: false,
}
}
}
const app = new Vue({
el: "#app",
data: {
show: true,
},
components: { // Vue例項內部進行註冊
cpn,
},
})
</script>
</body>
作用域插槽
作用域插槽使用較少,它核心理念就是用父元件來渲染子元件。
如下程式碼中出現一個問題,我們如果直接進行渲染,就把程式碼寫死了,要想改變樣式那麼所有引用該子元件的地方樣式都會改變:
<body>
<div id="app">
<cpn :user-msg="msg"></cpn>
</div>
<!-- 子元件模板 -->
<template id="cpn-template">
<div>
<ul>
<li v-for="row in userMsg">{{row}}</li>
</ul>
</div>
</template>
<script src="./vue.js"></script>
<script>
var cpn = {
template: "#cpn-template",
props: ["userMsg",],
}
const app = new Vue({
el: "#app",
data: {
msg: {
id: 1,
name: "yunya",
age: 18,
}
},
components: {
cpn,
}
})
</script>
</body>
此時就可以使用作用域插槽,由父元件來渲染子元件。
使用作用域插槽遵循三個點:
1.必須使用DOM不識別的標籤,如template進行接收子元件插槽屬性
2.接收子元件插槽屬性的屬性是scope
3.scope是一個物件
以下是渲染結果,由父元件渲染子元件,給他加粗:
<body>
<div id="app">
<cpn :user-msg="msg">
<template slot="message" scope="v">
<ul>
<li><b>{{v.field}}</b></li>
</ul>
</template>
</cpn>
</div>
<!-- 子元件模板 -->
<template id="cpn-template">
<div>
<slot name="message" v-for="row in userMsg" :field="row"></slot>
</div>
</template>
<script src="./vue.js"></script>
<script>
var cpn = {
template: "#cpn-template",
props: ["userMsg",],
}
const app = new Vue({
el: "#app",
data: {
msg: {
id: 1,
name: "yunya",
age: 18,
}
},
components: {
cpn,
}
})
</script>
</body>
再配一張圖吧,看看每次的v
是長什麼樣子: