Skip to content

组件封装与插槽

Vue的template一般使用slot,但tsx中的写法有点不同,具体可以查看babel-plugin-jsx

插槽有多种写法如下所示:

  • 案例一
tsx
import { defineComponent } from 'vue';
import s from './First.module.scss';
export const WelcomeLayout = defineComponent({
  setup: (props, context) => {
    const { slots: { icons, title, buttons } } = context
    return () => (
      <div class={s.wrapper}>
        <div class={s.card}>
          { icons?.() }
          { title?.() }
        </div>
        <div class={s.actions}>
          { buttons?.() }
        </div>
      </div>
    )
  }
})
tsx
import s from './First.module.scss';
import pig from '../../assets/icons/pig.svg';
import { RouterLink } from 'vue-router';
import { WelcomeLayout } from './WelcomeLayout';
import { defineComponent } from 'vue';
export const First = defineComponent({
  setup: (props, context) => {
    const slots = {
      icon: () => <img class={s.pig} src={pig} />,
      title: () => <h2>会挣钱<br />还要会省钱</h2>,
      buttons: () => <>
        <RouterLink class={s.fake} to="/start" >跳过</RouterLink>
        <RouterLink to="/welcome/2" >下一页</RouterLink>
        <RouterLink to="/start" >跳过</RouterLink>
      </>
    }
    return () => <WelcomeLayout v-slots={slots}/>
  }
})
tsx
import { defineComponent } from 'vue'
import s from './First.module.scss';
import chart from '../../assets/icons/chart.svg'
import { RouterLink } from 'vue-router'
import { WelcomeLayout } from './WelcomeLayout'
export const Third = defineComponent({
  setup: (props, context) => {
    return () => (
      <WelcomeLayout>
      {{
        icon: () => <img class={s.icon} src={chart} />,
        title: () => <h2>每日提醒<br />不遗漏每一笔账单</h2>,
        buttons: () => <>
          <RouterLink class={s.fake} to="/start" >跳过</RouterLink>
          <RouterLink to="/welcome/4" >下一页</RouterLink>
          <RouterLink to="/start" >跳过</RouterLink>
        </>
      }}
    </WelcomeLayout>
    )
  }
})
  • 案例二,最终采用这种方法重构
tsx
import { FunctionalComponent } from 'vue';
import s from './WelcomeLayout.module.scss';
export const WelcomeLayout: FunctionalComponent = (props, context) => {
  const { slots: { icon, title, buttons } } = context
  return (
    <div class={s.wrapper}>
      <div class={s.card}>
        {icon?.()}
        {title?.()}
      </div>
      <div class={s.actions}>
        {buttons?.()}
      </div>
    </div>
  )
}
tsx
import s from './WelcomeLayout.module.scss';
import pig from '../../assets/icons/pig.svg';
import { RouterLink } from 'vue-router';
import { WelcomeLayout } from './WelcomeLayout';
import { FunctionalComponent } from 'vue';
export const First: FunctionalComponent = () => {
  return <WelcomeLayout>
    {{
      icon: () => <img class={s.pig} src={pig} />,
      title: () => <h2>会挣钱<br />还要会省钱</h2>,
      buttons: () => <>
        <RouterLink class={s.fake} to="/start" >跳过</RouterLink>
        <RouterLink to="/welcome/2" >下一页</RouterLink>
        <RouterLink to="/start" >跳过</RouterLink>
      </>
    }}
  </WelcomeLayout>
}
First.displayName = 'First'