使用react context 实现vue插槽slot功能


Posted in Javascript onJuly 18, 2019

首先来看下vue的slot的实现

<base-layout>组件,具名插槽name定义以及默认插槽

<div class="container">
 <header>
  <slot name="header"></slot>
 </header>
 <main>
  <slot></slot>
 </main>
 <footer>
  <slot name="footer"></slot>
 </footer>
</div>
<template>

提供内容渲染的组件

<base-layout>
 <template v-slot:header>
  <h1>Here might be a page title</h1>
 </template>
 <p>A paragraph for the main content.</p>
 <p>And another one.</p>
 <template v-slot:footer>
  <p>Here's some contact info</p>
 </template>
</base-layout>

最终会渲染出已下架结构

<base-layout>
 <template v-slot:header>
  <h1>Here might be a page title</h1>
 </template>
 <p>A paragraph for the main content.</p>
 <p>And another one.</p>
 <template v-slot:footer>
  <p>Here's some contact info</p>
 </template>
</base-layout>

言归正传,怎样使用react的context实现vue的这一功能呢

1 首先确认下layout组件的结构

import React, { Component } from 'react';
import SlotProvider from './SlotProvider'
import Slot from './Slot'
class AppLayout extends Component {
 static displayName = 'AppLayout'
 render () {
  return (
   <div className="container">
    <header>
     <Slot name="header"></Slot>
    </header>
    <main>
     <Slot></Slot>
    </main>
    <footer>
     <Slot name="footer"></Slot>
    </footer>
   </div>
  )
 }
}
export default SlotProvider(AppLayout)

2 对此结构输出具体内容的组件

import React, { Component } from 'react';
import AppLayout from './AppLayout'
import AddOn from './AddOn'
export default class App extends Component {
  render() {
    return (
      <AppLayout>
        <AddOn slot="header">
          <h1>这里可能是一个页面标题</h1>
        </AddOn>
        <AddOn>
          <p>主要内容的一个段落。</p>
          <p>另一个段落。</p>
        </AddOn>
        <AddOn slot="footer">
          <p>这里有一些联系信息</p>
        </AddOn>
      </AppLayout>
    )
  }
}

3 其中AddOn类似于上面vue的template,所以下面来实现这个简单的只是用来提供slot标识和children内容的组件AddOn的实现

import React from 'react';
import PropTypes from 'prop-types'
const AddOn = () => null
AddOn.propTypes = { slot: PropTypes.string }
AddOn.defaultTypes = { slot: '$$default' }
AddOn.displayName = 'AddOn'
export default AddOn

4 Slot组件

import React from 'react';
import { SlotContext } from './SlotProvider'
import PropTypes from 'prop-types'
const Slot = ({ name, children }) => {
 return (
  <SlotContext.Consumer>
   {(value) => {
    const addOnRenderer = value.requestAddOnRenderer(name)
     return (addOnRenderer && addOnRenderer()) || children || null
   }}
  </SlotContext.Consumer>
 )
}
Slot.displayName = 'Slot'
Slot.propTypes = { name: PropTypes.string }
Slot.defaultProps = { name: '$$default' }
export default Slot

5 接下来就是对Slot进行解析的HOC SlotProvider组件了

import React, { Component } from 'react';
function getDisplayName(component) {
  return component.displayName || component.name || 'component'
}
export const SlotContext = React.createContext({
  requestAddOnRenderer: () => { }
})
const SlotProviderHoC = (WrappedComponent) => {
  return class extends Component {
    static displayName = `SlotProvider(${getDisplayName(WrappedComponent)})`
    // 用于缓存每个<AddOn />的内容
    addOnRenderers = {}
    requestAddOnRenderer = (name) => {
      if (!this.addOnRenderers[name]) {
        return undefined
      }
      return () => (
        this.addOnRenderers[name]
      )
    }
    render() {
      const {
        children,
        ...restProps
      } = this.props
      if (children) {
        // 以k-v的方式缓存<AddOn />的内容
        const arr = React.Children.toArray(children)
        const nameChecked = []
        this.addOnRenderers = {}
        arr.forEach(item => {
          const itemType = item.type
          console.log('itemType',itemType)
          if (item.type.displayName === 'AddOn') {
            const slotName = item.props.slot || '$$default'
            // 确保内容唯一性
            if (nameChecked.findIndex(item => item === slotName) !== -1) {
              throw new Error(`Slot(${slotName}) has been occupied`)
            }
            this.addOnRenderers[slotName] = item.props.children
            nameChecked.push(slotName)
          }
        })
      }
      return (
        <SlotContext.Provider value={{ requestAddOnRenderer: this.requestAddOnRenderer }}>
          <WrappedComponent {...restProps} />
        </SlotContext.Provider >
      )
    }
  }
 }
 export default SlotProviderHoC

