The so-called no rules, no circumference, front-end time in the team code-review found that different developers at different times write a variety of code. So we came up with some code specifications that we hope will form the team’s code specifications in the future.
The purpose of the development specification
- Unified coding style, specification, improve team collaboration efficiency
- Output readable, maintainable, consistent code in a team environment
This article is published on gitthub: github.com/Michael-lzg…
HTML report
Enabling standard Mode
Use HTML5’s DocType to enable standard mode
Copy the code
Utf-8 encoding is used
<meta charset="utf-8" />
Copy the code
Preferentially use the latest version of IE and Chrome
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
Copy the code
Add a Viewport for a mobile device
<meta name="viewport" content="initial-scale=1, maximum-scale=3, minimum-scale=1, user-scalable=no" />
Copy the code
Self-closing labels do not need to be closed
For example: img, input, br, hr, etc
<img src="https://xxx.png" alt="Google" />
<br />
<input type="text" name="title" />
Copy the code
Use semantic tags
HTML tags can be semantic. Use semantic tags instead of div or P tags
<! -- bad -->
<div>
<p></p>
</div>
<! -- good -->
<header></header>
<footer></footer>
Copy the code
Attribute order requirements
HTML attributes should appear in a specific order to ensure legibility.
id
class
name
data-xxx
src, for.type, href
title, alt
aria-xxx, role
Copy the code
CSS article
BEM naming principles
- Block: modules with names and words connected by –
- Element: element, a child element of a module, connected to a block by __
- Modifier: modifier, a variant of a module that defines a special module to — connect to a block
/* For example */
.block__element{}.block--modifier{}Copy the code
Use CSS selectors effectively
Selectors should be nested at less than 3 levels
/* bad */
.page .header .login #username input{}/* good */
#username input{}Copy the code
Using CSS selectors effectively follows the following principles
- Keep it simple and don’t use too many complex selectors.
- Wildcards and attribute selectors are the least efficient and have the most elements to match, so avoid them.
- Do not decorate element tags with class selectors and ID selectors.
- Don’t sacrifice readability and maintainability for speed
- Avoid CSS expressions
Choose expensive styles carefully
High cost attributes require a lot of computation by the browser before drawing:
Box-shadows Border-RADIUS Transparency Transforms CSS FiltersCopy the code
Avoid redrawing and rearranging
When a rearrangement occurs, the browser needs to recalculate the layout position and size, which is not good for performance optimization.
Common causes to redraw rearrange properties and methods
- Add or remove visible
DOM
Elements; - Element size changes – margins, fills, borders, width, and height
- Content changes, such as users in
input
Enter text in the box - Browser window size changed
resize
When the event occurs - To calculate
offsetWidth
和offsetHeight
attribute - Set up the
style
The value of the attribute
Methods to reduce redrawing and rearrangement
- use
transform
alternativetop
- use
visibility
replacedisplay: none
Because the former only causes redrawing, the latter causes backflow (changes the layout) - Do not put attribute values of nodes in a loop as variables in the loop.
- Don’t use
table
Layout, perhaps a small change can cause the entiretable
Relayout of - Animation speed to achieve the choice, the faster the animation speed, the more reflux times, can also choose to use
requestAnimationFrame
- CSS selectors match from right to left to avoid too many layers of nodes
Javascript article
About the name
The common naming uses the small hump type naming
let userName = 'jack'
Copy the code
If I’m naming complex numbers, I need to add s, so let’s say I want to declare an array of people’s names
let names = new Array(a)Copy the code
Each constant should be named to make it easier for others to read the meaning
// good
const COL_NUM = 10
let row = Math.ceil(num / COL_NUM)
// bad
let row = Math.ceil(num / 10)
Copy the code
The naming should be semantic. If a function is named, it can be prefixed with a verb:
- Can Determines whether an action can be performed
- Has determines whether it contains a value
- Is determines whether it is a value
- Get Gets a value
- Set Sets a value
// Whether it is readable
function canRead(){
return true;
}
// Get the name
function getName{
return this.name
}
Copy the code
About Strings
Use single quotes instead of double quotes
// bad
const name = 'jack'
// good
const name = 'jack'
Copy the code
Concatenate strings with string templates instead of ‘+’
function sayHi(name) {
return 'How are you, ' + name + '? '
}
// good
function sayHi(name) {
return `How are you, ${name}? `
}
Copy the code
About array
Assign values with literals
// bad
const items = new Array(a)// good
const items = []
Copy the code
Make a shallow copy of the array with the extension operator
// bad
let arr = [1.2.3]
const len = arr.length
const copyArr = []
for (let i = 0; i < len; i += 1) {
copyArr[i] = arr[i]
}
// good
const copyArr = [...arr]
Copy the code
Use array. from to turn an array-like object into an Array.
const arrLike = { 0: 'foo'.1: 'bar'.2: 'baz'.length: 3 }
// bad
const arr = Array.prototype.slice.call(arrLike)
// good
const arr = Array.from(arrLike)
Copy the code
Using array deconstruction
const arr = [1.2.3.4]
// bad
const first = arr[0]
const second = arr[1]
// good
const [first, second] = arr
Copy the code
About the object
It is recommended to use literals for object and array creation because they are not only optimal for performance but also help save code.
// good
let obj = {
name: 'Tom'.age: 15.sex: 'male',}// bad
let obj = {}
obj.name = 'Tom'
obj.age = 15
obj.sex = 'male'
Copy the code
ES6 uses attribute value abbreviations
const lukeSkywalker = 'Luke Skywalker'
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
}
// good
const obj = {
lukeSkywalker,
}
Copy the code
Put the abbreviation for the property at the beginning of the object declaration
const anakinSkywalker = 'Anakin Skywalker'
const lukeSkywalker = 'Luke Skywalker'
// bad
const obj = {
episodeOne: 1.twoJediWalkIntoACantina: 2,
lukeSkywalker,
episodeThree: 3.mayTheFourth: 4,
anakinSkywalker,
}
// good
const obj = {
lukeSkywalker,
anakinSkywalker,
episodeOne: 1.twoJediWalkIntoACantina: 2.episodeThree: 3.mayTheFourth: 4,}Copy the code
For shallow copies of objects, it is recommended to use the extended operator… , instead of object.assign. The rest operator is recommended when deconstructing an assignment to obtain several properties specified by an object. .
// very bad
const original = { a: 1.b: 2 }
const copy = Object.assign(original, { c: 3 })
delete copy.a // Change original
// bad
const original = { a: 1.b: 2 }
const copy = Object.assign({}, original, { c: 3 }) // copy => { a: 1, b: 2, c: 3 }
// good
const original = { a: 1.b: 2 }
constcopy = { ... original,c: 3 } // copy => { a: 1, b: 2, c: 3 }
const{ a, ... noA } = copy// noA => { b: 2, c: 3 }
Copy the code
About the function
Function arguments are assigned with default values instead of conditional statements.
// good
function createMicrobrewery(name = 'Jack') {... }// bad
function createMicrobrewery(name) {
const userNameName = name || 'Jack'. }Copy the code
Use structure syntax for function arguments. The fewer the arguments, the better. If there are more than two arguments, use ES6’s destruct syntax, regardless of the order of the arguments.
// good
function createMenu({ title, body, buttonText, cancellable }) {... } createMenu({title: 'Foo'.body: 'Bar'.buttonText: 'Baz'.cancellable: true,})// bad
function createMenu(title, body, buttonText, cancellable) {
// ...
}
Copy the code
Rest syntax is preferred… “Instead of arguments
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments)
return args.join(' ')}// good
function concatenateAll(. args) {
return args.join(' ')}Copy the code
Put the default parameter assignment last
// bad
function handleThings(opts = {}, name) {
// ...
}
// good
function handleThings(name, opts = {}) {
// ...
}
Copy the code
Use arrow functions whenever possible
// bad
[1.2.3].map(function (x) {
const y = x + 1
return x * y
})
// good
[1.2.3].map((x) = > {
const y = x + 1
return x * y
})
Copy the code
About the module
Use (import/export) on nonstandard module systems
// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide')
module.exports = AirbnbStyleGuide.es6
// ok
import AirbnbStyleGuide from './AirbnbStyleGuide'
export default AirbnbStyleGuide.es6
// best
import { es6 } from './AirbnbStyleGuide'
export default es6
Copy the code
An entry is imported only once
// bad
import foo from 'foo'
/ /... Some other imports... //
import { named1, named2 } from 'foo'
// good
import foo, { named1, named2 } from 'foo'
Copy the code
In modules where there is only one export, use export Default
// bad
export function foo() {}
// good
export default function foo() {
Copy the code
The for loop
When you do a for loop, you take the length of the array, you take it in a variable, so it’s much more efficient for your code to execute, rather than having to recalculate the length of the array every time you go through the loop
// bad
for(var i = 0; i < arr.length; i++){
}
// good
for(var i = 0; len = arr.length; i < len; i++){
}
Copy the code
Vue article
Prop definitions are as detailed as possible.
The definition of a Prop should be as detailed as possible, at least specifying its type.
// bad
props: ['status']
// good
props: {
status: String
}
// better
props: {
status: {
type: String.required: true.validator: function (value) {
return ['syncing'.'synced'.'version-conflict'.'error'].indexOf(value) ! = =- 1}}}Copy the code
A key must be added for v-for traversal
In the traversal rendering of the list data, it is necessary to set a unique key value for each item, so that the internal mechanism of vue. js can accurately find the list data. When the state is updated, the new state value is compared to the old state value, locating diff more quickly.
<! -- bad -->
<ul>
<li v-for="todo in todos">{{ todo.text }}</li>
</ul>
<! -- good -->
<ul>
<li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
</ul>
Copy the code
Don’t use v-if and V-for on the same element.
V-for has a higher priority than V-if. If you have to traverse the entire array every time, it will affect the speed, especially if you need to render a small portion.
<! -- bad -->
<ul>
<li v-for="user in users" v-if="shouldShowUsers" :key="user.id">{{ user.name }}</li>
</ul>
<! -- good -->
<ul v-if="shouldShowUsers">
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
</ul>
Copy the code
The data of a component must be a function
Instances in JS are created by constructors. Each constructor can create multiple instances, so each instance inherits a method or property from the prototype. Vue’s data is actually a property on the Vue prototype that exists in memory.
When a component is reused multiple times, multiple instances are created. These instances use the same constructor if data is an object. Then all components share the same object. In order to ensure the data independence of components, each component must return an object as the state of the component through the data function, so that each time the component is reused, a new copy of data will be returned.
// bad
Vue.component('some-comp', {
data: {
foo: 'bar',}})// good
Vue.component('some-comp', {
data: function () {
return {
foo: 'bar',}}})Copy the code
Component templates should be concise in writing
Component templates should contain only simple expressions, and complex expressions should be refactored to evaluate properties or methods.
// bad
{{
fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')}}// good
// In the template
{{ normalizedFullName }}
// The complex expression has been moved into a evaluated property
computed: {
normalizedFullName: function () {
return this.fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')}}Copy the code
Instructions for
<! -- bad -->
<input v-bind:value="newTodoText" :placeholder="newTodoInstructions" v-on:input="onInput" />
<! -- good -->
<input :value="newTodoText" :placeholder="newTodoInstructions" @input="onInput" />
Copy the code
Component names are multiple words
Our custom component names need to be multiple words during development to avoid conflicts with existing and future HTML elements, since all HTML element names are single words.
// good
Vue.component('todo-item', {
// ...
})
export default {
name: 'TodoItem'.// ...
}
// bad
Vue.component('todo', {
// ...
})
export default {
name: 'Todo'.// ...
}
Copy the code
Multiple properties to branch
In JavaScript, it is a common best practice to separate multiple properties of an object with multiple lines because it is easier to read.
<! -- good -->
<MyComponent
foo="a"
bar="b"
baz="c"
/>
<! -- bad -->
<MyComponent foo="a" bar="b" baz="c" />
Copy the code
The order of element properties
Native attributes go first, instructions next, and pass parameters and methods last
- class, id, ref
- name, data-*, src, alt, for.type, href, value, max, min
- title, placeholder, aria-*, role
- required, readonly, disabled
- v-model, v-for, key, v-if, v-show, v-bind,:
- foo="a" bar="b" baz="c"
Copy the code
About styles within components
Set scope for the component style
/* bad */
<style>
.btn-close {
background-color: red;
}
</style>
/* good */
<style scoped>
.button-close {
background-color: red;
}
</style>
Copy the code
To change the style of a third-party component library, you need to add a top-level scope.
/* bad */
.ivu-input {
width: 254px ! important;
}
/* good */
.customerForm .ivu-input {
width: 254px ! important;
}
/*.customerForm is the top-level DOM of the current component */
Copy the code
About Component Architecture
The component structure follows the template, script, and style structure from top to bottom.
<template>
<div></div>
</template>
<script>
export default {}
</script>
<style lang="scss" scoped></style>
Copy the code
The method members of the script section are placed in the following order.
- name
- components
- props
- data
- methods
- computed
- watch
- created
- mounted
- update
Copy the code
Clear the timer or event listener
Because some pages in the project will inevitably encounter the need for timers or event listening. However, when leaving the current page, if the timer is not properly cleared in a timely manner, it will cause confusion of business logic and even the application is stuck. In this case, it is necessary to clear the timer event listener, that is, in the page uninstall (close) life cycle function, clear the timer.
methods:{
resizeFun () {
this.tableHeight = window.innerHeight - document.getElementById('table').offsetTop - 128
},
setTimer() {
this.timer = setInterval((a)= > { })
},
clearTimer() {
clearInterval(this.timer)
this.timer = null
}
},
mounted() {
this.setTimer()
window.addEventListener('resize'.this.resizeFun)
},
beforeDestroy() {
window.removeEventListener('resize'.this.resizeFun)
this.clearTimer()
}
Copy the code
The route was loaded lazily. Procedure
Vue is a single-page application, and many routes may be imported. In this way, the files packaged by WebPCAk are large. When entering the home page, too many resources are loaded, and the page will appear white screen, which is not good for user experience. It would be more efficient if we could split the components of different routes into separate code blocks and then load the components when the route is accessed.
{
path: '/Home'.component: (a)= > import('@/views/Home.vue')}Copy the code
Responsibility of the single
Try to make each function do one thing at a time, rather than coupling all sorts of logic together, improving the reusability and readability of individual functions. For example, each page requests data when it is loaded and is presented to the page.
// bad
methods: {
getList1() {
// to do ...
},
getList2() {
// to do ...
}
},
created() {
this.getList1()
this.getList2()
},
// good
methods: {
// Aggregate all requests in the init function
init() {
this.getList1()
this.getList2()
},
getList1() {
// to do ...
},
getList2() {
// to do ...
}
},
created() {
this.init();
},
Copy the code
Third-party UI components are introduced on demand
The third party UI components we used in the project would be too large if we directly introduced the entire component library. We can use Babel-plugin-Component and then introduce only the required components to reduce the size of the project. The following is an example of introducing Vant to a project:
1. First, install babel-plugin-Component
npm install babel-plugin-component -D
Copy the code
2. Modify.babelrc
{
"plugins": [["import", {
"libraryName": "vant"."libraryDirectory": "es"."style": true}}]]Copy the code
3. Introduce some components:
import Vue from 'vue'
import { Button } from 'vant'
Vue.use(Button)
Copy the code
Photo paper:
Use the appropriate image format.
- JPG: For content, images are mostly photos and so on.
- PNG: Suitable for decorative images, usually more suitable for lossless compression.
- GIF: Basically don’t use it except for GIF animations.
- WebP: Greatly reduces the size of images, but has compatibility issues on mobile.
Use a Sprite chart
Sprites, CSS Sprites, also known as CSS Sprites, is a CSS image synthesis technology, mainly used for small picture display.
The advantage of Sprite graph is that many small images are combined into a large image, and the backround-position attribute value is used to determine the position of the image, which can reduce HTTP requests and achieve performance optimization.
Using iconfont
Iconfont (font icon), that is, through the font way to display ICONS, mostly used for rendering ICONS, simple graphics, special fonts, etc.
When using iconFont, because only the corresponding font file needs to be introduced, this method can effectively reduce the number of HTTP requests, and the general font size is small, so the request transmission data amount is less. Instead of importing images directly, iconFont allows you to set the size, color, and other styles just like a font, without distortion.
Lazy image loading
The SRC attribute of the image is not set, but the URL of the image is hidden, for example, first write in the data-src, and when some events trigger (such as scroll to the bottom, click load image), then the actual image URL into the SRC attribute. In order to achieve the image of the lazy loading.
function lazyload() {
var images = document.getElementsByTagName('img')
var len = images.length
var n = 0 // Store the location where the image was loaded to avoid having to iterate from the first image every time
return function () {
var seeHeight = document.documentElement.clientHeight
for (var i = n; i < len; i++) {
if (images[i].getBoundingClientRect().top < seeHeight) {
// Method 2: When the viewport top of the image appears in viewport
if (images[i].getAttribute('src') = = ='images/default.jpg') {
images[i].src = images[i].getAttribute('data-src')
}
n = n + 1}}}}Copy the code
The vue project can use the Vue-Lazyload plugin to load images lazily
Global import in main.js:
import VueLazyLoad from 'vue-lazyload'
Vue.use(VueLazyLoad, {
preLoad: 1.error: require('./assets/img/error.jpg'),
loading: require('./assets/img/homePage_top.jpg'),
attempt: 2,})Copy the code
Page use
<li v-for="(item,index) in imgList">
<img v-lazy="item" alt="" />
</li>
Copy the code