Vue如何跨组件传递Slot的实现


Posted in Vue.js onDecember 14, 2020

在开发过程中遇到这样一个问题,如何跨组件传递插槽。因为在开发类似树组件的过程中,插槽需要通过外部传递到树的根节点,然后通过根节点依次传递到各个叶子节点。那么如何把根节点的Slot如传递给子组件呢?
我们在开发过程中,希望可以这样实现重新定义叶子节点的结构:

<data-tree>
 <template v-slot:node="data">
   <div>{{data.title}} - {{data.text}}</div>
  </template>
</data-tree>

那么如何在组件内传递Slot就是一个问题。

嵌套传递

通过固定级别的组件结构里可以通过直接书写<v-slot ...>来传递对应的Slot元素,来实现一层一层的传递。

<data-tree>
 <data-tree-item>
   <template :node="data">
      <slot :data="data"> xxx </slot>
    </template>
  </data-tree-item>
</data-tree>

通过在外层创建slot可以逐层将slot进行传递,但是如果过多的嵌套层次,这样就显得很麻烦。

Render

还有一种方案是通过Render函数来进行显示,可以通过$slots来访问当前组件的slot元素,然后通过Render函数创建新组件时,将slot传递给下一层。

h('data-tree-item',{
 scopedSlots: {
    node: props => this.$slots.node(props)
  },
})

这样通过Render子元素就可以接受到对应的Slot,也实现了传递。

动态组件

还有一种方式是通过动态组件,也是认为比较推荐的实现方式,不是通过传递Slot,而是通过子节点主动去获取根节点的Slot对象,然后直接在UI中渲染出来。

为此我们需要创建一个组件来渲染对应的Slot对象。

首先需要获取根节点:

const rootComponentName = 'data-tree'
/**
 * 获取父组件
 */
const getRootComponent = (
  component: ComponentInternalInstance | null
): ComponentInternalInstance | undefined => {
  if (component && component.type.name === rootComponentName) {
    return component
  }

  if (component && component.parent) {
    const parent = component.parent
    return getRootComponent(parent)
  }
}

通过递归我们可以获取到对应的父节点,这样我们就可以把Slot作为Data暴露出来

setup(props) {
    // 获取根节点
    const dataTree = getRootComponent(getCurrentInstance())
    const parentSlots = dataTree?.slots
    const nodeTemplate = parentSlots?.node as any
    return {
      nodeTemplate
    }
  }

这时候我们需要一个组件来渲染暴露出来的Slot:

components: {
    TemplateContainer: {
      functional: true,
      props: {
        template: {
          type: Function
        },
        data: {
          type: Object
        }
      },
      render: (props, ctx) => h('div', [props.template(props.data)])
    }
  }

好了现在该准备的都准备好了,可以去实现UI的显示了:

<template-container
          v-if="nodeTemplate"
          :template="nodeTemplate"
          :data="node">
</template-container>
<template v-else>
    {{ node.label }}
</template>

这样我们就实现了类似下面定义Slot的传递,也解决了我们跨组件传递Slot的问题。

<slot :data="node" name="node">
 {{ node.label }}
</slot>

本文使用的是Vue 3的事例,Vue 2也是相同的概念,在Vue 3中除了使用getRootComponent来查询跟节点,也可以使用Provide/Inject来将Slot主动传递给子节点。

到此这篇关于Vue如何跨组件传递Slot的实现的文章就介绍到这了,更多相关Vue 跨组件传递Slot内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Vue.js 相关文章推荐
快速解决vue2+vue-cli3项目ie兼容的问题
Nov 17 Vue.js
解决vue页面刷新,数据丢失的问题
Nov 24 Vue.js
vuex页面刷新导致数据丢失的解决方案
Dec 10 Vue.js
Vue实现指令式动态追加小球动画组件的步骤
Dec 18 Vue.js
Vue通过阿里云oss的url连接直接下载文件并修改文件名的方法
Dec 25 Vue.js
Vue中引入svg图标的两种方式
Jan 14 Vue.js
vue.js实现点击图标放大离开时缩小的代码
Jan 27 Vue.js
Vite和Vue CLI的优劣
Jan 30 Vue.js
详解Vue.js 可拖放文本框组件的使用
Mar 03 Vue.js
vue中三级导航的菜单权限控制
Mar 31 Vue.js
vue Element-ui表格实现树形结构表格
Jun 07 Vue.js
Vue vee-validate插件的简单使用
Jun 22 Vue.js
VUE中鼠标滚轮使div左右滚动的方法详解
Dec 14 #Vue.js
vue3.0实现插件封装
Dec 14 #Vue.js
vue 基于abstract 路由模式 实现页面内嵌的示例代码
Dec 14 #Vue.js
Vue实现点击当前行变色
Dec 14 #Vue.js
Vue实现简单购物车功能
Dec 13 #Vue.js
vue使用element-ui实现表单验证
Dec 13 #Vue.js
vue+element实现动态加载表单
Dec 13 #Vue.js
You might like
使用PHP+AJAX让WordPress动态加载文章的教程
2015/12/11 PHP
示例详解Laravel的注册重构
2016/08/14 PHP
jQuery select操作控制方法小结
2010/05/26 Javascript
javascript动态加载二
2012/08/22 Javascript
利用ajaxfileupload插件实现文件上传无刷新的具体方法
2013/06/08 Javascript
js实现可拖动DIV的方法
2013/12/17 Javascript
javascript中interval与setTimeOut的区别示例介绍
2014/03/14 Javascript
JavaScript中的ubound函数使用实例
2014/11/04 Javascript
详解jQuery中的元素的属性和相关操作
2015/08/14 Javascript
详解JavaScript对Date对象的操作问题(生成一个倒数7天的数组)
2015/10/01 Javascript
DeviceOne 让你一见钟情的App快速开发平台
2016/02/17 Javascript
js判断主流浏览器类型和版本号的简单实现代码
2016/05/26 Javascript
jQuery中JSONP的两种实现方式详解
2016/09/26 Javascript
原生js轮播特效
2017/05/18 Javascript
浅谈对于react-thunk中间件的简单理解
2019/05/01 Javascript
解决layui调用自定义方法提示未定义的问题
2019/09/14 Javascript
解决vue刷新页面以后丢失store的数据问题
2020/08/11 Javascript
pytorch 预训练层的使用方法
2019/08/20 Python
python-opencv获取二值图像轮廓及中心点坐标的代码
2019/08/27 Python
python实现把二维列表变为一维列表的方法分析
2019/10/08 Python
MxNet预训练模型到Pytorch模型的转换方式
2020/05/25 Python
使用Keras训练好的.h5模型来测试一个实例
2020/07/06 Python
英国领先的狗和宠物美容专家:Christies Direct
2017/04/03 全球购物
英国汽车座椅和婴儿车购物网站:Uber Kids
2017/04/19 全球购物
纽约手袋品牌:KARA
2018/03/18 全球购物
英国电气世界:Electrical World
2019/09/08 全球购物
银行实习鉴定
2013/12/13 职场文书
安全检查管理制度
2014/02/02 职场文书
小学班主任寄语大全
2014/04/04 职场文书
寝室长工作失责检讨书
2014/10/06 职场文书
2015年万圣节活动总结
2015/03/24 职场文书
出生证明格式
2015/06/15 职场文书
安全温馨提示语大全
2015/07/14 职场文书
2019假期福利管理制度!
2019/07/15 职场文书
优秀范文:读《红岩》有感3篇
2019/10/14 职场文书
MySQL8.0升级的踩坑历险记
2021/11/01 MySQL