『精』Vue 组件如何模块化抽离Props

2023-11-05 03:30

本文主要是介绍『精』Vue 组件如何模块化抽离Props,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

『精』Vue 组件如何模块化抽离Props.jpg

『精』Vue 组件如何模块化抽离Props

文章目录

  • 『精』Vue 组件如何模块化抽离Props
    • 一、为什么要抽离Props
    • 二、选项式API方式抽离
    • 三、组合式API方式抽离
        • 3.1 TypeScript类型方式
        • 3.2 文件分离方式
        • 3.3 对文件分离方式优化
    • 参考资料💘
    • 推荐博文🍗


一、为什么要抽离Props

在前端框架中封装一个组件是非常常见的,对于组件来讲,往往离不开组件之间属性的传递,通过属性能够控制组件的样式内容、处理逻辑类型、数据传递。假如有这么一个用于签名的组件,能够控制画笔的大小、颜色、画布背景颜色宽高、按钮的文案提示等,那么它的属性必定是有十几个选项,假设 800 行代码里可能就得花费 100 行去声明这些属性,这明显是不合适的。
这也是我为什么提议要抽离组件 Props 的原因,实际上这个签名组件也确实存在,源自于我在 Uniapp 插件市场上的一个提交。
图 1-1
抽离Props的好处有这么几点:

  • 降低、隔离组件的复杂度,降低维护成本与提高程序可靠率。
  • 引入一个中间的、易于理解的抽象概览。
  • 隐藏非核心处理部分的实现细节,提高组件源码的可阅读性。
  • 促进代码的重用,包装一定的结构风范。
  • 属性的抽离,有助于自动化程序生成对应文档。

那么要怎么做才能抽离出 Props 呢,在 Vue 身上根据选项式 API 和组合式 API 写法的不同,做法也不一样。
一些简单的组件可能只有一两个属性,甚至是没有属性,对于这种情况下,可能不抽离 Props 会显得更方便一些,但一定要注意的是应当把组件以后要做的和其扩展维护性放在一起考虑,往往十几个属性堆叠的组件都是从一两个属性的组件开始的,既然以后会越加越多,那为何不提早抽离处理方便以后再加呢,当然具体怎么做取决于自己。


二、选项式API方式抽离

选项式 API 适用于 Vue2 和 Vue3,需要使用到 Mixins 混合方法。Mixins 不只是能抽离 Props,它能做到更多,我相信大部分对这个功能会比较熟悉,有兴趣的可以参考此文档 Mixins。

import type { PropType } from "vue";export default {props: {prop1: {type: String,required: true},prop2: {type: Array as PropType<string[]>,default: ["a", "b", "c"]},prop3: {type: Array as PropType<Record<string, unknown>[]>,defalue: []}}
};
<script lang="ts">import props from "./props";export default {mixins: [props]};</script>

三、组合式API方式抽离

组合式 API 属性的声明依赖于 defineProps 编译宏,这个编译宏只能出现在 .vue 的文件中才能正确识别,那么对于 Hook 来说,抽离 Props 是行不通的。

3.1 TypeScript类型方式

defineProps 是支持 typescript 类型标注声明的,直接引入一个类型行不行得通的呢?关于这个问题要分 Vue3.3 版本之前与之后,Vue3.3 版本之前是不允许将类型接口以导入的形式传给 defineProps 泛型,在官方文档中也有对应的标注,相关讨论在这 issue。
图 3-1
图 3-2

但这还有一个问题,typescript只能声明类型,如果要配置默认值的话需要搭配另外一个编译宏 withDefaults 去实现,且类型接口能导入还好,若是不能导入的话,本地类型接口又违背降低复杂度而抽离的初衷了,在我看来还不如不用。依据 Vue3.3 版本之后,可以参考下列示例:

export interface Props {prop1: string;prop2?: string[];prop3?: Record<string, unknown>[];
}export const propsDefault = {prop1: "默认值",prop2: () => ["a", "b", "c"]
};
<template><div>{{ $props.prop1 }}</div><div>{{ $props.prop2 }}</div>
</template><script lang="ts" setup>import { type Props, propsDefault } from "./props";const $props = withDefaults(defineProps<Props>(), propsDefault);</script>
3.2 文件分离方式

人们往往容易把简单的东西想复杂,将 Props 类型声明存放到一个单独文件里,只要确保 defineProps 在 .vue 文件中使用即可,这么做有个好处就是简单易用且在不依赖typescript的时候基本兼容 Vue3 各版本,对于我来讲,我更习惯于使用 文件分离式 进行 Props 的抽离。
这种方式与 Hook 不同的是,Hook需要一层函数包裹执行,而这样相当于直接引入配置文件中的一个变量。

import type { PropType } from "vue";export const props = {prop1: {type: String,required: true},prop2: {type: Array as PropType<string[]>,default: ["a", "b", "c"]},prop3: {type: Array as PropType<Record<string, unknown>[]>,defalue: []}
};
<template><div>{{ $props.prop1 }}</div><div>{{ $props.prop2 }}</div>
</template><script lang="ts" setup>const $props = defineProps(props);</script>

对于 TypeScript 如果需要获取 Props 的类型,那就需要用到 Vue 的一个辅助类型 ExtractPropTypes,对于外部引用(父组件)的话使用 ExtractPublicPropTypes,只需在上面示例的基础上改造一下👇。

