声明:本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!
shi山项目中的shi山代码
不知道大家有没有发现,在这个行业中,在自己的职业生涯中 ,如果你没有接到过一个shi山
项目,
那么要恭喜你,真的是个天选之人
,快去买彩票!
我相信大多数的人,总会遇见以下内容
一个一千行的.vue
文件
这个就不再解释了,没法维护,dddd(懂得都懂)
各种vue中的mixin混入
shi山代码如下:
// mixinA.js
export const mixinA = {
data() {
return {
aValue: 'A'
};
},
methods: {
methodA() {
console.log('Method A');
}
},
mounted() {
console.log('Mixin A Mounted');
}
};
// mixinB.js
export const mixinB = {
data() {
return {
bValue: 'B'
};
},
methods: {
methodB() {
console.log('Method B');
}
},
mounted() {
console.log('Mixin B Mounted');
}
};
// mixinC.js
export const mixinC = {
data() {
return {
cValue: 'C'
};
},
methods: {
methodC() {
console.log('Method C');
}
},
mounted() {
console.log('Mixin C Mounted');
}
};
// 组件中混入了多个 mixin
export default {
mixins: [mixinA, mixinB, mixinC],
data() {
return {
localValue: 'Local'
};
},
methods: {
methodLocal() {
console.log('Local Method');
}
},
mounted() {
console.log('Component Mounted');
}
};
多重混入导致混乱,我相信后续维护的人也不知道每个mixins
中的mounted
中到底藏着多少坑
包含无数逻辑的单一的函数
shi山例代码如下:
function processUserData(user) {
// 1. 验证用户数据的必填字段
if (!user.name || !user.email || !user.age) {
return { success: false, message: "缺少必填字段" };
}
// 2. 检查年龄是否为有效的数字
if (isNaN(user.age) || user.age < 0 || user.age > 120) {
return { success: false, message: "无效的年龄" };
}
// 3. 验证邮箱格式
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(user.email)) {
return { success: false, message: "无效的邮箱格式" };
}
// 4. 检查用户是否提供了电话号码,并格式化
if (user.phone) {
user.phone = user.phone.replace(/[^0-9]/g, ""); // 移除非数字字符
if (user.phone.length !== 10) {
return { success: false, message: "无效的电话号码" };
}
}
// 5. 返回处理后的用户数据
return {
success: true,
message: "用户数据处理成功",
data: user
};
}
// 示例对象
const user = {
name: "john doe",
email: "john.doe@example.com",
age: 25,
phone: "(555) 123-4567"
};
console.log(processUserData(user));
这种一个函数中包含规则判断的,其实我们有必要给他每一个判断逻辑抽离为一个函数,并且方便维护
接下来我们看看优秀的代码怎么做的 ,参考elementui的表单验证
为例
// 可以随时动态添加
const fields= [
[
{ check: true, validator:(user)=>{
// 1. 验证用户数据的必填字段
if (!user.name || !user.email || !user.age) {
return { success: false, message: "缺少必填字段" };
}
}
},
],
[
{ check: true, validator:(user)=>{
// 2. 检查年龄是否为有效的数字
if (isNaN(user.age) || user.age < 0 || user.age > 120) {
return { success: false, message: "无效的年龄" };
}
}
}
],
[
{ check: true, validator:(user)=>{
// 3. 验证邮箱格式
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(user.email)) {
return { success: false, message: "无效的邮箱格式" };
}
}
}
],
[
{ check: true, validator:(user)=>{
// 4. 检查用户是否提供了电话号码,并格式化
if (user.phone) {
user.phone = user.phone.replace(/[^0-9]/g, ""); // 移除非数字字符
if (user.phone.length !== 10) {
return { success: false, message: "无效的电话号码" };
}
}
}
}
],
]
const user={}
// 校验函数
function validate(callback) {
// 如果需要验证的fields为空,调用验证时立刻返回callback
if (this.fields.length === 0 && callback) {
callback(true);
}
let valid, invalidFields=[]
// 校验内容
this.fields.forEach(field => {
if(check){
const res = field.validator(user)
if (res.success) {
valid = true;
} else {
valid = false;
invalidFields.push(res.message);
}
}
if (typeof callback === 'function' && ++count === this.fields.length) {
// 返回是是否校验通过,如果没通过 就去除报错内容
callback(valid, invalidFields);
}
});
if (promise) {
return promise;
}
}
// 使用
validate((valid) => {
if (valid) {
alert('submit!');
} else {
console.log('error submit!!');
return false;
}
});
以上代码中,我们可以简单的发现,做对了以下事情,
- 1、 将函数分别拆开,提高可维护性
- 2、将校验函数变为动态提高可拓展性
- 3、用户可自定义校验失败后续操作,增加灵活性
多重for循环的遍历
shi山代码如下:
// 使用三重 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);
他有以下几个问题
-
长函数:
processMatrix
函数包含了多个嵌套的for循环,逻辑复杂,不易理解。 -
重复代码:在循环中,
console.log("Processing element:", matrix[i][j][k]);
和result += matrix[i][j][k];
可以提取到一个单独的函数中。 -
高复杂度:三重for循环使得代码的时间复杂度很高,对于大数据集,性能会变得很差。
其实以上代码中,我们只需要稍微的优化一下,就能将代码中的糟粕去除! 去除糟粕的方式很简单拆开就行了,
// 降低复杂度:每个函数的逻辑都变得简单,容易理解。
// 提高可读性:函数名明确地描述了它们的功能,使代码更加自解释。
// 易于维护:如果需要修改某一层的处理逻辑,只需要修改对应的函数,而不必担心影响到其他层次。
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上雕花
依稀记得,在当年刚入行的时候,我看了一本书叫《重构》 ,如获至宝!
他可以说打开了我整个职业生涯的好习惯
我还记得,他在开始的作者,就列出了一些代码中的坏味道
,
1、识别代码中的坏味道
书中列举了很多坏味道
,多达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上雕花,的第一步。
这些共勉
的具体示例就不再赘述,在文章开头已经有过举例和改进,接下来我们重点讲讲 vue 项目中如何 shi 上雕花
2、 第一步shi山项目重新配置
老说得好,工欲善其事,必先利其器,当接手了shi山项目之后,我们要做的第一步就是,代码格式化, shi山之所以叫shi山,是因为他乱,当然,除了代码乱,还有格式乱
于是,我们第一步一定要格式化所有的格式,如果公司内部有格式规范,那当然得用公司的。
毕竟人家给你发钱!!
如果没有,那自己看顺眼就行, 毕竟自己看的开心很重要
这里我们可以推荐使用vscode +.prettier 做标准的代码格式化以及校验
接下来就跟大家一起配置一下
1、第一步我们在 shi 山项目
中安装prettier
npm i prettier
2、项目中创建.prettierrc
指定配置(一般默认配置就够你用了)
常用配置如下
{
// 箭头函数参数周围加上括号
"arrowParens": "always",
// 大括号与代码在同一行
"bracketSameLine": true,
// 大括号内部不加空格
"bracketSpacing": false,
// 分号结尾
"semi": true,
// 不使用实验性三元表达式
"experimentalTernaries": false,
// 使用单引号
"singleQuote": true,
// JSX属性值使用单引号
"jsxSingleQuote": true,
// 保留引号样式
"quoteProps": "preserve",
// 尾随逗号保留
"trailingComma": "all",
// 不强制单个属性换行
"singleAttributePerLine": false,
// HTML空格敏感性为css
"htmlWhitespaceSensitivity": "css",
// Vue脚本和样式不缩进
"vueIndentScriptAndStyle": false,
// 文本不换行
"proseWrap": "never",
// 不插入格式化标记
"insertPragma": false,
// 打印宽度为80个字符
"printWidth": 80,
// 不要求格式化标记
"requirePragma": false,
// 使用Tab缩进
"useTabs": true,
// 嵌入语言格式自动
"embeddedLanguageFormatting": "auto",
// Tab宽度为4个空格
"tabWidth": 4
}
有了以上配置之后,我们在开发中,就可以有标准化的格式化插件,能够更容易的维护shi山
当然,这还是不够的
3、为了防止再次变成更烂的shi山
我们需要配合 git 在提交代码中将混乱的代码纠正
在git 中想要使用提交校验,我们还需要另外几个工具 husky
、lint-staged
、ESLint
- ESLint:对代码进行风格和规范进行检查,对不符合规范的代码给出提示,同时可以进行一定程度的自动修复,他和
prettier
的区别前者是常用代码书写标准(===和==),而后者是代码风格的标准(空几个字符) - Husky:Git hooks工具,通过配置一系列钩子,可以在git操作的不同阶段执行相应的命令;
- lint-staged:在提交代码前进行lint检查时,可以让lint只检查git暂存区(staged)的文件,而不会检查所有文件;
好了我们了解完了之后,就简单的配置一下
安装
npm add eslint husky lint-staged eslint-config-prettier @typescript-eslint/parser eslint-plugin-vue eslint-plugin-prettier -D
4、配置 eslint
创建 .eslintrc.js
并配置(这里我简单的列举常用配置,大家可以酌情使用)
复制内容module.exports = {
// 此项是用来告诉eslint找当前配置文件不能往父级查找
root: true,
// 此项指定环境的全局变量
env: {
browser: true, // 浏览器环境
node: true, // node环境
},
// 此项是用来提供插件的,插件名称省略了eslint-plugin-,下面这个配置是用来规范html的
// plugins: ["vue"],
// 指定javaScript语言类型和风格
parserOptions: {
ecmaVersion: 2020,
// parser: "babel-eslint"
},
// 指定eslint继承的模板
extends: [
'plugin:vue/essential',
'@vue/airbnb',
'@vue/typescript/recommended',
'plugin:vue/recommended',
'eslint:recommended',
'@vue/prettier', // 结合 .prettierrc.js
],
/** 规则 https://www.wenjiangs.com/docs/eslint,vue规则:https://eslint.vuejs.org/rules/
* 主要有如下的设置规则,可以设置字符串也可以设置数字,两者效果一致
* 'off' 或 0 - 关闭规则
* 'warn' 或 1 - 开启警告规则,使用警告级别的错误:warn (不会导致程序退出),
* 'error' 或 2 - 开启错误规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
*/
rules: {
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, // 禁止使用debugger
'no-console': 0, // 禁止使用console
'no-unused-vars': 0, // 存在声明但未使用的变量
'no-useless-escape': 0, // 禁止不必要的转义字符
'no-alert': 0, // 禁止使用 alert、confirm 和 prompt
'space-before-function-paren': [0, 'always'], // 函数定义时括号前面要不要有空格
'generator-star-spacing': 0, // 生成器函数*的前后空格
'@typescript-eslint/explicit-module-boundary-types': 0, // 函数的返回值类型必须被显式声明
'@typescript-eslint/no-empty-function': 0, // 禁止出现空函数
'@typescript-eslint/ban-types': 1, // 禁止使用特定的类型
'@typescript-eslint/no-var-requires': 0, // 禁止使用 require 语句
'arrow-parens': 0, // 箭头函数用小括号括起来
'@typescript-eslint/ban-ts-comment': 0, // 禁止使用ts的注释
'@typescript-eslint/no-unused-vars': 0, // 禁止出现未使用过的变量
'@typescript-eslint/no-this-alias': 0, // 禁止将 this 别名
'@typescript-eslint/no-inferrable-types': 0, // 禁止使用隐式 any 类型
'@typescript-eslint/no-extra-semi': 0, // 禁止不必要的分号
'prefer-const': 0, // 推荐使用const
'@typescript-eslint/no-explicit-any': 0, // 禁止使用any类型
'@typescript-eslint/no-empty-interface': 0, // 禁止空接口
'@typescript-eslint/no-non-null-assertion': 0, // 禁止使用!后缀运算符
'vue/no-side-effects-in-computed-properties': 1, // 禁止在计算属性中对属性修改
'linebreak-style': 'off', // 换行风格
'class-methods-use-this': 'off', // 确保在类的方法中没有无效的this引用
'import/no-cycle': [0, { ignoreExternal: true }], // 防止在 JavaScript 项目中导入路径产生循环引用
'global-require': 'off', // 检查是否在 ESLint 文件中全局调用了 require 函数
'no-unused-expressions': 'off', // 检查在 JavaScript 代码中是否有无用的表达式
'no-plusplus': 'off', // 禁止使用自增(++)和自减(--)操作符
'no-underscore-dangle': 'off', // 禁止使用前导下划线命名变量或函数
'no-tabs': 'off', // 禁止代码中的 tab 字符的使用,因为 tab 容易造成代码缩进混乱
'max-len': 'off', // 限制一行代码的最大长度
'no-async-promise-executor': 'warn', // 禁止在 Promise 构造函数中使用 async 函数作为执行器
'no-param-reassign': 'warn', // 禁止对函数参数进行重新赋值
'quotes': ['error', 'single'], // 指定字符串是否必须使用单引号'或双引号"
'no-nested-ternary': 'off', // 禁止使用嵌套的三元运算符
'complexity': ['off', 30], // 限制函数的复杂度
'vue/attributes-order': 'off', // 禁止在组件中使用未排序的属性
'lines-between-class-members': 'off', // 禁止类成员之间出现空行
'camelcase': [2, { properties: 'never' }], // 强制使用骆驼拼写法或强制使用小写单词拼写法
},
}
当然,这样还是不够的,因为在这个世界中,没有人会各司其职
,谁都想做大做强,再创辉煌
,
所以 eslint
与prettier
会有冲突
所以我们上头没有提到的两个插件派上了用场
-
eslint-plugin-prettier: 基于 prettier 代码风格的 eslint 规则,即eslint使用pretter规则来格式化代码。
-
eslint-config-prettier: 禁用所有与格式相关的 eslint 规则,解决 prettier 与 eslint 规则冲突,确保将其放在 extends 队列最后,这样它将覆盖其他配置
extends: [
// 加入这个插件
'plugin:prettier/recommended'
],
5、配置命令执行校验
eslint
与prettier
虽然安装了,却不能自动执行,所以我们需要有执行命令,我们在package.json
中添加命令
"scripts": {
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
"format": "prettier --write \"./**/*.{html,vue,ts,js,json,md}\"",
}
6、 配置git提交校验 之前我们安装过的
husky
是一个用来管理git hook
的工具,git hook
即在我们使用git
提交代码的过程中会触发的钩子
{
"scripts": {
"prepare": "husky install"
},
}
prepare
是一默认命令,脚本会在 npm install
时自动运行 并且创建.husky
目录包含以以下文件
** 7、 配置lint-staged**
lint-staged我们之前说过,他的使用方式只需要在package.json
配置即可
{
"lint-staged": {
"src/**/*.{js,ts,vue}": [
"npm run lint",
npm run format"
]
}
}
8、在 .husky中添加pre-commit
#!/usr/bin/env sh
npx --no-install lint-staged
ok 有了以上配置,我们在commit
代码时将自动校验代码,如此一来shi山就不会被提交了。
3、尽量不要改上shi山中的逻辑代码
之所以有这一点是因为,你怎么知道这些祖传代码有多少坑,你怎么知道前辈们为了他付出了多少汗水,当然也可能是泪水
老的代码虽然垃圾,可也是前辈们的智慧结晶 ,写代码和改代码的人能让他跑起来,那都是无与伦比的聪明人
比那些自以为聪明的人聪明的多 , 垃圾也罢,逻辑混乱也行,但是能跑
所以,我们对于这种代码要严格的遵循开闭原则
-
对扩展开放(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 山组件,从而快速的完成需求
4、尽量优化shi 山中的代码结构
这一点其实考验的就是我们架构能力,也就是怎样将我们的混乱代码进行拆分,但不改动业务逻辑。
这里我们用有名的element-admin
这个优秀的项目来举例
我们知道,一个秀优的项目,都具备一个素质————代码分层
所以当我们接手shi 山
项目的时候 要有一个共识,向优秀的项目看齐
我们可以将代码中的内容按照以下目录分层,如此一来不用更改逻辑代码,我们也能得到清晰的代码结构
一般而言,一个项目通常应该包含以下内容接口api模块
、公用组件模块
、directives指令模块
、 hooks模块
、router
模块、store模块
、views业务代码模块
、plugins插件模块
等等
当我们维护到相关代码,我们可以将混乱的代码做简单的归类
当然只用这一招是不够的,我们还要对用代码结构做优化(注意不是代码逻辑)
我们举一个简单的例子利用hooks
来优化代码
<template>
<div>
<div @click="edit">修改</div>
<div>
{{ form.sourceName }}
</div>
<div>
{{ form.sourceType }}
</div>
<div>
{{ form.sourceLink }}
</div>
<div>
{{ form.categoryId }}
</div>
<div>
{{ form.categoryName }}
</div>
<div>
{{ form.sourceLanguage }}
</div>
<div>
{{ form.sourceUrls }}
</div>
<div>
{{ form.sourceLogo }}
</div>
<div>
{{ form.id }}
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue"
const form = ref({
sourceName: "",
sourceType: 0,
sourceLink: "",
categoryId: "",
categoryName: "",
sourceLanguage: "",
sourceUrls: "",
sourceLogo: "",
id: ""
})
const edit = () => {
//假设这俩值是可以在别的组件中修改的
form.value.sourceName = "111111"
form.value.categoryName = "sourceLink"
}
</script>
假设我有个shi山的form表单,其中有几个值(sourceName
、categoryName
)需要在其他组件中能修改,这时候就麻烦了,我用store
吧 改动太大容易出问题,不用吧,在其他组件中不容易修改 ,可能要用到mitt发布订阅
、 父子组件传值
等等
我们在不改变业务逻辑的情况下,可以怎么做呢?
很简单,hooks 提取
import { ref } from "vue"
const form = ref({
sourceName: "",
sourceType: 0,
sourceLink: "",
categoryId: "",
categoryName: "",
sourceLanguage: "",
sourceUrls: "",
sourceLogo: "",
id: ""
})
const edit = () => {
//假设这俩值是可以在别的组件中修改的
form.value.sourceName = "111111"
form.value.categoryName = "sourceLink"
}
export const usestore = () => {
return { form, edit }
}
在以上代码中,我们只需要将代码提取出来即可,不改动任何业务逻辑
// 组件a 使用
<template>
<div>
<div @click="edit">修改</div>
<div>
{{ form.sourceName }}
</div>
<div>
{{ form.sourceType }}
</div>
<div>
{{ form.sourceLink }}
</div>
<div>
{{ form.categoryId }}
</div>
<div>
{{ form.categoryName }}
</div>
<div>
{{ form.sourceLanguage }}
</div>
<div>
{{ form.sourceUrls }}
</div>
<div>
{{ form.sourceLogo }}
</div>
<div>
{{ form.id }}
</div>
</div>
</template>
<script setup lang="ts">
import { usestore } from "./index.js"
const { form, edit } = usestore()
</script>
// 组件b更改
<template>
<div>
<div @click="edit">修改</div>
</div>
</template>
<script setup lang="ts">
import { usestore } from "./index.js"
const { edit } = usestore()
</script>
以上代码中,我们就能在不改动所有业务逻辑的情况下,解决问题,实现需求。
注意,这一招是相当于自己实现了一个store
ref的初始化要放在方法之外
5、vue 中尽量不要使用jsx
我们知道,jsx
是react 的首创,由于vue
中庸的框架特性,于是他支持了,完喽,业务代码中就开始全是jsx
外加模板
四不像
本质上来说,不是jsx
不好,而是,代码想要维护下去,就必须要有规范,所谓规范 就能让人记住的规则。
那么怎么能让人们更快速的记住呢?
就是风格统一,模板统一,约定俗成统一, 尽量的花最小的代价让团队更快的记住和熟悉
所以,就遵循vue
模板语法维护代码才是正道!!!
6、善用发布订阅模式
发布订阅模式 基于一个事件(主题)通道,希望接收通知的对象 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>
7、代码的改动,一定要写注释
这是一个比代码维护技巧,设计模式使用更重要的方式,原因很简单,好记性不如烂笔头
,
其实很多shi 山代码之所以shi 也不是写的这个人的代码能力不行,而是他的代码习惯不好不写注释
,本质上的讲我们不管利用什么设计模式,什么封装写法, 都是为了能有规律的记住和理解代码。
于是,我们为何不用注释来提醒自己呢?
除了能让别人对你五体投地之外,下次你自己维护,也不用抓耳挠腮, 一举两得!!
为什么代码会最终变成shi山
工作几年的jym
可能会有个惊奇的发现,几乎所有项目的结局只会有一个,shi山
原因很简单,所有的项目都是人写的,而既然是人,水平就会可能参差不齐,工作态度就可能会懈怠,代码风格就可能不尽相同。 长相,就可能有美有丑。。。
额,好像跑偏了
再加上各位产品大哥大姐,提出的各种奇葩的反人类的需求,需要不停的打补丁。
于是,日常的维护迭代中,他的结局只能有一个, shi山
以至于,很多jym
最终对职业的热爱,变成单纯的工作,对于代码的热爱变成了天天热更新。
最终他们的被磨平了棱角,遵循有一个能跑就行原则(要不代码跑,要不自己跑)
其实,他们曾经也是个风一样的少年,他们热爱代码。年轻气盛,期望用自己的能力改变世界。
然而面对这个污浊的世界,在赚钱和理想之间,他们选择了前者,做出了妥协, 虽不合适,但很合理。
要不要重构
相信文章写到这,很多jym
就会很疑惑,有这shi上雕花的功夫,为啥不重构代码呢?
难道重构这么难吗?
很好,问出这种问题的jym
是愿意思考的,其实这个问题当年我也想过
甚至在年轻的时候,直接私下议论领导的决策,具体怎么议论的?
TM这领导·#¥%~·#¥@$%&;!
请各位jym
自行体会!!
然而,当我工作几年我渐渐的理解了领导,理解了他的无奈,理解了他的妥协,更理解了他的人情世故
天下英雄出我辈,一入江湖岁月催
众所周知,有人的地方就有江湖
而互联网江湖虽然,待遇好,工资高, 管理扁平,阶级意识淡化,但也是人精的聚集地。 毕竟他挣得多
一个项目,特别是线上稳定运行的项目,在不同部门的人,不同职级的人的眼里,就可能有不同的看法。
在我们眼里,他可能就是日常吐槽的对象,
在我们领导的眼里,就可能是他在公司稳定发展的资本
在别的领导的眼里,就可能需要争取的地盘
在老板眼里,就可能是赚钱的机器
于是,站在更高维度的上帝视角去看待这个项目,你会发现,他不仅仅是个项目,他承载了人性,利益,地位,以及我们的理想,
然后你就会发现,你的一厢情愿的想法, 就是狗屁,你别说说服你的老板,你连你自己都说服不了
到底要不要重构,我可以很诚恳的告诉大家,重构是需要契机的,要符合老板的利益,领导的利益。以及大家的利益。
你提出重构应该是是顺应民意,而不是你的孤注一掷!
这里,根据我骥某人的经验 我给大家以下几点建议:
- 1、不是不能用就不要重构,时间紧任务重,瞎改代码,容易延期,代码瞎改改好了,没人给你加钱,改坏了,引起线上事故,完喽,扣钱,换句话说,多做多错、少做少错、不做不错 、不错不错
- 2、基于要不要重构,要遵循一个原则 一切都听领导的,毕竟领导总是英明的,即使不英明也能负责任!!!!
- 3、如果一定要重构,记得要使用ab测试验逐步替代,不要影响当前线上功能
- 4、 最最重要的是,在重构的时候,要小步前进 ,应逐步进行,每次只做一个小的改变,并在每次修改后进行测试