创建新组件技能

SkillDocs & knowledge

Creates a new component skeleton and the required registration points in the wot-ui project. Invoke when the user asks to create component source code from scratch, complete the types.vue.scss structure, or register global component types; does not handle Demo pages, tests, or documentation migratio

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the 创建新组件技能 skill

What this skill tells your AI

The instructions your AI receives, as published by wot-ui/wot-ui in .agents/skills/create-component/SKILL.md and read by ahel’s review.

本技能用于在 wot-ui 项目中创建新的 UI 组件骨架。

默认遵循 wot-ui-component-baseline 中的共享约束,命名与注释细则可配合 vue-comment 使用。

职责边界

  • 本 Skill 负责组件源码目录、基础文件、必要注册点。
  • 本 Skill 不负责 Demo 页编写,相关工作交给 create-demo-page
  • 本 Skill 不负责测试创建,相关工作交给 create-test
  • 本 Skill 不负责 Markdown 文档迁移或大规模文档编写,相关工作交给 migrate-component-doc

组件目录结构

每个组件位于 src/uni_modules/wot-ui/components/wd-{组件名}/ 目录下,包含以下文件:

wd-{组件名}/
├── types.ts           # 类型定义文件
├── wd-{组件名}.vue    # 组件主文件
└── index.scss         # 样式文件

创建步骤

1. 创建组件目录

mkdir -p src/uni_modules/wot-ui/components/wd-{组件名}

2. 创建类型定义文件 (types.ts)

import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
import { baseProps, makeBooleanProp, makeNumberProp, makeNumericProp, makeStringProp } from '../common/props'

// 如果需要定义枚举类型
export type {组件名}Type = 'primary' | 'success' | 'warning' | 'danger'

export const {组件名驼峰}Props = {
  // 继承基础 props (customStyle, customClass)
  ...baseProps,
  /**
   * 属性描述
   * 类型: string
   * 默认值: ''
   */
  prop1: makeStringProp(''),
  /**
   * 布尔属性描述
   * 类型: boolean
   * 默认值: false
   */
  disabled: makeBooleanProp(false),
  /**
   * 数字属性描述
   * 类型: number
   * 默认值: 0
   */
  count: makeNumberProp(0),
  /**
   * 数字或字符串属性
   * 类型: string | number
   * 默认值: ''
   */
  value: makeNumericProp('')
}

// Props 类型导出
export type {组件名}Props = ExtractPropTypes<typeof {组件名驼峰}Props>

// 如果组件暴露方法,定义 Expose 类型
export type {组件名}Expose = {
  /** 方法描述 */
  methodName: () => void
}

// 组件实例类型
export type {组件名}Instance = ComponentPublicInstance<{组件名}Expose, {组件名}Props>
Props 工具函数说明
工具函数用途示例
makeStringProp(default)字符串属性makeStringProp('')
makeBooleanProp(default)布尔属性makeBooleanProp(false)
makeNumberProp(default)数字属性makeNumberProp(0)
makeNumericProp(default)数字或字符串属性makeNumericProp('')
makeArrayProp<T>()数组属性makeArrayProp<string>()
makeRequiredProp(type)必填属性makeRequiredProp(String)

3. 创建组件文件 (wd-{组件名}.vue)

<template>
  <view :class="rootClass" :style="customStyle">
    <!-- 组件内容 -->
    <slot></slot>
  </view>
</template>

<script lang="ts">
export default {
  name: 'wd-{组件名}',
  options: {
    addGlobalClass: true,
    // #ifndef MP-TOUTIAO
    virtualHost: true,
    // #endif
    styleIsolation: 'shared'
  }
}
</script>

<script lang="ts" setup>
import { computed } from 'vue'
import { {组件名驼峰}Props, type {组件名}Expose } from './types'

const props = defineProps({组件名驼峰}Props)

// Emits 定义
const emit = defineEmits<{
  click: [event: Event]
  change: [value: string]
}>()