import type { PropType, ExtractPropTypes } from "vue";export const props = {prop1: {type: String,required: true},prop2: {type: Array as PropType<string[]>,default: ["a", "b", "c"]},prop3: {type: Array as PropType<Record<string, unknown>[]>,defalue: []}
};// 导出 Props 类型
export type Props = ExtractPropTypes<typeof props>;

其实 ElementUI 的源码也是这么去做的,以 el-empty 组件为例,源码中对于属性的分离是这么写的。
图 3-3

3.3 对文件分离方式优化

从优化的角度上看,Vue 的Props声明方式都是一样的,同样的代码写多次显得有些冗余,那不妨将这些 Props 声明再次优化一下,编写一个公共的 Props 辅助工具进行声明。

"use strict";
/*** 组件属性辅助* 🙌 能够使用更少的代码编写,有助于减少包体积*/
import type { PropType } from "vue";export const unknownProp = null as unknown as PropType<unknown>;export const numericProp = [Number, String];export const truthProp = {type: Boolean,default: true as const
};export const lieProp = {type: Boolean,default: false as const
};export const makeRequiredProp = <T>(type: T) => {return { type, required: true as const };
};export const makeNumericProp = <T>(defVal: T) => {return { type: numericProp, default: defVal };
};export const makeStringProp = <T>(defVal: T) => {return { type: String as unknown as PropType<T>, default: defVal };
};export const makeNumberProp = <T>(defVal: T) => {return { type: Number as unknown as PropType<T>, default: defVal };
};export const makeArrayProp = <T>(defVal: T[]) => {return { type: Array as PropType<T[]>, default: () => defVal };
};export const makeObjectProp = <T>(defVal: T) => {return { type: Object as PropType<T>, default: () => defVal };
};export const makeFuncProp = <T>(defVal: T) => {return { type: Function as PropType<T>, default: defVal };
};// 联和类型属性
export const makeUniteProp = <T, V>(type: T[], defVal: V) => {return { type, default: () => defVal };
};
import type { PropType, ExtractPropTypes } from "vue";import {makeArrayProp, makeRequiredProp} from "@/utils/props"export const props = {prop1: makeRequiredProp(String),prop2: makeArrayProp<string>(["a", "b", "c"]),prop3: makeArrayProp<Record<string, unknown>[]>([])
};export type Props = ExtractPropTypes<typeof props>;

参考资料💘

🍅因发布平台差异导致阅读体验不同,源文贴出:《『精』Vue 组件如何模块化抽离Props》

  • 官方手册:
    • Vue ExtractPropTypes
    • Vue defineProps
    • Vue Mixins

推荐博文🍗

  • 《Vue3 如何在<script setup>里设置组件name属性》
  • 《JavaScript 各声明var、let、const方式区别『详解』》

这篇关于『精』Vue 组件如何模块化抽离Props的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/347108

相关文章

四种Flutter子页面向父组件传递数据的方法介绍

《四种Flutter子页面向父组件传递数据的方法介绍》在Flutter中,如果父组件需要调用子组件的方法,可以通过常用的四种方式实现,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录方法 1:使用 GlobalKey 和 State 调用子组件方法方法 2:通过回调函数(Callb

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

详解如何在React中执行条件渲染

《详解如何在React中执行条件渲染》在现代Web开发中,React作为一种流行的JavaScript库,为开发者提供了一种高效构建用户界面的方式,条件渲染是React中的一个关键概念,本文将深入探讨... 目录引言什么是条件渲染?基础示例使用逻辑与运算符(&&)使用条件语句列表中的条件渲染总结引言在现代

详解Vue如何使用xlsx库导出Excel文件

《详解Vue如何使用xlsx库导出Excel文件》第三方库xlsx提供了强大的功能来处理Excel文件,它可以简化导出Excel文件这个过程,本文将为大家详细介绍一下它的具体使用,需要的小伙伴可以了解... 目录1. 安装依赖2. 创建vue组件3. 解释代码在Vue.js项目中导出Excel文件,使用第三

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

vue解决子组件样式覆盖问题scoped deep

《vue解决子组件样式覆盖问题scopeddeep》文章主要介绍了在Vue项目中处理全局样式和局部样式的方法,包括使用scoped属性和深度选择器(/deep/)来覆盖子组件的样式,作者建议所有组件... 目录前言scoped分析deep分析使用总结所有组件必须加scoped父组件覆盖子组件使用deep前言

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

基于Qt Qml实现时间轴组件

《基于QtQml实现时间轴组件》时间轴组件是现代用户界面中常见的元素,用于按时间顺序展示事件,本文主要为大家详细介绍了如何使用Qml实现一个简单的时间轴组件,需要的可以参考下... 目录写在前面效果图组件概述实现细节1. 组件结构2. 属性定义3. 数据模型4. 事件项的添加和排序5. 事件项的渲染如何使用

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

使用Vue.js报错:ReferenceError: “Vue is not defined“ 的原因与解决方案

《使用Vue.js报错:ReferenceError:“Vueisnotdefined“的原因与解决方案》在前端开发中,ReferenceError:Vueisnotdefined是一个常见... 目录一、错误描述二、错误成因分析三、解决方案1. 检查 vue.js 的引入方式2. 验证 npm 安装3.