ES6 coding specification

Variable declarations, constants

  • For variables that are valid only in the current scope, let declarations should be used instead of var. However, we should avoid polluting the environment by declaring too many global variables
  • Constants should be declared const, and names should follow the common convention of all uppercase letters. Const is used for data that is immutable.
  • Note that const and let are valid only in the block-level scope in which the declaration is made
/ / bad
const someNum = 123;
const AnotherStr = "Invariant string";
let SOME_ARR = ["No"."Change"."The number"."Group"];
varANOTHER_OBJ = {invariant object:true };

/ /
const SOME_NUM = 123;
const ANOTHER_STR = "Invariant string";
const SOME_ARR = ["No"."Change"."The number"."Group"];
constANOTHER_OBJ = {invariant object:true };
Copy the code

Template string

For multi-line strings, concatenating variables applies to template strings, where backquotes (‘) are more readable and easier to write

/ / bad
const multiStr = "Multiline string newline means,\n this is a newline.";
function sayHi(name) {
  return "How are you, " + name + "?";
}
console.log(multiStr);
console.log(sayHi("Zhang"));

/ /
const multiStr1 = 'Multi-line string newline indicates that this is a newline. `; // Notice how many Spaces there are in the template string
function sayHi1(name) {
  return `How are you, ${name}? `;
}
console.log(multiStr1);
console.log(sayHi1("Bill"));
Copy the code
A newline representation of a multi-line string, this is a newline. How are you, Zhang SAN? A multiline string newline means it's a newline. How are you, Li Si?Copy the code

deconstruction

1. The number of object layers in a nested structure cannot exceed three

let obj = {
  one: [{newTwo: [{three: [{four: "Too much. Dizzy.",},],},],},},};/ /
let obj = {
  one: ["two", { four: "Parse it out."}]};Copy the code

2. Object deconstruction: Object deconstruction elements have nothing to do with order. Object specifies a default value only for the identity of undefined (! == null)

01: If the function parameter is an object, use object destruct assignment

/ / bad
function someFun(opt) {
  let opt1 = opt.opt1;
  let opt2 = opt.opt2;
  console.log(opt);
}

/ /
function someFun(opt) {
  let { opt1, opt2 } = opt;
  console.log(`${opt1}add${opt2}`);
}

function someFun({ opt1, opt2 }) {
  console.log(opt1);
}
Copy the code

02: If a function has multiple return values, use object deconstruction instead of array deconstruction to avoid adding order problems

/ / bad
function anotherFun() {
  const one = 1;
  const two = 2;
  const three = 3;
  return [one, two, three];
}
const [one, three, two] = anotherFun(); // The order is out of order

/ /
function anotherFun() {
  const one = 1;
  const two = 2;
  const three = 3;
  return { one, two, three };
}
const { one, three, two } = anotherFun(); // Don't worry about the order
Copy the code

03: Declared variables cannot be used to destruct assignments

// Syntax error
let a;
{a} = {a: 123}
Copy the code

3. Array deconstruction: Array elements are sequentially related

01: Exchange variable values

let x = 1;
let y = 2;

/ / bad
let temp;
temp = x;
x = y;
y = temp;

/ /
[x, y] = [y, x]; // Swap variables
Copy the code

02: Array deconstruction is used when assigning an array member to a variable

const arr = [1.2.3.4.5];

/ / bad
const one = arr[0];
const two = arr[1];

/ /
const [one, two] = arr;
Copy the code

An array of

1. Convert array-like objects and traversable objects (such as sets and maps) into real arrays

Use array. from for conversion

/ / bad
function foo() {
  let args = Array.prototype.slice.call(arguments);
}

/ /
function foo() {
  let args = Array.from(arguments);
}
Copy the code

2. Array deduplication

ES6 provides a new data structure, Set. It is similar to an array, but the values of the members are unique and there are no duplicate values. The Set itself is a constructor used to generate the Set data structure.

Array to heavy

const arr = [3.5.2.2.5.5];
const unique = [...new Set(arr)]; / /,5,2 [3]
Copy the code

Combine the Set structure with array.from

function deduplication(arr) {
  return Array.from(new Set(arr));
}
Copy the code

The idea from array de-duplication to character de-duplication

let str = [...new Set("ababbc")].join("");
console.log(str); // 'abc'
Copy the code

In addition, Set is so powerful that it is easy to implement Union, intersection, and Difference using Set.

let a = new Set([1.2.3]);
let b = new Set([4.3.2]);

/ / and set
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}

/ / intersection
let intersect = new Set([...a].filter(x= > b.has(x)));
// set {2, 3}

/ / difference set
let difference = new Set([...a].filter(x= >! b.has(x)));// Set {1}
Copy the code

3. Array copy

Using array extensions… In the form of

const items = [1.2.3];

/ / bad
const len = items.length;
let copyTemp = [];
for (let i = 0; i < len; i++) {
  copyTemp[i] = items[i];
}

/ /
let copyTemp = [...items];
Copy the code

4. Convert a set of values to an array

Array.of is used for conversion

/ / bad
let arr1 = new Array(2); / / / the empty x 2
let arr2 = new Array(1.2.3); / / [1, 2, 3]

