实用的VUE系列——接手shi山 vue 项目,我们如何shi上雕花!!
我们的苦恼
不知道大家有没有发现,在这个行业中,在自己的职业生涯中 ,如果你没有接到过一个shi山
项目,
那么要恭喜你,真的是个天选之人
,快去买彩票!
我相信大多数的人,总会遇见,一个一千行的.vue
文件, 三重for循环的 遍历, 包含无数逻辑的单一函数, 过度耦合多个方法 ,传二十个参数的参数列表垃圾调用,各种mixin随便混
垃圾代码示例如下:
// 我们用三重for循环遍历举例
function processMatrix(matrix) {
let result = 0;
for (let i = 0; i < matrix.length; i++) {
for (let j = 0; j < matrix[i].length; j++) {
for (let k = 0; k < matrix[i][j].length; k++) {
result += matrix[i][j][k];
console.log("Processing element:", matrix[i][j][k]);
}
}
}
console.log("Final result:", result);
return result;
}
// 示例调用
let matrix = [
[
[1, 2, 3],
[4, 5, 6]
],
[
[7, 8, 9],
[10, 11, 12]
]
];
processMatrix(matrix);
以上代码中, 我相信各位jym
在日常业务代码中一定见过,我们可以发现,他结结实实的存在几个问题
-
长函数:
processMatrix
函数包含了多个嵌套的for循环,逻辑复杂,不易理解。 -
重复代码:在循环中,
console.log("Processing element:", matrix[i][j][k]);
和result += matrix[i][j][k];
可以提取到一个单独的函数中。 -
高复杂度:三重for循环使得代码的时间复杂度很高,对于大数据集,性能会变得很差。
其实以上代码中,我们只需要稍微的优化一下,就能将代码中的糟粕去除! 去除糟粕的方式很简单,根本不需要做什么架构设计,代码构思,画uml类图等等
直接简单粗暴,拆开就行了
代码如下:
function processMatrix(matrix) {
let result = 0;
for (let layer of matrix) {
result += processLayer(layer);
}
console.log("Final result:", result);
return result;
}
function processLayer(layer) {
let layerResult = 0;
for (let row of layer) {
layerResult += processRow(row);
}
return layerResult;
}
function processRow(row) {
let rowResult = 0;
for (let element of row) {
rowResult += processElement(element);
}
return rowResult;
}
function processElement(element) {
console.log("Processing element:", element);
return element;
}
// 示例调用
let matrix = [
[
[1, 2, 3],
[4, 5, 6]
],
[
[7, 8, 9],
[10, 11, 12]
]
];
processMatrix(matrix);
改进后的代码中,我们将处理矩阵的逻辑分解为多个小函数,每个函数只负责一层的处理,这样做的好处是:
-
- 降低复杂度:每个函数的逻辑都变得简单,容易理解。
-
- 提高可读性:函数名明确地描述了它们的功能,使代码更加自解释。
-
- 易于维护:如果需要修改某一层的处理逻辑,只需要修改对应的函数,而不必担心影响到其他层次。
所以说,高端的代码总是用很简单的书写方式
如何shi 上雕花
好了,片汤话我们讲完了,下面说点有用的, shi上雕花
依稀记得,在当年刚入行的时候,我看了一本书叫《重构》 ,如获至宝!
他可以说打开了我整个职业生涯的好习惯
我还记得,他在开始的作者,就列出了一些代码中的坏味道
,
代码中的坏味道
书中列举了很多坏味道
,多达21种,这里我们简单的列举一下,其中一些我骥某人
认为比较典型的!!
1. 重复代码(Duplicated Code)
当同样的代码出现在多个地方时,修改某处代码需要同时修改所有地方,容易出错且增加维护成本。
2. 过长函数(Long Method)
函数或方法太长,包含太多逻辑,使得代码难以理解和维护。长函数应该拆分为多个短小且功能单一的函数。
4. 过长参数列表(Long Parameter List)
函数或方法的参数列表过长,通常是因为传递了过多的依赖对象。可以考虑使用对象来封装参数,或通过构造方法注入依赖。
5. 冗赘注释(Comments)
过多或不必要的注释,通常是代码不清晰的标志。应通过改善代码的可读性来减少对注释的依赖。 所以说,瞎写不如不写
6. 过度耦合(Inappropriate Intimacy)
两个类之间的耦合过于紧密,频繁访问对方的私有成员。应通过重构来减少耦合。
7. 异曲同工的类(Inappropriate Intimacy)
两个类的职责有过多的重叠,应该通过重构将其职责明确分离。
8. Switch语句(Switch Statements)
频繁出现的switch语句通常表示需要使用多态来代替。
我们选了八个大家经经常犯错的坏味道
的代码,望大家共勉
然而有jym
发现,这个坏味道,在vue 中也是经常犯,所以 以上错误的改进,就是我们在vue 项目中shi上雕花,的第一步。
这时候有jym
要问了,那你还有什么绝活,能专门针对vue 项目的shi上雕花呢?
额, 那个当然有了,我们只需要简单的做以下几步!
shi山项目配置
有句话说得好,工欲善其事,必先利其器,当接手了shi山项目之后,我们要做的第一步就是,代码格式化, shi山之所以叫shi山,是因为他乱,当然,除了代码乱,还有格式乱
于是,我们第一步一定要格式化所有的格式,如果公司内部有格式规范,那当���得用公司的。
毕竟人家给你发钱!!
如果没有,那自己看顺眼就行, 毕竟自己看的开心很重要
这里我们可以推荐使用vscode +.prettier 做标准的代码格式化以及校验
其实很简单,我们只需要在vscode 的插件商店中,
下载一个他
尽量保证原始代码不被改动
之所以有这一点是因为,你怎么知道这些祖传代码有多少坑,你怎么知道前辈们为了他付出了多少汗水,当然也可能是泪水
老的代码虽然垃圾,可也是前辈们的智慧结晶 ,写代码和改代码的人能让他跑起来,那都是无与伦比的聪明人
比那些自以为聪明的人聪明的多 , 垃圾也罢,逻辑混乱也行,但是能跑
而你,初生牛犊,觉得他们写的太烂,东改改,西改改, 闹不好,就给搞成了线上的bug
出了事,扣钱那都是好的,指不定就得收拾包袱滚蛋
所以,我们对于这种代码要严格的遵循开闭原则
-
对扩展开放(Open for extension) : 这意味着软件实体应该可以通过增加新功能进行扩展,而不需要修改现有代码。也就是说,程序应该可以在不修改现有代码的情况下增加新的行为。
-
对修改关闭(Closed for modification) : 这意味着一旦软件实体被开发和测试完成,它就不应该被修改。通过遵循这一原则,可以减少对现有功能的风险和影响。
于是,要实现这个设计原则,我当然就要利用vue
的一些不常用的api
跨组件传值$attrs /$listeners
$attrs/$listeners 的本质,就是一个转发api 他本质是将 props、 emit 的内容向更高一层或者更低一层传递,从而能保证中间组件不会被污染,来可控的维护shi
山
代码如下
// 顶层组件
<template>
<div>
<B @changeMyData="changeMyData" :myData="myData"></B>
</div>
</template>
<script>
import B from "./B";
export default {
data() {
return {
myData: "100"
};
},
components: { B },
methods: {
changeMyData(val) {
this.myData = val;
}
}
};
</script>
// shi 山组件,不需要更改任何逻辑,只需要透传
<template>
<div>
<C v-bind="$attrs" v-on="$listeners"></C>
</div>
</template>
<script>
import C from "./C";
export default {
components: { C },
};
</script>
// 我们要新加的业务组件 不需要更改shi山
<template>
<div>
<h5>组件C</h5>
<input v-model="myc" @input="hInput" />
</div>
</template>
<script>
export default {
props: { myData: { String } },
created() {
this.myc = this.myData; // 在组件A中传递过来的属性
console.info(this.$attrs, this.$listeners);
},
methods: {
hInput() {
this.$emit("changeMyData", this.myc); // // 在组件A中传递过来的事件
}
}
};
</script>
provide / inject
provide / inject 在vue
中的解释为依赖注入
provide
:可以让我们指定想要提供给后代组件的数据或函数也
inject
:在任何后代中就可可以使用祖先组件中的数据或者函数
代码如下:
// Parent.vue
<script setup>
import { provide } from "vue"
provide("name", "老骥farmer")
</script>
// 中间shi山组件
<script setup>
// 这个组件啥也不需要动
</script>
// Child.vue
<script setup>
import { inject } from "vue"
const name = inject("name")
console.log(name)
</script>
上述代码中,我们可以完美的避过,shi 山组件,从而快速的完成需求
vue 中尽量不要使用jsx
我们知道,jsx
是react 的首创,由于vue
中庸的框架特性,于是他支持了,完喽,业务代码中就开始全是jsx
外加模板
四不像
本质上来说,不是jsx
不好,而是,代码想要维护下去,就必须要有规范,所谓规范 就能让人记住的规则。
那么怎么能让人们更快速的记住呢?
就是风格统一,模板统一,约定俗成统一, 尽量的花最小的代价让团队更快的记住和熟悉
所以,就遵循vue
模板语法维护代码才是正道!!!
什么技巧,什么jsx
什么装x
, 早点写完需求早点回家才是王道!!!
善用发布订阅模式
发布订阅模式 基于一个事件(主题)通道,希望接收通知的对象 Subscriber
通过自定义事件订阅主题,被激活事件的对象 Publisher
通过发布主题事件的方式通知各个订阅该主题的 Subscriber
对象。
各位听不懂是吧? 我也听不懂,因为我是在百科上抄的!!
其实所谓的发布订阅模式的本质,就是利用对象或者数组的能力,保存订阅者的订阅内容,当发布者要发布内容时, 从数组中取出对应的订阅者的值(也就是订阅函数),仅此而已!
代码如下:
class EventEmitter {
constructor() {
// 初始化事件和回调函数的存储对象
this.handles = {};
}
// 订阅事件
on(eventName, callback) {
if (!this.handles[eventName]) {
this.handles[eventName] = [];
}
this.handles[eventName].push(callback);
}
// 触发事件
emit(eventName) {
if (this.handles[eventName]) {
// 获取事件对应的回调函数数组
const handles = this.handles[eventName];
handles.forEach(callback => {
callback();
});
}
}
}
// 创建一个事件管理器实例
const emitter = new EventEmitter();
// 订阅'onSell'事件,添加两个回调函数
emitter.on('onSell', () => {
console.log('hello');
});
emitter.on('onSell', () => {
console.log('world');
});
emitter.emit('onSell'); // 触发'onSell'事件
那么他在vue shi
山代码里有啥用呢? 告诉你,这里头学问大了 ,并且我是切身体会过的
假设假设有一个shi山组件中,突然要根据接口的内容去控制某一块 业务代码的显示隐藏,而这个shi 山代码可是有上千行啊, 且不说你改动成本高不高,就问你感不感动(敢不敢动)?
如果此时一定要动,按照常规的情况,以及我们通常有一个能跑的做法,首先,我找一个变量,然后通过层层传递,最终直达病灶
然后再利用计算属性
包裹一层,接下来在某个业务逻辑中插入当前片段,或者控制某个代码段的v-if
来解决问题?
其实我想说这一招,虽然可用,但却着实不是最优解?
原因很简单, 一个破变量,垮了那么多组件,你就不怕出问题?
那么此时发布订阅就可以救命了,我们只需要在shi山代码中订阅一下, 如果在接口中发现启用或者禁用的标识,直接利用发布者
发布即可,从而其他组件中和当前shi山组件没有任何关联和耦合
当然,你也不用担心,那种诡异的bug
代码如下
这里给大家安利一个很好用的发布订阅插件mitt
,这次我们就用他来解决问题
// 先创建发布订阅实例
mitt.js
import mitt from 'mitt'
const mitt = mitt()
export default mitt
// 拉取接口的组件
<script setup>
import mitt from './mitt'
axios().then((res) => {
// 可以根据啊res 的状态,来判断要不要执行
mitt.emit('handleChange')
})
}
</script>
// 真实的需要显示隐藏的业务组件
<template>
<div v-if="isShow">控制这个内容的显示隐藏</div>
</template>
<script setup>
import mitt from './mitt'
import { ref } from 'vue'
import { onUnmounted } from 'vue'
const isShow = ref(fasle)
const someMethed = () => {
isShow.value = ture
}
mitt.on('handleChange',someMethed)
onUnmounted(()=>{
mitt.off('handleChange',someMethed)
})
</script>
代码的改动,一定要写注释
这是一个比代码维护技巧,设计模式使用更重要的方式,原因很简单,好记性不如烂笔头
,
其实很多shi 山代码之所以shi 也不是写的这个人的代码能力不行,而是他的代码习惯不好不写注释
,本质上的讲我们不管利用什么设计模式,什么封装写法, 都是为了能有规律的记住和理解代码。
于是,我们为何不用注释来提醒自己呢?
除了能让别人对你五体投地之外,下次你自己维护,也不用抓耳挠腮, 一举两得!!
为什么代码会最终变成shi山
工作几年的jym
可能会有个惊奇的发现,几乎所有项目的结局只会有一个,shi山
原因很简单,所有的项目都是人写的,而既然是人,水平就会可能参差不齐,工作态度就可能会懈怠,代码风格就可能不尽相同。 长相,就可能有美有丑。。。
额,好像跑偏了
再加上各位产品大哥大姐,提出的各种奇葩的反人类的需求,需要不停的打补丁。
于是,日常的维护迭代中,他的结局只能有一个, shi山
以至于,很多jym
最终对职业的热爱,变成单纯的工作,对于代码的热爱变成了天天热更新。
最终他们的被磨平了棱角,遵循有一个能跑就行原则(要不代码跑,要不自己跑)
其实,他们曾经也是个风一样的少年,他们热爱代码。年轻气盛,期望用自己的能力改变世界。
然而面对这个污浊的世界,在赚钱和理想之间,他们选择了前者,做出了妥协, 虽不合适,但很合理。
要不要重构
相信文章写到这,很多jym
就会很疑惑,有这shi上雕花的功夫,为啥不重构代码呢?
难道重构这么难吗?
很好,问出这种问题的jym
是愿意思考的,其实这个问题当年我也想过
甚至在年轻的时候,直接私下议论领导的决策,具体怎么议论的?
TM这领导·#¥%~·#¥@$%&;!
请各位jym
自行体会!!
然而,当我工作几年我渐渐的理解了领导,理解了他的无奈,理解了他的妥协,更理解了他的人情世故
天下英雄出我辈,一入江湖岁月催
众所周知,有人的地方就有江湖
而互联网江湖虽然,待遇好,工资高, 管理扁平,阶级意识淡化,但也是人精的聚集地。 毕竟他挣得多
一个项目,特别是线上稳定运行的项目,在不同部门的人,不同职级的人的眼里,就可能有不同的看法。
在我们眼里,他可能就是日常吐槽的对象,
在我们领导的眼里,就可能是他在公司稳定发展的资本
在别的领导的眼里,就可能需要争取的地盘
在老板眼里,就可能是赚钱的机器
于是,站在更高维度的上帝视角去看待这个项目,你会发现,他不仅仅是个项目,他承载了人性,利益,地位,以及我们的理想,
然后你就会发现,你的一厢情愿的想法, 就是狗屁,你别说说服你的老板,你连你自己都说服不了
到底要不要重构,我可以很诚恳的告诉大家,重构是需要契机的,要符合老板的利益,领导的利益。以及大家的利益。
你提出重构应该是是顺应民意,而不是你的孤注一掷!
这里,根据我骥某人的经验 我给大家以下几点建议:
- 1、不是不能用就不要重构,时间紧任务重,瞎改代码,容易延期,代码瞎改改好了,没人给你加钱,改坏了,引起线上事故,完喽,扣钱,换句话说,多做多错、少做少错、不做不错 、不错不错
- 2、基于要不要重构,要遵循一个原则 一切都听领导的,毕竟领导总是英明的,即使不英明也能负责任!!!!
- 3、如果一定要重构,记得要使用ab测试验逐步替代,不要影响当前线上功能
- 4、 最最重要的是,在重构的时候,要小步前进 ,应逐步进行,每次只做一个小的改变,并在每次修改后进行测试
转载自:https://juejin.cn/post/7391324758859546664