每个贡献者的代码风格都是不同的,在认同 CompositionAPI
理念的情况下。我们希望能够有较为标准的代码组织结构。让整体的代码保持一个大概的代码块风格,组件的维护会更加清晰,避免代码的堆积。
以 upload
组件为例,代码块应该是分层设计的。第一步先进行合理的组件拆分,拆分的原则:
upload
组件存在多种表现类型,因此会衍生出4个子组件:Dragger
、ImageCard
、FlowList
、SingleFile
hook
与表现层代码挂钩:useComponentsStatus
, useImgPreview
, useRemove
, useDragger
, useActions
。provider
向子组件注入,也可以使用 context
向子组件传递。const isSingle = computed(() => props.theme === 'single')
TD
的 API
在多个框架下使用,会融合一些 react API
的设计,在事件方面 XXX evnt
通常会伴随一个 onXXX
的函数参数,组件事件options API
中,methods
可以直接暴露出去,不需要 expose
,而 setup
中,需要按需 expose
相关函数。import { defineComponent } from 'vue';
import { TdUploadProps } from './type'; _// 标准的type文件_
import props from './props'; _// 标准的props文件_
import { xxx } from './interface' _// 如果需要自定义一些 `interface`, 则统一放到 `interface` 文件当中_
_// 子组件_
import Dragger from './dragger';
import ImageCard from './image';
import FlowList from './flow-list';
import SingleFile from './single-file';
_// hooks_
import { useConfig, usePrefixClass, useCommonClassName } from '../hooks/useConfig'; _// 全局的config配置, classPrefix, commonClass_
import useVModel from '../hooks/useVModel'; _// 语法糖与受控处理_
import { useLogicHook } from './hook'; _// 纯逻辑代码的组件内部hook,按逻辑区分,方便后续的维护_
export default defineComponent({
name: "TUpload",
props,
setup(props: TdUploadProps) {
const { classPrefix: prefix, global } = useConfig('upload');
const COMPONENT\_NAME = usePrefixClass('upload');
const { STATUS } = useCommonClassName();
const { files, modelValue } = toRefs(props);
_// `files` 的更新统一使用 `setUploadValue`_
const [uploadValue, setUploadValue] = useVModel(
files,
modelValue,
props.defaultFiles || [],
props.onChange,
);
_// 组件上下文,集中管理组件内置的状态_
const uploadCtx: UploadCtxType = reactive({
uploadValue,
setUploadValue,
loadingFile: null, _// 加载中的文件_
toUploadFiles: [], _// 等待上传的文件队列_
errorMsg: '',
});
_// 逻辑层 `hook` 导出表现层需要的变量, 相关的effect函数。_
const { logicVar, logicHandler } = useLogicHook(props, uploadCtx)
_// 表现层 `render` 函数, 按模块拆分,避免主 `render` 函数内容过多。_
const renderContent = () => {
<div class={[COMPONENT\_NAME.value, {
STATUS.disabled: props.disabled
}]} onClick={logicHandler}>
{logicVar}
</div>
}
_// 可以直接在setup返回render函数,不需要再单独写 `render` 函数。同时 `setup render` 函数里面也有很完整的类型支持。需要对外暴露的方法可以使用 `ctx.expose`_
return () => (
<div>{renderContent()}</div>
)
},
})
为 TNode
的 API
中,需要使用 useTNodeJSX
得到渲染函数进行渲染,函数内会处理好 props
function props
与插槽的关系。
import { useTNodeJSX } from '../hooks/tnode';
defineComponent({
setup() {
const renderTNode = useTNodeJSX();
const renderChild = () => {
return renderTNode('default')
}
return () => (
<div>
// 两种写法
{renderTNode('TNodeName', options)}
{renderChild()}
</div>
)
},
})
统一使用 useConfig
, useConfig
会导出 global
, classPrefix
, t
。
在很多情况下你可能只需要导出一个带prefix的类名,你可以使用 usePrefixClass
。
const COMPONENT\_NAME = usePrefixClass('componentName');
_// 也可以只得到一个classPrefix_
const classPrefix = usePrefixClass();
commonClass
集合了一些公用的 class
。分为 SIZE
和 STATUS
。
const { SIZE, STATUS } = useCommonClassName()
ConfigReceiverMixins
会被废弃。
逐渐放弃使用高阶函数 mapProps
。实现 v-model
使用 useVModel
, 实现 v-model:xx
使用 useDefaultValue
。这两个 hook
在内部会处理好受控与非受控,组件内部使用暴露出来的值即可,同时对外的参数更新也需要使用暴露出的函数进行更新。
用于实现主参数的双向绑定 v-model
,受控与非受控
import useVModel from '../hooks/useVModel';
const { value, modelValue } = toRefs(props)
const [innerValue, setInnerValue] = useVModel(
value,
modelValue,
props.defaultValue,
props.onChange,
'propsName' _// 可选参数,用于类似 `files` 这种别名主双向绑定参数的处理_
);
用于实现辅助参数的双向绑定v-model:visible
,受控与非受控
import useDefaultValue from '../hooks/useDefaultValue';
const { visible } = toRefs(props)
const [innerVisible, setInnerVisible] = useDefaultValue(
visible,
props.defaultVisible,
props.onVisibleChange,
'visible',
);
在 TDesign vue
中事件都会存在 onXXX
的 props
函数,可以通过 props.onXXX
的方法进行处理。对于 props
中定义了的事件不需要再调用 emit('xxx')
.
_// props_
{
onChange?: (...args) => {};
}
_// tsx_
setup(props) {
props.onChange?.(args)
}
Provide
与 inject
,按需 provide
,避免 children
调用 $parent
这类代码.InjectionKey
,需要注意 InjectionKey
的导出位置,避免循环引用。import { InjectionKey } from 'vue';
const CheckboxGroupInjectionKey: InjectionKey<{
name: string;
componentProps: string,
xxxProvideProps: string,
}> = Symbol('componentName');
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。