Vue 组件设计

本文探讨Vue组件设计的重要性,包括复用、隔离、单一职责等原则。组件设计应遵循保持简单、避免副作用,以及正确处理数据流动。通过props、$emit、$refs进行组件间通信,使用v-model和.sync修饰符实现双向绑定。组件划分需考虑粒度,避免过多的props传递,合理使用mixins和插件,以及处理好DOM操作。
摘要由CSDN通过智能技术生成

Vue 组件设计

Vue 作为 MVVM 框架一员,不管是写业务还是基础服务,都少不了书写组件。本文总结一下书写业务组件的一些心得。

为什么要写组件?

我们知道,只要是组件,就需要在引用的时候与 view 或者其他组件进行相关的交互,即 props 传值,$emit 触发事件,
使用 $refs 调用组件方法等,与写在同一个文件相比,耗费的精力明显更多。那为什么需要拆分出组件呢?我认为有两种目的:
复用和隔离。

复用

在业务代码中,会有大量类似的界面,保证交互唯一,即使我们有了类似 element-ui 或者 iview 这种基础组件库,
我们同样需要为这些基础组件添加 props 或者 events,只有一处使用时,没有任何问题,当你的业务中出现两次、三次甚至更多时,
代码中会出现大量重复的代码,而且这些代码在线上可能会慢慢露出一些深层次的 bug,要修复这些 BUG,就需要 n 倍的时间去写同样的代码,
让人抓狂。所以我们页面同样需要像 js 抽出公用的方法一样抽出公用组件,这就是复用的目的。

隔离

复用针对的是代码重复问题,而隔离则是针对代码逻辑过于复杂的问题。通常我们要实现一个复杂的逻辑,它是一个扁平化的多逻辑并行问题,
人脑对于同时思考是有一定限制的,过于复杂就很难一下考虑全面。
首先需要抽象出它的目的,然后对实现进行分层,让每一层只解决一个简单的问题,这些层合起来形成一个完整的解决方案;
或者将问题拆分成几块,每块之间具有一定的联系,每次思考时只需要考虑局部的逻辑即可。
不管是分层、分块还是混合式,它的目的是对进行隔离,从而简化问题。如果某个页面 js + template 行数非常多(1k+),
这个时候就可以考虑是不是要对部分功能拆解,便于在后续添加新功能,或者修改 BUG 的时候更为方便定位到问题的代码,
不会出现改错函数的问题。

需要注意的是,虽然复用和隔离是让逻辑更为清晰,但使用自己写的组件会让项目的入手难度提高,需要先了解整体的设计,
才能针对性的修改代码或者添加新的功能,得失各半。

组件设计的一些理念
网上有关于组件设计的基本原则:http://www.fly63.com/article/detial/996,
内容比较多,下面进行一些常用的原则归纳。

单一职责

之前提到的组件拆分目的:复用与隔离,对于隔离的类型,组件业务必然很重,此时虽然要保证组件尽可能简单,
而复用类型的,通用性更强,所以功能越单一,使用起来就越方便。我们知道 react 有一个概念:container/component,
即 component 只是渲染组件,而 container 才是产生业务的组件,我们 Vue 也可以依照这个理念进行设计。
即把数据处理等带有副作用的工作放在父组件中,而子组件只进行展示或操作,通过事件的方式让父组件进行处理,
保证逻辑归一,后续维护也更为方便。或者使用 slot 等类似高阶组件的方式来简化当前组件的内容。

无副作用/引用透明
和纯函数类似,设计的一个组件不应该对父组件产生副作用,从而达到引用透明(引用多次不影响结果)。
数据操作前必须进行复制。比如需要添加额外的键值,或者需要对数组类型的数据进行操作,会对原始数据产生影响,
需要使用解构的方式进行复制:

const newData = { …oldData }
const newList = […oldList]
注:引用类型的 props 千万不要直接修改对象,虽然能够达到传递数据的目的,但会产生副作用,如果有其他地方用到该数据,可能产生未知的影响。

入口和出口正确性检查
Vue 提供了类型检查工具,只在 dev 情况下生效,虽然和 JSON Schema 相比功能比较少,但能够做基本的类型检查了,
我们只需要在 props 时不使用字符串型,而是为它定义详细的类型, 并为它设置默认值(vue-cli 的 eslint 严格模式已经强制要求):

