Vue组件开发实践之scopedSlot的传递
来源:互联网 发布:微信授权登陆 java 编辑:程序博客网 时间:2024/06/04 19:00
收录待用,修改转载已取得腾讯云授权
导语
现今的前端开发都讲究模块化组件化,即把公共的交互和功能封装到一个个的组件之中,在开发整体界面的时候就能像搭积木一样快速清晰高效。在使用Vue开发我们的vhtml-ui的组件库的过程中遇到了组件嵌套组件时需要传递scopedSlot的情况,官方的文档和教程目前还没有比较明确的指引,所以摸着石头过河,调通了想要的效果。记录下来方便大家和自己。
在Vue中,为了让组件可以组合,我们使用Slot来混合父组件的内容与子组件自己的模板。这样就实现了Vue的内容分发。
Scoped Slot(作用域插槽)是在Vue 2.1引入的更进阶的功能,它是一种特殊类型的slot,用作使用一个(能够传递数据到)可重用模板替换已渲染元素。我的理解就是使用scoped slot能在插槽里自定义模板并且使用组件传递过来的context。这大大提高了组件开发的灵活性。
Select组件一期
在开发我们的select组件时很自然就用上了scoped slot这一特性。我们需要遍历数据中的选项数组,渲染成界面上的下拉选项列表。如果是比较复杂的允许自定义的list item,在组件里写死dom结构就行不通了,比如:
有了scoped slot实现很轻松:
<v-select kind="popup" :options="options4"> <template slot="listItem" scope="props"> <div> <div><span>{{ props.item.text }}<span> | <span>{{ props.item.value }}<span></div><div>{{ props.item.area }}</div> <div>{{ props.item.url }}</div> </div> </template> </v-select>
很好,非常好,现在有一个新需求:这个列表有的时候想要脱离select使用,比如就直接展示在页面上,不需要通过下拉弹出。
select-list组件
这好办啊,作为组件开发的老司机们自然能想到把这个list独立做成一个组件,页面可以直接调用,select组件也可以在它之上再封装一层。
完美!
开干!
select-list template结构示意:
<ul class="v-select-list"> <li class="v-select-list__item" v-for="(item, index) in options"> <slot name="listItem" :item="item"> <span>{{ item.text }}</span> </slot> </li> </ul>
select template结构示意:
<div class="v-select"> <v-popper> <v-select-list> <slot name="listItem"> </slot> </v-select-list> </v-popper> </div>
然后问题来了,最里层的select-list组件并没有接收到用户自定义的scoped slot。通过查找Vue官方文档以及谷歌,也没有找到使用template方式传递scoped slot的介绍和例子。
Render函数和JSX
人总不能让尿给憋死,一条路走不通我们就看看有没有其他办法。在Vue的官方文档上有这么一句话:
“ Vue 推荐在绝大多数情况下使用 template 来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力,这就是 render 函数,它比 template 更接近编译器。”
查看文档,通过render函数确实能够传递scoped slot,以下图的方式
把scoped slot作为createElement方法的第二参数(data object)的一个属性传递到子组件中。
但是render函数的缺点就是不灵活,特别是在定义你的组件的dom结构模板的时候,如果写很多 render 函数,可能会觉得痛苦。它比较适用于外层组件仅仅是对内层组件的一次逻辑封装,而渲染的模板结构变化扩展不多的情况。
还好我们还有最后一把杀手锏–JSX。它可以让我们回到于更接近模板的语法上。具体关于JSX的使用不是本文的主题,我们可以阅读使用文档 ,学习关于 JSX 映射到 JavaScript的用法。
JSX实现上文的嵌套例子
通过参阅文档及不断地摸索,最终实现了自己想要的功能。我们直接上关键代码(select的render函数),看看有什么奥秘:
render(h) { let directives = [{ name: 'popper', arg: 'selector', modifiers: { click: true } }]; return ( <div class={{ 'v-select': true, 'is-open': this.isPopperShown, 'is-disabled': this.disabled }}> <v-popper ref="selector" placement="bottom-start" onVisibleChange={this.togglePopper}> <v-select-list class="v-select__options" onChange={this.handleChange} multiple={this.multiple} value={this.currentValue} onInput={this.handleListInput} scopedSlots={{listItem: this.$scopedSlots.listItem}} > </v-select-list> </v-popper> <div class="v-select__header" { ...{directives} }> { this.currentIndex !== -1 && this.$scopedSlots.headItem ? this.$scopedSlots.headItem(this.current) : (<span>{this.currentText}</span>) } <v-icon class="v-select__header-arrow" name="v-arrow_dropdown"> </v-icon> </div> </div> ) }
关键点:
在子组件的标签上通过
scopedSlots
属性可以向其传递自己的scoped slot;自身的scoped slot可以通过
this.$scopedSlots
对象获取,默认就是default,具名slot就是它的名字。本例为“listItem”;如果不在标签上传递而是需要使用表达式传递,也可以通过
this.$scopedSlots
对象。并且一个具体的scoped slot对象其实就是一个函数,其内部的scope可以在参数中传入。比如本例中的this.$scopedSlots.headItem(this.current)
JSX中对template常用点的转换
上面的介绍涵盖了基本的用法,但是我们在组件中往往会用一些不基本但常用的vue特性。我们接下来一起看看。
细心地小伙伴可能发现了上面的代码中已经出现了这些用法
directives
如果我们在组件中使用了directives,那么jsx里就不能想之前在template里那么自然的书写
v-popper:third.click
而是需要workaround:
Pass everything as an object via value, e.g. v-name={{ value, modifier: true }}
Use the raw vnode directive data format:
上面的例子中就是用了方法二。
v-model
render函数(JSX也是写在render函数中)中没有与v-model
相应的api -
你必须自己来实现相应的逻辑。即通过value属性传递值,并通过绑定input事件来响应变化。
没有template 中的v-if
和 v-for
:
这意味着我们需要在render函数或者JSX的表达式中手写if-else逻辑判断。或者如本例中使用三目表达式来实现。
这就是深入底层要付出的,尽管麻烦了一些,但你可以更灵活地控制。
希望这边文章能让我们在开发Vue组件的时候少走一些弯路,如果有大神有更好的办法或直接在template中实现传递scoped slot的功能,请多多指教!
原文链接:https://www.qcloud.com/community/article/693017
- Vue组件开发实践之scopedSlot的传递
- Vue组件开发实践
- Vue组件开发实践
- Vue.js组件化开发实践
- Vue.js组件化开发实践
- vue.js组件化开发实践
- vue.js 组件 之 prop 传递数据
- Vue实践之--非父子组件通信
- vue父子组件的数据传递
- Vue---组件之间的数据传递
- vue组件中数据的传递
- vue 父子组件之间的数据传递
- vue开发:vue全局组件的方法
- Vue之父组件向子组件传递数据
- vue组件最佳实践
- vue组件最佳实践
- vue组件最佳实践
- vue组件最佳实践
- linux系统文件类型
- YARN资源调度策略
- 2010年程序员上半年上午试题
- php获取上一页url
- Zabbix爆高危漏洞CVE-2017-2824
- Vue组件开发实践之scopedSlot的传递
- 跟我一起写 Makefile
- KW41Z_FreeRTOS学习笔记
- 用户登录
- Java版中文分词 IKAnalyzer
- LintCode 解题记录17.5.10(tag:线段树)
- 面向容器技术资源调度关键技术对比
- JSP内置对象response
- POJ 1185 炮兵阵地 (状态压缩DP)