使用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 相关文章推荐
JavaScript实现定时隐藏与显示图片的方法
Aug 06 Javascript
原生javascript+css3编写的3D魔方动画旋扭特效
Mar 14 Javascript
Knockoutjs 学习系列(一)ko初体验
Jun 07 Javascript
bootstrapValidator.min.js表单验证插件
Feb 09 Javascript
js 动态生成html 触发事件传参字符转义的实例
Feb 14 Javascript
微信小程序promsie.all和promise顺序执行
Oct 27 Javascript
vue对storejs获取的数据进行处理时遇到的几种问题小结
Mar 20 Javascript
Vue三层嵌套路由的示例代码
May 05 Javascript
js限制input只能输入有效的数字(第一个不能是小数点)
Sep 28 Javascript
angular4强制刷新视图的方法
Oct 09 Javascript
微信小程序日历组件使用方法详解
Dec 29 Javascript
关于React Native 无法链接模拟器的问题
Jun 21 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
动画 《Pokemon Sword·Shield》系列WEB动画《薄明之翼》第2话声优阵容公开!
2020/03/06 日漫
8个出色的WordPress SEO插件收集
2011/02/26 PHP
PHP实现蛇形矩阵,回环矩阵及数字螺旋矩阵的方法分析
2017/05/29 PHP
laravel自定义分页效果
2017/07/23 PHP
整理的比较全的event对像在ie与firefox浏览器中的区别
2013/11/25 Javascript
jquery如何根据值设置默认的选中项
2014/03/17 Javascript
模拟一个类似百度google的模糊搜索下拉列表
2014/04/15 Javascript
原生js封装的一些jquery方法(详解)
2016/09/20 Javascript
SVG描边动画
2017/02/23 Javascript
Bootstrap 过渡效果Transition 模态框(Modal)
2017/03/17 Javascript
Vue打包后出现一些map文件的解决方法
2018/02/13 Javascript
深入学习JavaScript中的bom
2019/05/27 Javascript
[01:00:06]加油DOTA_EP01_网络版
2014/08/09 DOTA
浅析python 内置字符串处理函数的使用方法
2014/06/11 Python
Python Web框架Flask信号机制(signals)介绍
2015/01/01 Python
python实现在sqlite动态创建表的方法
2015/05/08 Python
python对url格式解析的方法
2015/05/13 Python
在Django的视图(View)外使用Session的方法
2015/07/23 Python
python实现周期方波信号频谱图
2018/07/21 Python
Python XML转Json之XML2Dict的使用方法
2019/01/15 Python
详解Python数据可视化编程 - 词云生成并保存(jieba+WordCloud)
2019/03/26 Python
Python根据当前日期取去年同星期日期
2019/04/14 Python
把vgg-face.mat权重迁移到pytorch模型示例
2019/12/27 Python
Python jieba结巴分词原理及用法解析
2020/11/05 Python
解决python 在for循环并且pop数组的时候会跳过某些元素的问题
2020/12/11 Python
详解background属性的8个属性值(面试题)
2020/11/02 HTML / CSS
浅谈基于Canvas的手绘风格图形库Rough.js
2018/03/19 HTML / CSS
香港钟表珠宝首饰商城:OneMallTime网摩间
2016/10/14 全球购物
英国假睫毛购买网站:FalseEyelashes.co.uk
2018/05/23 全球购物
Ralph Lauren意大利官方网站:时尚界最负盛名的品牌之一
2018/10/18 全球购物
吉力贝官方网站:Jelly Belly
2019/03/11 全球购物
新西兰最大的连锁超市:Countdown
2020/06/04 全球购物
电子商务专业个人的自我评价分享
2013/10/29 职场文书
建筑总经理岗位职责
2014/02/02 职场文书
Nginx location 和 proxy_pass路径配置问题小结
2021/09/04 Servers
Python编程源码报错解决方法总结经验分享
2021/10/05 Python