这篇文章不是单纯把文档的话和api拿来翻译和演示,而是谈谈我对于slot-scope的使用场景的我的理解,若是理解错误,欢迎讨论!vue
Vue的插槽slot,分为3种ajax
前两种很好理解,不管就是子组件里定义一个slot占位符,父组件调用时,在slot对应的位置填充模板就行了。vuex
做用域插槽的慨念,文档却只有一句简单的描述element-ui
有的时候你但愿提供的组件带有一个可从子组件获取数据的可复用的插槽。api
网络上大多数文章,也是千篇一概的翻译这句话,但是仅凭这一句话,我想象不到slot-scope的使用场景。数组
介绍了写这篇文章的来由,接下来简述一下本文的脉络网络
下面是2个父子的vue组件,先解释一下2个组件作了什么事情ui
我建议从数据流动的角度,理解插槽做用域的使用方式,(先学会怎么用,暂时不用理解为何要这么用,使用场景是第二部分)spa
因此数据的流动经历了翻译
好啦,这就是slot-scope的使用方法,就这么简单,完结撒花~
我贴出所有代码,方便你们本身研究
父组件的源码,也就是调用者
<template> <todo-list :todos="todos"> <template slot-scope="slotProps"> <span v-if="slotProps.todo.isComplete">✓</span> <span>{{slotProps.todo.text}}</span> </template> </todo-list> </template> <script> import todoList from './todoList' export default { data () { return { todos: [ { id: 0, text: 'ziwei0', isComplete: false }, { text: 'ziwei1', id: 1, isComplete: true }, { text: 'ziwei2', id: 2, isComplete: false }, { text: 'ziwei3', id: 3, isComplete: false } ] } }, components: { todoList }, } </script>
子组件源码,也就是封装组件的人
<template> <ul> <li v-for="todo in todos" :key="todo.id"> <slot :todo="todo"> </slot> </li> </ul> </template> <script> export default { props: { todos: { type: Array } } } </script>
想象一个场景:
当你要给同事封装一个列表组件,你就须要使用做用域插槽(注意是列表或者相似列表的组件)
你开发的这个列表组件要如何使用呢?
通常来讲做为列表组件的调用者,你的同事先作ajax请求,拿到一个这样的数组
todos: [ { id: 0, text: 'ziwei0', isComplete: false }, { text: 'ziwei1', id: 1, isComplete: true }, { text: 'ziwei2', id: 2, isComplete: false }, { text: 'ziwei3', id: 3, isComplete: false } ]
以后会把todso传递给列表组件吧,那么列表组件内部作什么事情呢?
列表内部确定会v-for去帮你的同事渲染这个数组嘛。 就相似element-ui里的table组件同样
问题的关键就在这里
列表组件的循环,是发生在组件内部的,因此经过 v-for="todo in todos" ,列表组件很容易拿到每一项todo,但列表拿到数据没用呀,列表只是一个瓜皮,它又不懂业务逻辑
这个数据是你同事的业务数据,因此这个数据必须得交给组件的调用者,也就是把数据交给你的同事才对。
那么你怎样才能把每一项的todo数据给传递出去呢?
你会发现没有办法!
不管是用$emit、vuex仍是localStorage,能够考虑一下,会发现没有合适的时机,能让你把todo传递出去
因此为了应对这个场景下,发明了做用域插槽,列表组件能够经过<slot :todo="todo"></slot>传递todo出去
你的同事能够经过 slot-scope="slotsProps"拿到todo。
回答几个疑问,其实若是你看懂上面的问题,应该能够回答下面的问题。这也是我曾经的疑问
疑问1:通常不是咱们传参数来调用组件吗?为何组件还把数据传递回来?
的确,调用ui组件时通常是咱们传递配置参数给他们。 可是就像elemnt-ui的table组件,你把数组传递给table后,是否是有时候须要拿到某一行的row对象 并根据row对象里的字段,来判断一些内容的显示隐藏? 由于循环的过程发生在table组件内部,因此table组件能够方便的获取到每一项数据,可是这些数据最终不是给组件的,而是咱们本身要用的业务数据。因此也须要一个方式,让调用者能拿到本身想要的数据
疑问2: 既然子组件最终还要把我给他的数据,再返还给我,那我当初还干吗给它,能不能就本身在父组件里玩?
若是你不把数据给子组件固然能够。可是就等于抛弃掉了子组件的封装,只能你直接在父组件本身写一个列表 毕竟你不把数据给子组件,子组件还渲染个锤子?没有父子关系的话,也就不用什么插槽了。 可是咱不是为了封装后,能够复用嘛,总不能永远不用组件嘛
疑问3: 父组件须要子组件的数据?那不会有$emit和vuex嘛,为何要有slot-scope?
$emit和vuex是数据传递的一种方法,可是你能够尝试用$emit和vuex把todo传递给父组件。 你会发现的确没有合适的钩子、时机来$emit数据
我认为几种说法是不太恰当的,也是给我形成一些困惑的
这种说法,会让我以为slot-scope跟emit和vuex是一类东西
这些举例子的不恰当之处,我以为是不该该把数据定义在子组件里。
由于真正的使用场景下,子组件的数据都是来自父组件的。做为组件内部应该保持纯净。
就像element-ui里的table组件,确定不会定义一些数据在组件内部,而后传递给你。
table组件的数据都是来自调用者的,而后table会把每一行的row,在开发者须要时,传递出去。
这些例子虽然不是错误,可是我以为反而不利于理解slot-scope