Vue2--Vue中slot插槽

278 阅读2分钟

插槽介绍

1、作用:让父组件可以向子组件指定位置插入html,也是一种组件间通信的方式,适用于父组件==>子组件

2、分类:默认插槽、具名插槽、作用域插槽

3、使用方式:

(1)默认插槽

父组件中:
    <Category>
        <div>html结构1</div>
    </Category>
    
子组件中:
    <template>
        <div>
            <!-- 定义插槽 -->
            <slot>插槽默认内容....</slot>
        </div>
    </template>

(2)具名插槽

父组件中:
    <Category>
        <template slot = "center">
            <div>html结构1</div>
        </template>
        
        <template v-slot:footer>
            <div>html结构2</div>
        </template>
    </Category>
    
子组件中:
    <template>
        <div>
            <!-- 定义插槽 -->
            <slot name="center">插槽默认内容....</slot>
            <slot name="footer">插槽默认内容....</slot>
        </div>
    </template>

(3)作用域插槽

  • 理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据再Category组件中,但使用数据所遍历出来的结构由App组件决定)

  • 具体编码:

父组件中:
    <Category>
        <template slot = "scopeData">
            <!-- 生成的是ul列表 -->
            <ul>
                <li v-for="g in scopeData.games" :key="g>{{g}}</li>
            </ul>
        </template>
        
        <!-- slot的另一种写法 -->
        <template slot-scope="scopeData">
            <!-- 生成的是h4标题 -->
            <ul>
                <h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
            </ul>
        </template>
    </Category>
    
子组件中:
    <template>
        <div>
            <!-- 定义插槽 -->
            <slot :games="games"></slot>
        </div>
    </template>
    
    
    <script>
        export default{
            name:'Category',
            props:['title'],
            //数据在子组件自身
            data() {
                return {
                    games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
                }
            }
        }
    </script>
    

案例一(默认插槽)

1、需求,三个列表,第一个和第三个显示图片,第二个显示列表文字

2、实现:

  • App.vue
<template>
	<div class="category">
		<h3>{{title}}分类</h3>
		<!-- 使用默认插槽,等待组件的使用者进行填充,如果不传内容会出现slot中的文字内容 -->
		<slot>我是一些默认值,当使用者没有传递具体结构时我会出现</slot>
	</div>
</template>

<script>
	export default {
		name:'Category',
		props:['title'],
	}
</script>

<style>
	.category{
		background-color: skyblue;
		width: 200px;
		height: 300px;
	}
	h3{
		text-align: center;
		background-color: orange;
	}
</style>

  • Category.vue
<template>
    <div class="container">
		<Category title="美食">
			<!-- 组件标签的标签体内容 -->
			<img src="./components/foods.png" alt="" />
		</Category>

		<Category title="游戏">
			<ul>
				<li v-for="(g,index) in games" :key="index">{{g}}</li>
			</ul>
		</Category>
		
		<Category title="电影">
			<img src="./components/Default.jpg" alt="" />
		</Category>
	</div>
</template>

<script scoped>
	import Category from './components/Category.vue'
	export default {
		name:'App',
		components:{Category},
		data() {
			return {
				foods:['火锅','烧烤','小龙虾','牛排'],
				games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
				films:['《教父》','《拆弹专家》','《你好,李焕英》','《上硅谷》'],
			}
		},
	}
</script>

<style>
	.container{
		display: flex;
		justify-content: space-around;
	}
	img{
		width: 100%;
	}
	
</style>

3、效果:

image.png

案例二(具名插槽)

1、需求:在组件中定义两个插槽,每个插槽展示不同的内容

2、实现:

  • App.vue
<template>
    <div class="container">
		<Category title="美食">
			<img slot="slot1" src="./components/foods.png" alt="" />
			<a slot="slot2" href="http://baidu.com">更多美食</a>
		</Category>
		<Category title="游戏">
			<ul slot="slot1">
				<li v-for="(g,index) in games" :key="index">{{g}}</li>
			</ul>
			<div class="meishi" slot="slot2">
				<a href="http://baidu.com">单机游戏</a>
				<a href="http://baidu.com">网络游戏</a>
			</div>
		</Category>
		<Category title="电影">
			<img slot="slot1" src="./components/Default.jpg" alt="" />
			<!-- 只有template才能写成v-slot:slot2,其他标签都要写成slot="slot2" -->
			<template v-slot:slot2>
				<div class="meishi">
					<a href="http://baidu.com">经典</a>
					<a href="http://baidu.com">热门</a>
					<a href="http://baidu.com">推荐</a>
				</div>
				<h4>欢迎前来观影</h4>
			</template>
		</Category>
	</div>
</template>

<script scoped>
	import Category from './components/Category.vue'
	export default {
		name:'App',
		components:{Category},
		data() {
			return {
				foods:['火锅','烧烤','小龙虾','牛排'],
				games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
				films:['《教父》','《拆弹专家》','《你好,李焕英》','《上硅谷》'],
			}
		},
	}
</script>

<style>
	.container, .meishi{
		display: flex;
		justify-content: space-around;
	}
	img{
		width: 100%;
	}
	h4{
		text-align: center;
	}
	
</style>

  • Category.vue
<template>
	<div class="category">
		<h3>{{title}}分类</h3>
		<slot name="slot1" >我是一些默认值1,当使用者没有传递具体结构时我会出现</slot>
		<slot name="slot2" >我是一些默认值2,当使用者没有传递具体结构时我会出现</slot>
	</div>
</template>

<script>
	export default {
		name:'Category',
		props:['title'],
	}
</script>

<style>
	.category{
		background-color: skyblue;
		width: 200px;
		height: 300px;
	}
	h3{
		text-align: center;
		background-color: orange;
	}
</style>

3、效果:

image.png

案例三(作用域插槽)

1、需求:将数据放在Categoy组件中,只保留游戏数据;第一次生成一个无序列表,第二次生成一个有序列表,第三次生成一个h4标题

2、实现:

  • App.vue
<template>
    <div class="container">
		<Category title="美食">
			<!-- 使用template标签接收插槽中传来的数据 -->
			<template scope="atguigu">
				<ul>
					<li v-for="(g,index) in atguigu.games" :key="index">{{g}}</li>
				</ul>
			</template>
		</Category>
		<Category title="游戏">
			<template scope="{games}">
				<ol style="color: red;">
					<li v-for="(g,index) in games" :key="index">{{g}}</li>
				</ol>
			</template>
		</Category>
		<Category title="电影">
			<template scope="{games}">
					<h4 v-for="(g,index) in games" :key="index">{{g}}</h4>
			</template>
		</Category>
	</div>
</template>

<script scoped>
	import Category from './components/Category.vue'
	export default {
		name:'App',
		components:{Category},
	}
</script>

<style>
	.container, .meishi{
		display: flex;
		justify-content: space-around;
	}
	video{
		width: 100%;
	}
	img{
		width: 100%;
	}
	h4{
		text-align: center;
	}
	
</style>

  • Category.vue
<template>
	<div class="category">
		<h3>{{title}}分类</h3>
		<slot :games="games" >我是一些默认值,当使用者没有传递具体结构时我会出现</slot>
	</div>
</template>

<script>
	export default {
		name:'Category',
		props:['title'],
		data() {
			return {
				games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
			}
		},
	}
</script>

<style>
	.category{
		background-color: skyblue;
		width: 200px;
		height: 300px;
	}
	h3{
		text-align: center;
		background-color: orange;
	}
</style>

3、效果:

image.png