/ /
let arr1 = Array.of(2); / / [2]
let arr2 = Array.of(1.2.3); / / [1, 2, 3].
Copy the code

5. Flatten the nested array

Array has a method called array.flat, which requires a depth parameter to flatter the nested Array (default is 1). But if you don’t know the depth, just use Infinity as an argument. There is also a nice flatMap method.

const arrays = [[10].50[100[2000.3000[40000]]]];
arrays.flat(Infinity); // [10, 50, 100, 2000, 3000, 40000]
Copy the code

6. Array summing

let foo = [1.2.3.4.5];

/ / not elegant
function sum(arr) {
  let x = 0;
  for (let i = 0; i < arr.length; i++) {
    x += arr[i];
  }
  return x;
}
sum(foo); / / = > 15

/ / elegant
foo.reduce((a, b) = > a + b); / / = > 15
Copy the code

7. Insert elements into the array

You can use push to insert elements at the end of the array, unshift to insert elements at the head of the array, or splice to insert elements in the middle of the array.

var arr = [1.2.3.4.5];

// Insert the tail
// old method
arr.push(6);

// New method is 43% faster
arr[arr.length] = 6; 

// Insert the header
// old method
arr.unshift(0);

// New method is 98% faster
[0].concat(arr);
Copy the code

8. Arrange syllabic character strings

Javascript has a native method called sort that arranges arrays. A simple array.sort() treats each array element as a string and alphabetizes it. But when you try to organize an array of non-ASCII elements, you might get a strange result.

['Shanghai'.'New York'.'Mumbai'.'Buenos Aires'].sort();
 // ["Buenos Aires", "Mumbai", "New York", "Shanghai"] 

//method1
// Spanish
[' ' '.'árbol'.'cosas'.'fútbol'].sort();
/ / / "cosas", "futbol", "arbol," "'"] / / bad order

