实战篇笔记-山竹记账前端(六)


创建 Button 组件

透传 Attributes

“透传 attribute”指的是传递给一个组件,却没有被该组件声明为 props 或 emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 class、style 和 id。

当一个组件以单个元素为根作渲染时,透传的 attribute 会自动被添加到根元素上。

// src/shared/Button.tsx
...
// 这里定义接口是因为 TS 错误提示
interface Props{
  onClick: (e: MouseEvent) => void
}

export const Button = defineComponent<Props>({
  setup: (props, context) => {
    return () => (
      <button class={s.button}>
        {context.slots.default?.()}
      </button>
    )
  }
})

// src/views/StartPage.tsx
...
export const StartPage = defineComponent({
  setup: (props, context) => {
    const onClick = () => {
      console.log('hi')
    }
    return () => (
      <div>
        <div class={s.button_wrapper}>
          <Button class={s.button} onClick={onClick}>测试</Button>  // Button 组件并没有声明 props,点击按钮也可以执行 onClick 事件
        </div>
      </div>
    )
  }
})

创建 FloatButton 和 Icon 组件

FloatButton 组件调用 Icon 组件

// src/shared/FloatButton.tsx
...
export const FloatButton = defineComponent({
  setup: (props, context) => {
    return () => (
      <div class={s.floatButton}>
        <Icon name="add" class={s.icon}/>
      </div>
    )
  }
})

封装 Icon 组件

  1. 虽然声明了 Props,TypeScript 转译成 JavaScript 后声明信息就消失了
// src/shared/Icon.tsx
...
interface Props{
  name: 'add' | 'chart' | 'clock' | 'cloud' | 'mangosteen' | 'pig'
}
export const Icon = defineComponent<Props>({
  setup: (props, context) => {
    console.log(props.name) // undefined
    return () => (
      <svg class={s.icon}>
        <use xlinkHref={'#' + props.name}></use>
      </svg>
    )
  }
})
  1. 声明运行时的 props,会提示 没有与此调用匹配的重载,查看 defineComponent 声明可知 <Props>props 不能共存
interface Props{
  name: 'add' | 'chart' | 'clock' | 'cloud' | 'mangosteen' | 'pig'
}
export const Icon = defineComponent<Props>({
  props: ['name'],  // 这里会有错误提示
  setup: (props, context) => {
    console.log(props.name) // undefined
    return () => (
      <svg class={s.icon}>
        <use xlinkHref={'#' + props.name}></use>
      </svg>
    )
  }
})
  1. 考虑用 defineProps,结果不行,会有警告 defineProps 是一个仅 <script setup> 中可用的编译宏命令 ,而且 name 是 null 的报错

  2. 最后选择的是不用 <Props>,使用 PropType 这个工具类型来标记 props 类型

...
export const Icon = defineComponent({
  props: {
    name: {
      type: String as PropType<'add' | 'chart' | 'clock' | 'cloud' | 'mangosteen' | 'pig'>
    }
  },
  setup: (props, context) => {
    return () => (
      <svg class={s.icon}>
        <use xlinkHref={'#' + props.name}></use>
      </svg>
    )
  }
})

组件需要透传的 attribute 不在根节点,设置 inheritAttrs: false 可以禁用 Attributes 继承。

sass 内置模块用法

@use "sass:color";

.button {
  $primary-color: #6b717f;
  color: $primary-color;
  border: 1px solid color.scale($primary-color, $lightness: 20%);
}

文章作者: April-cl
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 April-cl !
  目录