🍂好的代码习惯为你添砖加瓦!!!
代码规范的好处是什么?
好的代码是:健壮、多态、复用等。总的来说就是利于维护。可以如人类的发展文明一样把写代码分为3个阶段如下:
-
- 野蛮开荒-这个阶段一般算是
初级程序员
(每个人的定义不一样)都是刚工作没多久,或者说不注重自己的代码风格,只求快。那么这个阶段是最令同事头疼的阶段,功能呢可能也能搞,出来全是bug
,代码简直没得看。
- 野蛮开荒-这个阶段一般算是
-
- 精耕细作-这个阶段一般算是
中级程序员
每个人的定义不一样)发现或者认识到写好的代码更利于维护,对自己有一定的代码规范要求。会去设计一定的数据结构、运用一些设计模式、代码风格,会阅读社区好的类库、组件设计等。
- 精耕细作-这个阶段一般算是
-
- 发明创造-这个阶段一般算是
高级程序员
了(每个人的定义不一样)会解决工作中遇到的困难,写脚本、制定代码规范、开发组件、开发类库、代码重构、制定工作流等。
- 发明创造-这个阶段一般算是
态度端正
我觉得想要编码好、规范,态度一定要端正,时刻注意自己的代码规范。 不能老是着急着编码,最后让领导吐槽
bug
多,加个小功能就提到要重构
了。
要想着每次编码,不论功能模块大小,简单与否都要按照规范编程,编出一行行艺术的代码,至少编出让自己看到会觉得很好看的代码。
文件篇幅过长
编码大忌,单个文件上千、大几百行也就是俗称的
屎山
,你会觉得现在大几百行没啥问题,我写的还蛮好的啊,函数都挺抽象的,但是再下个再维护尼编码的人,再新加功能的时候。持续迭代,这个时候问题就会越来越明显了,每次迭代比其他项目工时增多,每个人都吐槽这个代码太烂,重构要么没时间、要么就是没人去推进等。
现在都准寻函数式编程
、组件式编程
、模块化编程
,我觉得一个文件不要超过200行。如果超过了就该考虑要再细化拆分模块了。
拿一个简单例子举例吧: 一个后台管理系统的一个页面,有搜索项(输入框若干、下拉框若干),有表格的增、删、改、查。 表格还有好多项需要自定义内容,展现形式可能不单单式文本,可能式另一种自定义形态。
有些同学就习惯把搜索项、表格逻辑都放在一个文件里面(.vue
),这个时候呢写下来这个界面就发现行数已经上千行了!。
像这种其实用现成的UI组件比如element
,有人会说没法抽了啊,篇幅过长主要是因为这个界面逻辑太多,需要的搜索项太多、自定义的表格插槽太多了,还有增删改查数据转换的逻辑。
咱们把上面有业务再得组件可以叫做业务组件
,业务组件
可能不像是通用组件
考虑多层各种场景复用得情况,但是也不能就这么摆烂,任由成为屎山
吧!
正确得模块划分如下:(文件名应该是你的业务名,我这里都是举例)
-- 业务文件名 # 文件夹
|--search #文件夹
|-- config.js # 放一些数据枚举值、下来框数据、初始化数据
|-- index.vue # 就是单纯得form表单搜索
|--content #文件夹
|--components # 文件夹 那个列需要自定义 不是单纯映射文本得 都抽出来
|-- 组件1.vue
|-- 组件2.vue
|-- 组件3.vue
|-- config.js # 放表格列数据、等一些其他枚举映射数据
|-- transform.js # 可以存放一些数据转换函数
|--dialog # 文件夹
|-- index.vue # 处理表格得增、改、查看等逻辑
|-- handler.js # 可以存放一些处理方法逻辑
|-- index.vue
|-- index.vue
再上面这种设计模块下,假如要新增一个搜索项,直接再search
下书写就好了,如果要新增一列刚好还需要自定义展现形式,就直接再compoents
下面写个小组件。
就近原则
编码请遵循
就近原则
存放目录,不要把所有项目枚举值
都放在最外面的constants
下。
假如这个枚举就再当前业务模块用到了,请就近
创建一个config.js
、options.js
存放,不用都写到外面的constants
下。
如果这个枚举值再别的模块也要用到就等下次抽离到外面constants
就好了,一定要做好业务模块数据分层,不要都再一个index.js
下
好的constants
如下:
--constants 文件夹
|-- index.js
|-- a.js
|-- b.js
|-- c.js
// index.js
export * from './a.js'
export * from './b.js'
export * from './c.js'
utils 文件
请不要把业务处理函数放到这里面来!
这里面存放的文件一定是遵循纯函数
编程的,每个函数是有使用说明的例如lodash
里面的注释。
/**
*
* @param {*} value The value to recursively clone.
* @returns {*} Returns the deep cloned value.
* @example
*
* var objects = [{ 'a': 1 }, { 'b': 2 }];
*
* var deep = _.cloneDeep(objects);
* console.log(deep[0] === objects[0]);
* // => false
*/
function cloneDeep(value) {
//
}
文件存放格式如constants
一样,如下:
--utils 文件夹
|-- index.js
|-- a.js
|-- b.js
|-- c.js
// index.js
export * from './a.js'
export * from './b.js'
export * from './c.js'
assets 文件夹
不要整个资源都堆、平铺再这个文件夹下,应该多创建子文件夹,按业务名称分类
services 文件夹
有些同学会创建一个
services
文件夹,里面写一个http.js
然后把交互逻辑axios
、还有api
都创建一个对象里面都是各个api
函数,最后挂载再vue
原型上上this.$api.方法
这么去用。这么是不好的
正确的是services
只是存放和后端统一交互的逻辑就好了,比如axios
的拦截器相关配置。
创建api
文件夹这个下面按业务模块分文件夹如下:
--api 文件夹
|-- index.js
|-- a #文件夹
|-- index.js
|-- b #文件夹
|-- index.js
|-- c #文件夹
|-- index.js
// index.js
export * from './a/index.js'
export * from './b/index.js'
export * from './c/index.js'
全局挂载
尽可能不要图方便就把方法啥的放在
window
上,和vue
原型上了。
不知道尼的项目vue
出现过没把交互函数都放在$api
上 还有全局的$filter
、全局的自定义指令等!!,统统不要放。 以后就是累赘!!!
把需要的全局过滤器等方法封装成一个函数 再需要的地方去引入就好了。
vuex的三个不要
不要再
vuex
去写逻辑!!不要用vuex
去做通讯!! 不要vuex
引入数据本地持久性!!
-
vuex
的定位就是全局数据存储共享
,他就是存数据的。存数据供给需要的模块使用。 -
组件通讯不涉及数据存储也不要使用。最好的是使用
props
、emit
去保持一个数据正确的流向。真需要跨多搁组件通讯可以使用发布订阅模式
。 -
不要引入什么插件做数据持久性,这真的是碰到想骂人,还要时刻考虑数据清理掉的问题。
注释
删除掉你没用的注释!!!保持代码整洁
- 使用语义化命名,删除掉没用的解释变量名注释信息,以及每次打印的
console.log
日志信息。 - 可以对复杂逻辑做个简单的注释说明。
vue 文件好的习惯
.vue
文件好的习惯如下:
-
- 每个
vue
文件有name
值,组件名, 首字母大写例如ElHome
;
- 每个
-
- 把空的没用到的方法删除掉例如下面:
<template>
<div>{{ name }}</div>
</template>
<script>
export default {
name: 'Elname',
data() {
return {
name: '21222'
}
},
mounted() {
},
methods: {
},
wacth: {
},
}
</script>
好的习惯不应该保留用不到的方法定义,不要怕同事
、队友
不知道这些api
删除掉就好了,需要用到了再定义! 如下:
<template>
<div>{{ name }}</div>
</template>
<script>
export default {
name: 'Elname',
data() {
return {
name: '21222'
}
},
}
</script>
-
props
定义,应该统一有默认值
、类型
、是否必穿
如下:
<template>
<div>{{ name }}</div>
</template>
<script>
export default {
name: 'Elname',
props: {
name: {
type: String,
default: '123',
required: true,
},
isShow: {
type: Boolean,
default: false,
required: false,
},
desc: {
type: String,
default: '123',
required: false,
},
}
}
</script>
-
- 事件再不需要传参不用带
()
;@click="onClick()"
->@click="onClick"
- 事件再不需要传参不用带
-
- 不要出现魔法字符串,应该用枚举代替;
<template>
<div @click="onClick">{{ name }}
<span v-if="type === 1">我是type1的逻辑</span>
<span v-if="type === 2">我是type2的逻辑</span>
<span v-if="type === 3">我是type3的逻辑</span>
</div>
</template>
<script>
export default {
name: 'Elname',
data() {
return {
type: 1,
name: '测试',
}
},
methods: {
onClick() {
if(type === 1) {
//
}
if(type === 2) {
//
}
if(type === 3) {
//
}
}
}
}
</script>
好的应该是:
<template>
<div @click="onClick">
{{ name }}
<span v-if="type === TYPE_MAP.ADD">我是type1的逻辑</span>
<span v-if="type === TYPE_MAP.DELETE">我是type2的逻辑</span>
<span v-if="type === TYPE_MAP.EDIT">我是type3的逻辑</span>
</div>
</template>
<script>
const TYPE_MAP = {
ADD: 1,
DELETE: 2,
EDIT: 3,
VIEW: 4,
};
export default {
name: 'Elname',
data() {
return {
TYPE_MAP,
type: 1,
name: '测试',
}
},
methods: {
onClick() {
if(type === TYPE_MAP.ADD) {
//
}
if(type === TYPE_MAP.DELETE) {
//
}
if(type === TYPE_MAP.EDIT) {
//
}
}
}
}
</script>
-
- 命名规范
-
Event
命名直接使用事件名称,无需在事件名称前加on等词。例如- click
- xxx-click
- xxx-dblclick
- validate
- change
- xxx-change
- close
- remove
-
绑定命名可是使用
on、handler
:@click="onHomeClick"、@click="handleHomeClick"
等 -
Slot 命名 优先使用功能名,其次使用位置名称。
title
:标题区域header
:头部区域footer
:底部区域content
:主体内容区域description
:描述文本区域prefix
: 前缀suffix
: 后缀append
: 添加
-
- 组件通讯
- 禁止通过
this.$parent
来访问父组件的上下文。如果子组件依赖父组件的一些内容,或许你需要的是依赖注入 (provide/inject)。 - 在大多数情况下,通过
this.$refs
来访问其它组件的上下文是可以避免的。在使用的的时候你需要注意避免调用了不恰当的组件 API,所以应该尽量避免使用this.$refs
。 - 尽量使用
props
、emit
通讯,保证数据的一个正确的流向。
-
- 组件导出
- 没编写一个组件都应该具备一个对应的导出
js
模板如下:
import CustomButton from './index.vue';
export {
CustomButton
};
const plugin = {
install (Vue, options) {
Vue.component(CustomButton.name, CustomButton);
}
};
export default plugin;
let GlobalVue = null;
if (typeof window !== 'undefined') {
GlobalVue = window.Vue;
} else if (typeof globalThis !== 'undefined') {
GlobalVue = globalThis.Vue;
}
if (GlobalVue) {
GlobalVue.use(plugin);
}
-
- 组件文档 每个组件编写好都必须有
README.md
,对应的组件使用示例以及各个api
示例,避免人员流动,使用组件还要看源码照成不必要的资源浪费。
- 组件文档 每个组件编写好都必须有
-
- 组件分格(仅个人习惯)会把每个
api
间隔用换一行隔开,会更好读(element ui
就是此风格)如下。
- 组件分格(仅个人习惯)会把每个
<template>
<div @click="onClick">
{{ name }}
<span v-if="type === TYPE_MAP.ADD">我是type1的逻辑</span>
<span v-if="type === TYPE_MAP.DELETE">我是type2的逻辑</span>
<span v-if="type === TYPE_MAP.EDIT">我是type3的逻辑</span>
</div>
</template>
<script>
const TYPE_MAP = {
ADD: 1,
DELETE: 2,
EDIT: 3,
VIEW: 4,
};
export default {
name: 'Elname',
data() {
return {
TYPE_MAP,
type: 1,
name: '测试',
}
},
props: {
isShow: {
type: Boolean,
default: false,
required: false,
},
desc: {
type: String,
default: '123',
required: false,
},
},
methods: {
onClick() {
if(type === TYPE_MAP.ADD) {
//
}
if(type === TYPE_MAP.DELETE) {
//
}
if(type === TYPE_MAP.EDIT) {
//
}
}
},
mounted() {
// 逻辑
},
computed: {
a() {
return '123'
},
b() {
return '123'
},
}
}
</script>
代码中不可少判断
再编码中可能大家会为了更快、更简洁等因素会莫名少了许多错误数据判断,导致只要是数据结构发生一丁点的变化,尼的程序就崩溃了。
比如如下:
async function getList() {
const response = getListApi();
const list = response.data.map((item) => {
return {
...item,
a: item.name,
}
});
return list;
}
-
好像看起来也没啥问题,都挺好的啊。获取接口数据给每条数据新增字段
a
。 但是这个时候假如数据结构有些许变化程序就崩溃了!! 就是说程序会死掉了。 -
那我加个
try/catch
兜底,(这个能解决程序死掉的问题,但是不是最好的处理方式),不要对能知道的错误做错误捕获。
async function getList() {
let list = []
try {
const response = getListApi();
list = response.data.map((item) => {
return {
...item,
a: item.name,
}
});
} catch (error){
console.log('getList error:' error)
}
return list;
}
- 最佳处理时增加一些判断如下(不要担心你加判断了程序就执行慢了的问题,影响不了太多的):
async function getList() {
const { data } = getListApi() || { data: [] }; // 注意这里 或者
if(data?.length) { // 增加判断
return data.map((item) => {
return {
...item,
a: item.name,
}
});
} else {
console.log('获取数据为空或者失败!')
return [];
}
}
UI 得还原
UI
一定得高度尽可能100%
还原,不要你觉得,要ued
觉得。有些开发觉得自己也不去吸UI
得颜色、间距、大小 看着设计就直接开搞,搞出来得东西上下、左右间距都没对齐,最后产品不满意,会逐渐对你失去信任,这是一份工作,不是差不多就行了。虽然样式影响不了太大事,但是会让别人觉得你这个产品不够专业, 研发不够强!!!
scss/less 嵌套
嵌套不要缩写, 不好找到具体
class
,会全局查,查不出来比如:
.item {
cursor: pointer;
&__title {
}
&__content {
}
&__footer {
}
}
优化成:(这个样查就很方便了)
.item {
cursor: pointer;
.item__title {
}
.item__content {
}
.item__footer {
}
}
转载自:https://juejin.cn/post/7237036467894468664