Nezha front end weekly No. 001

preface

Nezha front end weekly No. 001

Are you still using this in computed?

In the calculated attribute, use this.xxx to get the data in data and the methods in methods. Maybe you can also use this.route to get the data in the route. In fact, we can avoid these ugly this, which will even bring us invisible performance problems. In terms of implementation, the data we can access through this can be structured on the first parameter of computed.

How to avoid using v-if and v-for together?

Why avoid using v-if and v-for on the same element at the same time? Because there is a section of code in the source code of vue that deals with the priority of instructions, this section of code deals with v-for first and then v-if. Therefore, if we use two instructions together in the same layer, there will be some unnecessary performance problems. For example, there are 100 pieces of data in the list. In some cases, they do not need to be displayed. When vue still cycles the display of 100 pieces of data, and then judge v-if. Therefore, we should avoid this situation.

$attrs and $listeners let you encapsulate components like a duck to water

Contains attribute bindings (except class and style) in the parent scope that are not recognized (and obtained) as props. When a component does not declare any prop, all parent scope bindings (except class and style) will be included here, and internal components can be passed in through v-bind="$attrs" - very useful when creating high-level components.

Receive all binding properties except props declaration (except class and style)

With v-bind="$attrs", you can continue to pass attributes down

Contains v-on event listeners in the parent scope (without. native modifiers). It can pass in internal components through v-on="$listeners" - very useful when creating higher-level components.

Receives all event listeners except those with the. native event modifier

You can continue to pass event listeners down through v-on="$listeners"

The browser rendering process is as follows

  1. Parse HTML, generate DOM tree, parse CSS, generate CSSOM tree
  2. Combine the DOM tree and CSSOM tree to generate a render tree
  3. Layout: according to the generated rendering tree, perform layout to obtain the geometric information (position and size) of the node
  4. Painting: obtain the absolute pixels of the node according to the geometric information obtained from the rendering tree and reflow
  5. Display: send pixels to GPU and display them on the page.

In order to build the rendering tree, the browser mainly completes the following work:

  1. Each visible node is traversed from the root node of the DOM tree.
  2. For each visible node, find the corresponding rules in the CSSOM tree and apply them.
  3. According to each visible node and its corresponding style, the combination generates a rendering tree.

In the first step, since we talked about traversing the visible nodes, we must first know what nodes are invisible. Invisible nodes include:

  • Some nodes that do not render output, such as script, meta, link, etc.
  • Some nodes hidden through css. For example, display:none. Note that nodes hidden by visibility and opacity will still be displayed in the rendering tree. Only the nodes of display:none are not displayed on the render tree.

Note: the render tree contains only visible nodes

Before reflow, we construct a rendering tree. We combine the visible DOM nodes and their corresponding styles, but we also need to calculate their exact position and size in the device viewport. The stage of this calculation is reflow.

[Vue event bus: this.$bus.$emit and this.$bus.$on]

1. Create Vue instance

copy//main.js
Vue.prototype.$bus = new Vue();

2. Launch event

copy//GoodsList
this.$bus.$emit("aaa")

3. Listening events

copy//home.vue
this.$bus.$on("aaa",()=>{
   this.$refs.scroll.scroll.refresh()
})

4. Example: monitor picture loading

copy//GoodsListItem.vue
<template>
<img :src="showImage"
             alt=""
             @load="imgLoad" />
</template>


imgLoad() {
      if (this.$route.path.indexOf("/home") !== 1) {
        this.$bus.$emit("homeImgLoad");
      } else if (this.$route.path.indexOf("/detail") !== 1) {
        this.$bus.$emit("detailImgLoad");
      }
    },
copy//home.vue
mounted() {
    const refresh = debounce(this.$refs.scroll.refresh, 50);

    this.$bus.$on("homeImgLoad", () => {
      refresh();
    });
  },
copy//detail.vue
mounted() {
    const refresh = debounce(this.$refs.scroll.refresh, 50);
    this.$bus.$on("detailImgLoad", () => refresh());
  },

pinyin-engine

This is a simple and efficient Pinyin matching engine. It can use pinyin to quickly retrieve the data in the list.

  1. Index and cache mechanism are used to realize millisecond data retrieval on the client
  2. Its dictionary data format is compressed, and the simplified Chinese version is only 17 kb in size (Gzip)
  3. Support multi tone characters and Pinyin initial matching
  4. The simplified version covers 6718 Chinese characters and the traditional Chinese version covers 20846 Chinese characters

https://www.npmjs.com/package/pinyin-engine

JavaScript Array map() method

Each element in the array is multiplied by the value specified in the input box and returns a new array:

var numbers = [65, 44, 12, 4];

function multiplyArrayElement(num) {
    return num * document.getElementById("multiplyWith").value;
}