['name1'] // 不规范写法
{
   
  name1: {
   
    type: String,
    default: undefined
  }
}

组件划分颗粒度

组件拆分出来之后,拆成几层或者是拆成几块,影响文件的数量。如果层级比较多,各种 props 传递,事件传递,维护成本比较高。
举例:如果是一个二级的列表,即有多个一级列表,一级列表各有一级列表,这个时候应该怎么拆分呢?
按单一原则,我们可能需要拆分成以下几个:一级列表卡片本身,二级列表卡片,二级列表承载组件,一级列表承载组件。
这种划分,组件是三级,两块,数据的传递就会比较困难。如果一级卡片列表不复杂,我们可以将几个 v-for 与组件本身合并,
即一级列表承载组件+一级列表卡片+二级列表卡片,二级列表卡片。这种处理方式保证所有的数据处理在第一层上,二级卡片只做渲染,
保证逻辑处理集中在一个组件,维护也比较方便。当然,如果一级卡片非常复杂,或者数据需要大量的处理,需要根据情况把最细的进行合并。

新功能下添加新属性/新文件

对于通用类型组件,我们要求它尽可能的短小精悍,调用起来更为简单,所以不能设计太多的参数。基础组件库不能符合这个要求,
主要是因为基础组件库需要尽可能增加普适性,不会因为没有某个常用的属性,导致该组件需要复制一份重写,再加上日积月累的 pull request,
属性和参数必然会越来越多。而我们在业务中使用,完全不需要这么多的配置,如果有重大差别,重新复制一份,对于后续的维护反而更方便。
所以是否新增加属性还是拷贝一份,是根据后续该组件是否会产生比较大的发展方向差异来决定的。

Vue 组件之间的交互设计
Vue 组件与 React 组件有比较大的区别,模板的设计更偏向于 HTML,所以要实现类似 react 的高阶组件的需求通常比较少,
而高阶组件集成度过高,对于业务来说,当业务越来越复杂,组件内部逻辑将拆分困难,未必是件好事,所以我们只讨论普通的组件设计。
组件设计是考虑组件通讯方式,主要分为以下几个方面:向下传值,向上传值,伪双向绑定,方法调用。

数据流转
向下传值
向下传值就是父级传给子级数据。前面已经提到了,在 props 传值尽量对传入数据进行类型校验,保证尽快发现问题。除此之外,也有一些注意事项。
传值类型如果是引用类型的 Object 类型

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,对于你的问题,我的回答如下: 要实现Vue中5秒后自动隐藏的功能,可以通过以下步骤实现: 1. 在需要隐藏的元素中添加一个v-show或v-if的指令,用于控制元素的显示和隐藏。 2. 在Vue组件中添加一个定时器,用于在5秒后将指令的值改为false,从而隐藏元素。 3. 在组件销毁时清除定时器,避免内存泄漏。 示例代码如下: ```html <template> <div v-show="show">这是需要自动隐藏的元素</div> </template> <script> export default { data() { return { show: true, timer: null } }, mounted() { this.timer = setTimeout(() => { this.show = false }, 5000) }, beforeDestroy() { clearTimeout(this.timer) } } </script> ``` 关于Vue组件设计方面,如果需要实现一个Tag组件和Empty组件,可以参考以下步骤: 1. 创建一个Tag组件和一个Empty组件Vue文件,分别命名为Tag.vue和Empty.vue。 2. 在Tag组件中添加props属性,用于接收标签的数据。 3. 在Tag组件中使用v-for指令遍历标签数据,渲染每个标签。 4. 在Empty组件中添加props属性,用于接收空状态的提示文字。 5. 在Empty组件中渲染提示文字。 示例代码如下: Tag.vue ```html <template> <div> <span v-for="(tag, index) in tags" :key="index">{{ tag }}</span> </div> </template> <script> export default { props: { tags: { type: Array, default: () => [] } } } </script> ``` Empty.vue ```html <template> <div>{{ text }}</div> </template> <script> export default { props: { text: { type: String, default: '' } } } </script> ``` 以上是我对你问题的回答,希望能够对你有所帮助。如果你还有其他问题,可以继续提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值