h5-tdsign-for-vue
v0.1.18
Published
基于 TDesign Mobile 的 Vue 3 智能表单组件库
Maintainers
Readme
h5-tdsign-for-vue
基于 TDesign Mobile Vue 的智能表单组件库,提供开箱即用的动态表单解决方案。
✨ 特性
- 🚀 动态表单 - 通过 JSON Schema 配置生成表单,无需手写模板
- 📱 移动端优化 - 基于 TDesign Mobile,完美适配移动端
- 🎯 TypeScript - 完整的类型定义,提供良好的开发体验
- 🔌 自动引入 - 支持
unplugin-vue-components自动按需引入 - 🎨 丰富组件 - 内置多种表单控件,满足常见业务场景
📦 安装
# npm
npm install h5-tdsign-for-vue
# pnpm
pnpm add h5-tdsign-for-vue
# yarn
yarn add h5-tdsign-for-vue前置依赖
pnpm add vue tdesign-mobile-vue🚀 快速开始
全局注册
// main.ts
import { createApp } from 'vue'
import TDesign from 'tdesign-mobile-vue'
import 'tdesign-mobile-vue/es/style/index.css'
import { SmartForm, SmartUpload } from 'h5-tdsign-for-vue'
import 'h5-tdsign-for-vue/style.css'
const app = createApp(App)
app.use(TDesign)
app.component('SmartForm', SmartForm)
app.component('SmartUpload', SmartUpload)
app.mount('#app')自动引入(推荐)
// vite.config.ts
import Components from 'unplugin-vue-components/vite'
import { SmartFormResolver } from 'h5-tdsign-for-vue/resolver'
export default defineConfig({
plugins: [
Components({
resolvers: [SmartFormResolver()],
}),
],
})📖 组件文档
SmartForm 智能表单
通过 JSON Schema 配置生成动态表单。
<template>
<SmartForm
v-model="formData"
:schemas="schemas"
@submit="handleSubmit"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { FormSchema } from 'h5-tdsign-for-vue'
interface FormData {
name: string
phone: string
gender: string
}
const formData = ref<FormData>({
name: '',
phone: '',
gender: '',
})
const schemas: FormSchema<FormData>[] = [
{
name: 'name',
label: '姓名',
type: 'input',
required: true,
requiredMark: false, // 隐藏必填星号
props: { placeholder: '请输入姓名' },
},
{
name: 'idCard',
label: '身份证号', // 配合 showLabel: false 可隐藏标签
showLabel: false, // 隐藏标签
type: 'input',
props: { placeholder: '请输入身份证号' },
},
{
name: 'phone',
label: '手机号',
type: 'input',
props: { type: 'tel', placeholder: '请输入手机号' },
},
{
name: 'gender',
label: '性别',
type: 'select',
props: {
columns: [
{ label: '男', value: 'male' },
{ label: '女', value: 'female' },
],
},
},
]
const handleSubmit = (data: FormData) => {
console.log('提交数据:', data)
}
</script>Props
| 属性 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| modelValue | 表单数据 | T | - |
| schemas | 表单配置 | FormSchema<T>[] | [] |
| labelWidth | 标签宽度 | string \| number | - |
| labelAlign | 标签对齐 | 'left' \| 'right' \| 'top' | 'left' |
| showFooter | 显示底部按钮 | boolean | true |
| submitBtnText | 提交按钮文字 | string | '提交' |
| resetBtnText | 重置按钮文字 | string | '重置' |
| loading | 加载状态 | boolean | false |
| disabled | 禁用状态 | boolean | false |
Slots
| 插槽 | 说明 | 参数 |
|------|------|------|
| default | 表单内容插槽(通常不需要手动使用) | - |
| footer-top | 底部按钮上方的自定义内容插槽 | - |
FormSchema 配置
基础配置项:
| 属性 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| name | 字段名 | string | - |
| label | 标签文本 | string | - |
| type | 组件类型 | ComponentType | 'input' |
| required | 是否必填 | boolean | false |
| requiredMark | 显示必填星号 | boolean | true |
| showLabel | 显示标签 | boolean | true |
| hidden | 是否隐藏 | boolean \| ((model) => boolean) | false |
| disabled | 是否禁用 | boolean \| ((model) => boolean) | false |
| props | 组件属性 | object | {} |
| rules | 校验规则 | FormRule[] | [] |
支持的组件类型
| type | 说明 | 对应组件 |
|------|------|----------|
| input | 输入框 | Input |
| textarea | 多行文本 | Textarea |
| password | 密码输入 | Input |
| number | 数字输入 | Input |
| select | 选择器 | SmartSelect |
| cascader | 级联选择 | SmartCascader |
| tree-select | 树形选择 | SmartTreeSelect |
| date | 日期选择 | SmartTimePicker |
| time | 时间选择 | SmartTimePicker |
| switch | 开关 | Switch |
| radio | 单选 | RadioGroup |
| checkbox | 多选 | CheckboxGroup |
| stepper | 步进器 | Stepper |
| upload | 上传 | SmartUpload |
| slot | 自定义插槽 | - |
SmartUpload 智能上传
支持多种数据格式的图片/文件上传组件。
<template>
<SmartUpload
v-model="fileList"
:request-method="uploadFile"
:format-response="formatResponse"
value-type="objectArray"
url-key="fileUrl"
name-key="filename"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
interface FileData {
id: number
filename: string
fileUrl: string
}
const fileList = ref<FileData[]>([])
const uploadFile = async (file: File) => {
const formData = new FormData()
formData.append('file', file)
const res = await fetch('/api/upload', { method: 'POST', body: formData })
return { status: 'success', response: await res.json() }
}
const formatResponse = (res: any) => ({
id: res.data.id,
filename: res.data.name,
fileUrl: res.data.url,
})
</script>Props
| 属性 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| modelValue | 文件列表 | string \| string[] \| object[] | '' |
| valueType | 值类型 | 'string' \| 'stringArray' \| 'objectArray' | 自动推断 |
| urlKey | URL 字段名 | string | 'fileUrl' |
| nameKey | 名称字段名 | string | 'filename' |
| separator | 分隔符 | string | ',' |
| urlPrefix | URL 前缀 | string | '' |
| mode | 上传模式 | 'image' \| 'file' | 'image' |
| accept | 接受类型 | string \| string[] | 'image/*' |
| max | 最大数量 | number | 9 |
| maxSize | 最大大小(KB) | number | 10240 |
| multiple | 多选 | boolean | true |
| disabled | 禁用 | boolean | false |
| requestMethod | 上传方法 | Function | - |
| formatResponse | 格式化响应 | Function | - |
SmartSelect 选择器
带输入框触发的选择器组件。
<SmartSelect
v-model="value"
label="城市"
placeholder="请选择城市"
:columns="[
{ label: '北京', value: 'beijing' },
{ label: '上海', value: 'shanghai' },
]"
/>SmartCascader 级联选择
多级联动选择器。
<SmartCascader
v-model="value"
label="地区"
placeholder="请选择地区"
:options="areaOptions"
/>SmartTreeSelect 树形选择
树形结构选择器。
<SmartTreeSelect
v-model="value"
label="部门"
placeholder="请选择部门"
:options="deptOptions"
/>SmartTimePicker 时间选择器
日期/时间选择器。
<SmartTimePicker
v-model="value"
label="日期"
placeholder="请选择日期"
mode="date"
format="YYYY-MM-DD"
/>SmartList 智能列表
支持下拉刷新、上拉加载、骨架屏的列表组件。
<template>
<SmartList
v-model:pagination="pagination"
:fetch-api="fetchList"
:skeleton-rows="5"
finished-text="— 没有更多了 —"
>
<template #item="{ item, index }">
<div class="list-item">
<span>{{ index + 1 }}. {{ item.title }}</span>
</div>
</template>
</SmartList>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
interface ListItem {
id: number
title: string
}
const pagination = reactive({
pageNum: 1,
pageSize: 10,
total: 0,
})
const fetchList = async (params: Record<string, unknown>): Promise<ListItem[]> => {
const res = await fetch(`/api/list?page=${params.pageNum}&size=${params.pageSize}`)
const data = await res.json()
pagination.total = data.total
return data.list
}
</script>Props
| 属性 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| fetchApi | 获取数据的 API 函数 | (params) => Promise<T[]> | - |
| pagination | 分页对象(v-model) | Record<string, number> | - |
| paginationConfig | 分页字段映射 | PaginationConfig | 见下方 |
| immediate | 是否立即加载 | boolean | true |
| pullDownRefresh | 启用下拉刷新 | boolean | true |
| pullUpLoad | 启用上拉加载 | boolean | true |
| loadMode | 加载模式 | 'auto' \| 'click' | 'auto' |
| loadOffset | 自动加载触发距离 | number | 50 |
| skeleton | 显示骨架屏 | boolean | true |
| skeletonRows | 骨架屏行数 | number | 5 |
| finishedText | 加载完成提示 | string | '没有更多了' |
| emptyText | 空状态提示 | string | '暂无数据' |
PaginationConfig 默认值
{
pageKey: 'pageNum',
pageSizeKey: 'pageSize',
totalKey: 'total',
}Events
| 事件 | 说明 | 参数 |
|------|------|------|
| update:pagination | 分页更新 | pagination |
| load-success | 加载成功 | { list, isRefresh } |
| load-error | 加载失败 | error |
| refresh | 下拉刷新 | - |
| load-more | 上拉加载 | - |
Slots
| 插槽 | 说明 | 参数 |
|------|------|------|
| item | 列表项 | { item, index } |
| skeleton | 骨架屏 | - |
| empty | 空状态 | - |
| loading | 加载中 | - |
| finished | 加载完成 | - |
| header | 列表头部 | - |
| footer | 列表底部 | - |
Methods(通过 ref 调用)
| 方法 | 说明 |
|------|------|
| refresh() | 刷新列表 |
| getList() | 获取当前数据 |
| scrollToTop() | 滚动到顶部 |
SmartPage 页面容器
集成 Navbar 和 TabBar 的页面根组件,提供统一的页面布局方案。
<template>
<SmartPage
title="首页"
show-back
show-tab-bar
v-model:tab-bar-value="activeTab"
:tabs="tabList"
@back="handleBack"
@tab-change="handleTabChange"
>
<div class="page-content">
页面内容
</div>
</SmartPage>
</template>
<script setup lang="ts">
import { ref, h } from 'vue'
import { Icon as TIcon } from 'tdesign-mobile-vue'
import type { TabItem } from 'h5-tdsign-for-vue'
const activeTab = ref('home')
// 创建图标组件 - 支持 TDesign Icon、图片、SVG
const HomeIcon = () => h(TIcon, { name: 'home' })
const UserIcon = () => h(TIcon, { name: 'user' })
// 使用自定义图片作为图标
const CustomIcon = () => h('img', { src: '/icons/custom.png', style: { width: '24px' } })
const tabList: TabItem[] = [
{ value: 'home', label: '首页', icon: HomeIcon },
{ value: 'user', label: '我的', icon: UserIcon, badgeProps: { count: 5 } },
]
const handleBack = () => {
console.log('返回')
}
const handleTabChange = (value: string | number) => {
console.log('切换到:', value)
}
</script>
<style scoped>
.page-content {
/* 设置 height: 100% 可以正确撑满内容区域 */
height: 100%;
overflow: auto;
}
</style>Props
| 属性 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| title | 页面标题 | string | - |
| showNavbar | 显示顶部导航栏 | boolean | true |
| showBack | 显示返回按钮 | boolean | false |
| onBack | 自定义返回逻辑 | () => void | window.history.back() |
| showTabBar | 显示底部标签栏 | boolean | false |
| tabs | 标签栏配置 | TabItem[] | [] |
| tabBarValue | 当前选中标签(支持 v-model) | string \| number | - |
Navbar 相关属性
| 属性 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| navbarAnimation | 标题切换动画 | boolean | true |
| navbarFixed | 固定在顶部 | boolean | true |
| navbarPlaceholder | 固定时是否占位 | boolean | true |
| navbarSafeAreaInsetTop | 安全区域适配 | boolean | true |
| navbarZIndex | 层级 | number | - |
TabBar 相关属性
| 属性 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| tabBarBordered | 显示边框 | boolean | true |
| tabBarFixed | 固定在底部 | boolean | true |
| tabBarPlaceholder | 固定时是否占位 | boolean | true |
| tabBarSafeAreaInsetBottom | 安全区域适配 | boolean | true |
| tabBarShape | 形状 | 'round' \| 'normal' | 'round' |
| tabBarTheme | 主题 | 'normal' \| 'tag' | 'normal' |
| tabBarZIndex | 层级 | number | - |
TabItem 配置
| 属性 | 说明 | 类型 | 必填 |
|------|------|------|------|
| value | 标签值 | string \| number | ✅ |
| label | 标签文本 | string | - |
| icon | 图标组件 | Component | - |
| badgeProps | 徽标配置 | TdBadgeProps | - |
Events
| 事件 | 说明 | 参数 |
|------|------|------|
| back | 点击返回按钮 | - |
| tab-change | 切换标签 | (value: string \| number) |
| update:tabBarValue | 标签值变更 | (value: string \| number) |
| right-click | 点击导航栏右侧 | - |
Slots
| 插槽 | 说明 |
|------|------|
| default | 页面内容 |
| navbar-left | 导航栏左侧自定义内容 |
| navbar-right | 导航栏右侧自定义内容 |
| navbar-title | 导航栏标题自定义内容 |
| navbar-capsule | 导航栏胶囊区域 |
自定义图标
支持多种图标类型:
import { h } from 'vue'
import { Icon as TIcon } from 'tdesign-mobile-vue'
import CustomSvgIcon from '@/icons/CustomIcon.vue'
// 1. TDesign Icon
const TdIcon = () => h(TIcon, { name: 'home' })
// 2. 图片图标
const ImageIcon = () => h('img', {
src: '/icons/home.png',
style: { width: '24px', height: '24px' }
})
// 3. 内联 SVG
const SvgIcon = () => h('svg', { viewBox: '0 0 24 24' }, [
h('path', { d: 'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z', fill: 'currentColor' })
])
// 4. Vue 组件
const VueIcon = CustomSvgIcon📝 类型导出
import type {
// SmartForm 相关
FormSchema,
SmartFormProps,
ComponentType,
// SmartUpload 相关
SmartUploadProps,
SmartUploadFile,
FileListValue,
FileListValueType,
// SmartPage 相关
SmartPageProps,
TabItem,
// SmartList 相关
SmartListProps,
PaginationConfig,
} from 'h5-tdsign-for-vue'🔧 开发
# 安装依赖
pnpm install
# 启动开发服务器
pnpm dev
# 构建组件库
pnpm build:lib
# 类型检查
pnpm type-check
# 代码检查
pnpm lint