function myFunction() {
    document.getElementById("demo").innerHTML = numbers.map(multiplyArrayElement);
}

JS array flattening (flat) method

Array.prototype.flat() is used to "flatten" nested arrays into one-dimensional arrays. This method returns a new array without affecting the original data.

[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]

By default, flat() will "flatten" only one layer. If you want to "flatten" multi-layer nested arrays, you can write the parameters of flat() method as an integer to represent the number of layers you want to flatten, which is 1 by default.

[1, 2, [3, [4, 5]]].flat()
// [1, 2, 3, [4, 5]]
[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]

In the above code, the parameter of flat() is 2, which means to flatten two layers of nested arrays.

If you want to convert to a one-dimensional array no matter how many layers of nesting, you can use the Infinity keyword as a parameter.

[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]

If the original array has empty bits, the flat() method skips the empty bits.

[1, 2, , 4, 5].flat()
// [1, 2, 4, 5]

The flatMap() method executes a function on each member of the original array, which is equivalent to executing Array.prototype.map(), and then executes the flat() method on the array composed of return values. This method returns a new array without changing the original array.

// Equivalent to [[2,4], [3,6], [4,8]]. Flat ()
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]

flatMap() can only expand one layer of array.

flatMap() is similar to map(), but its callback returns a flat one-dimensional array (if the depth parameter is not specified).

const scattered = [ "my favorite", "hamburger", "is a", "chicken sandwich" ];
 
// map() returns the nested array results in nested arrays
const huh = scattered.map( chunk => chunk.split( " " ) );
console.log( huh ); // [ [ "my", "favorite" ], [ "hamburger" ], [ "is", "a" ], [ "chicken", "sandwich" ] ]
 
const better = scattered.flatMap( chunk => chunk.split( " " ) );
console.log( better ); // [ "my", "favorite", "hamburger", "is", "a", "chicken", "sandwich" ]

[difference between for in and for of]

for...in loop: only the key name of the object can be obtained, but not the key value

for...of loop: allows traversal to obtain key values

var arr = ['red', 'green', 'blue']
for(let item in arr) {
  console.log('for in item', item)
}
/*
  for in item 0
  for in item 1
  for in item 2
*/
for(let item of arr) {
  console.log('for of item', item)
}
/*
  for of item red
  for of item green
  for of item blue
*/

forEach()

image.png

find method in JS

usage

find() Method returns the value of the first element of the array that passed the test (judgment within the function).

If there are no qualified elements, return undefined

find() For an empty array, the function does not execute.

find() The original value of the array is not changed.

array.find(function(currentValue, index, arr),thisValue)´╝îamong currentValue Is the current item, index Is the current index, arr Is the current array

1636532033(1).png

[vue project realizes local storage of token s in combination with vuex and localstorage]

  • When logging in for the first time, the back-end server determines that the user account password is correct, generates a token according to the user id, user name, defined secret key and expiration time, and returns it to the front-end;
  • The front end gets the token returned by the back end and stores it in localStroage and Vuex;
  • Each time the front-end route jumps, it judges whether the localstrap has a token. If not, it jumps to the login page. If yes, it requests to obtain user information and change the login status;
  • Each time an interface is requested, a token is carried in the Axios request header;
  • The back-end interface judges whether the request header has a token or not. If there is no token or the token expires, it returns 401;
  • The front end gets the 401 status code and redirects to the login page.

Maintain and supplement Vuex status between page reloads.

vuex-persistedstate

Usage

import { createStore } from "vuex";
import createPersistedState from "vuex-persistedstate";

const store = createStore({
  // ...
  plugins: [createPersistedState()],
});
import Vue from 'vue'
import Vuex from 'vuex';
import createPersistedState from 'vuex-persistedstate';

Vue.use(Vuex)

const store = new Vuex.Store({
state: {
count: 0
},
plugins: [createPersistedState()],
mutations: {
increment: state => state.count++,
decrement: state => state.count--
}
});

new Vue({
el: '#app',
computed: {
count() {
return store.state.count;
}
},
methods: {
increment() {
store.commit('increment');
},
decrement() {
store.commit('decrement');
}
}
});
import Vue from 'vue'
import Vuex from 'vuex';
import createPersistedState from 'vuex-persistedstate';
import Cookies from 'js-cookie';

Vue.use(Vuex)

const store = new Vuex.Store({
state: {
count: 0
},
plugins: [createPersistedState({
storage: {
getItem: key => Cookies.get(key),
setItem: (key, value) => Cookies.set(key, value, { expires: 3, secure: true }),
removeItem: key => Cookies.remove(key)
}
})],
mutations: {
increment: state => state.count++,
decrement: state => state.count--
}
});

new Vue({
el: '#app',
computed: {
count() {
return store.state.count;
}
},
methods: {
increment() {
store.commit('increment');
},
decrement() {
store.commit('decrement');
}
}
});