// 计算根节点类名
const rootClass = computed(() => {
  return `wd-{组件名} ${props.customClass}`
})

// 组件方法
function handleClick(event: Event) {
  emit('click', event)
}

// 暴露给父组件的方法
defineExpose<{组件名}Expose>({
  methodName: () => {
    // 实现
  }
})
</script>

<style lang="scss">
@use './index.scss';
</style>
组件选项说明
  • addGlobalClass: true - 允许使用全局样式类
  • virtualHost: true - 开启虚拟节点模式
  • styleIsolation: 'shared' - 样式共享模式

4. 创建样式文件 (index.scss)

@use '../../styles/mixin/mixin.scss' as *;
@use '../../styles/variable.scss' as *;

// 定义组件级 CSS 变量(支持主题定制)
${组件名}-bg: var(--wot-{组件名}-bg, $filled-oppo);
${组件名}-padding: var(--wot-{组件名}-padding, $padding-loose);
${组件名}-border-radius: var(--wot-{组件名}-border-radius, $radius-main);

@include b({组件名}) {
  display: flex;
  padding: ${组件名}-padding;
  background: ${组件名}-bg;
  border-radius: ${组件名}-border-radius;

  // 定义元素 (Element)
  @include e(header) {
    // .wd-{组件名}__header
  }

  @include e(content) {
    // .wd-{组件名}__content
  }

  @include e(footer) {
    // .wd-{组件名}__footer
  }

  // 定义状态修饰符 (Modifier)
  @include when(disabled) {
    // .wd-{组件名}.is-disabled
    opacity: $opacity-disabled;
  }

  @include when(active) {
    // .wd-{组件名}.is-active
  }

  // 定义变体修饰符
  @include m(primary) {
    // .wd-{组件名}--primary
  }

  @include m(large) {
    // .wd-{组件名}--large
  }
}
BEM 命名规范
Mixin生成选择器说明
@include b(name).wd-name定义块 (Block)
@include e(elem).wd-name__elem定义元素 (Element)
@include m(mod).wd-name--mod定义修饰符 (Modifier)
@include when(state).wd-name.is-state定义状态
@include edeep(elem):deep(.wd-name__elem)穿透子组件样式
@include me(elem)嵌套在 m 下的 e修饰符下的元素
常用样式变量
类别变量示例说明
颜色$primary-6, $danger-main, $text-main语义化颜色
间距$padding-loose, $spacing-tight内边距/间距
圆角$radius-main, $radius-large边框圆角
字体$typography-body-size-main字号
边框$border-main, $stroke-main边框

常用 Composables

项目提供了多个可复用的组合式函数:

Composable用途
useParent获取父组件实例
useChildren管理子组件
useLockScroll锁定页面滚动
useClickAway点击外部区域检测
useQueueToast/Notify 队列管理
useTranslate国际化

使用示例:

import { useLockScroll } from '../composables/useLockScroll'

// #ifdef H5
useLockScroll(() => showPopup.value)
// #endif

条件编译

uni-app 支持跨平台条件编译:

<!-- 仅 H5 平台 -->
// #ifdef H5
<view>H5 专用内容</view>
// #endif

<!-- 仅微信小程序 -->
// #ifdef MP-WEIXIN
<view>微信小程序专用</view>
// #endif

<!-- 非 App 平台 -->
// #ifndef APP
<view>非 App 内容</view>
// #endif

5. 注册全局类型声明 (global.d.ts)

src/uni_modules/wot-ui/global.d.ts 中添加组件类型声明:

declare module 'vue' {
  export interface GlobalComponents {
    // ... 已有组件
    Wd{组件名帕斯卡}: typeof import('./components/wd-{组件名}/wd-{组件名}.vue')['default']
  }
}

命名规则:组件名使用帕斯卡命名法(PascalCase),如 WdVideoPreviewWdIndexBar

