11. React组件插槽用法
4. React组件插槽用法
-
4.1. React中的插槽(
Slot
)-
- 在开发中,我们抽取一个组件,但是为了让这个组件具备更强的通用性,我们不能将组件中的内容限制为固定的div、span等等这些元素
-
-
- 这种需求在Vue当中有一个固定的做法是通过slot来完成的,React呢?
- 在React中是没有插槽的概念的,或者说React中不需要插槽,因为React太灵活了,React中可以通过多种形式来实现插槽的效果,例如可以传递任意属性给子组件
-
- React对于这种需要插槽的情况非常灵活,有两种方案可以实现:
- 组件的
children子元素
; props属性传递
React元素`;
-
-
4.2. children实现插槽
-
- 每个组件之间都可以获取到
props.children属性
:它包含组件的开始标签和结束标签之间的内容
。
- 每个组件之间都可以获取到
-
- 示例代码如下:
-
如图:
-
父组件代码:
// React中是没有插槽的概念的,或者说React中不需要插槽,因为React太灵活了,React中可以通过多种形式来实现插槽的效果,例如可以传递任意属性给子组件 import React, { Component } from 'react' import NavBar from './nav-bar'export class App extends Component {render() {// NavBar实例对象 -> this// this.props.children -> [button, h2, i]return (<div><NavBar><button>按钮</button><h2>我是标题</h2><i>我是斜体字</i></NavBar></div>)} }// function createElement(type, props, children) { // children -> arguments.length - 2 // }export default App
- 子组件代码:
import React, { Component } from 'react'import './style.css'import PropTypes from 'prop-types'export class NavBar extends Component {render() {const { children } = this.props// 子元素放多个的时候,children是一个数组,一个的时候是一个对象console.log('children===', children)return (<div className='nav-bar'><div>{children}</div> {/* <div className="left">{children[0]}</div><div className="center">{children[1]}</div><div className="right">{children[2]}</div> */}</div>)}}NavBar.propTypes = {children: PropTypes.array}export default NavBar
-
-
4.3. props实现插槽
-
- 通过
children
实现的方案虽然可行,但是有以下两个弊端:
children的弊端
:childre
n可能是一个元素
也可能是数组
,使时需要慎重
children
的对索引顺序要求太高
,通过索引值获取传入的元素很容易出错
,不能准确的获取传入的元素
;
- 通过
-
- 另外一种方案就是
使用props实现
:
通过具体的属性名,可以让我们在传入和获取时更加的精准
- 另外一种方案就是
-
- 实例代码如下:
- 父组件代码如下:
// React中是没有插槽的概念的,或者说React中不需要插槽,因为React太灵活了,React中可以通过多种形式来实现插槽的效果,例如可以传递任意属性给子组件import React, { Component } from 'react'import NavBar from './nav-bar'import NavBarTwo from './nav-bar-two'export class App extends Component {render() {// NavBar实例对象 -> this// this.props.children -> [button, h2, i]const btn = <button>按钮</button>return (<div>{/* 1.吃用children实现插槽 */}<NavBar><button>按钮</button><h2>我是标题</h2><i>我是斜体字</i></NavBar>{/* 2.使用props现插槽实 */}{/* 推荐使用props方案,children有点不可控 */}<NavBarTwostyle={{marginTop: '20px'}}leftSlot={ btn }centerSlot={ <h2>呵呵呵呵</h2> }rightSlot={ <i>斜体2</i> }/></div>)}}// function createElement(type, props, children) {// children -> arguments.length - 2// }export default App
- 子组件代码如下:
import React, { Component } from 'react'export class NavBarTwo extends Component {render() {const { leftSlot, centerSlot, rightSlot } = this.propsreturn (<div className='nav-bar'><div className="left">{leftSlot}</div><div className="center">{centerSlot}</div><div className="right">{rightSlot}</div></div>)}}export default NavBarTwo
-
-
4.4. 作用域插槽实现
-
- 作用域插槽案例;现在子组件的item都是span,
希望子组件的内容是根据父组件传进来的类型渲染
- 作用域插槽案例;现在子组件的item都是span,
-
父组件代码:
import React, { Component } from 'react'import TabControl from './TabControl'export class App extends Component {constructor() {super()this.state = {titles: ['流行', '新款', '热门'],tabIndex: 0}}tabClick (index) {this.setState({tabIndex: index})}getTabItem (item) {if(item ==='流行') {return <span>{item}</span>} else if(item === '新款') {return <button>{item}</button> } else {return <i>{item}</i>}}render() {const { titles,tabIndex } = this.state// 现在子组件的item都是span,希望子组件的内容是根据父组件传进来的类型渲染// 作用域插槽return (<div className='app'><TabControl titles={ titles } tabClick={i => this.tabClick(i)}// itemType={(item) => <button>{item}</button>}/>itemType={(item) => this.getTabItem(item)}/><h2>{titles[tabIndex]}</h2></div>)}}export default App
-
子组件代码:
import React, { Component } from 'react' import './style.css'export class TabControl extends Component {constructor() {super()this.state = {currentIndex: 0}}changeTab (index) {this.props.tabClick(index)this.setState({currentIndex: index})} render() {const { titles, itemType } = this.propsconst { currentIndex } = this.statereturn (<div><div className="tab-control">{titles.map((item, index) => {return (<div className={`item ${currentIndex === index ? 'active' : ''}`} key={index}onClick={(e) => this.changeTab(index)}>{/* <span className='text' >{item}</span> */}{itemType(item)}</div>)})}</div></div>)} }export default TabControl
-