[JavaScript replace multiple spaces with 1 space]

// Replace multiple spaces with one space
let value = '1    Zhang San';
value = value.replace(/ +/g, ' ');
console.log(value);
// Output: 1 sheet 3

JS cookie Chinese document

image.png

image.png

Properties supported by the set method

  1. expires Define the validity period. If you pass in Number, the unit is day. You can also pass in a Date object to indicate the validity period to the time specified on Date. By default, cookie s are valid until the user exits the browser.
  2. path string, indicating which address this cookie is visible to. The default is "/".
  3. domain string, indicating which domain name this cookie is visible to. After setting, the cookie will be visible to all subdomains. By default, it is visible to the domain name and subdomain name that created this cookie.
  4. secure true or false, indicating whether cookie transmission only supports https. The default is No. the protocol must be https.

Asynchronous queue

var funcs = [func1, func2, func3];
var funcPromise = funcs.map(function(func, i) {
    return new Promise(function(resolve) {
        func();
        console.log('func'+(i+1)+' well done!');
        resolve();  //If func is an asynchronous method, you need to define resolve in the callback of the method
    });
});
Promise.all(funcPromise).then(function() {
    console.log('all well done');
});

Better, you can use async/await directly

var funcs = [func1, func2, func3];
(async () => {
    for(let i=0;i<funcs.length;i++) {
        await funcs[i]();
        console.log('func'+(i+1)+' well done');
    }
    console.log('all well done');
})()
// Build queue
function queue(arr) {
 var sequence = Promise.resolve()
 arr.forEach(function (item) {
  sequence = sequence.then(item)
 })
 return sequence
}
 
// Execution queue
queue([a, b, c])
 .then(data => {
  console.log(data)// abc
 })

Data access across projects

Save the required data to the local storage, and Vue reads the data from the local storage

The traditional approach is to set the domain name that needs to be cross domain in the domain attribute of the cookie, so that the cookie can be shared among multiple sites, that is, the login status can be shared in this way. This method is relatively simple and fast, but one defect is that the sites sharing cookies need to be the same top-level domain name

After logging in under my domain name, when you jump to another domain name that needs to share the login status, you can carry the token together. In this way, the target site obtains the carried token and stores it. In this way, it is considered to realize the shared login status. But this also has a defect, that is, if you log in under the xx1 site and have a token, if you don't jump to the xx2 site through the link of the xx1 site, but directly visit the xx2 site, you can't carry the token

