Basic knowledge address (continuously updated) : juejin.cn/post/686307…

webpack

What is loader?

Loader is essentially a function that converts the received content and returns the converted result. Because Webpack only knows JavaScript, the Loader acts as a translator, preprocessing the translation of other types of resources.

Loader configures test and use in module.rules. Test accepts a regular expression, and only the modules on the regular match use this rule. Use accepts an array containing the loader used by the rule.

Common loader:

  • File-loader allows us to import image resources such as PNG \ JPG in JS files
  • Url-loader is similar to file-loader. The only difference is that the user can set a threshold for the file size. If the threshold is larger than the threshold, publicPath is returned as file-loader. If the threshold is smaller than the threshold, base64 file encoding is returned.
  • Style-loader csS-loader: import require() @import/url; Style-loader inserts the style into the DOM by inserting a style tag into the head and writing the style into the innerHTML of the tag.
  • Sass-loader converts SCSS to CSS
  • Less-loader converts less to CSS
  • Babel-loader intermediate bridge that tells WebPack how to handle JS by calling the API in Babel /core.
    • Babel is a toolchain for converting ECMAScript 2015+ version code into backwardly compatible JavaScript syntax so it can run in current and older versions of browsers or other environments.
    • @babel/core is the core library of Babel. All the core apis are in this library. These apis are called by babel-loader
    • The main configuration fields for @babel/preset-env are useBuiltIns and target; Target represents the environment in which the code to be compiled will run. It can be a browser or node. As long as the corresponding fields are set, it can escape the corresponding syntax and API according to the rules. UseBuiltIns: no need to manually import ‘@babel/polyfill’; The new API used by the business code is polyfilled as needed.
    "@babel/env", { targets: { "browsers": ["> 1%", "last 2 versions", "not IE <= 8"] //Copy the code
    • @babel/preset-env just provides rules for syntactic transformations, but it doesn’t compensate for some new features that browsers are missing.

    Original code:Just @ Babel/preset – env@babel/polyfill “useBuiltIns”: “usage”

Custom loader segmentfault.com/a/119000001…

Plugin

Plugin is a plug-in, based on the event flow framework Tapable, plug-in can extend the function of Webpack, in the life cycle of Webpack running will broadcast many events, Plugin can monitor these events, at the appropriate time through the API provided by Webpack to change the output result.

Common plugins:

  • Html-webpack-plugin automatically generates HTML5 files and introduces js files packed by Webpack.
  • Clean-webpack-plugin is used to empty the dist folder before packaging
  • Hot-module-replacement -plugin module Hot-module-replacement plugin, that is, HMR, webpack4 plug-in, does not need to be installed. It is used with devServer in development mode
  • The mini-CSs-extract-plugin extracts CSS into a separate file, similar to the extract-text-webpack-plugin (deprecated webPack4). The advantages of the mini-CSS-extract-Plugin are as follows:
    • Asynchronous loading
    • No duplicate compilation (performance)
    • Easier to use
    • Specific CSS
  • PurgecssPlugin can remove unused CSS. It is usually used with glob and glob-all.
  • Optimize – CSS -assets-webpack-plugin for CSS compression
  • Commons-chunk-plugin is used to extract common js code (webpack4 has been deprecated). Reduce the overall resource volume; Properly sharded code can make better use of the client-side cache.
  • Split-chunk-plugin is used to extract common code in JS. Webpack4 built-in plug-in. Advantages over commons-chunk-Plugin:
    • From imperative to declarative
    • Optimised commons-chunk-plugin for asynchronously extracting public module code (not extracting public modules of asynchronous code correctly).
  • Webpack-bundle-analyzer Visualizes the volume of webpack output files

Mp.weixin.qq.com/s/WfW_L0Qs1… www.cnblogs.com/guolao/arch… Blog.csdn.net/weixin_4390… www.cnblogs.com/susouth/p/1…

Webpack hot update principle

Command line does not support the HMR webpack itself, we can use the webpack cooperate HotModuleReplacementPlugin open HMR – dev – server:

const webpack = require('webpack');
module.exports = {
	plugins: [
    	new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
    	hot: true}}Copy the code

In a local development environment, the browser is the client, and Webpack-dev-Server (WDS) is our server. The core of HMR is that the client pulls updated resources from the server. (To be precise, HMR pulls not the entire resource file, but the chunk diff, the part of chunk that needs to be updated.

In effect, WDS maintains a Websocket with the browser, and when a local resource changes, WDS pushes an update event to the browser, along with a hash built this time, for the client to compare with the last resource. The client compares whether the file changes based on the hash value. If there is a difference, the client issues a request to WDS to get a list of the files, which modules have changed. The client can then use this information to get incremental updates of chunks from WDS.

Once the client gets the chunk updates, there is a very important question: how does the client handle these incremental updates? Which states need to be preserved and which need to be updated? This can be handled by the relevant API (such as module.hot.accept) according to its own scenario. React-hot-loader and Vue-loader also use these apis to implement HMR.

Webpack build process

The running flow of Webpack is a sequential process, from start to finish:

  • Initialization parameters: Read and merge parameters from configuration files and Shell statements to get the final parameters

  • Start compiling: Initialize the Compiler object with the parameters obtained in the previous step, load all configured plug-ins, and execute the object’s run method to start compiling

  • Define entry: Locate all entry files according to the entry in the configuration

  • Compiling modules: Starting from the entry file, call all configured Loader to translate the module, and then find out the module that the module depends on. Repeat this step until all the entry dependent files are processed in this step.

  • Complete module compilation: After using Loader to translate all modules in Step 4, the final content of each module after translation and the dependencies between them are obtained.

  • Output resources: Assemble chunks containing multiple modules according to the dependencies between entries and modules, convert each Chunk into a separate file and load it into the output list. This step is the last chance to modify the output content.

  • Output complete: After determining the output content, determine the output path and file name based on the configuration, and write the file content to the file system.

In the above process, Webpack broadcasts a specific event at a specific point in time, the plug-in executes specific logic after listening for the event of interest, and the plug-in can call the API provided by Webpack to change the results of The Webpack run.

Simple said.

  • Initialization: From start build, read and merge configuration parameters, load Plugin, instantiate Compiler

  • Compilation: Starting from Entry, the corresponding Loader is successively called for each Module to translate the content of the file, and then the Module that the Module depends on is found and compiled recursively

  • Output: Combine compiled modules into chunks, convert chunks into files, and output them to the file system.

Source code analysis article: juejin.cn/post/684490…

module chunk bundle

  • Module: each source file, everything in Webpack is a module
  • Chunk: Multiple chunks are merged. Places where chunks can be set, such as Entry, import(), and splitChunks
  • Bundle: Final output file

Optimize packing efficiency

  • Optimize babel-loader: Enable caching and specify packaging scope
  • IgnorePlugin: Avoid referencing useless modules
  • NoParse avoids repeated packaging
  • HappyPack multi-process packaging
  • ParallelUglyPlugin For multi-process compression of JS
  • Automatically refresh
  • Automatically updated (new code generation, web page won’t refresh, status is not lost) : webpack dev – server and HotModuleReplacementPlugin
  • DllPlugin: Build the same version only once, not every time.

Optimized output code

  • Small images are converted to Base64 encoding by urL-loader
  • Bundle and hash hit cache (contentHash)
  • Lazy loading
  • Extract common code (splitChunks)
  • IgnorePlugin
  • Use CND acceleration
  • Using production mode
  • Scope: Smaller code volume; Create functions with less scope; The code is more readable. (ModuleConcatenationPlugin)
  • Gzip compression (CompressionWebpackPlugin)

Javascript higher-order

Event loop

JS tasks are divided into synchronous tasks and asynchronous tasks:

  • Task queues are divided into synchronous task queues and asynchronous task queues.
  • During code execution, the synchronized code will be directly pushed into the synchronization task queue and executed successively.
  • Asynchronous code (such as setTimeout and setInteval) will be directly pushed into the asynchronous task queue.
  • When the synchronization task queue is complete, the tasks in the asynchronous task queue are pushed to the synchronization task queue and executed in sequence

The JS task queue is divided into: macro task: setTimeout setInterval microtask: promise.then method. Note that new Promise() is synchronized and executes immediately.

Note: There are now three queues: synchronous queue (also known as stack), macro task queue, and micro task queue. Therefore, for this mechanism, js event loop mechanism should look like this:

  • When the synchronization code is encountered, push the synchronization queue in turn and execute
  • When setTimeout setInterval is encountered, it is pushed to the macro task queue
  • If dot then is encountered, it’s treated as a microtask and pushed into the microtask queue
  • After the synchronization queue is complete, the task is fetched from the microtask until the microtask queue is empty. Then check the macro task queue, go to the macro queue to fetch tasks, and each macro task will run to the micro task queue, see if there is a new micro task, if there is, then the micro task empty. And so on.

Synchronize code – > Microtasks (all to be executed) – > macro tasks (one to be executed) – > Microtasks (all to be executed) – > macro tasks (one to be executed)

  console.log('script start')

  async function async1() {
    await async2()
    console.log('async1 end')}async function async2() {
    console.log('async2 end')
  }
  async1()

  setTimeout(function() {
    console.log('setTimeout')},0)

  new Promise(resolve= > {
    console.log('Promise')
    resolve()
  })
    .then(function() {
      console.log('promise1')
    })
    .then(function() {
      console.log('promise2')})console.log('script end')
Copy the code
Script start async2 end Promise Script end AsynC1 end promise1 promise2 setTimeoutCopy the code

Async function async1(){… } new Promise(resolve=>{… ; Resolve ()}) code. Is the synchronization code. New Promise(). Then (res=>{… }); Is a microtask, which is put into the microtask queue, waiting to be executed. This is consistent with what I explained in another blog post juejin.cn/post/688367… Here’s another example of homemade:

  async function asyncf1() {
    console.log("async1 start");
    await asyncf2();
    console.log("async1 middle")
    return "hello async"
  }

  async function asyncf2() {
    console.log("async2 start");
    return "hello async222"
  }
  asyncf1().then(res= >{
    console.log(res);
  });

  console.log("tongbu");
Copy the code

Order of execution:

  async1 start
  async2 start
  tongbu
  async1 middle
  hello async
Copy the code

Promise application

Write a Promise

Juejin. Cn/post / 691571…

Promise loading images

    function loadImg(url){
      return new Promise((resolve, reject) = > {
        var imgDom = document.createElement("img");
        imgDom.src = url;
        // Image loading success callback
        imgDom.onload = () = >{
          resolve(imgDom);
        }
        // Image loading failed callback
        imgDom.onerroe = (error) = >{
          reject(error)
        }
        document.body.appendChild(imgDom); })}const url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603026217111&di=fb11837b4633e99c0b71ff48b5213cf1&i mgtype=0&src=http%3A%2F%2Fa0.att.hudong.com%2F56%2F12%2F01300000164151121576126282411.jpg";
    loadImg(url).then(res= >{
      console.log(res.width);
    }, error= >{
      console.log(error)
    })
Copy the code

Promise native XHR request

   function promiseGet(url) {
        return new Promise((resolve, reject) = >{
          const xhr = new XMLHttpRequest();
          xhr.open('GET', url, true);
          xhr.send();
          xhr.onreadystatechange = function () {
            // 4 Response completed; 0: The request is not initialized and open() has not been called. 1: The request has been established, but has not been sent. Send () has not been called.
            // 2: The request has been sent and is being processed (usually you can now get the content header from the response). 3: The request is being processed.
            if(xhr.readyState === 4) {/ / success
              if(xhr.status===200){
                resolve(xhr.response);
              }
            }
          }
          xhr.onerror = () = >{
            reject(xhr.response);
          }
          xhr.upload.onprogress = function (e) {
           const percent = (e.loaded / e.total) * 100;
           console.log("percent: " + percent)
          }
        })
    }
    const url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603026217111&di=fb11837b4633e99c0b71ff48b5213cf1&i mgtype=0&src=http%3A%2F%2Fa0.att.hudong.com%2F56%2F12%2F01300000164151121576126282411.jpg";
    promiseGet(url).then(res= >{
      console.log(res);
    }).catch(error= >{
      console.log("error...", error)
    })
Copy the code

Handwritten publish-subscribe model

class EventHub{
    cache = {};
    on(eventName, fn){
    	this.cache[eventName] = this.cache[eventName] || [];
        this.cache[eventName].push(fn);
    }
    emit(eventName, data){(this.cache[eventName]||[]).forEach(fn= >fn&&fn(data));
    }
    off(eventName, fn){
    	const index = indexOf(this.cache[eventName], fn);
        if(index==-1) {return;
        }
        this.cache[eventName].splice(index, 1); }}function indexOf(arr, item){
	if(arr===undefined) {return -1;
    }
    let index = -1;
    for(let i=0; i<arr.length; i++){if(arr[i]===item){
        	index = i;
            break; }}return index;
}

Copy the code

Vue

Omit the abbreviation

V – short for bind

  <! -- Complete syntax -->
  <a v-bind:href="url"></a>
  <! - for - >
  <a :href="url"></a>
Copy the code

V – on abbreviation

  <! -- Complete syntax -->
  <a v-on:click="doSomething"></a>
  <! - for - >
  <a @click="doSomething"></a>
Copy the code

Difference between V-show and V-if

  • V-show is a CSS switch, display: none; V-if is completely destroyed and recreated, not created when v-if=”false”
  • Frequent switching is v-show; V-if is used when the runtime changes less

Bind class methods

  1. Bind :class=”{‘orange’: isRipe}” //orange is the name of class, isRipe is the variable
  2. Array methods v-bind:class=”[‘class1’, class2]” //class1 is the class name, class2 is the variable
  3. Inline v – bind: style = “{color: color}”

Why is component data a function

Why does data in a component have to be a function and then return an object, while data in a New Vue instance can be an object?

Because components are used for reuse, objects in JS are reference types, so there is no scope isolation; The instance of new Vue is not reused, so there is no object reference problem.

Watch and computed

  • Watch: When one data change affects multiple data, watch is used. Example: Search for data
    • The wACTH configuration items are: Handler deep Immediate
    • “Deep” : indicates whether to listen deeply
    • Immediate: Indicates whether to execute the command immediately. True means that the listener function is also executed when the value is first bound. For example, when the parent component transmits values dynamically to its child components and the child component obtains the default value from the parent component for the first time, the function needs to be executed. In this case, set immediate to true
  • Computed: Compute when an attribute is affected by more than one attribute; Example: Shopping cart checkout

keep-alive

Keep-alive is a built-in Vue component that is used to preserve component state or avoid re-rendering.

  • Props:
    • Include: string or regular expression. Only components with matching names are cached.
    • Exclude: indicates a string or regular expression. Any component with a matching name will not be cached.
  <keep-alive include="a">
   <component>
    <! -- Component with name a will be cached! -->
   </component>
  </keep-alive>You can preserve its state or avoid re-rendering<keep-alive exclude="a">
   <component>
    <! All components except a will be cached! -->
   </component>
  </keep-alive>You can preserve its state or avoid re-rendering<keep-alive include="a">
    <router-view>
      <! Only view A components whose path matches will be cached! -->
    </router-view>
  </keep-alive>
Copy the code

v-model

V-models are syntactically sugar, and v-models on a component are equivalent to prop: Value and input events.

  <testComp v-model="initMsg"></testComp>/ / equivalent to the<testComp v-bind:value="initMsg" v-on:input="initMsg=$event"></testComp>
Copy the code

Unidirectional data flow

All prop forms a one-way downlink binding between their parent prop: updates to the parent prop flow down to the child, but not the other way around. This prevents accidental modification of the parent’s state from the child. Additionally, every time the parent component changes, all prop in the child component will be refreshed to the latest value. This means that you should not change a prop inside a child component. If you do, Vue will issue a warning in the browser console.

Component communication

Father and son components

The parent component passes data to its children through props, and the children send information to the parent through events.

  // Subcomponent item.vue
  export default {
    name: "Item".props: {
      content: {
        type: String.default: "item"}},methods: {
      change(){
        this.$emit('changeContent'."new msg"); }}}Copy the code
  <! -- Parent component -->
  <Item :content="content" v-on:changeContent="fChange"></Item>
Copy the code

The parent component V-ON subscribes to the event changeContent, and the child component $emit fires the event to send the message.

Any component

$emit(“fnName”, data); $emit(“fnName”, data) Other components Components subscribe to the event fnName via event.$on(“fnName”, callback) and trigger the callback function callback.

//event.js
import Vue from 'vue';
export default new Vue();
Copy the code

Release event:

   / / component A
  change(){
    event.$emit("changeVersion"."3.0");
  },
Copy the code

Any other component subscribes to the changeVersion event and remember to unsubscribe in the beforeDestroy event.

  mounted(){
    event.$on("changeVersion".this.alertVersion)
  },
  beforeDestroy(){
    event.$off("changeVersion")},Copy the code

The life cycle

  • BeforeCreate /created before and after creation
    • Created Data and Methods are already initialized; If you want to use methods in methods or manipulate data in data, you can do it in this phase at the earliest
  • BeforeMount/Mounted before and after loading
    • Mounted Indicates that the Vue instance is initialized. In this case, the component exits the creation phase and enters the running phase. If we want to manipulate DOM nodes on the page through plug-ins, we can do so at this stage at the earliest.
  • BeforeUpdate /update
    • BeforeUpdate: When executing this hook, the data displayed in the page is old, the data in data is updated, and the page has not yet been synchronized with the latest data
    • Updated: The data displayed on the page is updated with the data in data
  • BeforeDestory/Destroyed before and after destruction
    • BeforeDestory: The Vue instance moves from run to destroy, where all data and methods, instructions, filters… They’re all available. It hasn’t really been destroyed yet
    • Destroyed: all data, methods, commands, filters… They are all unavailable. The component has been destroyed.

Parent component life cycle

Loading the rendering process

Parent beforeCreate -> Parent created -> parent beforeMount -> child beforeCreate -> child created -> child beforeMount -> Child Mounted -> parent Mounted

Child component update process

Parent beforeUpdate -> Child beforeUpdate -> Child updated -> Parent updated

Destruction of the process

Parent beforeDestroy -> Child beforeDestroy -> Child destroyed -> Parent destroyed

BeforeDestroy What needs to be done

  • Unbind custom eventsevent.$off
  • Clear timer
  • Unbind custom DOM events, such as those on Windows.

Precautions for detecting changes

In Vue2.0, Object data responds by using Object.defineProperty to track whether the contents of the key of the Object are changed or not. New attributes and deleted attributes cannot be traced.

var vm = new Vue({
	el: '#el'.methods: {
    	action(){
        	// Cannot be detected
        	delete this.obj.name;
            // Cannot be detected
            this.obj.age = 12; }},data: {
    	obj: {
        	name: 'zhangsan'}}})Copy the code

In Vue2.0, arrays are responsive by intercepting seven methods of data (push, POP, Shift, unshift, splice, sort, reverse). Rather than listening for changes to each key (array is ordinal) based on Object.defineProperty. Therefore, we can not directly modify the content of the array subscript and modify the length of the array by using length, which can not realize the dynamic response of the data.

	// Cannot be tracked
    this.list[0] = 12;
    // Cannot be traced
    this.list.length = 0;
Copy the code

In the source code of Vue2.0, arrays respond as follows:

// Utility functions
function def(obj, key, val, enumerable){
    Object.defineProperty(obj, key, {
        value: val,
        enumerable:!!!!! enumerable,writable: true.configurable: true})}const hasProto = '__proto__' in {};
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
['push'.'pop'.'shift'.'unshift'.'splice'.'sort'.'reverse'].forEach(function(method){
    const original = arrayProto[method];
    Object.defineProperty(arrayMethods, method, {
        value: function mutator(. args){
            console.log("here")
            return original.apply(this, args);
        },
        enumerable: false.writable: true.configurable: true})});const arrayKeys = Object.getOwnPropertyNames(arrayMethods);

function copyAugment(target, src, keys){
    for(let i=0; i<keys.length; i++){constkey = keys[i] def(target, key, src[key]); }}const arr = [2.5.13.90];
if(Array.isArray(arr)){
	__proto__ / / support
    if(hasProto){
        arr.__proto__ = arrayMethods;
    } else{
        copyAugment(arr, arrayMethods, arrayKeys);
    }
}

arr.push(4);
console.log(arr);
console.log(arrayMethods);
Copy the code

You can see that there are two cases depending on whether the browser supports __proto__. If the browser supports __proto__, the seven intercepted methods are passed arr._proto_ = arrayMethods; Put seven interception methods on the prototype object of the ARR. If not, the seven interception methods are set directly on arR objects. In this way, the user can be heard manipulating the array in any of the seven ways.

$nextTick

Instead of updating the DOM directly when Vue observes data changes, it starts a queue (microtask) to update the DOM. So if you use a for loop to dynamically change the data 100 times, it only applies the last change. Without this mechanism, the DOM would have to be redrawn 100 times. (Vue.js updates the DOM using asynchronous update queues)

$nextTick takes a callback function as an argument that will defer the callback until after the next DOM update cycle. Put the callback function into an asynchronous queue. Vue prioritizes native Promise.then, MutationObserver, and setImmediate depending on the current browser environment. If none is supported, setTimeout is used instead.

In the Vue2.5 source code, MacroTask degrades through setImmediate, MessageChannel, and setTimeout

The realization principle of VUE’s nextTick method is as follows:

  • Vue uses an asynchronous queue to control when DOM updates and nextTick callbacks are executed
  • Due to its high-priority nature, MicroTask ensures that the microtasks in the queue are completed before an event loop
  • Considering compatibility, Vue made a demotion scheme from microtask to Macrotask
  / / simulation nextTick
  const callbacks = [];
  // Variable control microTimerFunc executes only once in a single event loop.
  let pending = false;
  function flushCallbacks(){
      pending = false;
      const copies = callbacks.slice(0);
      callbacks.length = 0;
      for(let i = 0; i < copies.length; i++){ copies[i]() } }let microTimerFunc;
  const p = Promise.resolve();
  microTimerFunc = () = >{
      p.then(flushCallbacks)
  }
  function nextTick(cb, ctx){
      callbacks.push(() = >{
          if(cb){
              cb.call(ctx)
          }
      })
      if(! pending){ pending =true;
          microTimerFunc()
      }
  }
  // Test it
  nextTick(function(){
      console.log(this.name);
  }, {name: 'Berwin'});
  console.log("start...");
  nextTick(function(){
      console.log(this.name);
  }, {name: 'lisi'});
Copy the code

Diff algorithm in VUE

The data detection principle of VUE is that it can know where a certain data is used, and when the data changes, it can directly notify the corresponding Watcher for modification. So why do we need diff? Because the granularity is too fine, there will be many watchers observing a state at the same time, there will be some memory overhead, and there will be some tracking overhead, so Vue. Js 2.0 adopts a medium granularity solution. The state detection is no longer refined to a specific node, but to components, which render views internally through the virtual DOM. This can greatly reduce the number of dependencies and the number of watchers.

What is a virtual node? A virtual node (vNode) is a common object in Javascript whose properties hold some of the data needed to generate a DOM node.

In Vue. Js 2.0 version, when the component updates the rendering, it will compare the newly created virtual nodes with the virtual nodes cached in the last rendering, and then update only the real DOM nodes that need to be updated according to the comparison results, so as to avoid unnecessary DOM operations and save certain performance. This is the comparison algorithm and this is the diff algorithm.

When the diff algorithm is used to compare the old and new nodes, the comparison will only be performed at the same level, not across levels.

<div>
    <p>123</p>
</div>

<div>
    <span>456</span>
</div>
Copy the code

The code above compares two divs at the same level and p and SPAN at the second level, but it does not compare div and SPAN. A graphic image seen elsewhere:

Diff algorithm source code execution functions are: patch (oldVnode, vnode) -> patchVnode (oldVnode, vnode) -> updateChildren (parentElm, oldCh, newCh)

More details: juejin.cn/post/684490…

Why use key in V-for

According to the diff algorithm above, vUE decides whether to reuse the real DOM node according to the tag and key of the virtual DOM. If a key is not used in v-for, the diff algorithm will only use the tag to determine whether to reuse the real DOM node. If the tag stays the same and the content is changed, there will be a problem. Vue will fool itself into thinking that the real DOM is available and will simply reuse the real DOM. Look at the following example:

In this example, the components are generated by the SPAN, input, and Button tags. There is no key in V-for, and when the page is updated, the old virtual DOM is [1, 2, 3] and the new one is [1, 3]. The first data will be reused; Since each component does not have a unique id as a key, the diff algorithm will first compare the second data of the old virtual DOM with the second data of the new virtual DOM, and the tag will directly reuse the real DOM node as well. The page information is incorrect.

So, using key in V-for can:

  1. In the virtual DOM algorithm, vNodes are identified when old and new nodes are compared.
  2. If keys are not used, Vue uses an algorithm that minimizes additions or deletions and tries to repair/reuse elements of the same type whenever possible. (Reuse the real DOM element with the same tag in place).
  3. With key, the elements with the same key value are reused directly.
  4. A component with a key can trigger transition effects, as well as trigger the component’s declaration cycle.

Details To identify the uniqueness of the component and make the diff algorithm more accurate, use a unique key instead of index or random in the for loop.

Vue rendering process

First render:

  • The parse template isrenderfunction
  • Trigger reactive, listeningdataGetter setter for property
  • performrenderFunction, will generatevnodeAnd render the page

Update render:

  • Modify data, triggersetter
  • To performrenderFunction to generate a newvnode
  • Diff algorithm versus old and newvnode, update the page

Vuex principle

Vuex extracts the shared state of components and manages it in a global singleton pattern. At the heart of every Vuex application is the Store. A Store is basically a container that contains most of the states in your app. Vuex differs from a purely global object in two ways:

  1. Vuex’s state storage is reactive. When the Vue component reads the state from the Store, if the state in the store changes, the corresponding component will be updated efficiently accordingly.
  2. You can’t change the state in the Store directly. The only way to change the state in a store is to commit mutation. This makes it easy to track changes in each state.

The implementation principle of Vuex is to convert state data into responsive data after passing new Vue(). At the same time, the data defined in the getter is computed using computed data in New Vue, and it is recalculated only when its dependency values change.

Using Vue to implement Vuex ourselves, we can customize a myStore.js that defines the data items shared by the project and how to modify the data. Then mount it in the root data.

// MyStore.js
export default class{
	constructor(){
    	this.count = 10;
        let self = this;
        this.mutations = {
        	incrementCount(){ self.count++; }}}}Copy the code

Introduced into the project:

import MyStore from './MyStore.js';
var app = new Vue({
	el: "#app".data: {
    	myStore: new MyStore()
    }
})
Copy the code

So we can access the global variable count in the component through this.$root.myStore.count. Through this. $root. MyStore. Mutations. IncrementCount (); Modify variables.

Difference between Action and mutation in Vuex

  • Actions handle asynchronous operations, mutation is best left out. (mutation) The page data was modified, but the devTools values remained unchanged. There are data inconsistencies and data changes cannot be tracked.
  • Mutation does atomic operations
  • An action can integrate multiple mutations

Vue Router

Hash pattern

The Vue Router uses hash mode by default. The Vue Router switches components based on the hash value in the URL to switch modules. The entire page is not refreshed.

const router = new VueRouter({
    mode: 'hash'.routes: [...]. })Copy the code

Hash routing works by listening for the Window’s Hashchange event, which is triggered when the HASH value in the URL changes. And when we refresh the page, no new resource requests are made to the back end. /index.html#user requests the same address as /index.html.

<p id="content">default</p>
<script>
    window.location.hash = "qq";
    window.addEventListener('hashchange'.() = >{
        document.getElementById("content").innerHTML = window.location.hash;
    })
</script>
Copy the code

The history mode

If hash is ugly, the Vue Router also provides history mode

const router = new VueRouter({
    mode: 'hash'.routes: [...]. })Copy the code

The idea isto take advantage of the pushState and replaceState apis provided by History in HTML5. They provide a way to manipulate the browser history stack. PushState and replaceState can change the browser URL without loading the page.

  <button id="changePage1">page1</button>
  <button id="changePage2">page2</button>
  <script>
      document.getElementById("changePage1").addEventListener("click".() = >{
          const state = {name: 'page1'};
          history.pushState(state, ' '.'page1')});document.getElementById("changePage2").addEventListener("click".() = >{
          const state = {name: 'page2'};
          history.replaceState(state, ' '.'page2')});window.onpopstate = (event) = >{
          console.log('onpopstate', event.state, location.pathname);
      }
  </script>
Copy the code

PushState and replaceState can change urls, but do not actively trigger browser reload. History.pushstate () is a new historical entry; History.replacestate () modifies (replaces) the current history entry.

Here’s an example: From history.html, pushState() adds page1 to history; ReplaceState () replaces page2 with page1. Click the browser back button at this time, you will find that you are directly returned to the history. HTML page, not the page1 page. You can see that history.replacestate () is used to replace history.

The window. onpopState event listens for browser forward and backward events.

When the page is refreshed, the resource ‘127.0.0.1:5500/page1’ will be requested from the server in History mode. If the backend does not handle this, the browser will report a 404 error. A backend is needed to locate the missing pages to the HTML address of the project resource such as index.html. At the same time, the front-end routing control 404 page display content.

Developer.mozilla.org/zh-CN/docs/…

Dynamic path parameter

Method 1: Params

We often need to map all the routes that a pattern matches to the same component. For example, we have a User component that is used to render for all users with different ids. We can use dynamic segments on vue-router routes to achieve this effect:

const User = {
	template: '<div>User</div>'
}
const router = new VueRouter({
	routes: [
        // Dynamic path parameters start with a colon
    	{ path: 'user/:id'.name: 'user'.component: User}
    ]
})
Copy the code

Now, things like /user/foo and /user/bar will map to the same route.

A “path parameter” uses the colon: notation. When a route is matched, the parameter value is set to this.$route.params, which can be used within each component. So we can update the User template to print the ID of the current User:

const User = {
	template: '<div>{{ $route.params.id }}</div>'
}
Copy the code

Use:

this.$router.push({name: 'user'.params: {id: "zs"}});
Copy the code

The http://localhost:8080/#/user/zs parameter appears in the path

Method 2: Query

this.$router.push({name: 'list'.query: {name: 'William'}})
Copy the code

use

<div>List: {{$route. The query. The name}}</div>
Copy the code

The http://localhost:8080/#/list?name=William parameter is displayed in the format of? A =b

Route lazy loading

This is mainly implemented using the import() function.

const router = new VueRouter({
  routes: [
    // Dynamic path parameters start with a colon
    { path: '/user/:id'.component: () = >import(/* webpackChunkName: "User"*/'./components/User.vue')}]})Copy the code

$router and $route

  • $router refers to the entire routing object; You can usethis.$router.push({name: 'user'})Go to the jump page.
  • $route refers to the routing object of the current page; You can usethis.$route.params.idorthis.$route.query.idGets the argument passed in by the current route object

Navigation guard

Global front guard

const router = newVueRouter({... }); router.beforeEach((to, from, next) = >{
   / /...
})
Copy the code
  • To: Route object, the destination Route object to be entered
  • From: Route object, the Route that the current navigation is about to leave
  • Next: Function, the Function to continue.
    • next(); Continue down
    • next({ path: ‘/’}); To switch to the specified route address

TypeScript

The characteristics of the TypeScript

  • Type checking. TypeScript compiles code with strict static type checking. This means that potential pitfalls in the coding phase don’t have to be brought online.

  • Language extensions. TypeScript will include features in ES6 and future proposals, such as asynchronous operations and decorators. It also borrows some features from other languages, such as interfaces and abstract classes.

  • Tool properties. TypeScript compiles to standard Javascript. It runs on any browser and operating system. There is no additional runtime overhead. In this sense, TypeScript is more like a tool.

type

TypeScript defines Boolean values, number, string, Array Array, tuples, enumerations, interfaces, any, void, and more.

  • Tuples. A tuple represents an array with a known number and type of elements. The elements need not be of the same type.
let x: [string.number.boolean] = ['hello'.100.true];
Copy the code
  • Interface. Interface defines an interface, which can be interpreted as describing a data type. For example, we define the parameters that a method takes, and what properties or methods that parameter must have. At this point, you can use the interface to define the parameters of the method.
interface params{
	search: string; page? :number; size? :number;
}

function foo(p: params) :string{}
Copy the code
  • Generics. Generics guarantee type nondeterminism and consistency. For example, in functions, we can use generics to ensure that the return value type of the function is the same as the input variable type.

The difference between extra meal Type and interface:

  • Type can declare basic type, union type, tuple alias, interface does not
  • Typeof can be used in type statements to get type instances
  • Type supports type mapping, but interface does not
  • Interface can declare merge, type cannot

www.cnblogs.com/mengff/p/12…

Modules and namespaces

  • Modules in TypeScript are used the same way as modules in ES6. Use the export syntax to export module variables and methods. Use import to import variables and methods from other modules.

  • Namespace. The namespace keyword is used in TypeScript to implement namespaces. For example, variables in the Shape namespace can be accessed only in that namespace. Variables and methods that need to be accessed globally need to be exported using the export keyword.

  • A namespace can be split into several files.

  • The namespace is eventually compiled as a global variable and an immediate function.

Finally, namespaces should not be mixed with modules, and the use of namespaces is best used in a global environment

Declaration file

If we want to use third-party libraries such as jQuery and Lodash in TypeScript, we need to provide the library declaration files (ending in.d.ts) that expose the API. We can use TypeScript by installing the type declaration package from a third-party class library. Take jQuery as an example:

npm install -D jquery @types/jquery
Copy the code

TS Compilation Process

Like Babel and other tools that compile to Javascript, the TS compilation process consists of three steps:

Parse -> Transform -> build

It contains the following key parts:

  • Scanner: Generates tokens from source code
  • Parser: Generates the AST from the Token
  • Binder: Generates symbols from AST
  • Checker: type check
  • Emitter: Generates the final JS file

Quote:Juejin. Cn/post / 684490…

For more on TypeScript: juejin.cn/post/690313…

Thank you

If there is any mistake or not precise place, please give correction, thank you very much. If you like or have some inspiration, welcome to like, to the author is also a kind of encouragement.