likes
comments
collection
share

从零开始:如何在Vue.js和React.js中使用slot实现自定义内容

作者站长头像
站长
· 阅读数 20

slot相当于组件中的一个占位符,等待后续的模板片段,解析到当前占位符的位置。在 vue 中实现了 slot 标签,而在 react 中默认没有 slot 标签,但是在 react 中可以借助 props 实现 vue 中类似 slot 的效果。

vueslot 的示例

<button class="fancy-btn">
  <slot></slot> <!-- 插槽出口 -->
</button>

使用

<FancyButton>
  Click me! <!-- 插槽内容会渲染到上面 插槽出口 的位置 -->
</FancyButton>

slot 默认内容

在外部没有提供任何内容的情况下,可以为插槽指定默认内容。如果在父组件没有提供任何插槽内容时在 <button> 内会渲染默认的内容,如果提供了内容,就会渲染父组件中提供的内容,默认的内容则不会再次渲染

<button type="submit">
  <slot>
    Submit <!-- 默认内容 -->
  </slot>
</button>

具名插槽

在一个组件中可以提供多个 slot 插槽,为区别不同的插槽,可以在定义为每一个插槽提供一个唯一的名称。在父组件中可以根据名称传递不同的内容到指定的名称的插槽处。 带 name 的插槽被称为具名插槽, 不带 name 的插槽有一个隐式的名称 default

具名插槽定义

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

使用时

<BaseLayout>
  <template #header>
    <h1>Here might be a page title</h1>
  </template>

  <template #default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>

  <template #footer>
    <p>Here's some contact info</p>
  </template>
</BaseLayout>

vue中还支持动态插槽名

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>

  <!-- 缩写为 -->
  <template #[dynamicSlotName]>
    ...
  </template>
</base-layout>

作用域插槽

插槽的作用原则

父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域。

但是有些情况下,想在插槽内容中使用子组件作用域中的内容,可以像对组件传递 props 那样,向一个插槽的出口上传递 attributes,如在项目开发时定义一个 FancyList 列表组件,在组件内获取列表数据,但是数据的展现形式和样式由父组件定义

FancyList.vue

const response = await fetch(url)
await response.json();
<ul>
  <li v-for="item in items">
    <!--使用了具名插槽-->
    <slot name="item" v-bind="item"></slot>
  </li>
</ul>

调用组件时再定义列表数据的样式

<FancyList>
  <template #item="{ body, username, likes }">
    <!--定义每个列表项目的样式-->
    <div class="item">
      <p>{{ body }}</p>
      <p>by {{ username }} | {{ likes }} likes</p>
    </div>
  </template>
</FancyList>

react 中的 slot

reactprops 中会有一个默认的属性 children

FancyButton.jsx

const FancyButton = (props) => {
  return (
    <div>
        {props.children}
    </div>
  )
}
// 析构版本
const FancyButton = ({children}) => {
  return (
    <div>
        {children}
    </div>
  )
}

使用时在 FancyButton 中嵌套的组件会渲染上面 children 位置

<FancyButton>
    <p>Submit</p>
</FancyButton>

默认内容

const FancyButton = ({children}) => {
  return (
    <div>
        {children || 'default 默认内容或组件'}
    </div>
  )
}

使用时,如果没有嵌套内容或组件,将显示默认的内容

<FancyButton />

具名插槽

react 中可以通过 props 传递自定义的组件,这样可以通过定义不同的 props 值,传递不同的组件,并渲染指定的位置

const BaseLayout = ({header, children, footer}) => {
  return (
    <div>
        <div>{header}</div>
        <main>{children}</main>
        <div>{footer}</div>
    </div>
  )
}

使用时通过属性名传递不同的组件

import Header from './Header'
import Footer from './Footer'

<BaseLayout header={<Header />} footer={<Footer />}>
    <div>主要内容</div>
</BaseLayout>

相关主题

通过Vue3对比学习Reactjs: 模板语法 vs JSX Vue vs Reactjs之 props Vuejs vs Reactjs:组件之间如何通信 解密v-model:揭示Vue.js和React.js中实现双向数据绑定的不同策略

转载自:https://juejin.cn/post/7249956290629632055
评论
请登录