export function setToken(token) {
  return Cookies.set("token", token, { domain: ['localhost', '127.0.0.1'].includes(document.domain) ? document.domain:".xxx.com"
}

Proxy proxy using webpack

devServer: {
    disableHostCheck: true,   // If there is a cross request between host and hosts, you need to ignore the host check in webpack
    proxy: {
        'api/': {
            target: 'www.bbb.com', // Destination host of the final request
            changeOrigin: true, // The default is false, and the header of the original host is saved
            secure: false   // When the default value is true, the back-end server that does not accept the https protocol and the certificate is invalid
        }
    }
}

Because this scheme does not check the request header protocol, there will be CSRP attacks, which is only suitable for the development stage.

In multiple application systems, you only need to log in once to access other mutually trusted application systems.

The full English name of Single Sign On is Single Sign On, or SSO for short.

Single sign on in the same domain

Generally, an enterprise has only one domain name, and different systems are distinguished by secondary domain names. For example, we have a domain name called a.com and two business systems: app1.a.com and app2.a.com. To do single sign on (SSO), we need a login system called sso.a.com.

As long as we log in at sso.a.com, app1.a.com and app2.a.com will also log in. Through the above login authentication mechanism, we can know that logging in to sso.a.com actually records the login status in the session on the server side of sso.a.com, and writes cookies under sso.a.com on the Browser side. So how can we log in to app1.a.com and app2.a.com? Here are two questions:

  • Cookie s cannot cross domains. The domain attribute of our cookies is sso.a.com, which cannot be brought when sending requests to app1.a.com and app2.a.com.
  • sso, app1 and app2 are different applications. Their session s exist in their own applications and are not shared.

So how do we solve these two problems? To solve the first problem, after sso logs in, you can set the Cookie domain as the top domain, that is. a.com, so that all sub domain systems can access the cookies in the top domain. When setting cookies, we can only set the top domain and our own domain, not other domains. For example, we can't set cookies for the domain of baidu.com in our own system.

The Cookie problem has been solved. Let's take a look at the session problem. We log in to the sso system and then visit app1. The Cookie is also brought to the Server of app1. How can the Server of app1 find the session corresponding to this Cookie? Here we need to share the sessions of the three systems. There are many solutions for sharing sessions, such as spring session. In this way, the second problem is also solved.

Single sign on under the same domain is realized, but this is not a real single sign on.

vue-scrollto

image.png

Object.assign() method in ES6

Object merge The Object.assign method is used to merge objects and copy all enumerable attributes of the source object to the target object. The following code demonstrates:

image.png

If null and undefined cannot be converted to Object, an error will be reported under the console

Object.assign(null);  // report errors
Object.assign(undefined);  // report errors

For object merging, if the source object is null or undefined, no error will be reported during object merging. The merging of the object will be skipped and the target object will be returned directly.

var obj = {a: 1};
console.log(Object.assign(obj, null) === obj); // true
console.log(obj); // {a: 1}

var obj = {a: 1};
console.log(Object.assign(obj, undefined) === obj); // true
console.log(obj); // {a: 1}

If it is a combination of numeric, Boolean, and string objects, no error will be reported, but the string will be expressed in the form of array. Let's first look at the code of the numerical merging object as follows:

var obj = {a: 1};
console.log(Object.assign(obj, 12) === obj); // true
console.log(obj); // {a: 1}

The Boolean merge object code is as follows:

var obj = {a: 1};
console.log(Object.assign(obj, true) === obj); // true
console.log(obj); // {a: 1}

The string merge object code is as follows:

var obj = {a: 1};
console.log(Object.assign(obj, "bcd") === obj); // true
console.log(obj); // {0: 'b', 1: 'c', 2: 'd', a: 1}

In the above code, only strings and objects are merged, because only strings have wrapped objects, which will produce enumerable type properties

Therefore, the Object.assign method is a shallow copy, not a deep copy. That is, if the value of an attribute of the source object is an object, the target object copies the reference of the object. For example, the following code:

var o1 = {a: {b: 1} };
var o2 = Object.assign({}, o1);
o1.a.b = 2;
console.log(o2.a.b); // 2

[Object.freeze()]

The Object.freeze() method is used to freeze an object. Modifying the properties of the object is prohibited

You can freeze an object. A frozen object can no longer be modified; If an object is frozen, you cannot add new attributes to the object, delete existing attributes, modify the enumerability, configurability and Writeability of existing attributes of the object, and modify the value of existing attributes. In addition, after freezing an object, the prototype of the object cannot be modified

  • Object.freeze() takes an object as a parameter and returns the same immutable object. This means that we cannot add, delete or change any properties of the object.
  • Object.freeze() is to make an object immutable.

Object.freeze() is "shallow freeze"

image.png

Object.freeze() prevents Vue from implementing a responsive system

When a Vue instance is created, it adds all the attributes that can be found in its data object to Vue's responsive system. When the values of these attributes change, the view will produce a "response", that is, the match is updated to the new value. However, if Object.freeze() is used, it will prevent the modification of existing properties, which also means that the response system can no longer track changes.

[formData parameter]

FormData and content type: multipart / form data

  1. The FrmData type is actually defined at the XMLHttpRequest Level 2. It facilitates the serialization of tables and the creation of data in the same format as the form (for XHR transmission, of course).
  2. Form data: it is multipart / form data in the http request. It will process the form data into a message, with labels as units and separators. You can upload both key value pairs and files. When the uploaded field is a file, there will be content type to the table name file type; Due to boundary isolation, multipart / form data can upload both files and key value pairs. It adopts the method of key value pairs, so multiple files can be uploaded.
var form = new formData();

At this point, you can call the append(key, value) method to add data to the form instance. First, we should clarify the data form stored in formData. A pair of keys / values form a piece of data. The key is unique, and a key may correspond to multiple values. If form initialization is used, each form field corresponds to a piece of data, their HTML name attribute is the key value, and their value attribute corresponds to the value value.

form.append('checked', 'A')

form.append('checked', 'B')

form.append('userName', 'Susan')

// The form key value pair should be:
// checked: ['A', 'B']
// userName: 'Susan'

The transmitted data is encapsulated in a method named objToFormData. The code is as follows:

/**
 * objToFormData
 * @param {Object}
 * @returns {formData}
 * Convert interface parameters to formData format
 */
export const objToFormData = (obj) => {
    let data = new FormData()
    for (let i in obj) {
        data.append(i, obj[i])
    }
    return data
}

async function

The return value of the async function is the promise object

Because the return value of the async function is a promise object (Promise.resolve(value)), you need to obtain the value value through the then() function

Note that the then() function is called with the return value asyncFun() of the async function, which must be enclosed in parentheses

After using await, you can get the value of Promise.resolve(value) directly without calling the then() function

Use try... Catch to catch exceptions, which is used in async functions

Use Promise.catch() to catch exceptions, which is used outside the async function

Posted on Mon, 29 Nov 2021 01:58:13 -0500 by samshel