React中实现Slot(插槽)效果

1,687 阅读2分钟

思维图

图片

前面的

1)在实际开发中,我们抽取了一个组件,为了让这个组件具备更强的通用性,我们不能将组件中的 子元素写死固定的div、span等等这些元素;

2)我们应该让使用者可以决定某一块区域到底存放什么内容;

3)比如 Vue 中有一个插槽的概念,可以任意放置内容;

一、搭建Demo项目

1. 首先,我们将代码中的一些无用代码都删除掉,只留下index.js 和 App.js 即可;

2. 新建 NavBar.js 和 NavBar2.js 文件,因为有两种实现方式,所以新建两个组件引用在App.js;

import React, { Component } from 'react';

import NavBar from './NavBar';
import NavBar2 from './NavBar2';

export default class App extends Component {
  render() {
    return (
      <div>
        <NavBar></NavBar>
        
        <NavBar2 />
      </div>
    )
  }
}

3. 新建 nav-bar.style.css 文件用来编写NavBar组件的样式;

body {
  padding: 0;
  margin: 0;
}
.nav_bar {
  display: flex;
  margin-bottom: 20px;
}

.nav_bar div {
  text-align: center;
  height: 40px;
  line-height: 40px;
}

.nav_center {
  flex: 1;
  background-color: sandybrown;
}
.nav_left, .nav_right {
  width: 50px;
  background-color: rosybrown;
}

二、通过props.children方式实现

//App.js
import React, { Component } from 'react';

import NavBar from './NavBar';

export default class App extends Component {
  render() {
    return (
      <div>
        <NavBar> 
          <span>left</span>
          <em>center</em>
          <a href="/#">right</a>
        </NavBar>
      </div>
    )
  }
};
//NavBar.js
import React, { Component } from 'react';

import './nav-bar.style.css';

export default class NavBar extends Component {
  render() {
    // console.log(this.props)
    return (
      //1.通过children的索引方式取出,但是不保序。
      <div className="nav_bar">
        <div className="nav_left">
          {this.props.children[0]}
        </div>
        <div className="nav_center">
          {this.props.children[1]}
        </div>
        <div className="nav_right">
          {this.props.children[2]}
        </div>
      </div>
    )
  }
};

注意: 如果children中有多个元素, 那么children是一个数组, 例如上面数组中存放着0、1、2三项元素; 如果只插入一个元素 <NavBar><div>哈哈哈</div></NavBar> 到子组件中, 那么children(对象)本身就是插入的该元素{this.props.children};

三、通过props数据的方式传递实现

//App.js
import React, { Component } from 'react';

import NavBar2 from './NavBar2';

export default class App extends Component {
  render() {
    return (
      <div>
        {/*2. 通过数据的方式传递 */}
        <NavBar2 
          leftSlot={<span>left</span>} 
          centerSlot={<em>center</em>}  
          rightSlot={<a href="/#">right</a>}  
        />
      </div>
    )
  }
};
import React, { Component } from 'react';

import './nav-bar.style.css';

export default class NavBar extends Component {
  render() {
    // console.log(this.props);
    const { leftSlot, centerSlot, rightSlot } = this.props;
    
    return (
      <div className="nav_bar">
        <div className="nav_left">
          {leftSlot}
        </div>
        <div className="nav_center">
          {centerSlot}
        </div>
        <div className="nav_right">
          {rightSlot}
        </div>
      </div>
    )
  }
};

四、效果

两种实现方式的效果都是一样的; result.png

最后的

写Vue多了会发现props.children方式实现比较好理解,但是存在缺陷:父组件转的时候需要考虑顺序问题,子组件在展示的时候需按照顺序取放,顺序不可以错误,代码不宜读;

另一种方式是通过传值的方式,将 JSX 代码传递过去,并且使用 leftSlot、centerSlot 等语义化变量使代码变的易读,子组件只关心放的位置;

当你犹豫选择哪条路时,可能已经启程了好一阵。