• React有slot吗?


    写在前面

    最近也学习了React一段时间了,之前都是写Vue,所以在这个过程中难免就会有一些比较。我也就是一激灵,Vueslot其实蛮神奇的,那Reactslot吗?


    本篇文章你将会了解到:

    • 1.Vue的插槽使用
      • a.匿名插槽的使用
      • b.具名插槽的使用
    • 2.React来使用插槽
      • a.React来实现匿名插槽
      • b.React来实现具名插槽
    • 3.阅读一下antdReact实现
    • 注意:文章不包括项目搭建,只有核心代码
      • 项目搭建去看官方文档就可以很快搭起来了的
      • 这里不多啰嗦了…

    从Vue的角度来认识slot

    • 为什么会有slot呢?
      • 你会发现,你写好了一个组件,比如叫Button,是个按钮组件,然后你想给Button一个名字
      • <Button>我是button</Button>
        • 然后你发现我是button被吃掉了
        • 所以我们就需要匿名插槽来解决这个问题
    • 看一下slot的官方解释
      • <slot> 元素作为组件模板之中的内容分发插槽。<slot> 元素自身将被替换。
      • 我们组件写好后,想不通过属性就直接传入,就需要提前把位置准备好

    从代码角度来认识一下匿名插槽

    我们先一个HelloWorld组件如下,里面实际是一个button

    <script setup>
    </script>
    
    <template>
        <button>
          <slot></slot>
        </button>
    </template>
    
    <style scoped>
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    然后我们在App.vue中来调用

    <script setup>
    import HelloWorld from './components/HelloWorld.vue'
    </script>
    
    <template>
      <HelloWorld>
        我是按钮
      </HelloWorld>
    </template>
    
    <style>
    #app {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    因为我们在组件的button里面放了一个slot,所以这个位置会空出来用来放输入的插槽内容,那么这个我是按钮就会被接收

    从代码角度认识一下具名插槽

    OK!那么现在,我们就对slot有一个初步的认识了,那么,可以有多个插槽吗?

    • 是可以的,每个插槽都有一个名字就可以解决这个问题了

    我们改写HelloWorld组件如下:

    <script setup>
    </script>
    
    <template>
      <div>
        <button>
          <slot></slot>
        </button>
        <slot name="41"></slot>
        <slot name="42"></slot>
      </div>
    </template>
    
    <style scoped>
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    我们再写一个Children组件方便来调用具名插槽

    <script setup>
    const props = defineProps({
      msg: String
    })
    </script>
    
    <template>
      <div>
        <div>我是子组件</div>
        <div>传入的msg是{{ props.msg }}</div>
        <div>我被当成一个插槽传入了</div>
      </div>
    </template>
    
    <style scoped>
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    App.vue中调用如下:

    <script setup>
    import HelloWorld from './components/HelloWorld.vue'
    import Children from './components/Children.vue';
    </script>
    
    <template>
      <img alt="Vue logo" src="./assets/logo.png" />
      <HelloWorld>
        我是按钮
        <!-- 匿名插槽还可以写成下面这种形式 
        <template v-slot>
          <div>我是匿名插槽</div>
        </template> -->
        <template #41>
          <Children msg="我是41插槽"></Children>
        </template>
        <template #42>
          <Children msg="我是42插槽"></Children>
        </template>
      </HelloWorld>
    </template>
    
    <style>
    #app {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • #41v-slot:41的缩写
    • 匿名插槽可以不写template直接用的

    从React的角度来认识slot

    我们先看一下React支不支持上面操作

    import './App.css';
    
    function Button () {
      return <button></button>
    }
    
    
    function App () {
      return (
        <div className="App">
          <Button>我是button</Button>
        </div>
      );
    }
    
    export default App;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 你会发现按钮萎缩了,是的,没有插槽功能!

    React实现一下匿名插槽

    • 首先我们要思考,传入的这个我是按钮为什么没有实现?
      • 是没接收到吗?
        • 感觉不是,输入的东西应该不会凭空消失!
      • 查阅资料我们知道这个值是props.children
    • 拿到数据,我们做一次渲染就好了
    import './App.css';
    
    function Button (props) {
      const { children } = props
      return <button>
        {children}
      </button>
    }
    
    function App () {
      return (
        <div className="App">
          <Button>
            我是按钮
          </Button>
        </div>
      );
    }
    
    export default App;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    • 这次我是按钮就显示出来了
    • 说实话,就这点来说,感觉react会让人感觉很清爽

    React来实现一下具名插槽

    • 这个具名好像只能具体定义然后具体传值了
    • 实现如下:
    import './App.css';
    
    function Button (props) {
      const { children, slotTop, slotBottom } = props
      return <>
        {slotTop()}
        <button>
          {children}
        </button>
        {slotBottom()}
      </>
    
    }
    function slotTop () {
      return <div>我是slotTop</div>
    }
    function slotBottom () {
      return <div>我是slotBottom</div>
    }
    function App () {
      return (
        <div className="App">
          <Button
            slotTop={slotTop}
            slotBottom={slotBottom}>
            我是按钮
          </Button>
        </div>
      );
    }
    
    export default App;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    对比vuereact,谈谈感受

    • 我觉得react的思维方式更加直接简约
      • 可能是本人的偏爱吧
    • 其实react这里实现的具名插槽有一些肤浅
      • 因为在vue中插槽的值是通过template传入的
      • 这里改成了传值
      • 之后我们看看antd的处理吧

    阅读一下antdReact实现

    • 写得挺复杂
    const kids =
      children || children === 0
          ? spaceChildren(children, isNeedInserted() && autoInsertSpace)
          : null;
      if (linkButtonRestProps.href !== undefined) {
        return (
          <a {...linkButtonRestProps} className={classes} onClick={handleClick} ref={buttonRef}>
            {iconNode}
            {kids}
          </a>
        );
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 匿名插槽他这里写得是{kid}可以看到上面还有一个{iconNode},具体是啥没仔细看
    • 然后kid是上面的spaceChildren函数来生成的,我们继续看一层
    function spaceChildren(children: React.ReactNode, needInserted: boolean) {
      let isPrevChildPure: boolean = false;
      const childList: React.ReactNode[] = [];
      React.Children.forEach(children, child => {
        const type = typeof child;
        const isCurrentChildPure = type === 'string' || type === 'number';
        if (isPrevChildPure && isCurrentChildPure) {
          const lastIndex = childList.length - 1;
          const lastChild = childList[lastIndex];
          childList[lastIndex] = `${lastChild}${child}`;
        } else {
          childList.push(child);
        }
    
        isPrevChildPure = isCurrentChildPure;
      });
    
      // Pass to React.Children.map to auto fill key
      return React.Children.map(childList, child =>
        insertSpace(child as React.ReactChild, needInserted),
      );
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 思路解析如下:
      • a.用到了数组,soga,所以是可以输入多个的,可以输入html标签和组件
        • 这是我们没有做到的
      • b.stringnumber就直接拼接到上一个children
      • c.否则就放到childList队列中,这个就应该可以理解为单个组件了

    不再深入探究了,各位道友可以指导一下,个人理解难免会有错误,希望大家批评指正!

  • 相关阅读:
    iOS 关于UIWebView常见使用方法
    【leetcode】【剑指offer Ⅱ】038. 每日温度
    tb6612电机驱动与JGB37-520减速直流电机
    肝了一周的八万字Redis实战篇
    Node.js之path路径模块
    065:vue+openlayers显示不同颜色point(示例代码)
    使用 Redis 实现生成分布式全局唯一ID(使用SpringBoot环境实现)
    熟悉Vue路由的beforeEach陷入死循环的情况
    智慧公厕:探索未来公共厕所的创新设计
    安防监控项目---通信结构体设计
  • 原文地址:https://blog.csdn.net/qq_42136832/article/details/125465849