对作用域插槽的理解:slot-scope

一,先来看看普通的组件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<link rel="stylesheet" type="text/css" href="css/base.css"/>
		<style type="text/css">
			#app{
				width: 20%;
				margin: 200px auto;
				border: 1px solid #ccc;
				line-height: 30px;
				padding: 20px;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<fruit-list :sonlist="list">
				<!-- 这里的fruit-list是父组件app的一个html标签,
				父组件向子组件fruit-list属性绑定的方式传值list,
				于是fruit-list子组件里面必然有props:['sonlist'],来接收这个父组件传过来的list -->
			</fruit-list>
		</div>
		
		<script type="text/javascript" src="js/vue.min.js"></script>
		<script type="text/javascript">
		//子组件
			Vue.component('fruit-list',{
				props:['sonlist'],
				template:`
					<div>
						<li :key='item.id' v-for='item in sonlist'>
							<span>{{item.name}}</span>
						</li>
					</div>
				`
				})
				//父组件
			var vm= new Vue({
			    el:'#app',
				data:{
					list:[{
						id:1,
						name:'apple'
					},
					{
						id:2,
						name:'orange'
					},
					{
						id:3,
						name:'banana'
					}]
				}
			})
			
		</script>
	</body>
</html>

实现的效果:
在这里插入图片描述
但如果想要对其中的一个数据做出一些变化,比如第三个数据让它显示为红色?那该怎么办?
匿名插槽??他不行,他只是在本组件的html结构基础上的其中一个位置中加入新的html结构:
在这里插入图片描述
具名插槽??他也不行,他只是在本组件的html结构基础上的特定几个位置中加入新的html结构:
在这里插入图片描述

另外,还有一件事需要明确一下:
在这里插入图片描述
这里模板字符串里面的标签虽然是写在子组件中的,但是实际在浏览器中渲染出来:
,,在这里插入图片描述
却是在父组件app下的,也就是说想要让第三个数据变成红色(不考虑之前学过的css样式的知识哈!),就需要让父组件知道,哪个是第三个组件,于是引入了作用域插槽,它可以把子组件的数据通过slot-scope再传递给父组件,然后在父组件中直接书写html结构:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<link rel="stylesheet" type="text/css" href="css/base.css"/>
		<style type="text/css">
			#app{
				width: 20%;
				margin: 200px auto;
				border: 1px solid #ccc;
				line-height: 30px;
				padding: 20px;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<fruit-list :sonlist="list">
				<template slot-scope='slotprops'>
					 <!-- 通过template的slot-scope获取子组件传过来的数据,存在slotprops对象中 -->
					 <!-- 也就是说子组件属性绑定的每一个info都将作为这个对象的属性值 -->
					<strong v-if='slotprops.info.id==3' style="color: red;">{{slotprops.info.name}}</strong>
					<span v-else>{{slotprops.info.name}}</span>
				</template>
			</fruit-list>
		</div>
		
		<script type="text/javascript" src="js/vue.min.js"></script>
		<script type="text/javascript">
			Vue.component('fruit-list',{
				props:['sonlist'],
				template:`
					<div>
						<li :key='item.id' v-for='item in sonlist'>
							<slot :info='item'></slot>
						</li>
					</div>
				`
				//利用属性绑定,将每一个item转化为info,传递给父组件
				})
			var vm= new Vue({
			    el:'#app',
				data:{
					list:[{
						id:1,
						name:'apple'
					},
					{
						id:2,
						name:'orange'
					},
					{
						id:3,
						name:'banana'
					}]
				}
			})
			
		</script>
	</body>
</html>

二,作用域插槽的使用方法

第一步:父组件通过子组件标签属性绑定传递了list数组给子组件
第二步:子组件通过propos接收了父组件传递过来的数据
第三步:子组件拿到数组后,使用v-for渲染列表,并通过slot :info='item’的方式,把数据同样通过属性绑定的方式(渲染出来后就到父组件那边去了),把数组中的每一个对象都传递给父组件。
第四步:父组件通过template slot-scope=‘slotprops’></template的方式接收对象,并把所有接收到的对象保存到slotprops对象当中。

这样一来,list数组就经历了以下几个步骤:
1,父组件传递list数组给子组件
2,子组件接收list数组,用v-for取出里面的每一个对象后,又传递给父组件。
3,父组件接收每一个对象,并存储在slotprops对象中。

三,一个疑惑

既然数据在父组件中,为啥要传给子组件,又要子组件传回来。不麻烦吗?不是有病吗???
这是因为,列表的渲染是需要子组件利用v-for进行的!所以子组件需要获取数据。
而父组件中插槽位置处添加的html结构,又需要使用到对应的信息,所以数据又得从子组件处传递回来。
那为什么不直接使用父组件中的数据呢?
当然是可以的,但这样一来,组件化开发不复存在,只是很机械地使用父组件的数据写html结构罢了。

四,一个简单的案例

网上也有人说,作用域插槽是带数据的插槽。也可以这么理解,而且这个数据来源于子组件的模板字符串通过属性绑定携带过来的,也就是说,作用域插槽,子组件的模板字符串属性绑定来控制传递过来的数据,而父组件的插槽内容则是控制显示的html内容。
子组件的模板字符串属性绑定来控制传递过来的数据:

Vue.component('fruit-list',{
	props:['sonlist'],
		template:`
			<div>
				<li :key='item.id' v-for='item in sonlist'>
					<slot :info='item'></slot>
				</li>
			</div>
		`
		//利用属性绑定,将每一个item转化为info,传递给父组件
		})

父组件的插槽内容则是控制显示的html内容:

<fruit-list :sonlist="list">
	<template slot-scope='slotprops'>
			 <!-- 通过template的slot-scope获取子组件传过来的数据,存在slotprops对象中 -->
			 <!-- 也就是说子组件属性绑定的每一个info都将作为这个对象的属性值 -->
			<strong v-if='slotprops.info.id==3' style="color: red;">{{slotprops.info.name}}</strong>
			<span v-else>{{slotprops.info.name}}</span>
		</template>
	</fruit-list>

举个简单的示例:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<link rel="stylesheet" type="text/css" href="css/base.css"/>
		<style type="text/css">
			#app{
				width: 20%;
				margin: 200px auto;
				border: 1px solid #ccc;
				line-height: 30px;
				padding: 20px;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<testone :sonlist="list">
				<template slot-scope="fatherObject">
					<span>{{fatherObject.info.name}}</span>
				</template>
			</testone>
			
			<hr>
			
			<testone :sonlist="list">
				<template slot-scope="fatherObject">
					<span>{{fatherObject.info.id}}</span>
				</template>
			</testone>
		</div>
		
		<script type="text/javascript" src="js/vue.min.js"></script>
		<script type="text/javascript">
			Vue.component('testone',{
				props:['sonlist'],
				template:`
					<div>
						<li :key='item.id' v-for='item in sonlist'>
							<slot :info='item'></slot>
						</li>
					</div>
				`
				//利用属性绑定,将每一个item转化为info,传递给父组件
				})
			var vm= new Vue({
			    el:'#app',
				data:{
					list:[{
						id:1,
						name:'apple'
					},
					{
						id:2,
						name:'orange'
					},
					{
						id:3,
						name:'banana'
					}]
				}
			})
			
		</script>
	</body>
</html>

这里利用作用域插槽。使用同一个子组件,可以写出不同的东西:
在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值