1、编译作用域:
官方的解释是:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译
例如:
Son.vue
<template>
<div>
<h2>子组件</h2>
<p>西安邮电大学</p>
</div>
</template>
<script>
export default {
name: "Son",
data(){
return {
isShow : true
}
}
}
</script>
Father.vue
<template>
<div>
<son v-show="isShow"></son>
</div>
</template>
<script>
import Son from "@/components/Son";
export default {
name: "Father",
data(){
return {
isShow: true
}
},
components: {Son}
}
</script>
最终的结果是:父组件中的isShow为true,子组件的内容会显示;这是因为:使用的时候,子组件的使用过程是在父组件中出现的,作用域就是父组件,使用的属性也是属于父组件的属性。因此,isShow使用的父组件中的属性,而不是子组件的属性。
2、什么是插槽(slot)?
插槽(slot)将父组件的内容与子组件的模板相混合,从而弥补了视图的不足。如果父组件没有插入内容,那么 slot 的内容就作为默认出现;若父组件插入了内容,则 slot 的内容将被插入的内容替换掉。
3、为什么要使用插槽slot
插槽的目的在于:使组件更具有扩展性。例如,电脑预留的usb接口,可以用来连接多种外部设备,耳机、音响、U盘等等,使得更具有扩展性。插槽slot的作用正是如此,例如,组件中的一个地方,默认情况下为button,而在使用的时候,有需求需扩展为span,扩展为input,这时候就需要使用到插槽。
组件的封装方式(抽取共性,保留不同):就是将共性抽取到组件中,将不同暴露为插槽。一旦预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容。是搜索框,还是文字,还是菜单。由调用者自己来决定。
4、插槽的使用
(1)匿名插槽(默认插槽):<slot></slot>,有且只有一个
Son.vue
<template>
<div>
<h2>子组件</h2>
<p>西安邮电大学</p>
<slot></slot> <!-- 插槽 -->
</div>
</template>
<script>
export default {
name: "Son"
}
</script>
Father.vue
<template>
<div>
<son>
<button>演示按钮</button> <!-- 放在插槽位置 -->
</son>
<son></son>
</div>
</template>
<script>
import Son from "@/components/Son";
export default {
name: "Father",
components: {Son}
}
</script>
(2)具名插槽
当子组件的功能复杂时,子组件的插槽可能并非是一个。比如封装一个导航栏的子组件,可能就需要三个插槽,分别代表左边、中间、右边。那么,外面在给插槽插入内容时,如何区分插入的是哪一个呢?这时候,就需要给slot指定一个name属性,也就是具名插槽。
Son.vue
<template>
<div>
<slot name="top"></slot><!-- 插槽 -->
<h2>子组件</h2>
<slot name="center"></slot><!-- 插槽 -->
<p>西安邮电大学</p>
<slot name="bottom"></slot><!-- 插槽 -->
</div>
</template>
<script>
export default {
name: "Son"
}
</script>
Father.vue
<template>
<son>
<template v-slot:top>
<button>插槽演示</button>
</template>
<template v-slot:center>
<input type="text"/>
</template>
<template #bottom> <!--具名插槽的简写-->
<p>Vue3中插槽</p>
</template>
<template v-slot:default> <!--默认插槽-->
<select>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</template>
</son>
</template>
<script>
import Son from "@/components/Son";
export default {
name: "Father",
components: {Son}
}
</script>
(3)作用域插槽
父组件在使用的时候可以替换slot插槽中的显示页面结构,但展示的数据还是来源于子组件。
例如:有一个需求,子组件中包括一组数据,比如:Languages: [‘JavaScript’, ‘Python’, ‘Swift’, ‘Go’, ‘C++’]
需要在多个界面进行展示:
A、某些界面以水平方向展示
B、某些界面以列表方式展示
Son.vue
<template>
<div>
<h2>子组件</h2>
<p>西安邮电大学</p>
<slot :language="languageList"></slot>
</div>
</template>
<script>
export default {
name: "Son",
data(){
return {
languageList:['JavaScript','Python','Swift','Go','C++']
}
}
}
</script>
Father.vue
<template>
<div>
<!--展示结构1:水平方向展示-->
<son>
<template slot-scope="slotProps">
<h2>{{ slotProps.language.join('--')}}</h2>
</template>
</son>
<!--展示结构2:列表形式展示-->
<son>
<template slot-scope="slotProps">
<ul>
<li v-for="(item,index) in slotProps.language" :key="index">{{ item }}</li>
</ul>
</template>
</son>
</div>
</template>
<script>
import Son from "@/components/Son";
export default {
name: "Father",
components: {Son}
}
</script>
5、v-slot指令
在 Vue2.6.0 中,为插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍在使用的特性
(1)匿名插槽(默认插槽default)中使用v-slot指令
Son.vue
<template>
<div>
<h2>子组件</h2>
<p>西安邮电大学</p>
<slot></slot>
</div>
</template>
<script>
export default {
name: "Son"
}
</script>
Father.vue
<template>
<div>
<son>
<template v-slot:default>
<button>匿名插槽演示</button>
</template>
</son>
</div>
</template>
<script>
import Son from "@/components/Son";
export default {
name: "Father",
components: {Son}
}
</script>
(2)具名插槽中使用v-slot指令
Son.vue
<template>
<div>
<slot name="top"></slot>
<h2>子组件</h2>
<slot name="center"></slot>
<p>西安邮电大学</p>
<slot name="bottom"></slot>
</div>
</template>
<script>
export default {
name: "Son"
}
</script>
Father.vue
<template>
<div>
<son>
<template v-slot:center>
<button>具名插槽演示</button>
</template>
</son>
</div>
</template>
<script>
import Son from "@/components/Son";
export default {
name: "Father",
components: {Son}
}
</script>
(3)作用域插槽中使用v-slot指令
Son.vue
<template>
<div>
<h2>子组件</h2>
<p>西安邮电大学</p>
<slot :language="languageList" name="xy"></slot>
<slot :language="languageList" name="zf"></slot>
</div>
</template>
<script>
export default {
name: "Son",
data(){
return {
languageList:['JavaScript','Python','Swift','Go','C++']
}
}
}
</script>
Father.vue
<template>
<div>
<!--展示结构1:水平方向展示-->
<son>
<template v-slot:zf="slotProps">
<h2>{{ slotProps.language.join('--')}}</h2>
</template>
</son>
<!--展示结构2:列表形式展示-->
<son>
<template v-slot:xy="slotProps">
<ul>
<li v-for="(item,index) in slotProps.language" :key="index">{{ item }}</li>
</ul>
</template>
</son>
</div>
</template>
<script>
import Son from "@/components/Son";
export default {
name: "Father",
components: {Son}
}
</script>