
首先来看下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 AddOn4 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 Slot5 接下来就是对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 SlotProviderHoC6 最终渲染结果

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