使用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 相关文章推荐
Jquery网页出现的乱码问题的三种解决方法
Jun 30 Javascript
JS如何判断移动端访问设备并解析对应CSS
Nov 27 Javascript
JS实现简单的图书馆享元模式实例
Jun 30 Javascript
JavaScript地理位置信息API
Jun 11 Javascript
JS实现密码框的显示密码和隐藏密码功能示例
Dec 26 Javascript
关于jQuery中fade(),show()起始位置的一点小发现
Apr 25 jQuery
详解Vue爬坑之vuex初识
Jun 14 Javascript
详解Vue路由钩子及应用场景(小结)
Nov 07 Javascript
axios post提交formdata的实例
Mar 16 Javascript
laydate时间日历插件使用方法详解
Nov 14 Javascript
如何自定义微信小程序tabbar上边框的颜色
Jul 09 Javascript
Vue + Node.js + MongoDB图片上传组件实现图片预览和删除功能详解
Apr 29 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 curl模拟post请求和提交多维数组的示例代码
2015/11/19 PHP
JScript的条件编译
2007/05/29 Javascript
关于hashchangebroker和statehashable的补充文档
2011/08/08 Javascript
extjs关于treePanel+chekBox全部选中以及清空选中问题探讨
2013/04/02 Javascript
js动态拼接正则表达式的两种方法
2014/03/04 Javascript
jQuery 回调函数(callback)的使用和基础
2015/02/26 Javascript
seajs学习教程之基础篇
2016/10/20 Javascript
微信JS-SDK自定义分享功能实例详解【分享给朋友/分享到朋友圈】
2016/11/25 Javascript
走进javascript——不起眼的基础,值和分号
2017/02/24 Javascript
使用jquery的jsonp如何发起跨域请求及其原理详解
2017/08/17 jQuery
JS实现将链接生成二维码并转为图片的方法
2018/03/17 Javascript
讲解vue-router之什么是动态路由
2018/05/28 Javascript
js拖动滑块和点击水波纹效果实例代码
2018/10/16 Javascript
react同构实践之实现自己的同构模板
2019/03/13 Javascript
Vue页面切换和a链接的本质区别详解
2019/11/12 Javascript
[01:06]欢迎来到上海,TI9
2018/08/26 DOTA
[28:05]完美世界DOTA2联赛循环赛Inki vs DeMonsTer 第一场 10月30日
2020/10/31 DOTA
python 查找文件夹下所有文件 实现代码
2009/07/01 Python
Python实现队列的方法
2015/05/26 Python
在Mac OS上搭建Python的开发环境
2015/12/24 Python
python向已存在的excel中新增表,不覆盖原数据的实例
2018/05/02 Python
python读取有密码的zip压缩文件实例
2019/02/08 Python
Python如何处理大数据?3个技巧效率提升攻略(推荐)
2019/04/15 Python
python多线程下信号处理程序示例
2019/05/31 Python
windows 10 设定计划任务自动执行 python 脚本的方法
2019/09/11 Python
python OpenCV GrabCut使用实例解析
2019/11/11 Python
PyTorch中Tensor的数据类型和运算的使用
2020/09/03 Python
pycharm 2020 1.1的安装流程
2020/09/29 Python
如何快速一次性卸载所有python包(第三方库)呢
2020/10/20 Python
小学优秀班干部事迹材料
2014/05/25 职场文书
捐书倡议书
2014/08/29 职场文书
单位租房协议书范本
2014/12/04 职场文书
2016廉洁从业学习心得体会
2016/01/19 职场文书
《天使的翅膀》读后感3篇
2019/12/20 职场文书
Python+Tkinter制作专属图形化界面
2022/04/01 Python
Golang 实现WebSockets
2022/04/24 Golang