使用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 相关文章推荐
JSON 编辑器实现代码
Dec 06 Javascript
JavaScript 事件冒泡简介及应用
Jan 11 Javascript
引用 js在IE与FF之间的区别详细解析
Nov 20 Javascript
JavaScript的arguments对象应用示例
Sep 15 Javascript
jQuery对指定元素中指定字符串进行替换的方法
Mar 17 Javascript
JavaScript判断DIV内容是否为空的方法
Jan 29 Javascript
AngularJs解决跨域问题案例详解(简单方法)
May 19 Javascript
vue中mint-ui环境搭建详细介绍
Apr 06 Javascript
JS Testing Properties 判断属性是否在对象里的方法
Oct 01 Javascript
Node层模拟实现multipart表单的文件上传示例
Jan 02 Javascript
在Vue中使用axios请求拦截的实现方法
Oct 25 Javascript
全面解析js中的原型,原型对象,原型链
Jan 25 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
smarty模板引擎从php中获取数据的方法
2015/01/22 PHP
php使用Jpgraph创建折线图效果示例
2017/02/15 PHP
不要在cookie中使用特殊字符的原因分析
2010/07/13 Javascript
学习面向对象之面向对象的基本概念:对象和其他基本要素
2010/11/30 Javascript
javascript开发技术大全-第1章javascript概述
2011/07/03 Javascript
JQuery循环滚动图片代码
2011/12/08 Javascript
jquery怎样实现ajax联动框(一)
2013/03/08 Javascript
javascript中直接引用Microsoft的COM生成Word
2014/01/20 Javascript
js仿支付宝填写支付密码效果实现多方框输入密码
2016/03/09 Javascript
jQuery UI结合Ajax创建可定制的Web界面
2016/06/22 Javascript
JavaScript中校验银行卡号的实现代码
2016/12/19 Javascript
CodeMirror js代码加亮使用总结
2017/03/25 Javascript
加载 vue 远程代码的组件实例详解
2017/11/20 Javascript
基于vue2.0实现简单轮播图
2017/11/27 Javascript
vue项目实现记住密码到cookie功能示例(附源码)
2018/01/31 Javascript
Electron vue的使用教程图文详解
2019/07/05 Javascript
微信头像地址失效踩坑记附带解决方案
2019/09/23 Javascript
vue项目配置 webpack-obfuscator 进行代码加密混淆的实现
2021/02/26 Vue.js
[36:02]DOTA2上海特级锦标赛D组小组赛#2 Liquid VS VP第一局
2016/02/28 DOTA
Python正确重载运算符的方法示例详解
2017/08/27 Python
python读取Excel实例详解
2018/08/17 Python
Python基于datetime或time模块分别获取当前时间戳的方法实例
2019/02/19 Python
python实现while循环打印星星的四种形状
2019/11/23 Python
Python3 虚拟开发环境搭建过程(图文详解)
2020/01/06 Python
CSS3实现彩色进度条动画的示例
2020/10/29 HTML / CSS
HTML5中的postMessage API基本使用教程
2016/05/20 HTML / CSS
SVG实现多彩圆环倒计时效果的示例代码
2017/11/21 HTML / CSS
Giglio俄罗斯奢侈品购物网:男士、女士、儿童高级时装
2018/07/27 全球购物
abstract class和interface有什么区别?
2012/01/03 面试题
GWT的应用有哪两种部署模式
2012/12/21 面试题
硕士研究生个人求职信
2013/12/04 职场文书
陈欧的广告词
2014/03/18 职场文书
岗位聘任报告
2015/03/02 职场文书
小学教师求职信范文
2015/03/20 职场文书
民事答辩状范本
2015/05/21 职场文书
运动会三级跳加油稿
2015/07/21 职场文书