6 最终渲染结果

使用react context 实现vue插槽slot功能

总结

以上所述是小编给大家介绍的使用react context 实现vue插槽slot功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
JScript中的undefined和&quot;undefined&quot;的区别
Mar 08 Javascript
JavaScript Cookie显示用户上次访问的时间和次数
Dec 08 Javascript
js 刷新页面的代码小结 推荐
Apr 02 Javascript
js location.replace与location.reload的区别
Sep 08 Javascript
裁剪字符串trim()自定义改进版
Apr 10 Javascript
jQuery使用$.ajax进行即时验证的方法
Dec 08 Javascript
JS 事件绑定、事件监听、事件委托详细介绍
Sep 28 Javascript
浅谈javascript中执行环境(作用域)与作用域链
Dec 08 Javascript
浅析vue数据绑定
Jan 17 Javascript
jQuery获取table下某一行某一列的值实现代码
Apr 07 jQuery
微信小程序中页面FOR循环和嵌套循环
Jun 21 Javascript
vue2.0 自定义 饼状图 (Echarts)组件的方法
Mar 02 Javascript
jquery图片预览插件实现方法详解
Jul 18 #jQuery
vue使用自定义指令实现拖拽
Jan 29 #Javascript
对TypeScript库进行单元测试的方法
Jul 18 #Javascript
基于JS实现数字动态变化显示效果附源码
Jul 18 #Javascript
微信小程序实现拍照画布指定区域生成图片
Jul 18 #Javascript
vue使用video.js进行视频播放功能
Jul 18 #Javascript
百度小程序之间的页面通信过程详解
Jul 18 #Javascript
You might like
php中XMLHttpRequest(Ajax)不能设置自定义的Referer的解决方法
2011/11/26 PHP
PHP 之Section与Cookie使用总结
2012/09/14 PHP
用mysql_fetch_array()获取当前行数据的方法详解
2013/06/05 PHP
利用laravel搭建一个迷你博客实战教程
2017/08/13 PHP
thinkPHP框架中执行原生SQL语句的方法
2017/10/25 PHP
PHP7原生MySQL数据库操作实现代码
2020/07/03 PHP
IE7中javascript操作CheckBox的checked=true不打勾的解决方法
2009/12/07 Javascript
AeroWindow 基于JQuery的弹出窗口插件
2011/06/27 Javascript
JS保存、读取、换行、转Json报错处理方法
2013/06/14 Javascript
javascript上传图片前预览图片兼容大多数浏览器
2013/10/25 Javascript
jquery自定义函数的多种方法
2014/01/09 Javascript
Jquery Uploadify上传带进度条的简单实例
2014/02/12 Javascript
Jquery对象和Dom对象的区别分析
2014/11/20 Javascript
Javascript技术栈中的四种依赖注入小结
2016/02/27 Javascript
jQuery解决浏览器兼容性问题案例分析
2016/04/15 Javascript
详解Node 定时器
2018/02/26 Javascript
jQuery实现简单的Ajax调用功能示例
2019/02/15 jQuery
深入Node TCP模块的理解
2019/03/13 Javascript
Vue使用Proxy监听所有接口状态的方法实现
2019/06/07 Javascript
微信小程序实现批量倒计时功能
2020/11/01 Javascript
Vue filter 过滤器、以及在table中的使用介绍
2020/09/07 Javascript
浅析微信小程序自定义日历组件及flex布局最后一行对齐问题
2020/10/29 Javascript
Python2.7基于笛卡尔积算法实现N个数组的排列组合运算示例
2017/11/23 Python
Django实现表单验证
2018/09/08 Python
pytorch numpy list类型之间的相互转换实例
2019/08/18 Python
Python API 操作Hadoop hdfs详解
2020/06/06 Python
Python使用socketServer包搭建简易服务器过程详解
2020/06/12 Python
如何理解委托
2012/01/06 面试题
预备党员思想汇报范文
2013/12/29 职场文书
销售人员职业生涯规划范文
2014/03/01 职场文书
小学评语大全
2014/04/22 职场文书
学生会个人总结范文
2015/02/15 职场文书
销售口号霸气押韵
2015/12/24 职场文书
大学生各类奖学金申请书
2019/06/24 职场文书
php微信小程序解包过程实例详解
2021/03/31 PHP
Java 垃圾回收超详细讲解记忆集和卡表
2022/04/08 Java/Android