最近在 youtube 找到一个学习 webpack 很好用的教学影片,所以正努力的学习 webpack 中,一个不小心就太沉迷在新技术的练习了,导致有点忽略 Vue.js 的笔记,再次跟自己喊话,一定要做完 Vue.js 的系列(之後还有 Vuex 跟 Vuetify 呢!)。
另外说明一下,我笔记的顺序是我自己认为这样的顺序比较好理解,所以会跟文件中的说明顺序有差异。
在设定模组时,会透过 template
来决定模组在页面上要显示的内容,而我们可以在 template
中加入 <slot>
标签来设定模组标签内容的位置,并且在网页显示的时候,模组标签的内容会取代该 <slot>
标签。
模组标签里的内容可以是纯文本、 HTML 标签或其他模组等等。
<basic-slot>
Next
<i class="fas fa-angle-right"></i>
</basic-slot>
<script>
Vue.component("basic-slot", {
// <slot></slot>指定外层模组标签内容放置的位置
// 可放入纯文本、html标签、其他模组
template: `<div>
<div>
<slot></slot>
</div>
</div>`
});
</script>
直接在 <slot>
标签内写定预设内容,如果模组标签内没有任何内容,那麽该 component 的画面显示就是该预设内容。
<!-- 模组标签没有任何内容 -->
<basic-slot></basic-slot>
<script>
Vue.component("basic-slot", {
// 在 <slot> 标签中设定模组画面内容的预设值
template: `<div>
<div>
<slot>
Preview
</slot>
</div>
</div>`
});
</script>
如果要将不同内容的插槽资料分类,就可以透过 <slot name="slotName">
及 v-slot:slotName
的来命名插槽及决定不同内容所放置的位置。
如果 <slot
标签未命名的话,预设的名字是 default
,所以在模组标签可以透过 v-slot:default
或是不写 v-slot:default
来找到那个未命名的 <slot
标签。
须注意 v-slot
只能添加在 <template>
上。除非是只有默认插槽的状况才可写在模组标签上
<name-slot>
<!-- 为了最後显示时不要有太多标签,所以使用template来避免出现太多元素-->
<!-- 对应模组内名为 footer 的插槽位置-->
<template v-slot:footer>
<h4>Here is footer</h4>
</template>
<!-- 对应模组内名为 header 的插槽位置-->
<template v-slot:header>
<h4>Here is header</h4>
</template>
<!-- 对应模组内名为 container 的插槽位置-->
<template v-slot:container>
<h4>Here is container</h4>
</template>
<!-- 对应模组内未命名或名为 default 的插槽位置-->
<template>
<h4>Here is default</h4>
</template>
<!-- <template>
<h4>Here is default</h4>
</template> 跟下面意思相同-->
<template v-slot:default>
<h4>Here is default</h4>
</template>
</name-slot>
<script>
Vue.component("name-slot", {
// 在 <slot> 标签中利用 attribute 来命名插槽,并决定不同名字的插槽内容在画面显示後的位置
template: `<div>
<div>
<slot name="header"></slot>
<slot name="container"></slot>
<slot name="footer"></slot>
<slot></slot>
</div>
</div>`
});
</script>
只有下面这种情况才可以将 v-slot:default
写在模组标签上,另外要注意也不能将 default 改成其他名字喔!
<name-slot v-slot:default>
<h4>Here is default</h4>
</name-slot>
<script>
Vue.component("default-slot", {
template: `<div>
<slot></slot>
</div>`
});
</script>
在模组标签中的内容只能取得该层的资料,而在模组内的 <slot>
标签也只能取得模组内的资料,简单来说就是在哪设定要取资料就是只能取得那一层的资料。
<scoped-slot name="Michelle">
外层的 data 资料:{{ user.name }},
模组内的 props 资料: {{ name }}
模组内的 data 资料: {{ user2.name }}
</scoped-slot>
<script>
Vue.component("scoped-slot", {
template: `<div>
<div>
<slot></slot>
</div>
</div>`,
data() {
return {
user2: {
name: "Linda",
age: 9
}
};
}
});
const vm = new Vue({
el: "#vm",
data: {
user: {
name: "Celeste",
age: 18
}
}
});
</script>
以上面为例,会发现只要是想取得模组内的 data
或是 props
都会是失败的(会出错),但是取得外层(模组标签那一层)资料是成功的。
<scoped-slot name="Michelle"></scoped-slot>
<script>
Vue.component("scoped-slot", {
props:[ 'name' ],
template: `<div>
<div>
<slot>
模组内的 props 资料: {{ name }},
模组内的 data 资料: {{ user2.name }},
外层的 data 资料:{{ user.name }}
</slot>
</div>
</div>`,
data() {
return {
user2: {
name: "Linda",
age: 9
}
};
}
});
const vm = new Vue({
el: "#vm",
data: {
user: {
name: "Celeste",
age: 18
}
}
});
</script>
如果是在 <slot>
中设定预设值,会发现在 <slot>
内只能取得该模组内的资料(如 data
或是 props
),如果想要取得外层的 data
资料会出错。
如上面所说,一般情况下外层无法取得内层的资料,但是可以透过在 <slot name="slotName" v-bind:slotPropName="slotPropValue">
标签上设定 Attribute 来动态绑定值以将内层的值往外传到外层去,而外层透过 v-slot:slotName="customName"
或是 ES6语法 v-slot:slotName="{ slotPropName }"
来决定适用哪一个作用域。
使用 v-slot:slotName="customName"
设定 customName
来接收从 <slot>
接收的动态绑定值,像是将所有动态绑定的值放入 customName
这个物件中。
<!-- 用 slotProps 来接收从 slot 传进来的值 -->
<v-bind-slot v-slot:default="customName">
姓{{ slotProps.user.firstName }},
年龄{{ slotProps.user.age }}
喜欢水果{{ slotProps.fruit[0] }}
</v-bind-slot>
<script>
Vue.component("v-bind-slot", {
template: `<div>
<div>
<slot :user="user" :fruit="fruit">
{{ user.lastName }}
</slot>
</div>
</div>`,
data() {
return {
user: {
lastName: "Linda",
firstName: "KUO",
age: 9
},
fruit: ["apple", "banana", "orange"]
};
}
});
</script>
使用 v-slot:slotName="{ slotPropName }"
透过 ES6 解构语法来将动态绑定值一一传入。
<!-- 用解构语法来接收从 slot 传进来的值 -->
<v-bind-slot v-slot:default="{ user, fruit }">
姓{{ slotProps.user.firstName }},
年龄{{ slotProps.user.age }}
喜欢水果{{ slotProps.fruit[0] }}
</v-bind-slot>
<script>
Vue.component("v-bind-slot", {
template: `<div>
<div>
<slot :user="user" :fruit="fruit">
{{ user.lastName }}
</slot>
</div>
</div>`,
data() {
return {
user: {
lastName: "Linda",
firstName: "KUO",
age: 9
},
fruit: ["apple", "banana", "orange"]
};
}
});
</script>
只有在自己那个具名插槽中有绑定的 Attribute 才可以在外层相同名字的 v-slot
作用域中使用。
<v-bind-slot>
<template v-slot:default="{ user, fruit }">
姓{{ user.firstName }},
年龄{{ user.age }}
喜欢水果{{ fruit[1] }}
<br/>
</template>
<template v-slot:cellphone="{ cellphone, fruit }">
<!-- user未在名为 cellphone 的插槽中绑定,所以不可以在这个作用域使用 -->
姓{{ user.firstName }},
手机{{ cellphone[2] }}
喜欢水果{{ fruit[1] }}
</template>
</v-bind-slot>
<script>
Vue.component("v-bind-slot", {
template: `<div>
<div>
<slot name="default" :user="user" :fruit="fruit"></slot>
<slot name="cellphone" :cellphone="cellphone" :fruit="fruit"></slot>
</div>
</div>`,
data() {
return {
user: {
lastName: "Linda",
firstName: "KUO",
age: 9
},
fruit: ["apple", "banana", "orange"],
cellphone: ["iphone", "samsung", "oppo"]
};
}
});
</script>
可以透过 v-slot:[动态插槽名]
来动态可以模组标签内容的位置。
另须注意动态插槽名需全为小写,因为 Vue 会自动将该动态插槽名转为小写,而导致在外层找不到该笔资料( dynamicslotname
!==dynamicSlotName
)。
<dynamic-slot>
<!--动态插槽名要全为小写-->
<!--error-->
<template v-slot:[dynamicSlotName]>
I am {{dynamicSlotName}}
</template>
<template v-slot:[lowercaseslotname]>
I am {{lowercaseslotname}}
</template>
</dynamic-slot>
<script>
Vue.component("dynamic-slot", {
template: `<div>
<slot name="header">Here is header</slot>
<br/>
<slot name="container">Here is container</slot>
<br/>
<slot name="footer">Here is footer</slot>
<slot></slot>
</div>`
});
const vm = new Vue({
el: "#vm",
data: {
user: {
name: "Celeste"
},
dynamicSlotName: "header",
lowercaseslotname: "footer"
}
});
</script>
v-slot
缩写可以将以 #
来缩写 v-slot
,像是 v-slot:header
可以缩写成 #header
,v-slot:footer={ user }
可以缩写成 #footer={ user }
,另外要注意使用缩写字符时一定要有参数,例如 #footer={ user }
, footer
即为参数,不可以只有 #={ user }
,这样会出错,如果是预设值的状况可以写成 #default={ user }
。
Demo:DAY14 | 跟 Vue.js 认识的30天 - Vue 模组插槽(slot
)
参考资料:
>>: 〖WordPress主题〗ASTRA释出「AGENCY BUNDLE」头500名购买只要$149的超级优惠
昨天的字典进阶操作你有没有学会呢?如果还是不熟悉记得要再去复习呀~ 今天又是一个新容器了,集合跟串列...
Online threats, such as spyware, phishing and iden...
注:发文日和截图的日期不一定是同一天,所以价格计算上和当日不同,是很正常的。 声明:这一系列文章并无...
前言 前面两天刻了两个 view, 现在要用 Navigation 来把它们连接起来。 实作 在 R...
范例档案 GitHub Repo: https://github.com/kaochenlong/...