交付要求

  • 至少创建 types.tswd-<component>.vueindex.scss
  • 如组件需全局识别,补充 global.d.ts
  • 保持最小可运行骨架,不把 Demo、测试、文档强行塞入同一任务。
  • 完成后至少校验当前新增或修改文件无明显语法错误。 | 最低版本 | Min Version |

8. 配置文档侧边栏

需要在以下两个文件中添加侧边栏配置:

中文侧边栏 (docs/.vitepress/locales/zh-CN.ts)
// 在对应分类的 items 数组中添加
{
  link: '/component/{组件名}',
  text: '{组件名帕斯卡} {中文名}'
}
英文侧边栏 (docs/.vitepress/locales/en-US.ts)
{
  link: '/en-US/component/{组件名}',
  text: '{组件名帕斯卡} {英文名}'
}

分类参考

  • 基础:Button、Icon、Popup、Transition 等
  • 导航:Pagination、Tabs、Tabbar、Navbar 等
  • 数据输入:Input、Picker、Calendar、Form 等
  • 反馈:Toast、Loading、ActionSheet 等
  • 数据展示:Badge、Card、Cell、Tag 等

9. 创建演示页面 (src/subPages/{组件名驼峰}/Index.vue)

<template>
  <page-wraper>
    <view class="page-{组件名}">
      <demo-block :title="$t('jiBenYongFa')">
        <wd-{组件名}>基本用法</wd-{组件名}>
      </demo-block>

      <demo-block :title="$t('otherFeature')">
        <!-- 其他功能演示 -->
      </demo-block>
    </view>
  </page-wraper>
</template>

<script lang="ts" setup>
// 组件逻辑
</script>

<style lang="scss" scoped>
.page-{组件名} {
  // 页面样式
}
</style>

注意:使用 page-wraper 组件包裹页面,使用 demo-block 组件分块展示功能


10. 配置演示页面路由 (src/pages.json)

subPackagespages 数组中添加:

{
  "path": "{组件名驼峰}/Index",
  "name": "{组件名驼峰}",
  "style": {
    "mp-alipay": {
      "allowsBounceVertical": "NO"
    },
    // #ifdef MP
    "navigationBarTitleText": "{组件名帕斯卡} {中文名}",
    // #endif
    // #ifndef MP
    "navigationBarTitleText": "%{组件名小写}-title%"
    // #endif
  }
}

11. 配置首页入口 (src/pages/index/Index.vue)

在对应分类的 pages 数组中添加演示页面入口:

// 在对应分类(如 show 数据展示)的 pages 数组中添加
{
  id: '{组件名驼峰}',
  name: t('{组件名小写}-{中文名}')
}

分类对应关系

分类 ID说明示例组件
widget基础Button、Icon、Popup
nav导航Tabs、Tabbar、Navbar
form数据输入Input、Picker、Calendar
feedback反馈Toast、Loading、ActionSheet
show数据展示Badge、Card、Cell、Img

检查清单

创建组件后,确保完成以下事项:

组件代码

  • types.ts 中所有 props 都有中文注释
  • 组件支持 customClasscustomStyle 属性
  • 样式使用 BEM 命名规范
  • CSS 变量使用 --wot-{组件名}-* 格式命名
  • 如有暴露方法,定义正确的 Expose 类型
  • 组件设置了正确的 name 选项

类型声明

  • global.d.ts 中添加组件类型声明

文档

  • 创建中文文档 docs/component/{组件名}.md
  • 创建英文文档 docs/en-US/component/{组件名}.md
  • zh-CN.ts 中添加侧边栏配置
  • en-US.ts 中添加侧边栏配置

演示页面

  • 创建演示页面 src/subPages/{组件名驼峰}/Index.vue
  • pages.json 中配置页面路由
  • src/pages/index/Index.vue 中添加首页入口

Signals

GitHub stars
356
Forks
39
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
create-component-wot-ui
Source
github.com/wot-ui/wot-ui