背景 🌏
近年来,接手各个前端的代码,看着前人屎山,深恶痛绝
为了避免自己或者团队,继续添粪,因此经验总结一番~
规范化优点:
- 容易理解,维护性强
- 容易编写,扩展性强
- 精准定位,bug数量减少,容易改
- 接手难度低,交接容易
从长远来看,降本增效
做法 🤔
🤔那么我们应该怎么做?
回答:
命名统一,遵循原则,其他细节,编写代码
注:以下均为vue3 例子
命名统一 🤓
命名规则:最好由常见的英文单词组合(1~2个)
- 注释参半:若选择不常见命名,或又难以理解的流程,需简略注释
// 调用接口
const getData = () =>{ return ... }
// 重置清空
const reset = () => { ... }
// 刷新
const refresh = async() => {
reset();
await getData();
// 接口请求完,的后续流程
...
}
// 初始化
const init =() => {
refresh();
// 除了接口的,其他初始化流程
}
// 初次加载,先调用一次
init();
// 导出方法
defineExpose({
reset,
refresh,
init,
})
选用通用名,作为方法和参数,团队固定统一
影响:理解UP↑,低门槛接手
四大原则 😎
代码结构化上的一些规则,个人久经沙场,领悟
1、不超千行
单文件遵循 不超千行原则
解决:代码解构,分离样式 > 常量 > 模块(优先级)
样式分离:
<style lang="scss" scoped>
@import "./index.scss";
</style>
常量分离:
import { SORT_CONFIG, FILTER_CONFIG, OTHER_LABEL,
DATA_RANGE, PREACH_LABEL, USER_STATUS, HOSPITAL_AREA,
UNUSUAL_LABEL,DATA_STRATEGY } from "./constant";
模块分离:
import videoModel from "./model/video";
import audioModel from "./model/audio";
import lessonModel from "./model/lesson";
// 视频资源
const { videoIndex } = toRefs(videoModel.state)
// 音频资源
const { voiceIndex } = toRefs(audioModel.state)
// 课程资源
const { activeList, activeIndex, actionIndex, actionCount,
actionContinuityTime, lessonPaused, lessonTime, countDown
} = toRefs(lessonModel.state)
const toActionDetail = () => {
const id = actionVO.value.id
const version = actionVO.value.dataVersion
uni.navigateTo({
url: `../actionDetail/index?id=${id}&&v=${version}`,
})
// 调用课程模块,课程暂停
lessonModel.lessonPause()
}
要是超千行,按优先级分离:样式 > 常量 > 模块
影响:避免其他参数影响,理解UP↑,定位UP↑,扩展UP↑
2、注释参考
难以理解,注释参考原则
/**
* 重要说明:
* @constant: 配置文件
* @events: 主要事件
* onActivated(页面激活时触发/加载页面)
* getkeyItem(取值,塞值)
* setFilterType(排序、筛选点击事件)
* resetAll(重置所有条件)
* handleSearch(回传搜索参数 + 搜索)
*/
使用 copilot , 效果更佳
影响:交接难度DOWN↓,理解UP↑
3、策略模式
超双条件(>= 3种条件),使用策略模式原则
<template>
<div class="list">
<div class="item" v-for="key in personKeys">
<span class="item-value">{{personKeys[key].value}}</span>
<span class="item-title">{{personKeys[key].title}}</span>
</div>
</div>
</template>
<script lang="ts" setup>
import { getPersonList } from "@/api/workbench"
const PERSON_CONFIG: any = {
preachCount: {
value: 0,
title: "宣讲量",
},
validPreachCount: {
value: 0,
title: "有效宣讲量",
},
validPreachSuccessCount: {
value: 0,
title: "有效宣讲成功量",
},
}
const personObject: any = ref(deepClone(PERSON_CONFIG));
const personKeys = computed(() => Object.keys(personObject.value));
// 调用接口
const getData = async() => {
const res = await getPersonList()
if(res.data){
for (let key in hospObject.value) {
personObject.value[key].value = res.data[key] || PERSON_CONFIG[key].value;
}
}
}
</script>
多种条件,使用策略模式,结构配置化,更为清晰
影响:定位UP↑,扩展UP↑
4、变量内嵌
template语法内,内嵌 class/style,采取变量内嵌原则
<template>
<!-- 排序筛选 按钮 -->
<div class="others">
<div :class="filterTypeClass('sort')" @click="setFilterType('sort')">
<span class="icon shuliao icon-L-zhengxu font-14"></span>
<span class="font-10">排序</span>
</div>
<div :class="filterTypeClass('filter')" @click="setFilterType('filter')">
<span class="icon shuliao icon-L-shaixuan font-14"></span>
<span class="font-10">筛选</span>
</div>
</div>
</template>
<script lang="ts" setup>
// 选中类型 class
const filterTypeClass = (type: string) => {
const activeHide = [1, 2].includes(active.value) || (!openBedSort.value && active.value === 0)
// 排序按钮,显示规则
const btnHide = type == 'sort' && props.pageType === 'yxyyPatient' && activeHide
return {
'active': filterType.value === type,
'hide': btnHide ,
'pdr-16 others-btn': true,
}
}
</script>
尽量避免template语法内,出现多条件判断内嵌class,或者style
抽离至script里,配合注释,标明,更为清晰
影响:交接难度DOWN↓,理解UP↑
其他总结 🤭
感慨 ❤️🔥
不知不觉,入行前端,已经有4年半了
从当初一只小菜鸡,慢慢成长(当然现在还是小菜鸡😄)
看着一直以来的职业道路,道虽曲折,但也有收获
晋升成功后,经历疫情的最后裁员风波,忙于pad端的医疗开发,实在是抽不出时间更新。
看着还是上半年更新的博客,熟悉如往常,我又双叒叕来打破僵局了💪
再提一嘴,copilot是真的好用😍