面试官:谈谈大家项目当中的前端代码规范吧?css
本身先想一分钟。html
前面的话前端
有些同窗在开发某个新功能时根据需求就哐哐哐(按照本身的代码风格)一顿撸。写完发现,另外一个地方也有这个模块功能,可能只是标题的颜色,字体大小不对。怎么办? 因而很鸡贼的复制粘贴过去,改吧改吧,提交代码,万事大吉!本身却是爽了,功能是按照需求如期完成了啊,没毛病。但是你却忽视了一件很重要的东西: 团队 。vue
记住,你不是一我的在写代码。node
这篇文章有别于其余教程类的文章,不是教你如何制定代码规范,也不是告诉你这样写就是错的亦或说是正确的。本文是我这些天从优化别人代码过程当中的所见和所得,凝结成文。旨在分享给你们,对号入座,而后改之。 三人行,必有我师!;择其善者而从之,其不善者而改之。 因为我是作前端的,因此只说前端代码规范,其余语言一样适用!ios
目的git
把一些常见的错误的不良的代码示例分享给你们,但愿有的改之,无则加勉。看完以后,但愿对大家有所帮助,提升本身的代码质量,每一个人都能写出一手漂亮的代码。这是这篇文章最大的目的了!github
概述web
本文将以个人亲身项目经历为例,来谈谈咱们平常开发当中,就代码层面来说,咱们应该注意的一些小细节。但愿各位看客能吸收精华去其糟粕。主要涉及的方面有:面试
我将会从以上几个方面逐一枚举和你们分享讨论。
枚举
1. 项目结构
没说以前,您不妨看下本身的项目结构是什么样的。目前咱们的项目结构是这样的:
my-project
├── .idea # 这个是编辑器生成的
├── build # Webpack 配置文件放在这里
├── config # Vue 基本配置文件放在这里
├── node_modules # 第三方依赖
├── src # 项目源码(核心文件)
│ ├── assets # 资源文件(js, css, scss)
│ ├── components # 全部组件
│ ├── js # 本身写的 js,里面各类工具类方法等
│ ├── mixins # 混合
│ ├── router # 路由
│ ├── vuex # 状态管理
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
├── static # 静态资源,通常放 img
├── theme # 主题文件,修改的 Element-UI 主题
├── .babelrc # babel 编译配置
├── .editorconfig # 代码格式
├── .gitignore # Git 提交忽略的文件配置
├── .postcssrc.js # 转换 css 的工具配置文件
├── element-variables.css # Element 全局定义的变量,不明白为啥放这儿
├── index.html # 主页模板
├── package-lock.json # 用来锁定依赖的版本号(NPM 自动生成)
├── package.json # 项目基本信息
└── README.md # 项目介绍
复制代码
复制代码
都是用vue-cli 生成的,目录结构和命名规范也就没啥可说的。可能随着时间的推移,本身会在项目里加一些东西(文件或文件夹)。拿上面咱们的项目为例来讲几点吧:
关于项目结构,我发现的就这么多。每一个项目的目录可能会不一样,这个就看大家的规范了。
2. 文件的命名
它包含文件的命名和文件夹的命名。依咱们的项目为例,我重点说下 src/components 目录下的命名,真的是五花八门:
2.1. 文件名不够语义化
这个还算正常,但仍是有些问题。这里是一些问题清单:
下面是整理事后的样子:
robot
├── addQuestion.vue
├── editQuestion.vue
├── index.vue
└── missedQuestion.vue
复制代码
复制代码
这个我就不想说了,看的我头皮发麻。从字面意思上来说,我就认识一个 TreeNode2.vue 。后面还加个 2 是什么鬼?
2.2. 文件目录不统一
这属于一类问题,即里面太乱了,不统一,问题清单:
2.3. 文件名过长
若是一个模块下就一个文件,尽可能写成 index.vue 。这里文件夹和文件同名,路由是否是很长?你在其余文件中 import 的时候是否是也不方便? 并且我发现 problemManagement 和 problemRetrieve 都属于问题管理模块,彻底能够合并到一个文件夹里啊。还有,文件夹已经代表是问题管理模块了,因此文件就不要再以 problem*** 开头了。不以为啰嗦吗? 下面是整理事后的样子:
problemManagement
│ ├── index.vue
│ ├── retrieve.vue
qualityCheckAppeal
└── index.vue
复制代码
3. 路由
咱们系统里的路由都是一级路由。举个栗子:
userManagement
├── add.vue
└── update.vue
复制代码
用户管理下有增改两个功能,不使用弹框去作的前提下,假如说 add 和 update 对应两个路由是 /addUser , /updateUser 。咱们系统地址栏是这样显示的:
// 增长用户
localhost:3030/addUser
// 修改用户
localhost:3030/updateUser?id=1
复制代码
虽然地址栏路有短看起来虽然让人舒服,可是模块多的话,就不容易区分,其实应该这样作:
// 增长用户
localhost:3030/user/add
// 修改用户
localhost:3030/user/update?id=1
...
// 总结
localhost:3030/module/function?queryString
复制代码
4. Vue 组件
关于 Vue 组件开发规范能够参考官方的风格指南。下面是咱们项目的一些问题清单和改正意见,我列举一下做为对照:
App.vue 文件:
<!-- incorrect -->
...
<style>
.el-input__icon {
cursor: pointer
}
</style>
<!-- correct -->
...
<style>
@import 'element-style-overwrite';
...
</style>
复制代码
_element-style-overwrite.scss 外部样式文件:
.el-input__icon {
cursor: pointer
}
复制代码
// incorrect
export default {
...
}
// correct
export default {
name: 'MyDialog', // 以大驼峰命名
...
}
复制代码
若是你在某个子组件中修改了全局样式,原本只想在该组件中使用,没想到形成了全局污染。等进行代码 review 的时候是很难排查的。
例如,用户管理( UserManagement.vue )组件:
<style scoped>
...
</style>
复制代码
// incorrect
components/
└── mycomponent.vue
components/
└── myComponent.vue
// correct
components/
└── MyComponent.vue
// 或者
components/
└── my-component.vue
复制代码
有的人喜欢这样写:
<style>...</style>
<template>...</template>
<script>...</script>
复制代码
也有人喜欢这样写:
<script>...</script>
<style>...</style>
<template>...</template>
复制代码
若是你想写,那好,不阻拦,拜托你统一下行不?别这个组件这个顺序,那个组件那个顺序。累不累? 这里我强力推荐你们按照官方的写法,即下面的顺序来写:
<template>...</template>
<script>...</script>
<style scoped>...</style>
复制代码
这个放在全局规范会比较好一些。为何是两个空格? 大神们都是这样作的!并且更重要的是,使用两个空格开发项目,传到 github 或者 gitlab 上排版会很好看。什么?不会设置?百度啊!你用的什么编辑器就查这个编辑器怎么设置的。
通常是统一把全局规范设置放到一个叫.editorconfig 的文件夹里,有的编辑器支持这个文件,好比: webstorm 。有的则不支持,对于不支持的编辑器,能够下载安装 editorConfig 插件,如: atom 、 sublime 、 vscode 等。
// incorrect
export default {
data () {
return {
text: 'wwwwwwww', // 这是啥?
editBoxId: null, // 很明显Id是String,这里他初始化一个 null
flag: '', // 这个表示的啥?看意思应该是个 Boolean 类型,为啥弄个 String ?
pSize: 10, // pSize 是啥?
cPage: 1, // cPage 是啥?
popCsr:true, // popCsr 是啥,恐怕如今连那个开发者本身都不知道了吧
callcenterAuthority: false, // 这么长你告诉是一个 Boolean 类型的
}
}
}
// correct
export default {
data () {
return {
text: '', // 'wwwwwwww' 没卵用删掉
editBoxId: -1, // 它应该是个 Number 类型
flag: false, // 它应该是个 Boolean 类型啊
pageSize: 10, // pSize -> pageSize 多好
currentPage: 1, // 完整写法更易懂,不是吗?
isPopcsr: true, // Boolean 类型的老是前面加个 is
isAuthority: false, // 是否受权。
}
}
}
复制代码
其实还有好多问题,我就不一一列举了。诸如此类的问题,但愿各位看客们都能吸收精华,去其糟粕。
// incorrect
export default {
props: ['node', 'size']
}
// correct
export default {
props: {
node: Object, // 对象
size: [String, Number], // 两种类型均可以
}
}
复制代码
为何说这个呢? 咱们项目中有的组件就 methods 中的代码就上千行。若是生命周期函数放在 methods 以后,拉来拉去很是不方便:
// incorrect
export default {
...
created () {},
methods: {
// 省略 1000 行代码
// ...
},
mounted () {},
beforeDestroy () {},
destroy () {},
}
// correct
export default {
...
created () {},
mounted () {},
beforeDestroy () {},
destroy () {},
methods: {
// 省略 1000 行代码
// ...
}
}
复制代码
代码中,有时候咱们须要把 this 赋给一个变量,你要么统一赋值给变量 vm ,要么统一赋值给变量 self 。别一个组件里,变来变去。
// incorrect
export default {
...
methods: {
one () {
let vm = this
},
two () {
let self = this
}
}
}
// incorrect
export default {
...
methods: {
one () {
let vm = this
// 或者
let self = this
},
two () {
let vm = this
// 或者
let self = this
}
}
}
复制代码
<!-- incorrect -->
<el-input v-model="ruleForm.maskInput" size="small" class="nodeIpt" :icon="ruleForm.maskInput ? 'circle-close':''" @click="ruleForm.maskInput = ''" @keyup.enter.native="nodesure($event,'ruleForm')"></el-input>
<!-- correct -->
<el-input
v-model="ruleForm.maskInput"
size="small"
class="nodeIpt"
:icon="ruleForm.maskInput ? 'circle-close':''"
@click="ruleForm.maskInput = ''"
@keyup.enter.native="nodesure($event,'ruleForm')">
</el-input>
复制代码
举个例子,若是咱们在 Vue 组件的 created 声明周期钩子中监听了一个点击事件,那么,当组件销毁(beforeDestroy)以前记得把这个事件释放,看代码:
export default {
...
created () {
document.addEventListener('click', this.handleClick)
},
beforeDestroy () {
document.removeEventListener('click', this.handleClick)
}
}
复制代码
把全部的异步请求方法封装成一个独立 js 文件,或者放到 Vuex 中,千万不要耦合到 Vue 组件中。由于代码量太多,会加剧组件的后期维护,各司其职很差吗?
很差的范例:
// User.vue
export default {
...
mounted () {
this.getUsers()
},
methods: {
getUsers () {
this.axios(url, data, (response) => {
// Do something
}).catch(err => {
console.error(err)
})
}
}
}
复制代码
若是项目比较小还好,我没意见,若是项目较复杂,千万别这么干。下面是推荐的作法:
// server.js
// 专门处理数据请求的文件,也就是我没常说的MVC中的 M 层
import axios from 'axios'
export default {
/**
* 获取用户列表
*/
getUsers (url, data) {
return axios.get(url, data)
}
}
// User.vue
import api from '@/api/server.js'
export default {
...
data () {
return {
users: null
}
},
mounted () {
api.getUsers((response) => {
this.users = response.data.data
}).catch(err => {
console.log(err)
})
}
}
复制代码
5. JavaScript
下面全部的错误代码示例都是从咱们的项目中发现的,捡主要的列出来一些。但愿犯一样错误的你能及时改正哦~
要语义化命名
// incorrect
var a = document.getElementById(this.lastid) // 这里的 a
var aa = true // 这是啥大家知道吗?
// corrent
let orderId = this.order.id
let currentTime = Date.now()
复制代码
// incorrent
vm.timedefault = timedvalue
vm.currentsessionid = id
// corrent
vm.timeDefault = timedValue
vm.currentSessionId = id
复制代码
上面那一坨大家知道啥意思吗?若是这个开发人员离职了,那但是坑了后来人了。因此,作开发不能本身爽了,作一个帅气和代码于一身的工程师,难道不更好吗?
// incorrect
var name = 'test';
var age = 12;
var hobby = 'sport';
// correct
var name = 'test',
age = 12,
hobby = 'sport';
复制代码
错误的范例:
// 变量
var name='test'
var arr=[]
var obj={
id:1
}
// if 判断
if(this.id==currentId){
// Do something
}
// for 循环
for(let i=0;i<arr.length;i++){
// Do something
复制代码
上面三种状况是最多见的,其余雷同。下面是正确的范例:
// 变量
var name = 'test'
var arr = []
var obj = {
id: 1
}
// if 判断
if(this.id == currentId) {
// Do something
}
// for 循环
for(let i = 0; i < arr.length; i++) {
// Do something
}
复制代码
下面是错误的范例:
// if
if(a === b){
// Do something
}
// for
for(let i = 0; i < arr.length; i++){...}
// 函数
var T = function(params){
...
}
复制代码
常见的几种状况,其余状况再也不列举。下面是正确的范例:
// if
if (a === b) {
// Do something
}
// for
for (let i = 0; i < arr.length; i++) {...}
// 函数
var T = function(params) {
...
}
复制代码
在咱们项目里,有人这样写:
// 假如 Vue 组件中有一个叫 userId 的 data 属性
if (userId != '' || userId != null || userId != undefined) {
// ...
}
复制代码
真不知道怎么想的,简单一句话不就搞定了吗?
if (userId) {
// ...
}
复制代码
不要用下面的方式之一去声明一个对象:
// incorrect
var arr = new Array() // 数组
var arr = '' // 虽然 js 是弱类型,也不能这样声明
var obj = new object() // 对象
var obj = ''
复制代码
咱们在处理异步请求的时候,必定要对 response 中的数据进行异常处理,否则控制台回报 response.data is not undefined ,咱们项目我看了下,有些地方没作处理,结果在作测试的时候,浏览器控制台一顿报错。那叫一个难看啊!
// incorrect
this.axios(url, data, (response) => {
let result = response.data.data
})
// correct
this.axios(url, data, (response) => {
if (response.data && response.data.code === 1) {
let result = response.data.data
}
}).catch(err => {
console.error(err)
})
复制代码
export default {
...
methods: {
handleClick (evt) {
// incorrect
evt.target.parentNode.innerHTML = 'test'
evt.target.style.width = '100px'
evt.target.style.height = '200px'
// correct
let target = evt.target
target.parentNode.innerHTML = 'test'
target.style.width = '100px'
target.style.height = '200px'
}
}
}
6. HTML
复制代码
项目中我见有人写个按钮竟然用 span 标签,或者一个 div 。
下面是错误的范例:
// 用 div 当按钮
<div class="btn">搜索</div>
// 在 span 里 嵌套 el-input 组件
// 这样作的同窗,确定不知道 el-input 编译后的代码是啥样的!
<span>
<el-input></el-input>
</span>
// 用 label 当标题
// label 标签是配合表单使用的
<label>标题</label>
// 加粗字体没有用原生标签
<span class="bold">我是加粗字体</span>
复制代码
下面是改正后的范例:
// 用 H5 的 button
<button class="btn">搜索</button>
// 若是要包含 el-input 组件请使用块级元素,并加上合适的 class
<div class="el-input__wrapper">
<el-input></el-input>
</div>
// h1-h6 才是标题的正确打开方式
<h2>标题</h2>
// 加粗字体请使用原生标签
// 而后使用 class 控制字体样式
<strong class="bold">我是加粗字体</strong>
复制代码
a, button {
cursor: pointer
}
复制代码
不要命个名只有你本身知道。这样会带来后期维护困难。
<!-- incorrect -->
<div class="dfdf">
<el-form class="loginForm">...</el-form>
</div>
<!-- correct -->
<div class="login-form__wrapper">
<el-form class="loginForm">...</el-form>
</div>
复制代码
<!-- incorrect -->
<el-input v-model="form.loginUser" size="small" placeholder="请输入用户名"></el-input>
<!-- 不觉的上面的代码很丑吗,我知道你或许不会这样作 -->
<!-- 但还真有人这样作 -->
<!-- 下面是改进后的代码 -->
<el-input v-model="form.loginUser" size="small" placeholder="请输入用户名"></el-input>
复制代码
代码量少尚且不说,若是一个 .vue 文件很长的话,找起来就很痛苦了。你还别说,咱们项目里就是这样没注释。
<!-- 正确的示范 -->
<template>
<div class="user-managerment__wrapper">
<!-- Header -->
<div class="header">...</div>
<!-- User table -->
<div class="user-table__wrapper">
<el-table>...</el-table>
</div>
<!-- Add user dialog -->
<div class="add-user__dialog">
<el-dialog title="新增用户">...</el-dialog>
</div>
</div>
</template>
复制代码
7. CSS
.selector {
...
}
复制代码
// Global style
html, body, a, div {
margin: 0
}
// Login style
.login button {
...
}
// User manager style
.user-manager__wrapper {
...
}
复制代码
见上面的示例
嵌套太多层级会影响性能,尽可能保证在三层如下:
// incorrect
.user-management .user-box .user-form .el-form-item .remark {
color: #42b983
}
// correct
.user-management .user-form .remark {
color: #42b983
}
复制代码
8. Git 代码提交
你们能够看我沸点。同事写的注释。但愿有问题的同窗能够及时改正哦。另外,关于 Git 如何正确的写好注释 。这里有篇文章讲的很好,你们能够看看。传送门 ->
下面举个例子,好比我此次在用户管理模块中修改了两个 bug。如何以清单的方式提交呢? 看代码:
# add file
git add src/components/userManager/index.vue
# commit
git commit -m 'fix: 用户管理模块bug修改。 清单: - 修改了列表分页的bug - 修改了当用户点击编辑按钮弹框没法显示的bug '
# push code
git push
复制代码
你千万别用下面的方式之一去提交你的代码说明:
# 说一些毫无心义的内容
git commit -m "fix: ok!"
# or 不加 fix、feat、refactor、doc、style等前缀
# 为何要加这些前缀呢?问得好!
# 是方便往后检索,当咱们以这些前缀去搜索修改日志的时候
# 是很容易的哦,微笑。
git commit -m "修改用户模块bug"
复制代码
总结
最后,给你们找了几个大厂的团队规范文档,但愿你看完可以受益多多:
以上就是我在项目当中发现的一些问题,记录下来,暂时就记录这么多吧。但愿正好看d到这篇文章的你若是也正好有以上的不良问题,请加油改正哦。当你的代码质量又提高一个档次的时候,我相信,你离前端大神之门又