fix: supplement development document specifications (#4218)
* fix: supplement development document specifications * fix: change skill name * fix: change skill name * fix: add design.skill.md
This commit is contained in:
parent
c17736357c
commit
d953756931
|
|
@ -22,16 +22,17 @@ description: tinyvue组件库开发规范
|
|||
|
||||
## 组件库的架构
|
||||
|
||||
| 模块名称 | 代码目录 | 参考规范 | 说明 |
|
||||
| --------------- | ----------------------------------------------------------------------------- | ----------------------- | ------------------------------------ |
|
||||
| 模板层 | `packages/vue` | `./vue.skill.md` | 每个组件的模板,必须在相应的组件目录 |
|
||||
| 无渲染逻辑层 | `packages/renderless` | `./renderless.skill.md` | 每个组件的逻辑,必须在相应的组件目录 |
|
||||
| 样式层 | `packages/theme` | `./theme.skill.md` | 每个组件的样式,必须在相应的组件目录 |
|
||||
| 适配Vue2/Vue3层 | `packages/vue-common` | - | 禁止修改适配层的代码 |
|
||||
| 图标库 | `packages/vue-icon` | `./icon.skill.md` | 图标库 |
|
||||
| 国际化层 | `packages/vue-locale` | `./locale.skill.md` | 组件的国际化 |
|
||||
| 公用hooks | `packages/vue-hooks` | `./hooks.skill.md` | 跨组件可以复用的hooks函数 |
|
||||
| 公用指令 | `packages/vue-directive` | `./directive.skill.md` | 跨组件可以复用的指令 |
|
||||
| utils | `packages/utils` | `./utils.skill.md` | 公用函数 |
|
||||
| 组件测试 | `examples\sites\demos\pc\app\**\*.spec.ts` 或 `packages\vue\src\**\__tests__` | `./test.skill.md` | e2e测试和单元测试 |
|
||||
| 文档开发 | `examples\sites\demos\pc\app\**` | `./docs.skill.md` | 每一个组件的api和demo的开发 |
|
||||
| 模块名称 | 代码目录 | 参考规范 | 说明 |
|
||||
| --------------- | ----------------------------------------------------------------------------- | -------------------------- | -------------------------------------------- |
|
||||
| 模板层 | `packages/vue` | `./vue.skill.md` | 每个组件的模板,必须在相应的组件目录 |
|
||||
| 无渲染逻辑层 | `packages/renderless` | `./renderless.skill.md` | 每个组件的逻辑,必须在相应的组件目录 |
|
||||
| 样式层 | `packages/theme` | `./theme.skill.md` | 每个组件的样式,必须在相应的组件目录 |
|
||||
| 设计规范层 | `packages/design` | `./design.skill.md` | 交互规范、默认 props、图标与 renderless 扩展 |
|
||||
| 适配Vue2/Vue3层 | `packages/vue-common` | `./common.skill.md` | 非必要不修改适配层代码 |
|
||||
| 图标库 | `packages/vue-icon` | `./icon.skill.md` | 图标库 |
|
||||
| 国际化层 | `packages/vue-locale` | `./i18n-workflow.skill.md` | 组件的国际化 |
|
||||
| 公用hooks | `packages/vue-hooks` | `./hooks.skill.md` | 跨组件可以复用的hooks函数 |
|
||||
| 公用指令 | `packages/vue-directive` | `./directive.skill.md` | 跨组件可以复用的指令 |
|
||||
| utils | `packages/utils` | `./utils.skill.md` | 公用函数 |
|
||||
| 组件测试 | `examples/sites/demos/pc/app/**/*.spec.ts` 或 `packages/vue/src/**/__tests__` | `./testing-guide.skill.md` | e2e测试和单元测试 |
|
||||
| 文档开发 | `examples/sites/demos/pc/app/**` | `./vue.skill.md` | 每一个组件的 api 和 demo 的开发 |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,186 @@
|
|||
# @opentiny/vue-common 适配层开发规范
|
||||
|
||||
## 适用场景
|
||||
|
||||
- 理解 TinyVue 如何同时支持 Vue 2.6 / 2.7 / Vue 3
|
||||
- 编写或调试组件 `setup`、`$setup`、跨端模板选择
|
||||
- 使用 `defineComponent`、`hooks`、`directive`、`svg`、`mergeClass` 等适配 API
|
||||
- 排查「仅在某一 Vue 版本下复现」的问题
|
||||
|
||||
## 核心原则
|
||||
|
||||
### 1. 包定位
|
||||
|
||||
`packages/vue-common` 发布为 `@opentiny/vue-common`,是整个组件库的 **Vue 版本适配与运行时胶水层**:
|
||||
|
||||
- 通过 `virtual:common/adapter/vue` 在构建时指向 `adapter/vue2` | `vue2.7` | `vue3`
|
||||
- 向 renderless 提供统一的 `hooks` 对象(即对应 Vue 版本的 API)
|
||||
- 提供 `$setup` / `setup`,连接模板与 renderless
|
||||
- 提供主题/模式解析、设计规范注入、图标 `svg` 包装等
|
||||
|
||||
**修改约束**:表结构变更、新 Vue 版本支持需充分评估;日常组件开发**优先改 renderless / vue 模板**,避免随意改动适配层行为。`SKILL.md` 中亦提示:非必要不修改适配层。
|
||||
|
||||
### 2. 目录结构
|
||||
|
||||
```text
|
||||
packages/vue-common/src/
|
||||
├── index.ts # 对外主入口:$setup、setup、$prefix、svg 等
|
||||
├── adapter/
|
||||
│ ├── index.ts # 导出当前 Vue 版本 adapter
|
||||
│ ├── vue2/
|
||||
│ ├── vue2.7/
|
||||
│ └── vue3/
|
||||
├── breakpoint.ts # useBreakpoint 响应式断点
|
||||
├── csscls.ts # 类名序列化、去重
|
||||
├── usedefer.ts # useDefer
|
||||
└── generateIcon.ts # 渐变图标 id 处理
|
||||
```
|
||||
|
||||
### 3. 组件开发中最常用的 API
|
||||
|
||||
| API | 用途 |
|
||||
| ---------------------------------- | ----------------------------------------------------------------- |
|
||||
| `$prefix` | 组件名前缀 `'Tiny'`,如 `TinyButton` |
|
||||
| `$props` / `props` | 框架保留 prop:`tiny_mode`、`tiny_renderless`、`tiny_template` 等 |
|
||||
| `defineComponent` | 定义组件(跨版本) |
|
||||
| `$setup` | 跨端父组件:根据 `tiny_mode` 选择 `pc` / `mobile-first` 模板 |
|
||||
| `setup` | 子模板中连接 renderless,返回模板绑定对象 |
|
||||
| `hooks` | 当前 Vue 版本的 API 集合,可传给 renderless 第二参数 |
|
||||
| `isVue2` / `isVue3` | 版本判断(renderless 中应尽量避免,优先用 utils/vm) |
|
||||
| `directive` | 统一 Vue2/3 指令钩子名 |
|
||||
| `svg` | 包装 `@opentiny/vue-theme` 的 svg 为图标组件 |
|
||||
| `mergeClass` | mobile-first 下合并 Tailwind 类名 |
|
||||
| `filterAttrs`(模板中 `a`) | 过滤 `$attrs` 绑定 |
|
||||
| `Teleport` / `KeepAlive` | 须从此包导入以保证兼容 |
|
||||
| `useBreakpoint` / `useDefer` | 布局与渲染优化 |
|
||||
| `useInstanceSlots` / `useRelation` | 已注入 `isVue2` 的 hooks 封装 |
|
||||
|
||||
### 4. 双层组件:$setup + 子模板 setup
|
||||
|
||||
**跨端组件**(`pc.vue` + `mobile-first.vue`):
|
||||
|
||||
```typescript
|
||||
// packages/vue/src/alert/src/index.ts
|
||||
import { $props, $prefix, $setup, defineComponent } from '@opentiny/vue-common'
|
||||
import template from 'virtual-template?pc|mobile-first'
|
||||
|
||||
export default defineComponent({
|
||||
name: $prefix + 'Alert',
|
||||
props: alertProps,
|
||||
setup(props, context) {
|
||||
return $setup({ props, context, template })
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
`$setup` 会:
|
||||
|
||||
1. `resolveMode` 解析 `tiny_mode`(`pc` | `mobile` | `mobile-first`)
|
||||
2. 通过 `virtual-template` 插件加载对应模板
|
||||
3. `renderComponent` 渲染子组件,并合并设计规范 `designConfig` 中的默认 props
|
||||
|
||||
**具体模板**(`pc.vue`):
|
||||
|
||||
```typescript
|
||||
import { setup, defineComponent, props } from '@opentiny/vue-common'
|
||||
import { renderless, api } from '@opentiny/vue-renderless/alert/vue'
|
||||
import type { IAlertApi } from '@opentiny/vue-renderless/types/alert.type'
|
||||
|
||||
export default defineComponent({
|
||||
props: [...props, 'type', 'size' /* 其它组件 props */],
|
||||
setup(props, context) {
|
||||
return setup({ props, context, renderless, api }) as unknown as IAlertApi
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 5. setup 与 renderless 的协作
|
||||
|
||||
`setup` 内部流程概要:
|
||||
|
||||
1. 选择 `props.tiny_renderless` 或入参 `renderless`
|
||||
2. 构造 `utils`(含 `vm`、`emit`、`t`、`designConfig`、`mode`、`mergeClass` 等)
|
||||
3. 调用 `render(props, hooks, utils, extendOptions)` 得到 `sdk`
|
||||
4. 按 `api` 数组将 `sdk` 上的方法/状态暴露给模板(`attrs`)
|
||||
5. 双层组件默认 `mono: false`,将 api 同步到父组件 ref;单层组件传 `mono: true`
|
||||
|
||||
模板中常用简写:
|
||||
|
||||
- `t('ui.xxx')` — 国际化
|
||||
- `a($attrs, filters, include)` — `filterAttrs`
|
||||
- `m(...)` — `mergeClass`
|
||||
- `f` / `d` / `dp` — 过滤器与实例属性定义(见 renderless.skill.md)
|
||||
|
||||
### 6. 模式与主题解析
|
||||
|
||||
- **模式** `resolveMode`:`tiny_mode` prop > inject `TinyMode` > 全局 config > 默认 `'pc'`
|
||||
- **主题** `resolveTheme`:`'tiny'` | `'saas'`
|
||||
- 根组件可设 `tiny_mode_root` 以 `provide('TinyMode', mode)`
|
||||
|
||||
函数式组件(Modal、Loading、Notify)依赖全局 `tiny_mode`,需在应用级配置。
|
||||
|
||||
### 7. 设计规范 designConfig
|
||||
|
||||
适配层负责注入与合并 `designConfig`,详细约定见 [design.skill.md](./design.skill.md)。
|
||||
|
||||
```typescript
|
||||
import { provideDesignConfig } from '@opentiny/vue-common'
|
||||
|
||||
provideDesignConfig({
|
||||
components: {
|
||||
Button: { props: { round: true }, api: [], renderless: fn }
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
`setup` 会合并 `designConfig.renderless` 与组件级 props 默认值。
|
||||
|
||||
### 8. 图标 svg 工厂
|
||||
|
||||
```typescript
|
||||
import { svg } from '@opentiny/vue-common'
|
||||
import IconX from '@opentiny/vue-theme/svgs/icon-x.svg'
|
||||
|
||||
export default () => svg({ name: 'IconX', component: IconX, filledComponent: IconX })()
|
||||
```
|
||||
|
||||
详见 [icon.skill.md](./icon.skill.md)。
|
||||
|
||||
### 9. 版本判断与 hooks 使用
|
||||
|
||||
```typescript
|
||||
// ❌ renderless 中
|
||||
if (process.env.VUE_VERSION === '3') { ... }
|
||||
|
||||
// ✅ 模板/极少数适配代码
|
||||
import { isVue2, hooks } from '@opentiny/vue-common'
|
||||
|
||||
// ✅ renderless 接收第二参数
|
||||
export const renderless = (props, { computed, reactive, watch }, utils) => { ... }
|
||||
```
|
||||
|
||||
### 10. 禁止事项
|
||||
|
||||
- ❌ 组件模板中不要 `import from 'vue'`(使用 `@opentiny/vue-common` 的 `defineComponent`、`hooks`、`Teleport` 等)
|
||||
- ❌ renderless 中不要依赖适配层实现细节(仅使用文档化的 `utils` / `vm` 字段)
|
||||
- ❌ 不要随意修改 `adapter/` 下生命周期映射逻辑
|
||||
- ❌ 不要在 `.vue` 中写复杂业务逻辑,应下沉 renderless
|
||||
|
||||
## 与其它规范的关系
|
||||
|
||||
| 模块 | 规范文件 |
|
||||
| ---------- | -------------------------------------------- |
|
||||
| 模板层 | [vue.skill.md](./vue.skill.md) |
|
||||
| 逻辑层 | [renderless.skill.md](./renderless.skill.md) |
|
||||
| 样式 | [theme.skill.md](./theme.skill.md) |
|
||||
| 设计规范 | [design.skill.md](./design.skill.md) |
|
||||
| 工具函数 | [utils.skill.md](./utils.skill.md) |
|
||||
| 组合式逻辑 | [hooks.skill.md](./hooks.skill.md) |
|
||||
| 指令 | [directive.skill.md](./directive.skill.md) |
|
||||
|
||||
## 参考资源
|
||||
|
||||
- [主入口 setup / $setup](../../packages/vue-common/src/index.ts)
|
||||
- [Vue3 适配器](../../packages/vue-common/src/adapter/vue3/index.ts)
|
||||
- [Alert 跨端入口](../../packages/vue/src/alert/src/index.ts)
|
||||
- [Alert pc 模板 setup](../../packages/vue/src/alert/src/pc.vue)
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
# TinyVue 设计规范(Design)开发指南
|
||||
|
||||
## 适用场景
|
||||
|
||||
- 为 Aurora / SaaS / 企业自定义规范配置组件默认行为
|
||||
- 通过 `design` 覆盖图标、默认 props、renderless 扩展逻辑
|
||||
- 使用 `TinyConfigProvider` 在应用级注入交互规范
|
||||
- 在 renderless 中读取 `designConfig` 实现规范差异
|
||||
|
||||
## 与 Theme 的区别
|
||||
|
||||
| 维度 | Design(本规范) | Theme(见 [theme.skill.md](./theme.skill.md)) |
|
||||
| ---------- | -------------------------------------------- | ---------------------------------------------- |
|
||||
| 职责 | 交互行为、默认 props、图标、renderless 扩展 | 视觉样式、CSS 变量、Less |
|
||||
| 代码位置 | `packages/design/*`、`designConfig` | `packages/theme`、`packages/theme-saas` |
|
||||
| 注入方式 | `TinyConfigProvider` / `provideDesignConfig` | 引入 Less、`theme` prop、ThemeTool |
|
||||
| 运行时对象 | `utils.designConfig`(renderless 第三参数) | `tiny_theme`、`--tv-*` CSS 变量 |
|
||||
|
||||
二者可组合使用:SaaS 场景常见 `tiny_theme="saas"` + `@opentiny/vue-design-saas`。
|
||||
|
||||
## 架构概览
|
||||
|
||||
```text
|
||||
packages/design/
|
||||
├── aurora/ # Aurora 规范(@opentiny/vue-design-aurora)
|
||||
│ ├── index.ts # 导出 { name, version, components }
|
||||
│ └── src/<Component>/index.ts
|
||||
├── saas/ # SaaS 规范(@opentiny/vue-design-saas)
|
||||
│ └── src/<Component>/index.ts
|
||||
└── smb/ # SMB 示例规范(文档 demo 用)
|
||||
|
||||
packages/vue/src/config-provider/ # TinyConfigProvider
|
||||
packages/vue-common/src/index.ts # provideDesignConfig、getDesignConfig、setup 合并逻辑
|
||||
packages/vue-saas-common/ # 预置 customDesignConfig.designConfig = designSaasConfig
|
||||
```
|
||||
|
||||
全局配置结构(`DesignConfig`):
|
||||
|
||||
```typescript
|
||||
{
|
||||
name?: string // 规范名称,如 'saas'
|
||||
version?: string // 规范版本
|
||||
components?: {
|
||||
[ComponentName: string]: IComponentDesignConfig // 键名不含 Tiny 前缀,如 Button、Select、Alert
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
单组件配置(内部类型 `IComponentDesignConfig`,定义于 `packages/renderless/types/shared.type.ts`,未对外 export)常用字段:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| ------------ | ---------------------------------------------------------------------------------------- |
|
||||
| `props` | 默认 props;用户未传时才覆盖(仅在跨端父组件 **`$setup`** 中合并到 `customDesignProps`) |
|
||||
| `icons` | 图标映射,如 `{ warning: iconWarning() }` |
|
||||
| `state` | 规范级状态默认值,renderless 内通过 `designConfig.state` 读取 |
|
||||
| `renderless` | 扩展函数,在组件 renderless 执行后合并进 `sdk` |
|
||||
| `api` | 扩展暴露给模板的 api 名称列表(与组件 `api` 数组合并) |
|
||||
| 其它 | 组件自定义字段,如 `baseOpts`、`messageType`、`showText` 等 |
|
||||
|
||||
## 应用侧使用
|
||||
|
||||
### 1. ConfigProvider(推荐)
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<tiny-config-provider :design="design">
|
||||
<tiny-alert type="warning" />
|
||||
<tiny-button>按钮</tiny-button>
|
||||
</tiny-config-provider>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { TinyConfigProvider, TinyAlert, TinyButton } from '@opentiny/vue'
|
||||
import { iconWarningTriangle } from '@opentiny/vue-icon'
|
||||
|
||||
const design = {
|
||||
name: 'x-design',
|
||||
version: '1.0.0',
|
||||
components: {
|
||||
Alert: {
|
||||
icons: { warning: iconWarningTriangle() },
|
||||
props: { center: true },
|
||||
renderless: (props, hooks, utils, api) => ({
|
||||
handleClose() {
|
||||
api.state.show = false
|
||||
utils.emit('close')
|
||||
}
|
||||
})
|
||||
},
|
||||
Button: {
|
||||
props: { round: true, resetTime: 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
`TinyConfigProvider` 内部调用 `provideDesignConfig(design)`,子树组件通过 `inject` 获取。
|
||||
|
||||
### 2. 内置规范包(SaaS / Aurora)
|
||||
|
||||
SaaS 工程使用 `@opentiny/vue-saas-common` 时已注入:
|
||||
|
||||
```typescript
|
||||
// packages/vue-saas-common/src/index.ts
|
||||
import { customDesignConfig } from '@opentiny/vue-common'
|
||||
import designSaasConfig from '@opentiny/vue-design-saas'
|
||||
|
||||
customDesignConfig.designConfig = designSaasConfig
|
||||
```
|
||||
|
||||
Aurora 对应 `@opentiny/vue-design-aurora`,在应用入口赋值 `customDesignConfig.designConfig`(写法同 SaaS)。
|
||||
|
||||
> **注意**:`@opentiny/vue-saas-common` 启动时已写入 `customDesignConfig.designConfig`,会**优先于**子树 `TinyConfigProvider` 的 `inject` 配置。应用级临时覆盖需改 `customDesignConfig`,或勿使用 `vue-saas-common` 的全局注入。普通 `@opentiny/vue` 场景下 `customDesignConfig.designConfig` 默认为 `null`,以 `ConfigProvider` 的 `provide` 为准。
|
||||
|
||||
### 3. 编程式注入
|
||||
|
||||
须在组件 `setup` 中调用(需 Vue 上下文):
|
||||
|
||||
```typescript
|
||||
import { provideDesignConfig } from '@opentiny/vue-common'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
provideDesignConfig({
|
||||
components: {
|
||||
Form: { props: { hideRequiredAsterisk: true } }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`TinyConfigProvider` 传入的 `design` 为响应式 ref,`getDesignConfig` 会通过 `.value` 解包后读取。
|
||||
|
||||
## 运行时解析流程
|
||||
|
||||
1. `getDesignConfig()`:**优先** `customDesignConfig.designConfig`,否则 `inject(design.configKey, {})`;若结果为 ref/computed 则取 `.value`
|
||||
2. 按当前组件名去掉 `Tiny` 前缀(`getComponentName().replace('Tiny', '')`),取 `globalDesignConfig.components[ComponentName]`
|
||||
3. **`$setup`**:合并 `designConfig.props` 为默认 props(不覆盖用户已传属性)
|
||||
4. **`setup`**:
|
||||
- 将 `designConfig`、`globalDesignConfig` 放入 renderless 第三参数 `utils`
|
||||
- 执行组件 `renderless` 得到 `sdk`
|
||||
- 若存在 `designConfig.renderless`,将其返回值 `Object.assign` 到 `sdk`
|
||||
- 若 `designConfig.api` 存在,与组件 `api` 数组合并后暴露给模板
|
||||
|
||||
组件名映射示例:`TinySelect` → `Select`,`TinyAlert` → `Alert`。
|
||||
|
||||
## 在 renderless 中使用 designConfig
|
||||
|
||||
### 1. 从 utils 解构(推荐)
|
||||
|
||||
```typescript
|
||||
export const renderless = (
|
||||
props: IAlertProps,
|
||||
hooks: ISharedRenderlessParamHooks,
|
||||
{ designConfig, t, emit }: IAlertRenderlessParamUtils
|
||||
): IAlertApi => {
|
||||
// ...
|
||||
}
|
||||
|
||||
// index.ts 纯函数
|
||||
export const computedGetIcon =
|
||||
({ constants, props, designConfig }: Pick<IAlertRenderlessParams, 'constants' | 'props' | 'designConfig'>) =>
|
||||
() => {
|
||||
const designIcon = designConfig?.icons?.[props.type]
|
||||
return props.icon || designIcon || constants.ICON_MAP[props.type]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 读取 state / props 级配置
|
||||
|
||||
```typescript
|
||||
// select/vue.ts 示例
|
||||
autoHideDownIcon: (() => {
|
||||
if (designConfig?.state && 'autoHideDownIcon' in designConfig.state) {
|
||||
return designConfig.state.autoHideDownIcon
|
||||
}
|
||||
return true
|
||||
})(),
|
||||
designConfig // 挂到 state,供模板 state.designConfig?.icons 使用
|
||||
```
|
||||
|
||||
### 3. designConfig.renderless 扩展
|
||||
|
||||
规范包可覆盖或增补 api 方法,**不得**破坏原有 `api.state` 引用:
|
||||
|
||||
```typescript
|
||||
// packages/design/saas/src/select/index.ts
|
||||
// 签名:(props, hooks, utils, sdk) => Partial<api>
|
||||
renderless: (props, hooks, utils, api) => {
|
||||
const state = api.state
|
||||
return {
|
||||
toggleCheckAll: (filtered) => {
|
||||
/* 规范定制逻辑 */
|
||||
},
|
||||
computedShowTagText: () => state.isDisabled || state.isDisplayOnly
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
适配层实际调用:`Object.assign(sdk, designConfig.renderless(props, hooks, utils, sdk))`,第三参为完整 `utils`(含 `emit`、`designConfig`、`vm` 等),第四参为组件 renderless 已返回的 `sdk`。
|
||||
|
||||
## 新增 / 修改设计规范
|
||||
|
||||
### 在 packages/design 中增加组件配置
|
||||
|
||||
1. 在 `packages/design/saas/src/<component>/index.ts`(或 `aurora`)新增默认导出对象
|
||||
2. 在对应 `index.ts` 的 `components` 中注册(键名与组件名一致,PascalCase,无 `Tiny` 前缀)
|
||||
3. 图标优先使用对应主题的 icon 包(SaaS 用 `@opentiny/vue-icon-saas`)
|
||||
4. 在 renderless 中增加对 `designConfig` 的可选读取,并提供合理默认值(无 design 时行为不变)
|
||||
|
||||
示例(SaaS Alert 仅换图标):
|
||||
|
||||
```typescript
|
||||
// packages/design/saas/src/alert/index.ts
|
||||
import { iconWarning } from '@opentiny/vue-icon-saas'
|
||||
|
||||
export default {
|
||||
icons: {
|
||||
warning: iconWarning()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 在组件 renderless 中支持新 design 字段
|
||||
|
||||
1. 在 `index.ts` 纯函数中增加 `designConfig` 参数类型(`Pick<..., 'designConfig'>`)
|
||||
2. 使用可选链与 `in` 判断,避免假设 design 一定存在
|
||||
3. 模板需访问时,将 `designConfig` 挂到 `state`(参考 Select)
|
||||
|
||||
## mobile-first 与 twMerge
|
||||
|
||||
SaaS 多端模式依赖 `customDesignConfig.twMerge`(通常 `tailwind-merge`):
|
||||
|
||||
```typescript
|
||||
import { customDesignConfig } from '@opentiny/vue-common'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
customDesignConfig.twMerge = twMerge
|
||||
```
|
||||
|
||||
`mergeClass`(模板中的 `m(...)`)会经此函数合并 Tailwind 类名。
|
||||
|
||||
## 禁止事项
|
||||
|
||||
- ❌ 不要用 design 配置颜色/尺寸等纯样式(应走 theme / CSS 变量)
|
||||
- ❌ 不要在 design 的 `components` 键名中带 `Tiny` 前缀
|
||||
- ❌ 不要在 `designConfig.renderless` 中替换整个 `api` 或 `state` 对象
|
||||
- ❌ 不要在 renderless 中 `import` 规范包;规范由应用或 `vue-saas-common` 注入
|
||||
- ❌ 不要假设 `designConfig` 一定存在,必须提供默认行为
|
||||
|
||||
## 参考资源
|
||||
|
||||
- [ConfigProvider 组件](../../packages/vue/src/config-provider/src/index.vue)
|
||||
- [适配层 design 逻辑](../../packages/vue-common/src/index.ts)
|
||||
- [类型定义](../../packages/renderless/types/shared.type.ts)
|
||||
- [SaaS Select 规范示例](../../packages/design/saas/src/select/index.ts)
|
||||
- [文档 demo](../../examples/sites/demos/pc/app/config-provider/base-composition-api.vue)
|
||||
- [主题规范](./theme.skill.md)
|
||||
- [适配层规范](./common.skill.md)
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
# @opentiny/vue-directive 开发规范
|
||||
|
||||
## 适用场景
|
||||
|
||||
- 模板层需要声明式 DOM 行为(点击外部关闭、无限滚动、文本高亮、自动 Tooltip 等)
|
||||
- 逻辑与具体组件解耦,可在多个 `pc.vue` / `mobile-first.vue` 中复用
|
||||
- 不适合放入 renderless 的、强依赖 DOM 或全局监听的交互
|
||||
|
||||
## 核心原则
|
||||
|
||||
### 1. 包定位
|
||||
|
||||
`packages/vue-directive` 发布为 `@opentiny/vue-directive`。
|
||||
|
||||
- 指令实现放在 `src/<directive-name>.ts`
|
||||
- 在 `index.ts` 统一导出
|
||||
- 可依赖 `@opentiny/utils`、`@opentiny/vue-common`(如 `auto-tip` 使用 Tooltip 与 `hooks`)
|
||||
- **业务逻辑仍应优先下沉 renderless**;指令只负责 DOM 绑定与事件桥接
|
||||
|
||||
### 2. 内置指令一览
|
||||
|
||||
| 导出 | 指令名 | 说明 |
|
||||
| ------------------- | ---------------------- | ----------------------------------------------------------- |
|
||||
| `Clickoutside` | `v-clickoutside` | 点击元素外部触发回调,支持 `.mousedown` / `.mouseup` 修饰符 |
|
||||
| `AutoTip` | `v-auto-tip` | 文本溢出时自动展示 Tooltip |
|
||||
| `InfiniteScroll` | `v-infinite-scroll` | 滚动到底加载更多 |
|
||||
| `HighlightQuery` | `v-highlight-query` | 高亮匹配关键字 |
|
||||
| `ObserveVisibility` | `v-observe-visibility` | 元素可见性监听 |
|
||||
| `RepeatClick` | `v-repeat-click` | 长按/重复点击 |
|
||||
|
||||
文档示例:[自定义指令](https://opentiny.design/tiny-vue/zh-CN/smb-theme/components/directives-auto-tip)
|
||||
|
||||
### 3. 在组件模板中注册(必须)
|
||||
|
||||
指令在 **vue 模板层** 注册,不在 renderless 中注册。
|
||||
|
||||
**Vue 3 写法**(推荐通过 `directive` 适配函数兼容 Vue 2 生命周期名):
|
||||
|
||||
```vue
|
||||
<script lang="ts">
|
||||
import { setup, directive, defineComponent } from '@opentiny/vue-common'
|
||||
import { Clickoutside, AutoTip } from '@opentiny/vue-directive'
|
||||
|
||||
export default defineComponent({
|
||||
directives: directive({ Clickoutside, AutoTip }),
|
||||
setup(props, context) {
|
||||
return setup({ props, context, renderless, api })
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-clickoutside="handleClose" v-auto-tip>...</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
**仅含 Vue 2 钩子(`bind`/`inserted`/`unbind`)的指令**,应通过 `directive({ ... })` 包装。部分指令(如 `ObserveVisibility`、`HighlightQuery`)已在实现内同时声明 Vue 2 / Vue 3 钩子,可直接注册:`directives: { ObserveVisibility }`。
|
||||
|
||||
`directive` 辅助函数位于适配层,用于统一 Vue 2 / Vue 3 指令钩子名:
|
||||
|
||||
```typescript
|
||||
// packages/vue-common/src/adapter/vue3/index.ts
|
||||
mapping(content, 'bind', 'beforeMount')
|
||||
mapping(content, 'inserted', 'mounted')
|
||||
mapping(content, 'update', 'updated')
|
||||
mapping(content, 'unbind', 'unmounted')
|
||||
```
|
||||
|
||||
### 4. 指令实现规范
|
||||
|
||||
#### 指令钩子写法
|
||||
|
||||
**推荐(新指令)**:实现 `bind` / `update` / `unbind`,由 `directive()` 映射为 Vue 3 的 `beforeMount` / `updated` / `unmounted`:
|
||||
|
||||
**特例 `RepeatClick`**:导出为函数而非对象,需手动包装:
|
||||
|
||||
```typescript
|
||||
import { RepeatClick } from '@opentiny/vue-directive'
|
||||
|
||||
directives: {
|
||||
repeatClick: {
|
||||
bind: RepeatClick
|
||||
} // 模板中使用 v-repeat-click
|
||||
}
|
||||
```
|
||||
|
||||
**特例 `HighlightQuery` / `ObserveVisibility`**:实现内已同时声明 Vue 2 / Vue 3 钩子,可直接 `directives: { HighlightQuery }`,无需再经 `directive()` 转换。
|
||||
|
||||
新指令推荐模板:
|
||||
|
||||
```typescript
|
||||
import { on, isServer } from '@opentiny/utils'
|
||||
|
||||
export default {
|
||||
bind(el, binding, vnode) {
|
||||
// 初始化
|
||||
},
|
||||
update(el, binding, vnode) {
|
||||
// 更新 binding
|
||||
},
|
||||
unbind(el) {
|
||||
// 清理监听、移除 DOM 副作用
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 全局监听
|
||||
|
||||
若需 `document` 级监听(如 `Clickoutside`),在模块顶层用 `isServer` 守卫,维护共享 `nodeList`,在 `unbind` 中务必移除引用,防止泄漏。
|
||||
|
||||
#### Shadow DOM
|
||||
|
||||
点击外部判断需使用 `event.composedPath()`,参考 `clickoutside.ts`。
|
||||
|
||||
### 5. 典型用法示例
|
||||
|
||||
**Clickoutside**
|
||||
|
||||
```html
|
||||
<!-- 默认:外部按下并松开才触发 -->
|
||||
<div v-clickoutside="handleClose"></div>
|
||||
<!-- 修饰符 -->
|
||||
<div v-clickoutside.mousedown="handleClose"></div>
|
||||
<div v-clickoutside.mouseup="handleClose"></div>
|
||||
```
|
||||
|
||||
**AutoTip**
|
||||
|
||||
```html
|
||||
<div v-auto-tip>长文本...</div>
|
||||
<div v-auto-tip="{ content: '自定义', placement: 'top', effect: 'dark' }"></div>
|
||||
```
|
||||
|
||||
绑定值为 `false` / 空时禁用。模板内文字节点需用标签包裹,且避免指令节点直接包含裸文本节点(详见 `highlight-query.ts` 注释)。
|
||||
|
||||
**InfiniteScroll**
|
||||
|
||||
```html
|
||||
<div v-infinite-scroll="loadMore" :infinite-scroll-disabled="loading"></div>
|
||||
```
|
||||
|
||||
### 6. 新增指令流程
|
||||
|
||||
1. 在 `packages/vue-directive/src/` 新增实现,默认导出指令对象
|
||||
2. 在 `packages/vue-directive/index.ts` 具名导出
|
||||
3. 在使用的 `pc.vue` / `mobile-first.vue` 中 `import` 并通过 `directives: directive({ ... })` 注册
|
||||
4. 优先使用 `@opentiny/utils` 的 `on`/`off`、`throttle`、`getScrollContainer` 等
|
||||
5. 若需组件方法,通过 `binding.expression` 或 `binding.value` 与 `vnode.context` 通信(Vue 3 项目注意与 `setup` 返回方法的兼容方式,保持与现有指令一致)
|
||||
6. 在 `examples/sites/demos` 补充演示(若对用户可见)
|
||||
|
||||
### 7. 禁止事项
|
||||
|
||||
- ❌ 不得在 renderless 的 `index.ts` 中注册或使用 `v-*` 指令
|
||||
- ❌ 不得在指令中编写组件级业务状态机(应通过 binding 调用 renderless 暴露的方法)
|
||||
- ❌ 不得跳过 `unbind` 清理
|
||||
- ❌ 新增指令时避免直接 `import from 'vue'`,DOM 工具走 `@opentiny/utils`,组件/渲染走 `@opentiny/vue-common`
|
||||
|
||||
## 参考资源
|
||||
|
||||
- [Clickoutside](../../packages/vue-directive/src/clickoutside.ts)
|
||||
- [AutoTip](../../packages/vue-directive/src/auto-tip.ts)
|
||||
- [select pc 模板注册示例](../../packages/vue/src/select/src/pc.vue)
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
# @opentiny/vue-hooks 开发规范
|
||||
|
||||
## 适用场景
|
||||
|
||||
- 多个组件共享的组合式逻辑(Popper、弹层、父子关系、窗口尺寸等)
|
||||
- renderless 的 `vue.ts` 中需要 DOM/生命周期相关能力,但逻辑仍希望可测试、可复用
|
||||
- 不宜放入 `@opentiny/utils` 的、需要 Vue 生命周期或响应式 API 的逻辑
|
||||
|
||||
## 核心原则
|
||||
|
||||
### 1. 包定位
|
||||
|
||||
`packages/vue-hooks` 发布为 `@opentiny/vue-hooks`。
|
||||
|
||||
- **可以**依赖 `@opentiny/utils`
|
||||
- **不得**直接 `import from 'vue'`——Vue API 由调用方从 `hooks` 解构后传入(柯里化或直接传参,见下文)
|
||||
- renderless 与 vue-common 通过 renderless 第二参数或合并后的 `hooks` 对象实例化
|
||||
|
||||
### 2. 现有 Hooks 一览
|
||||
|
||||
| 导出 | 文件 | 用途 |
|
||||
| ------------------ | --------------------- | -------------------------------------------- |
|
||||
| `useEventListener` | `useEventListener.ts` | 绑定/自动清理 DOM 事件,支持 target 为 ref |
|
||||
| `useWindowSize` | `useWindowSize.ts` | 窗口宽高响应式 |
|
||||
| `useRect` | `useRect.ts` | 元素尺寸与位置 |
|
||||
| `useTouch` | `useTouch.ts` | 触摸手势 |
|
||||
| `useUserAgent` | `useUserAgent.ts` | UA / 浏览器能力判断 |
|
||||
| `useInstanceSlots` | `useInstanceSlots.ts` | 插槽访问(vue-common 已预绑定 `isVue2`) |
|
||||
| `useRelation` | `useRelation.ts` | 父子组件关系树(Tabs、Form 等) |
|
||||
| `useFloating` | `use-floating.ts` | 浮层定位 |
|
||||
| `useLazyShow` | `use-lazy-show.ts` | 延迟展示 |
|
||||
| `userPopper` | `vue-popper.ts` | Popper 弹层(注意导出名拼写为 `userPopper`) |
|
||||
| `usePopup` | `vue-popup.ts` | Popup 弹层管理 |
|
||||
|
||||
### 3. 两种调用形态
|
||||
|
||||
#### 形态 A:柯里化(多数 hooks)
|
||||
|
||||
第一个参数为 Vue 运行时 API 集合,返回可在 renderless 中调用的函数。适用于 `useEventListener`、`useRelation`、`useRect` 等。
|
||||
|
||||
```typescript
|
||||
// packages/vue-hooks/src/useEventListener.ts
|
||||
import { on, off, isServer } from '@opentiny/utils'
|
||||
|
||||
export const useEventListener =
|
||||
({ unref, isRef, watch, nextTick, onMounted, onUnmounted, onActivated, onDeactivated }) =>
|
||||
(type, listener, options = {}) => {
|
||||
if (isServer) return
|
||||
// ... 实现
|
||||
}
|
||||
```
|
||||
|
||||
在 renderless 的 `vue.ts` 中使用:
|
||||
|
||||
```typescript
|
||||
import { useEventListener } from '@opentiny/vue-hooks'
|
||||
|
||||
export const renderless = (props, hooks, utils) => {
|
||||
const addListener = useEventListener(hooks)
|
||||
addListener('scroll', onScroll, { target: scrollRef })
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
在 vue-common 中预绑定 Vue2 差异的示例:
|
||||
|
||||
```typescript
|
||||
import { useRelation as createUseRelation } from '@opentiny/vue-hooks'
|
||||
import hooks from './adapter'
|
||||
|
||||
export const useRelation = createUseRelation({ ...hooks, isVue2 })
|
||||
```
|
||||
|
||||
#### 形态 B:直接工厂(`userPopper`、`usePopup`)
|
||||
|
||||
接收合并了 Vue API 与业务上下文的对象,**不是**柯里化:
|
||||
|
||||
```typescript
|
||||
import { userPopper } from '@opentiny/vue-hooks'
|
||||
|
||||
export const renderless = (
|
||||
props,
|
||||
{ watch, reactive, onBeforeUnmount, onDeactivated, nextTick, toRefs },
|
||||
{ vm, slots, emit }
|
||||
) => {
|
||||
const popper = userPopper({
|
||||
emit,
|
||||
nextTick,
|
||||
onBeforeUnmount,
|
||||
onDeactivated,
|
||||
props,
|
||||
reactive,
|
||||
vm,
|
||||
slots,
|
||||
toRefs,
|
||||
watch
|
||||
})
|
||||
const state = initState({ reactive, popper })
|
||||
// 返回 updatePopper、destroyPopper、doDestroy 及 popper 相关 state 字段
|
||||
}
|
||||
```
|
||||
|
||||
`usePopup` 用法见 `dialog-box/vue.ts`,返回 `{ open, close, PopupManager, ...toRefs(state) }`。
|
||||
|
||||
### 4. useRelation 使用要点
|
||||
|
||||
用于「父收集子、子注册到父」的场景。典型写法(参考 `tabs-mf/vue.ts`):
|
||||
|
||||
```typescript
|
||||
import { useRelation } from '@opentiny/vue-hooks'
|
||||
|
||||
Object.assign(api, { useRelation: useRelation(hooks) })
|
||||
|
||||
api.useRelation({
|
||||
relationKey: `tabs-${state.tabsId}`,
|
||||
relationContainer: () => vm.$el.querySelector('[data-tag=tiny-tabs-hidden]'),
|
||||
childrenKey: 'childTabs',
|
||||
onChange: () => api.onRelationChange()
|
||||
})
|
||||
// 返回 { children, index, delivery }
|
||||
```
|
||||
|
||||
- `relationKey` 必须在父子树中一致
|
||||
- 子组件通过 inject 注册,在 `onUnmounted` 时自动 `unlink`
|
||||
- 也可从 `@opentiny/vue-common` 导入已绑定 `isVue2` 的 `useRelation`
|
||||
|
||||
### 5. userPopper / usePopup
|
||||
|
||||
Popper、Dialog、Select 等浮层在 renderless `vue.ts` 中按**形态 B**调用,将 `popper` / `usePopup` 传入 `initState` 或 `initApi`,勿 `Object.assign` 到整个 `api`。
|
||||
|
||||
内部依赖 `@opentiny/utils` 的 `PopupManager`、`PopperJS`、`on`/`off` 等,勿在 renderless 重复实现定位逻辑。
|
||||
|
||||
### 6. 新增 Hook 流程
|
||||
|
||||
1. 在 `packages/vue-hooks/src/` 新建实现文件
|
||||
2. 在 `packages/vue-hooks/index.ts` 导出
|
||||
3. 仅使用 `@opentiny/utils` 处理 DOM/工具,Vue API 一律从参数解构
|
||||
4. 在 renderless 或 vue-common 中接入并补充类型(`packages/vue-hooks/types/shared.type.ts` 若需扩展)
|
||||
5. 避免与 utils 中「待改造成 hooks」的模块重复(如 `touch`)
|
||||
|
||||
### 7. 禁止事项
|
||||
|
||||
- ❌ 不得在 vue-hooks 中 `import { ref } from 'vue'`
|
||||
- ❌ 不得在 hook 内写组件模板或 JSX
|
||||
- ❌ 不得被 `packages/utils` 反向依赖
|
||||
- ❌ renderless 的 `index.ts` 纯函数文件中不宜直接调用 vue-hooks(应在 `vue.ts` 中组装)
|
||||
|
||||
## 参考资源
|
||||
|
||||
- [入口导出](../../packages/vue-hooks/index.ts)
|
||||
- [useEventListener](../../packages/vue-hooks/src/useEventListener.ts)
|
||||
- [useRelation](../../packages/vue-hooks/src/useRelation.ts)
|
||||
- [sticky 组件中的组合使用](../../packages/renderless/src/sticky/vue.ts)
|
||||
- [tabs-mf 中 useRelation](../../packages/renderless/src/tabs-mf/vue.ts)
|
||||
- [select-dropdown 中 userPopper](../../packages/renderless/src/select-dropdown/vue.ts)
|
||||
|
|
@ -240,7 +240,7 @@ TypeScript 类型安全的开发规范
|
|||
|
||||
- 优先使用 TypeScript
|
||||
- 禁止使用 `any`,需要类型逃逸时加注释说明
|
||||
- 类型定义放在 `packages/vue-common/src/types/` 或组件目录下
|
||||
- 类型定义放在 `packages/renderless/types/` 或组件目录下
|
||||
|
||||
### 开发规范
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,122 @@
|
|||
# @opentiny/utils 开发规范
|
||||
|
||||
## 适用场景
|
||||
|
||||
- 在 renderless 层或 vue-hooks 中编写与框架无关的纯逻辑
|
||||
- 复用日期、字符串、DOM、校验等通用能力
|
||||
- 新增跨组件工具函数
|
||||
|
||||
## 核心原则
|
||||
|
||||
### 1. 包定位
|
||||
|
||||
`packages/utils` 发布为 `@opentiny/utils`,**不依赖 Vue**,可被以下模块引用:
|
||||
|
||||
- `packages/renderless`(无渲染逻辑层,主要消费方)
|
||||
- `packages/vue-hooks`
|
||||
- `packages/vue-directive`
|
||||
- `packages/vue-common`(适配层少量使用)
|
||||
|
||||
renderless 层约定:**除 `@opentiny/utils` 与 `@opentiny/vue-hooks` 外,不得依赖其它第三方包**。
|
||||
|
||||
### 2. 目录结构
|
||||
|
||||
```text
|
||||
packages/utils/src/
|
||||
├── index.ts # 统一导出入口
|
||||
├── array/ # 数组操作
|
||||
├── bigInt/ # 大数/精度计算
|
||||
├── calendar/ # 日历相关
|
||||
├── crypt/ # sha256 等
|
||||
├── date/ # 日期格式化、时区
|
||||
├── date-util/ # 日期工具(与 date 部分能力重叠,待整理)
|
||||
├── debounce/ # 防抖
|
||||
├── throttle/ # 节流
|
||||
├── dom/ # DOM 操作、样式、滚动
|
||||
├── decimal/ # 小数精度
|
||||
├── event/ # 事件派发
|
||||
├── form/ # 表单常量(待迁移至组件内部)
|
||||
├── function/ # noop、callInterceptor
|
||||
├── globalConfig/ # isServer、browserInfo、globalConfig
|
||||
├── logger/ # 日志
|
||||
├── nanoid/ # 唯一 ID
|
||||
├── object/ # 对象拷贝、合并、相等
|
||||
├── string/ # 字符串格式化、驼峰/连字符
|
||||
├── type/ # 类型判断
|
||||
├── validate/ # 校验器 Validator
|
||||
├── xss/ # XSS 过滤
|
||||
├── tree-model/ # 树形数据结构
|
||||
├── popper/ # Popper 定位
|
||||
├── popup-manager/ # 弹层层级管理
|
||||
└── ... # 其它模块见 src/index.ts
|
||||
```
|
||||
|
||||
新增工具时:在对应子目录实现,并在 `src/index.ts` 中导出。
|
||||
|
||||
### 3. 模块编写规范
|
||||
|
||||
1. **纯函数**:不持有组件状态,不 import Vue API
|
||||
2. **SSR 安全**:涉及 `window`/`document` 时,使用 `isServer`(来自 `globalConfig`)做守卫
|
||||
3. **单职责**:一个文件聚焦一类能力,避免在 utils 中写组件专属常量(`common/`、`form/` 中部分常量标注为「待移除」,新代码勿再扩展)
|
||||
4. **测试**:在模块目录下补充 `__tests__` 或 `__test__`,在 `packages/utils` 目录执行 `pnpm test`,或在仓库根目录执行 `pnpm --filter @opentiny/utils test`
|
||||
|
||||
### 4. 常用 API 分类
|
||||
|
||||
| 分类 | 代表导出 | 典型用途 |
|
||||
| --------- | --------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
||||
| 类型判断 | `isObject`, `isFunction`, `isDate`, `typeOf` | 参数校验 |
|
||||
| 字符串 | `camelize`, `hyphenate`, `formatString`, `guid` | 命名转换、展示格式化 |
|
||||
| 日期 | `formatDate`, `toDateStr`, `limitTimeRange`;`calendar` 的 `parseDate`;`date-util` 的 `parseDate1` | 日期/时间组件(注意两套 parse 勿混用) |
|
||||
| 对象/数组 | `extend`, `merge`, `isEqual`, `find`, `unique` | 数据处理 |
|
||||
| DOM | `on`, `off`, `addClass`, `getScrollParent` | 事件与布局 |
|
||||
| 性能 | `debounce`, `throttle`, `fastdom` | 高频回调、布局批处理 |
|
||||
| 安全 | `xss`, `sha256` | 内容过滤、摘要 |
|
||||
| ID | `nanoid`(`nanoid.api.nanoid(size)`) | 无障碍 id、唯一 key |
|
||||
|
||||
### 5. 在 renderless 中的引用方式
|
||||
|
||||
```typescript
|
||||
// ✅ 正确:从 @opentiny/utils 按需导入
|
||||
import { debounce } from '@opentiny/utils'
|
||||
import { nanoid } from '@opentiny/utils'
|
||||
|
||||
// 使用 nanoid
|
||||
const id = `tiny-alert-title-${nanoid.api.nanoid(8)}`
|
||||
|
||||
// ❌ 错误:在 renderless 中 import 'vue'
|
||||
// ❌ 错误:在 utils 中 import '@opentiny/vue-common'
|
||||
```
|
||||
|
||||
### 6. nanoid 使用说明
|
||||
|
||||
`nanoid` 以命名空间导出,推荐通过 `nanoid.api` 访问:
|
||||
|
||||
```typescript
|
||||
import { nanoid } from '@opentiny/utils'
|
||||
|
||||
nanoid.api.nanoid(8) // 默认长度
|
||||
nanoid.api.customAlphabet('abc', 10) // 自定义字母表
|
||||
nanoid.random() // 0~1 随机数(SSR 下返回 0)
|
||||
```
|
||||
|
||||
### 7. 禁止事项
|
||||
|
||||
- ❌ 不得在 utils 中引入 Vue、`@opentiny/vue-common`、`@opentiny/vue-hooks`
|
||||
- ❌ 不得将仅某一组件使用的常量长期放在 `common/`、`form/`(应下沉到对应 renderless 或组件)
|
||||
- ❌ 不得重复造轮子:新增前先检索 `src/index.ts` 是否已有同类方法
|
||||
- ❌ 注意 `date` 与 `date-util` 存在部分重名导出(如 `toDate` / `toDate1`),优先使用语义清晰的现有 API,避免再增加别名
|
||||
|
||||
## 构建与发布
|
||||
|
||||
```bash
|
||||
# 在 packages/utils 目录
|
||||
pnpm build # vite 构建
|
||||
pnpm test # vitest
|
||||
pnpm pub # 发布(维护者)
|
||||
```
|
||||
|
||||
## 参考资源
|
||||
|
||||
- [统一导出](../../packages/utils/src/index.ts)
|
||||
- [debounce 示例](../../packages/utils/src/debounce/index.ts)
|
||||
- [renderless 中的引用](../../packages/renderless/src/alert/vue.ts)
|
||||
Loading…
Reference in New Issue