# TinyVue 组件开发规范 ## 核心原则 在 `packages/vue/src` 目录中,每个组件有一个独立的文件夹进行隔离。 每一个组件的结构为: 1. index.ts: 整个组件的对外导出对象 2. src/index.ts: 整合 pc/mobile-first 模板为一个统一的组件。通常要把pc/mobile-first模板的全量属性定义在这里并导出给2个模板使用 3. src/pc.vue: pc 浏览器下的模板,需要引入外部的css样式文件。 4. src/mobile-first.vue: 移动优先的浏览器模板, 使用tailwind进行内联类名。 ## 详细解释每个文件的编写规范 1. index.ts 该文件是整个组件的对外导出对象,负责给组件添加install方法和veresion属性。 示例如下: ```typescript import Alert from './src/index' import { version } from './package.json' Alert.install = function (Vue) { Vue.component(Alert.name, Alert) } Alert.version = version if (process.env.BUILD_TARGET === 'runtime') { if (typeof window !== 'undefined' && window.Vue) { Alert.install(window.Vue) } } export default Alert ``` 2. src/index.ts 整合 pc/mobile-first 模板为一个统一的组件。示例如下: ```typescript import { $props, $prefix, $setup, defineComponent } from '@opentiny/vue-common' import template from 'virtual-template?pc|mobile-first' export const alertProps = { // ...... } export default defineComponent({ name: $prefix + 'Alert', props: alertProps, setup(props, context) { return $setup({ props, context, template }) } }) ``` 同时引入2个模板的语法为 `import template from 'virtual-template?pc|mobile-first'` , 它是非标准的TS用法,有专门的`vite`插件会将其编译为两个模板的引入。 `template`是一个函数,它需要传入 `$setup`函数。 3. src/pc.vue 和 src/mobile-first.vue 的模板共同规范 这2个文件是组件的**视图模板**, - 负责 UI 渲染和用户交互 - 通过适配层的 `setup` 调用 renderless 层的函数 - 可以包含2个跨端模板(如 `mobile-first.vue`、`pc.vue`) - 禁止内联样式,需要从外部引入。比如:import '@opentiny/vue-theme/alert/index.less' - 必须引入类型定义文件。 比如: import type { IAlertApi } from '@opentiny/vue-renderless/types/alert.type' 一个标准的模板文件写法如下: ```vue ``` **适配层 setup** 函数作用: 1. 纽带作用 我们从 '@opentiny/vue-common' 引入 `setup`函数, 它是联系`无渲染逻辑层` 和 `模板`的纽带。 将`无渲染逻辑层`的组件逻辑函数传入`setup`后, setup内部会调用该函数,并传入组件实例的 porps, vue官方包对象,以及适配层构造的vm上下文对象,这样`无渲染逻辑层`的组件逻辑函数就会获得组件的所有令牌。 最后它会返回一个 {state,api} 对象,以便模板的绑定。 2. 处理模板选择 如果组件是跨端组件,那么它本质上是一个双层组件,父组件是用来选择使用 pc.vue ,mobile-first.vue 哪个模板, 子组件就是真实的组件。 `setup`函数内部负责向父组件同步状态和属性。此时 setup可选择性传入 `mono:false` 的属性,来告诉setup函数来同步这个状态和属性。 如果组件是一个单一组件,没有通用 `$setup` 来选择模板,那么在调用setup时, 必须传入 `mono:true` 来指示,它是一个单一组件。示例如下: ```typescript setup(props, context) { return setup({ props, context, renderless, api, mono:true }) as unknown as IAlertApi } ``` 3. 向`无渲染逻辑层`的组件逻辑函数传入额外的数据 `无渲染逻辑层`的设计上,它不能依赖第三方的库,如果之它需要引入其它对象,需要在 `模板层` 引入它们,并通过`setup` 的`extendOptions`属性 传入 `无渲染逻辑层`的组件逻辑函数中,示例如下: ```typescript import FluentEditor from '@opentiny/fluent-editor' setup(props, context) { return setup({ props, context, renderless, api, extendOptions: { FluentEditor }}) } ``` ## 模板规范 1. 必须使用 vue2, vue3同时兼容的模板语法。 2. 必须是单根节点 3. 不允许 v-if / v-for在同一个节点上, 建议使用