//method2
[' ' '.'árbol'.'cosas'.'fútbol'].sort(Intl.Collator().compare);
// [" arBOL ", "cosas", "futBOL "," unico "]
Copy the code

function

1. When using function expressions or anonymous Functions, use Arrow Functions

The arrow function is more concise and has this bound

/ / bad
const foo = function (x) {
  console.log("There is a function promotion problem.");
  console.log("foo.name"); Function expressions cannot be named, function declarations can
};

[1.2.3].forEach(function (x) {
  return x + 1;
});

/ /
const foo = (x) = > {
  console.log("There is a function promotion problem.");
  console.log("foo.name"); / / return a 'foo'
};

[1.2.3].forEach((x) = > {
  return x + 1;
});
Copy the code

01: Arrow function writing convention

If the function body has only one line of statements, it is allowed to write on the same line and remove curly braces

When a function has only one argument, it is allowed to remove the parentheses around the argument

/ /
const foo = (x) = > x + x; // Note that the default is return x + x, not return with curly braces

[1.2.3].map((x) = > x * x);
Copy the code

02: Use the arrow function to return an object wrapped in parentheses

/ / bad
let test = (x) = > {
  x: x;
}; // Curly braces become statement blocks and do not represent objects
/ /
let test = (x) = > ({ x: x }); Return {x:x}
Copy the code

2. Call the function IIFE immediately

Using the arrow function

/ / bad
(function () {
  console.log("Hello"); }) ();/ /
(() = > {
  console.log("Hello"); }) ();Copy the code

3. Use rest syntax instead of arguments… Instead of

The rest arguments are real arrays and need no conversion. Note: You cannot use arguments objects in arrow functions

/ / bad
function foo() {
  let args = Array.prototype.slice.call(arguments);
  return args.join("");
}

/ /
function foo(. args) {
  return args.join("");
}
Copy the code

4. Function parameters specify default values

Use the function default parameter assignment syntax

/ / bad
function foo(opts) {
  lopts = opts || {}; // There is the side effect of converting 0, ", etc to default values
}

/ /
function foo(opts = {}) {
  console.log("More concise, more secure.");
}
Copy the code

5. Use abbreviations for function methods in objects

More concise

/ / bad
const shopObj = {
    desc: 'Object module writing'.foo: function() {
		console.log('Methods in objects')}; };/ /
const shopObj = {
    desc: 'Object module writing'.foo() {
		console.log('Methods in objects')}; };Copy the code

6. Handle data in a functional way

Functional programming asserts that a function must take at least one argument and return a value. So all operations on data can be handled in a functional way. Let’s say we need to change the structure of the objects in array foo, then pick out the qualified objects and put them into a new array result.

let foo = [
  {
    name: "Stark".age: 21
  },
  {
    name: "Jarvis".age: 20
  },
  {
    name: "Pepper".age: 16}];// We want objects with slightly different structures, with age greater than 16:
let result = [
  {
    person: {
      name: "Stark".age: 21
    },
    friends: []}, {person: {
      name: "Jarvis".age: 20
    },
    friends: []}]// It is intuitively easy to write code like this:
let result = [];
// Sometimes even plain for loops
foo.forEach(function(person){
    if(person.age > 16) {let newItem = {
            person: person,
            friends: []; }; result.push(newItem); }})// It is much more elegant to write this function
 
let result = foo
  .filter(person= > person.age > 16)
  .map(person= > ({
    person: person,
    friends: []}));Copy the code

class

1. The class name should be written in PascalCased format

class SomeClass {}
Copy the code

2. When defining a class, the order of the methods in the class is as follows:

constructor

Public GET /set Public accessor. Set can pass only one parameter

Public methods Public methods, distinguished by function names, without underscores

Private GET /set Private accessors. Private related names should be prefixed with an underscore _

Provate methods Private methods

class SomeClass {
  constructor() {
    // constructor
  }

  get aval() {
    // public getter
  }

  set aval(val) {
    // public setter
  }

  doSth() {
    // Public method
  }

  get _aval() {
    // private getter
  }

  set _aval(val) {
    // private setter
  }

  _doSth() {
    // Private methods}}Copy the code

3. If it is not a class, do not use new

/ / bad
function Foo() {}const foo = new Foo();

/ /
class Foo(a){}const foo = new Foo();
Copy the code

4. Use the real Class notation instead of using Prototype to simulate extensions

/ / bad
function Dog(names = []) {
    this._names = [...names];
}
Dogs.prototype.bark = function() {
    const curName = this._names[0];
    alert(`one one ${curName}`);
}

/ /
class Dog(a){
    constructor(names = []){
        this._names = [...names];
	}
    bark() {
        const curName = this._names[0];
        alert(`one one ${curName}`); }}Copy the code

5. Class should be defined before use

Although class does not have the problem of hoist in the specification, conversion tools such as Babel only convert to function expressions. When hoist is used here, the parent class should be defined first and then the subclass

/ / bad
let foo = new Foo();
class Foo {}

/ /
class Foo {}
let foo = new Foo();
class SubFoo extends Foo {}
Copy the code

6. What should I pay attention to

When subclasses use the super keyword, this should be called super before the chained invocation can be implemented using a return this in a method

class Foo {
  constructor(x, y) {
    this.x = x;
    this.y = y; }}Copy the code

The module

1. Use CommonJs(import/export) to load and export modules

Those who follow the standard do not have too bad luck

// bad
const vars = require("vars");
module.exports = vars.red;

// good
import { red } from "vars";
export default red;
Copy the code

2. Ensure that each module has one and only one default export module

Convenient for callers to use

// bad
const red = '#ff0000';
export red;

// good
const red = '#ff0000';
export default red;
Copy the code

3. Import Does not use the card * to import the whole file

Make sure the relationships between modules are clear

// bad
import * as vars from "vars";

// good
import vars from "vars";
Copy the code

4. Do not mix import and export on one line

Separate import and export to make the structure clearer and more readable

// bad
export {red as default} from './varColors';

// good
import {red} from './varColors';
export default red;
Copy the code

5. Multivariable should be exported in the form of object deconstruction

Export is placed at the bottom to make the exported variable clearer

// bad
export const red = "#00ff00";
export const black = "#00ff00";
export const white = "#00ff00";

// good
const red = "#00ff00";
const black = "#00ff00";
const white = "#00ff00";

export default { red, black, white };
Copy the code

Map and dictionary data

JavaScript implements dictionary data based on Object objects. But JavaScript objects can only have strings of keys. It’s a lot of inconvenience for programming. ES6 provides Map data structures. Similar to Object, it is also a collection of key-value pairs, but the range of “keys” is not limited to strings. Various types of values, strings, values, Booleans, arrays, objects, and so on, can be used as keys.

const resultMap = new Map()
  .set(-1, {text:'less than'.color:'yellow')
  .set(0, {text:'equal to'.color:'black')
  .set(1, {text:'more than'.color:'green')
  .set(null, {text:'No items'.color:'red'})

let state = resultMap.get(null) // {text:' no object ',color:'red'}
Copy the code

The traversal order of a Map is the insertion order

const map = new Map([["F"."no"], ["T"."yes"]]);

for (let key of map.keys) {
  console.log(key);
}
// "F"
// "T"

for (let value of map.value()) {
  console.log(value);
}
// "no"
// "yes"
Copy the code

other

1. Conditional expressions

To determine whether a variable is some specified value, a regular logical expression can be very long. What I did was put the values in an array:

if (['abc'.'def'.'ghi'.'jkl'].includes(x)) {
   // Other logic
}
Copy the code

2. To simplify the if… else

if… Else is so common that many people forget that there are other ways to judge conditions. For simple variable assignments, there is no need for such a long statement.

let test = x > 10; 
// Ternary expressions can do complex conditional branching at the expense of readability:
let x = 300.let test2 = (x > 100)?'greater 100' : (x < 50)?'less 50' : 'between 50 and 100;
Copy the code

3. Null and assign the default value

If the variable is not null, undefined “, assign to the second variable, otherwise give the default value:

if(first ! = =null|| first ! = =undefined|| first ! = =' ') {
    let second = first;
}
/ / short let second = first | | '.
Copy the code

4. Simplify the switch

This technique is also commonly used to convert the switch to the key-value form of the object. The code is much cleaner:

/ / bad
switch (data) {
  case 1:
    test1();
    break;  
  case 2:    
    test2();  
    break;  
  case 3:    
    test();  
    break;  // And so on... }
// Shorthand
var data = {
  1: test1,
  2: test2,
  3: test
};

/ /
data[anything] && data[anything]();
Copy the code

5. Simplify branch condition statements

/ / bad
if (type === 'test1') {
002  test1();
}
else if (type === 'test2') {
  test2();
}
else if (type === 'test3') {
  test3();
}
else if (type === 'test4') {
  test4();
} else {
  throw new Error('Invalid value ' + type);
}

/ /
var types = {
  test1: test1,
  test2: test2,
  test3: test3,
  test4: test4
};
varfunc = types[type]; (! func) &&throw new Error('Invalid value ' + type); func();
Copy the code

5. Repeat the string N times

Sometimes a string needs to be repeated N times for some purpose, and the stupidest way is to concatenate it with a for loop. Actually, the simpler way is to repeat:

/ / bad
let test = ' '; 
for(let i = 0; i < 5; i ++) { 
  test += 'test '; 
} 
console.log(str); // test test test test test 
/ /
'test '.repeat(5);
Copy the code

Vue code specification

Wrap HTML with multiple attributes

And HTML types. When a line has many attributes, proper line breaks can improve reading and aesthetics

.custom-style {
  You can define one or more attributes in a single declaration
  background: background-clip background-color background-image
    background-origin background-position background-repeat background-size;
}
Copy the code

Css

CSS nested hierarchies

Browsers parse CSS recursively from right to left. Too deep level nesting not only affects performance, but also reduces style reading and code maintenance. Generally, the layer shelf is controlled within 5 layers

Double quotation mark priority

Values in attribute selectors must be surrounded by double quotation marks. Single or unquoted values are not allowed, and double quotation marks are recommended for HTML attribute values

.custom-style {
  font-family: "PingFang SC"."STHeitSC-Light";
}
Copy the code

Selector with {space

.costom-style { // Space between selector and {
	margin: 0; // Before the attribute value
	transform: scale(1.5.2.2); // Add Spaces after commas
}
Copy the code

Common style

.custom .header .title..other .header .title {
	color: #f0f;
}
Copy the code

CSS property order

Properties under the same rule should be grouped by function when written. And writing in order of Formatting Model > Box Model > Typographic > Visual to improve the readability of the code.

Explanation:

Relative attributes of Formatting Model include position/top/right/bottom/left/float/display/overflow, etc

Box Model attributes include border/margin/padding/width/height, etc

Typographic related attributes include: font/line-height/text-align/word-wrap and so on

Visual attributes include: background/color/transition/list-style, etc

Also, for readability, if the content attribute is included, it should be placed first.

Style through

It is common to change third-party component styles during development, but due to the style isolation of the scoped property, you may need to remove scoped or create a different style. All of these have side effects (component style contamination, lack of elegance), and style penetration is only effective when used in CSS preprocessors.

Use/deep/less

<style lang="less" scoped>
.content /deep/ .el-button {
    height: 60px; } < /style>
Copy the code

SCSS use: : v – deep

<style lang="scss" scoped>
.content ::v-deep .el-button {
    height: 60px;
}
</style>
Copy the code

Stylus used > > >

<style lang="stylus"Scoped outer layer > > > >.custom-components {
    height: 60px;
}
</style>
Copy the code

Less modifies the style based on the returned value

> p {
    color: #15eee0;
    font-size: 36px;
    font-weight: bold;

    .d2 {
        color: #ece462;
    }
    .d3 {
        color: #ff9154;
    }
    .d4 {
        color: #ff2927; }}Copy the code
// assess at this time assess 2,3,4<p> Attention status and has reached <span:class="$style[`d${assess}`]"</span> </p>Copy the code

Vue development

Data not related to rendering

By default, bidirectional data binding is implemented for data in vue. If a large amount of non-rendering data is placed directly in data, the performance of bidirectional data binding will be lost.

For example, the columns data in the table can be extracted from an external JS file as a configuration file, or a constant can be defined in the current VUE file to define the columns data, because the data is fixed and will not be modified anyway. Freeze should be used for wrapping, both to improve performance and to extract fixed data. This is also recommended for some fixed data at the front of the drop-down box

const columnList = Object.freeze([
  {
    title: "Name".key: "name".align: "center"}, {title: "Gender".key: "gender".align: "center",}]);Copy the code

Note that object.freeze () can still be used to replace references to variables when the value is frozen. You can also use this syntax to ensure that the data does not change.

Control of the Modal box

A page usually has many bullet boxes with different functions. If each bullet box sets a corresponding variable to control its display, it will lead to the number of redundant variables and naming difficulties. You can use a variable to control the display of all Modal bullet boxes in the same page

For example, there are three Modal popboxes on a page

// bad
// Each data control corresponds to Modal display and hide
new Vue({
  data() {
    return {
      modal1: false.modal2: false.modal3: false}; }});// good
// When modalType is the corresponding value, the corresponding pop-up box is displayed
new Vue({
  data() {
    return {
      modalType: "".// modalType is modal1, modal2, modal3}; }});Copy the code

Debounce use

For example, in remote search, data is dynamically obtained through an interface. If the interface requests each user input, bandwidth and performance are wasted. If a button is clicked for multiple times, multiple events are triggered

import {debounce} from 'lodash'

method: {
    remoteMethod: debounce(function (query) {
     	//todo
     	// This is not a problem
    },200),}Copy the code

Use of pictures

In the process of functional development, image processing is often a relatively easy to be ignored, but also affect the efficiency of development and page performance to a certain extent

1. The problem of image compression, unless special requirements of the image must be high quality display, otherwise should carry out the corresponding compression processing

2. Select image formats for different business scenarios

01:JPG: suitable for presenting colorful images. JPG images are often used as large background images, rotating images or Banner images

02:PNG: Logo, simple color and strong contrast image or background, need transparency, etc

03: Combine commonly used small pictures with low change frequency into Sprite images, and base64 processing is carried out for pictures with frequent changes and those less than 6KB

04: According to the number of project pictures and user model distribution of the project, webP is considered for picture processing

Route component parameters are transmitted

Using $route in a component makes it highly coupled to its corresponding route, limiting its flexibility by limiting its use to certain urls

Decouple components and routes using props:

Replace coupling with $route

const User = {
  template: "<div>User {{ $route.params.id }}</div>"};const router = new VueRouter({
  routes: [{ path: "/user/:id".component: User }],
});
Copy the code

Decoupled by props

This allows you to use the component anywhere, making it easier to reuse and test.

const User = {
  props: ["id"].template: "<div>User {{ id }}</div>"};const router = new VueRouter({
  routes: [{path: "/user/:id".component: User, props: true },

    // For routes that contain named views, you must add the 'props' option for each named view:
    {
      path: "/user/:id".components: { default: User, sidebar: Sidebar },
      props: { default: true.sidebar: false}},]});Copy the code

The Select optimized

Note that the options label should be kept on the same line during the drop-down list. If there is a line break, the selected value will be left blank

<! -- bad --><Select :remote-method="remoteMethod">
    <Option v-for="item in temoteList" :value="item.value" :key="item.id">
        {{item.label}}
    </Option>
</Select>
Copy the code

You need to keep the Options and dropdown values on the same line

<! -- good --><Select :remote-method="remoteMethod">
    <Option v-for="item in temoteList" :value="item.value" :key="item.id">			{{item.label}}
    </Option>
</Select>
Copy the code

Data Data hierarchy

Data data has a data hierarchy structure, do not excessively flat or nested level too deep, if too flat will lead to data namespace conflict, parameter transfer and processing, if too deep nested level will also lead to vUE data hijacking recursive level too deep, be careful of the problem of recursive stack burst. Moreover, too deep level will lead to inconvenient data operation and processing, and the acquisition of data for fault tolerance is also cumbersome. Generally, it is best to keep 2-3 levels.

If there is only one layer of data, it is too flat

{
    name: ' '.age: ' '.gender: ' '
}
Copy the code

The processing is not convenient

// passed as an interface parameter
ajax({
 this.name, this.age, this.gender
})

// Interface to obtain data, batch processing
ajax().then(res= > {
 const {name, age, gender} = res.data
    this.name = name
    this.age = age
    this.gender = gender
})
Copy the code

Proper hierarchy not only increases the maintainability and readability of code, but also the ease of operation and processing

{
    person: { // Personal information
        name: ' '.age: ' '.gender: ' '}}Copy the code

You can operate on Person

// passed as an interface parameter
ajax(this.person);

// Interface to obtain data, batch processing
ajax().then((res) = > {
  const { name, age, gender } = res.data;
  this.$set(this."person", { name, age, gender });
});
Copy the code

The strategy pattern

The use of policy mode, to avoid excessive if else judgment, can also replace simple logic switch

const formatDemandItemType = (value) = > {
  switch (value) {
    case 1:
      return "Basic";
    case 2:
      return "Senior";
    case 3:
      return "VIP"; }};// Policy mode
const formatDemandItemType2 = (value) = > {
  const obj = {
    1: "Basic".2: "Senior".3: "VIP"};return obj[value];
};
Copy the code

deconstruction

Deconstruction assignment and default value. When the number of deconstruction is less than what, it is suitable to directly deconstruct and assign default value, whether the data should be aggregated

const { name = "", age = 10, gender = "man" } = res.data;

// bad
this.name = name;
this.age = age;
this.gender = gender;

// good
this.person = {
  name,
  age,
  gender,
};
Copy the code

Single responsibility principle

Try to do one thing for a function at any time, rather than coupling all the logic together, improving the reusability and readability of individual functions

created() {
  this.init();
},
methods: {
  // Aggregate all request behavior in init function
  // Split each request separately
  init() {
    this.getList1()
    this.getList2()
  },
  getList1() {
    // to do ...
  },
  getList2() {
    // to do ...}}Copy the code

Set the key value for V-for

Always use a key with v-for. A key must always be used with v-FOR on a component to maintain the state of the internal component and its subtrees. Even maintaining predictable behavior on elements, such as object constancy in animation, is a good practice.

/ / are:
<ul>
	<li
		v-for="todo in todos"
		:key='todo.id'
	>
		{{ todo.text }}
	</li>
</ul>

/ / the case:
<ul>
	<li
		v-for="todo in todos">
		{{ todo.text }}
	</li>
</ul>
Copy the code

Avoid v-if and V-for

Never use v-if and V-for on the same element. We tend to do this in two common situations:

  • 01: To filter items in a list (for example, v-for=”user in users” v-if=” user.isactive “). In this case, replace Users with a calculated property (such as activeUsers) and have it return the filtered list.
  • 02: To avoid rendering lists that should be hidden (such as v-for=”user in users” v-if=”shouldShowUsers”). In this case, move the V-if to the container element (such as ul, OL).
/ / are:
<ul v-if="sshouldShowUsers">
	<li
		v-for="user in users"
		:key='user.id'
	>
		{{ user.name }}
	</li>
</ul>

/ / the case:
<ul>
	<li
		v-for="user in users"
		:key='user.id'
		v-if="sshouldShowUsers"
	>
		{{ user.name }}
	</li>
</ul>
Copy the code

Set the scope for the component style

Styles in top-level App components and layout components can be global to an application, but all other components should be scoped. This rule applies only to single-file components. You don’t have to use the Scoped feature. Scopes can also be set via CSS Modules. However, for component libraries, we should prefer class-based strategies to scoped features. This makes it easier to override internal styles: it uses a class name that people can understand, doesn’t have too high a selector priority, and is less likely to cause conflicts.

/ / are:
<template>
	<button class="c-Button c-Button--close">X</button>
</template>

<!--useBEMconvention-->
<style>
.c-Button {
    border: none;
    border-radius: 2px;
}

.c-Button--close {
	background-color: red
}
</style>

/ / the case:
<template>
	<button class="btn btn-close">X</button>
</template>

<style>
.btn-close {
	background-color: red
}
</style>

<template>
	<button class="button button-close">X</button>
</template>

<style scoped>
.button {
    border: none;
    border-radius: 2px;
}

.button-close {
	background-color: red
}
</style>
Copy the code

Global state Management

Global state should be managed through Vuex in preference to this.$root or a global event bus.

  • However, it is not absolute that the global event bus cannot be used
Is:// store/modules/todos.js
export default {
  state: {
    list: []},mutations: {
    REMOVE_TODO (state, todoId) {
      state.list = state.list.filter(todo= >todo.id ! == todoId) } },actions: {
    removeTodo ({ commit, state }, todo) {
      commit('REMOVE_TODO', todo.id) } } } <! -- TodoItem.vue --><template>
  <span>
    {{ todo.text }}
    <button @click="removeTodo(todo)">
      X
    </button>
  </span>
</template>

<script>
import { mapActions } from 'vuex'

export default {
  props: {
    todo: {
      type: Object.required: true}},methods: mapActions(['removeTodo'])}</script>
Copy the code
Example:// main.js
new Vue({
  data: {
    todos: []},created: function () {
    this.$on('remove-todo'.this.removeTodo)
  },
  methods: {
    removeTodo: function (todo) {
      var todoIdToRemove = todo.id
      this.todos = this.todos.filter(function (todo) {
        returntodo.id ! == todoIdToRemove }) } } })Copy the code

Simplify the expression in template

Component templates should contain only simple expressions, and complex expressions should be refactored to evaluate properties or methods. Complex expressions can make your templates less declarative. We should try to describe what should happen, not how to calculate that value. And evaluating properties and methods makes code reusable.

/ / are:<! {{normalizedFullName}}// Complex expressions have been moved to a calculated property
computed: {
    normalizedFullName: function() {
        return this.fullName.split(' ').map(function(word) {
            return word[0].toUpperCase() + word.slice(1)
        }).join(' '); }}/ / the case:
{{
    fullName.split(' ').map(function(word) {
        return word[0].toUpperCase() + word.slice(1)
    }).join(' ');
}}
Copy the code

Evaluate properties as simply as possible

/ / are:
computed: {
    basePrice: function() {
        return this.manufactureCost / (1- this.profitMargin);
    },
    discount: function() {
        return this.basePrice * (this.discountPercent ||0);
    },
    finalPrice: function() {
        return this.basePrice - this.discount; }}/ / the case:
computed: {
    price: function() {
        var basePrice = this.manufactureCost / (1- this.profitMargin);
        return (
            basePrice - basePrice * (this.discountPercent ||0); }}Copy the code

Instructions for

Both abbreviate instructions (: for V-bind: and @ for V-on 🙂

/ / are:
<input @input="onInput" @focus="onFocus"></input>

/ / the case:
<input v-bind:value="newTodoText" :placeholder="newTodoInstructions"></input>
Copy the code

The order of the top-level elements of a single-file component

Single-file components should always let

<! -- ComponentA.vue --><template>.</template>
<script> / *... * / </script>
<style> / *... * / </style>
Copy the code

Try to use keys in v-if/ V-if-else/V-else

If a set of V-if + V-else elements are of the same type, it is best to use key (such as two elements)

Elements).

/ / are:
<div v-if="error" key="search-status"Error: {{error}} </div><div v-else key="search-results">
    {{ results }}
</div>

/ / the case:
<div v-if="error">Error: {{error}}</div>
<div v-else>
    {{ results }}
</div>
Copy the code

Element selector in scoped

Element selectors should be avoided in scoped. In the Scoped style, class selectors are better than element selectors because element selectors are slow to use in large quantities.

/ / are:
<template>
	<button class="btn btn-close">X</button>
</template>

<style scoped>
.btn-close {
	background-color: red
}
</style>

/ / the case:
<template>
	<button>X</button>
</template>

<style scoped>
button {
	background-color: red
}
</style>
Copy the code

Use form form validation in the table

<el-form :class="$style.form" :model="ruleInfo" label-width="12px" ref="form"> 
    <el-table :data="ruleInfo.list">
         <el-table-column label="Warning value">
            <template slot-scope="scope">
                <el-form-item label="" :prop="`list.${scope.$index}.value`"
                   :rules="[{required: true, message: 'Warning value cannot be empty ', type: 'number', trigger: 'blur'}, {validator: (rule, value, callback) => valueValidate( scope.row,value, callback), trigger: 'blur' } ]">
                </el-form-item>
            </template>
         </el-table-column>
    </el-table>
</el-form>
Copy the code
 valueValidate(item, value, callback) {
     if () {
     	callback(new Error(' '));
     } else{ callback(); }}Copy the code

The idea of componentization

As long as there is a build system that can concatenate files, separate each component into a file. When you need to edit a component or look up its usage, you can find it more quickly.

/ / are:
components/
|- TodoList.vue
|- TodoItem.vue

/ / the case:
Vue.component('TodoList', {
	// ...
})

Vue.component('TodoItem', {
	// ...
})
Copy the code

Lifecycle of Vue parent component

In the case of parent components, knowing the parent component’s lifecycle hook loading order allows the developer to do the right thing for the parent component at the right time

<template>
  <div>
    <h3>home</h3>
    <list @hook:mounted="listMounted" />
  </div>
</template>

<script>
import List from './list'

export default {
  name: "home".components: {
    List
  },
  methods: {
    listMounted(){
      console.log('------------ listMounted'); }},beforeCreate() {
    console.log("home beforeCreate");
  },
  created() {
    console.log("home created");
  },
  beforeMount() {
    console.log("home beforeMount");
  },
  mounted() {
    console.log("home mounted");
  },
  beforeDestroy() {
    console.log("home beforeDestroy");
  },
  destroyed() {
    console.log("home destroyed"); }}</script>
Copy the code

Child components

<template>
  <div>
    list
  </div>
</template>

<script>
export default {
  naem: "list".beforeCreate() {
    console.log("list beforeCreate");
  },
  created() {
    console.log("list created");
  },
  beforeMount() {
    console.log("list beforeMount");
  },
  mounted() {
    console.log("list mounted");
  },
  beforeDestroy() {
    console.log("list beforeDestroy");
  },
  destroyed() {
    console.log("list destroyed"); }}</script>
Copy the code

The loading order of the parent and child components during loading

home beforeCreate --> home created --> home beforeMount --> list created --> list beforeMount --> list mounted
Copy the code

The order in which parent and child components are destroyed

home beforeDestroy --> list beforeDestroy --> list destroyed --> home destroyed
Copy the code

In the actual development process, the parent component will be notified when the child component completes a life cycle, and then the parent component will do the corresponding processing

emit up

// The child component publishes the event in the corresponding hook
created(){
  this.$emit('done')}// The parent component subscribes to its message
<list @done="childDone">
Copy the code

hook

Listen for the life cycle of the child component via @hook

<list @hook:mounted="listMounted" />
Copy the code

Component names are multiple words

Component names should always be multiple words, except for the root component App.

/ / is
export default {
	name: 'TodoItem'.// ...
}

/ /
export default {
	name: 'Todo'.// ...
}
Copy the code

Component data data is a function

The component’s data must be a function. When using the data attribute in a component (anywhere but new Vue), its value must be a function that returns an object.

/ / is
// In a.vue file
export default {
    data() {
        return {
            foo: 'bar'}}}It is possible to use objects directly on the root instance of a Vue, since only one such instance exists
new Vue({
    data: {
        foo: 'bar'}})/ /
export default {
    data: {
        foo: 'bar'}}Copy the code

Prop definition

Prop definitions should be as detailed as possible. In your submitted code, the definition of prop should be as detailed as possible, or at least specify its type.

/ / is
props: {
    status: String
}
// There is a better way:
props: {
    status: {
        type: String.required: true.validator: function(value) {
            return [
                'syncing'.'synced'.'version-conflict'.'error'].indexOf(value) ! = = -1]}}}/ /
// This is acceptable only for developing prototype systems
props: ['status']
Copy the code

Component uppercase

The filename of a single-file component should either always start with the word uppercase (PascalCase)

/ / are:
components/
|- MyComponent.vue

/ / the case:
components/
|- myComponent.vue
|- mycomponent.vue
Copy the code

The underlying component name needs to be specific

Underlying components that apply specific styles and conventions (that is, components that present classes without logic or stateless) should all start with a specific prefix, such as Base, App, or V.

/ / are:
components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue

/ / the case:
components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
Copy the code

Singleton component name

Components that should only have a single active instance should be named with The prefix to indicate their uniqueness. This does not mean that components can only be used on a single page, but only once per page. These components never accept any prop because they are customized for your application, not their context in your application. If you find it necessary to add prop, that means it is actually a reusable component that is currently only used once per page.

/ / are:
components/
|- TheHeading.vue
|- TheSidebar.vue

/ / the case:
components/
|- Heading.vue
|- MySlidebar.vue
Copy the code

Tightly coupled component name

Child components that are tightly coupled to the parent component should be named prefixed with the parent component name. If a component only makes sense in the context of a parent component, this relationship should be reflected in its name. Because editors usually organize files alphabetically, doing so puts related files together.

/ / are:
components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue

components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue

/ / the case:
components/
|- SearchSidebar.vue
|- NavigationForSearchSidebar.vue
Copy the code

Word order in component names

Component names should start with high-level words and end with descriptive modifiers.

/ / are:
components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue

/ / the case:components/ |- ClearSearchButton.vue |- ExcludeFromSearchInput.vue |- LaunchOnStartupCheckbox.vue |- RunSearchButton.vue  |- SearchInput.vue |- TermsCheckbox.vueCopy the code

The component name in the template is always PascalCase

/ / are:<! -- In single-file components and string templates --><MyComponent />

/ / the case:<! -- In single-file components and string templates --><mycomponent /><! -- In single-file components and string templates --><myComponent />
Copy the code

Component names should tend to be full words rather than abbreviations

/ / are:
components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue

/ / the case:
components/
|- SdSettings.vue
|- UProfOpts.vue
Copy the code

Parent-child component communication

Parent component communication should take precedence over this.$parent or changing prop via prop and events.

  • Note that ** is “preferred” **, not absolute

Other code specifications

  1. Do not store xxx.copy files locally: If you delete unnecessary code in a timely manner, Git will keep a historical record. There is no need to save the copy version and unnecessary code locally.

  2. Remove useless CSS: After page structure changes, if the internal content of a div is removed as a component and placed in another VUE file, remember to remove the CSS from the original file.

  3. Reduce HTML useless nesting: for example, the following only need one layer to fix, set three layers; CSS also has three layers

    <div :class="$style.ehvOnline"> <div :class="$style.main"> <! <div :class="$style.equBox"> <div :class="$style.headTitle"> <span :class="$style.equName"> </span> <span :class="$style.equValue">{{ equName }}</span> </div> <big-tab ref="bigTabComp" :options="tabConf" @tabClick="tabNameClick"></big-tab> </div> <div :class="$style.imgBox"> <component :is="currentComp" :current-node="currentNode"></component> </div> </div> </div> </div> <style lang="less" module> .ehvOnline { width: calc(100% - 318px); height: 98%; display: flex; flex-direction: column; border-radius: 3px; .main { width: 100%; height: 850px; display: flex; background-color: #01373b; .mainRight { flex: 1; height: 100%; .equBox { .headTitle { height: 42px; line-height: 42px; .equName { font-size: 18px; color: #30f0e3; font-weight: bold; margin-right: 10px; } .equValue { font-size: 16px; color: #30f0e3; margin-right: 50px; } } } .imgBox { height: 730px; overflow: auto; } } } } </style>Copy the code
  4. Component separation and CSS layout should be business-oriented, otherwise it will increase the complexity of data interaction and component data interaction;

  5. Proper use of CSS selectors

    <div :class="$style.atlasBody"> <div :class="$style.leftBox"><img src="@/assets/images/dBone.png" alt="" /></div> <div :class="$style.rightBox"><img src="@/assets/images/dBtwo.png" alt="" /></div> </div> .atlasBody { height: calc(100% - 40px); display: flex; .leftBox { width: 734px; margin-right: 10px; } .rightBox { flex: 1; } .leftBox, .rightBox { background: #042f30; position: relative; > img { width: 80%; height: 80%; position: absolute; top: 50px; left: 50px; }}}Copy the code

    Could you write it like this:

    .atlasBody { height: calc(100% - 40px); display: flex; > div { background: #042f30; } .leftBox { margin-right: 10px; } img { height: 100%; }}Copy the code
  6. Valid comment

    The following 2,6 is an invalid comment, so it doesn’t make any sense

    EquName = newval. equName; // 1. data.equId = newVal.equId; Value = {equId: newval.equid, phaseList: newVal.newPhaselist}; / / 3. Switch the TAB bigTabComp. Value && bigTabComp. Value. ResetTab (); IsShowColum. Value = false; getCheckboxColumList(newCols); queryTableBodyData(newProps.currentNode? .equId); Tabphasedata. value = newProps. CurrentNode? .phaseList; Const name = ref('') // 7 Const stationName = ref('')Copy the code
  7. Proper naming: Business related parts, named after business component names