初衷
注 :TDesign 是腾讯各业务团队在服务业务过程中沉淀的一套企业级设计体系。
当我们使用Tdesign中的FileUpload组件时,我们可能希望对其进行二次封装,以满足特定的需求或增加额外的功能。我们的初衷是让这个组件更加灵活、易用,并且能够适应不同的场景。
通过二次封装,我们可以将其整合到我们的应用程序中,使其更符合我们的设计规范和UI风格。 之前写有一篇关于:
Vue3: 二次封装WangEditor富文本编辑器-hook
也得到了不少的好评,确实在工作中,如果遇到有一些公用的组件,不妨结合它们的官方文档进行一下定制,定制成符合我们业务需求的组件。
后面,我将在图片上传和视频上传,做一下hooks封装, 在开始实战总结之前,先说一下什么是hooks,有什么好处
hooks介绍
Hooks封装是React中一种强大的编程模式 尽管Vue3中没有像React中的Hooks一样的编程模式,但Vue3引入了Composition API,提供了类似于Hooks的功能,具有一些类似的魅力:
- 逻辑复用:Composition API允许将逻辑封装到可复用的函数中,称为"composition function"。这样可以将一些常见的逻辑和功能进行封装,并在多个组件中进行复用,从而减少代码的重复。
- 更好的组件组合性:通过Composition API的组合函数,我们可以更灵活地组合组件逻辑,并将其粒度化。这使得组件更加可组合,不再受限于单一的渲染函数和生命周期钩子。
- 提高代码可读性:使用可重用的composition function,可以将组件的逻辑细分为更小的部分,使得代码更加清晰和易于阅读。同时,通过Composition API的函数式风格,我们可以更好地组织和维护代码。
- 更好的测试性:通过将逻辑封装到composition function中,可以更容易地进行单元测试。我们可以针对每个composition function编写独立的测试,并更好地模拟输入和验证输出,提高代码质量和可维护性。
- 更好的性能优化:Composition API提供了更多的工具,例如响应式、计算属性和watch等,用于处理和优化应用的状态和数据流。这使得性能优化更加清晰和高效。
虽然Vue3中的Composition API与React Hooks略有不同,但它们都带来了类似的魅力,包括逻辑复用、可读性的提高、更好的组件组合性、更好的测试性和更好的性能优化。通过合理使用Composition API,我们可以更好地开发Vue3应用,提高开发效率和代码质量。
那么接下来,我将通过图片上传和视频上传,封装hooks的全过程做一下总结。
二次封装FileUpload实现图片、视频上传
介绍Tdesign中FileUpload文档属性
在做封装之前,我们需要知道FileUpload提供了哪些属性方法,后面我们需要在此基础上做扩展. 这里只贴出较为关键和需要扩展的几个属性方法:
requestMethod
beforeUpload
该方法可以不用写入hooks中,可以在具体需求的地方,单独编写。因为文件大小、文件类型等相关需求需要按产品的设计而定,所以不适宜写在hooks
至于文件大小限制,upload组件早有提供,可以直接传入相应参数
sizeLimit
如下代码:
html
<t-upload
ref="imageRef"
v-model="images"
theme="custom"
accept="image/jpg,image/jpeg,image/png,image/gif"
multiple
allow-upload-duplicate-file
:max="10"
:request-method="uploadImage"
:before-upload="beforeUpload"
:size-limit="{ size: 1, unit: 'MB', message: '上传的图片不符合要求,请重新上传' }"
@validate="onUploadValidate"
>
<t-icon name="add" class="icon" />
</t-upload>
html
<t-upload
ref="imageMultiRef"
v-model="multiImages"
theme="custom"
accept="image/jpg,image/jpeg,image/png,image/gif"
allow-upload-duplicate-file
:request-method="uploadMultiImage"
:before-upload="beforeUpload"
:size-limit="{ size: 1, unit: 'MB', message: '上传的图片不符合要求,请重新上传' }"
@validate="onUploadValidate"
>
<t-icon name="add" size="30" class="icon" />
<span>上传图片</span>
</t-upload>
我们需要将images、uploadImage, removeImage这些属性封装在hooks中操作,并将这些方法暴露出来 使用的方式,可以参考如下,可以声明不同别名进行多次引用
js
// 图片上传
const { images, uploadImage, removeImage } = useImageUpload((res) => {
// 重置选中图片索引
currIdx.value = -1;
updateGif(res.files[0]?.url, TAG_NAME.image);
});
// 多图上传
const {
images: multiImages,
uploadImage: uploadMultiImage,
removeImage: removeMultiImage,
} = useImageUpload((res) => {
// 重置选中图片索引
currIdx.value = -1;
updateGif(res.files[0]?.url, TAG_NAME.imageMulti);
});
// 轮播图上传
const {
images: swiperImages,
uploadImage: uploadSwiperImage,
removeImage: removeSwiperImage,
} = useImageUpload((res) => {
// 重置选中图片索引
currIdx.value = -1;
updateGif(res.files[0]?.url, TAG_NAME.swiper);
});
若是需要上传成功后,将信息回传到自定义的回调方法中,可如上useImageUpload,传入一个成功回调方法做处理。
hooks图片上传
js
// 图片上传
export function useImageUpload(uploadSuccess, opts = { rename: true }) {
const images = ref([]);
const uploadImage = (file) =>
new Promise((resolve) => {
upload(Array.isArray(file) ? file : file.raw, opts)
.then((res: PutObjectResult[] | PutObjectResult) => {
const response: { files?: { url: string; name: string }[]; url?: string } = {};
if (Array.isArray(res)) response.files = res.map((v) => ({ url: v.url, name: v.name }));
else response.url = res.url;
uploadSuccess?.(response, images);
resolve({ status: 'success', response });
})
.catch((res) => {
resolve({ status: 'fail', error: '上传失败', res });
});
});
const removeImage = (index) => {
images.value.splice(index, 1);
};
return {
images,
uploadImage,
removeImage,
};
}
这段代码定义了一个名为useImageUpload
的自定义Vue Composition API hook。该hook接受一个uploadSuccess
函数作为参数,以及一个可选的opts
对象参数。
代码中的upload为调用上传接口逻辑所封装的方法,可根据各自项目的情况做相应的封装。
在useImageUpload
函数内部,首先创建一个images
响应式引用ref([])
,用于存储上传成功的图片列表。
然后定义了uploadImage
函数,用于处理图片上传操作。该函数接受一个文件(或文件数组)作为参数,并返回一个Promise对象。在函数内部,调用了一个名为upload
的上传函数,传入文件参数和opts
选项。该upload
函数可能返回一个PutObjectResult
对象,或者一个PutObjectResult
对象数组。
根据上传结果的不同,构建了一个response
对象,该对象包含上传成功的文件的URL和名称。如果上传结果是一个数组,将每个文件的URL和名称保存在response.files
属性中,否则将文件的URL保存在response.url
属性中。
然后通过调用uploadSuccess
函数,将response
对象和images
列表传递给外部组件进行处理。最后通过Promise对象的resolve方法返回一个包含上传结果的对象,包括状态(success
或fail
)、可能的错误信息和上传结果本身。
最后,定义了removeImage
函数,用于从images
列表中删除指定索引的图片。
最后,返回一个对象,该对象包含了images
列表、uploadImage
函数和removeImage
函数,供外部组件使用。