Vue basis

Talk about the understanding of vUE two-way data binding

Vue core two-way data binding

View =>data implementation principle

Bind the onINPUT event to the input box, modify the value of the corresponding attribute in data in the method, it will immediately call the corresponding set method of the underlying object, and then update the data in data, and then render the data to the view

data => view

Two-way data binding is achieved by implementing the following four steps:

1. Implement a listener Observer that hijacks and listens to all attributes and notifies subscribers if they change;

Observer.prototype = {
    walk: function(data) {
        var self = this;
        Object.keys(data).forEach(function(key) {
            self.defineReactive(data, key, data[key]);
        });
    },
    defineReactive: function(data, key, val) {
        var dep = new Dep();
        var childObj = observe(val);
        Object.defineProperty(data, key, {
            enumerable: true.configurable: true.get: function getter () {
                if (Dep.target) {
                    dep.addSub(Dep.target);
                }
                return val;
            },
            set: function setter (newVal) {
                if (newVal === val) {
                    return; } val = newVal; dep.notify(); }}); }};Copy the code
  • Attributes in data are iterated recursively, adding get and set methods to each attribute via Object.defineProperty(obj, prop, Descriptor) to achieve data observability

2. Implement a subscriber Dep, which is used to collect subscribers, manage listener Observer and subscriber Watcher uniformly, that is, execute corresponding subscriber update function when data changes;

  • Dep subs: Store watcher object this.subs = []

    • Each time an attribute defineProperty of data is generated, a DEP instance of the corresponding attribute is generated
  • The deP method addSub: implements adding watcher to the subs array.

    • If Dep is null, watcher will not be added to Dep. If Dep is null, watcher will not be added to Dep
  • Dep’s notify method iterates over each watcher, triggering watcher’s update callback

function Dep () {
    this.subs = [];
}
Dep.prototype = {
    addSub: function(sub) {
        this.subs.push(sub);
    },
    notify: function() {
        this.subs.forEach(function(sub) { sub.update(); }); }}; Dep.target =null;
Copy the code

3. Implement a subscriber Watcher that can receive notification of property changes and execute corresponding methods to update the view;

function Watcher(vm, exp, cb) {
    this.vm = vm;
    this.exp = exp;
    this.cb = cb;
    this.value = this.get();  // Add yourself to the subscriber operation
}

Watcher.prototype = {
    update: function() {
        this.run();
    },
    run: function() {
        var value = this.vm.data[this.exp];
        var oldVal = this.value;
        if(value ! == oldVal) {this.value = value;
            this.cb.call(this.vm, value, oldVal); }},get: function() {
        Dep.target = this; // Global variable subscriber assignment
        var value = this.vm.data[this.exp]  // enforce get function in listener
        Dep.target = null; // Global variable subscriber release
        returnvalue; }};Copy the code
  • Properties of the Watcher class

    • Vm: an instance object of Vue
    • expIs:nodeThe node’sv-modelOr an interpolated symbol. Such asv-model="name".expisname;
    • cbIs:WatcherBinding update functions;
  • Get: When instantiating a render Watcher, first go to watcher’s constructor logic, which executes its this.get() method, which executes the get function

    get: function() {
        Dep.target = this;  // Cache yourself
        var value = this.vm.data[this.exp]  // enforce get function in listener
        Dep.target = null;  // Release yourself
        return value;
    }
    Copy the code
    • By triggering the GET method in defineProperty and assigning the current watcher instance to dep. target, you add watcher to the Dep and bind the current Watcher to the data in vm.data
  • Watcher update: Calls Watcher’s update function to update data when it changes.

    • Through the firstlet value = this.vm.data[this.exp];To get the latest data,
    • And then I’m going to compare it to beforeget()The old data obtained is compared, and if different, the update function is calledcbUpdate.

Ask the question: When should you create a Watcher instance?

4. Implement a parser Compile, which can parse the relevant instructions of each node, initialize the template data and the subscriber, bind the node corresponding to the template instructions to the corresponding update function, initialize the corresponding subscriber.

  • First, recursively iterate through the entire DOM node tree that copied the template and fetch the fragment

  • Traverse each child node of the root node one by one, judge and then do the corresponding operation

    • If node.nodeType == 3 and {{exp}} is the difference expression, then create a Watcher instance and pass the corresponding attribute exp to data. Then add the subscriber to this.vm[exp] and implement the data binding of model->view

    • If node.nodeType == 1, get the attributes of the current node,

      • If it isv-model=’name’, you need to bind data. throughmodelUpdaterMethod to initialize the data in the bound VM for the values in the view, create the Watcher instance, and pass the modelUpdater as a callback to update the data
      modelUpdater: function (node, value, oldValue) {
          node.value = typeof value == 'undefined' ? ' ' : value
      }
      Copy the code
      • If it isv-on:click=’handel’, you need to bind events. throughattr.nameTo get the click,attr.valueGet Handel and register the corresponding event function for the current node
var Watcher = require('./watcher')
function Compile(el, vm) {
  this.vm = vm
  this.el = document.querySelector(el)
  this.fragment = null
  this.init()
}

Compile.prototype = {
  init: function () {
    if (this.el) {
      // Copy the entire DOM node tree
      this.fragment = this.nodeToFragment(this.el)
      // Go through all the children of the root node one by one
      this.compileElement(this.fragment)
      // After template replacement, add the real DOM to the page
      this.el.appendChild(this.fragment)
    } else {
      console.log('Dom element does not exist ')}},nodeToFragment: function (el) {
    var fragment = document.createDocumentFragment()
    // Get the first node, containing the text node
    var child = el.firstChild
    while (child) {
      // Move the Dom element into the fragment
      fragment.appendChild(child)
      child = el.firstChild
    }
    return fragment
  },
  compileElement: function (el) {
    // el.childNodes gets all nodes in code order, including text newlines, etc
    // El.children gets only tag elements, not text newline nodes, etc
    var childNodes = el.childNodes
    var self = this; [].slice.call(childNodes).forEach(function (node) {
      var reg = / \ {\ {(. *) \} \} /
      // Get the text of the current node
      var text = node.textContent
      // Check whether it is a tag
      if (self.isElementNode(node)) {
        self.compile(node)
      } else if (self.isTextNode(node) && reg.test(text)) {
        // RegExp.$1------reg.exec(text)[1]
        self.compileText(node, reg.exec(text)[1])}if (node.childNodes && node.childNodes.length) {
        self.compileElement(node)
      }
    })
  },
  // Compile labels
  compile: function (node) {
    var nodeAttrs = node.attributes
    var self = this
    Array.prototype.forEach.call(nodeAttrs, function (attr) {
      // attr.name-- Get the key
      var attrName = attr.name
      // if it starts with a v-
      if (self.isDirective(attrName)) {
        // attr. Value -- Get value
        var exp = attr.value
        // Remove the v-, such as on:click
        var dir = attrName.substring(2)
        // Determine if it is an event command
        if (self.isEventDirective(dir)) {
          self.compileEvent(node, self.vm, exp, dir)
        } else {
          / / v - model instruction
          self.compileModel(node, self.vm, exp, dir)
        }
        node.removeAttribute(attrName)
      }
    })
  },
  {{exp}}
  compileText: function (node, exp) {
    var self = this
    var initText = this.vm[exp]
    this.updateText(node, initText)
    new Watcher(this.vm, exp, function (value) {
      self.updateText(node, value)
    })
  },
  // Compile the binding event such as v-on:click=' Handel ', exp is the binding value Handel, dir is on:click,
  compileEvent: function (node, vm, exp, dir) {
    / / get the click
    var eventType = dir.split(':') [1]
    // Get the Handel method
    var cb = vm.methods && vm.methods[exp]

    if (eventType && cb) {
      // Register events for the node
      node.addEventListener(eventType, cb.bind(vm), false)}},compileModel: function (node, vm, exp, dir) {
    var self = this
    // get the value exp in data
    var val = this.vm[exp]
    // View value===model data
    this.modelUpdater(node, val)

    // Create an instance of watcher. When data is updated, the cb callback function will be triggered.
    new Watcher(this.vm, exp, function (value) {
      self.modelUpdater(node, value)
    })

    node.addEventListener('input'.function (e) {
      var newValue = e.target.value
      if (val === newValue) {
        return
      }
      self.vm[exp] = newValue
      val = newValue
    })
  },
  updateText: function (node, value) {
    node.textContent = typeof value == 'undefined' ? ' ' : value
  },
  modelUpdater: function (node, value, oldValue) {
    node.value = typeof value == 'undefined' ? ' ' : value
  },
  isDirective: function (attr) {
    return attr.indexOf('v-') = =0
  },
  isEventDirective: function (dir) {
    return dir.indexOf('on:') = = =0
  },
  isElementNode: function (node) {
    return node.nodeType == 1
  },
  isTextNode: function (node) {
    return node.nodeType == 3}}module.exports = Compile
Copy the code

Implementation principle of vue-Router

Discuss the understanding that Vue is an incremental framework

Interviewer: Talk about your understanding of vue.js framework

Why must data be a function in a component

When a component is defined, data must be declared as a function that returns an initial data object, because the component may be used to create multiple instances. If data were still a pure object, all instances would share references to the same data object! By providing the data function, each time a new instance is created, we can call the data function to return a new copy of the original data.

To ensure component independence and reusability, data is not contaminated

Data is a function of component instantiation of this function will be called, returns an object, calculate the opportunity to give this object is assigned a memory address, how many times have you instantiated, allocate some memory address, their address is different, so will not interfere with the data of each component, change the status of one of the components, other components.

Virtual DOM and diff algorithms

Vue data is updated

Virtual DOM+ DIff algorithm is used to improve update performance

  • Generate a new virtual DOM structure
  • Contrast with the old virtual DOM structure
  • Using the Diff algorithm, find the difference and update only the changed parts (redraw/reflux) to the page – also known as patching

Virtual DOM

There are hundreds of real DOM attributes, and there’s no way to quickly tell which one has changed

The virtual DOM is stored in memory, and only key DOM information is recorded. The performance of DOM update can be improved with the DIff algorithm

Virtual DOM is to extract real DOM data and simulate tree structure in the form of objects.

For example, dom looks like this:

<div>
    <p>123</p>
</div>
Copy the code

Corresponding Virtual DOM (pseudocode) :

var Vnode = {
    tag: 'div'.children: [{tag: 'p'.text: '123'}};Copy the code

Note: Both vNodes and OldvNodes are objects

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.

The flow chart of the diff

When data changes, the set method will call dep. notify to notify all subscribers Watcher, and the subscribers will call Patch to patch the real DOM and update the corresponding view.

How does the Diff algorithm compare the old and new virtual DOM?

  • Root element changes – Remove the current DOM tree and rebuild
  • The root element remains unchanged, the attribute changes – the attribute is updated
  • The root element remains unchanged, and the child/content changes
  • Without key – Local update/with key – Compare by key

The role of key in V-for

The special attribute of key is mainly used in the virtual DOM algorithm of Vue to identify VNodes when comparing old and new nodes.

  • Instead of keys, Vue uses the in-place reuse principle: patch or reuse using an algorithm that minimizes moving elements and tries to repair/reuse the same type of elements as much as possible.
  • With keys, Vue records elements in the order of keys, rearranges elements based on changes in the key, and removes elements where the key does not exist.

Rendering functions & JSX (to be added)


Component Communication (to be added)

Six ways to Communicate between Vue components (full version)

1. Parent and child components

A. By sending and receiving messages

The parent component

For example,

The implementation listens for child events and receives data <son :uname= by v-bind or: implementation passing data from the parent to the child via V-ON or @"uname" @update-uname="uname = $event"></son>
Copy the code

Child components

For example,

export default {
  // Accept data from the parent component via props
  props: ['uname'].methods: {
    handle(){
      // Send data to the parent component via $emit
      this.$emit('update-uname'.'ls')}}}Copy the code

Syntactic sugar

v-model

The parent component

<son v-model="uname"></son>
Copy the code

Child components

export default {
  props: ['value'].methods: {
    handle(){
      this.$emit('input'.'ls')}}}Copy the code
.sync

The parent component

<son :uname.sync="uname"></son>
Copy the code

Child components

export default {
  props: ['uname'].methods: {
    handle(){
      this.$emit('update:uname'.'ls')}}}Copy the code

B. Communicate directly through component instances

Father – > the son

Through ref and $refs

<template>
  <son ref="sonRef"></son>
</template>
<script>
export default = {
  methods: {
    handle(){
      this.$refs.sonRef.uname // Access data
      this.$refs.sonRef.updateUname('ls')// Access methods}}}</script>
Copy the code

Children – > father

Through $parent

export default {
  methods: {
    handle(){
      this.$parent.uname // Access data
      this.$parent.upateUname('ls') // Access methods}}}Copy the code

2. Sibling components

A Through the incident center

Event center

For example,

import Vue from 'vue'
const eventBus = new Vue()
export funtion on(eventName, fn){
  eventBus.$on(eventName, fn)
}
export funtion emit(eventName, data){
  eventBus.$emit(eventName, data)
}
Copy the code

Brother A

For example,

import {emit} from '@/utils/eventBus.js'
export default {
  methods: {
     handle(){
        / / message
        emit('add-success'.4)}}}Copy the code

Brother B

For example,

import {on} from '@/utils/eventBus.js'
export default {
  data(){
    return {
        list: [1.2.3]}},mounted(){
    // Accept the message
    on('add-success'.function(data){
      this.list.push(data)
    })
  }
}
Copy the code

B. Communicate through parent components (via messages and direct communication)

The parent component

For example,

<template> <son-a @add-success="handle"><son-a> <son-b ref="sonbRef"><son-b> </template> <script> export defalut { $refs.sonbref.list.push (data)}} </script>Copy the code

Brother A

For example,

export default {
  methods: {
     handle(){
        / / message
        this.$emit('add-success'.4)}}}Copy the code

Brother B

For example,

export default {
  data(){
    return {
        list: [1.2.3]}}}Copy the code

C. Communicate via parent component (via message)

The parent component

For example,

<template> <son-a @add-success="handle"><son-a> <son-b :list="list"><son-b> </template> <script> export defalut { Data (){list: []}, methods: {handle(data){this.list. Push (data)}} </script>Copy the code

Brother A

For example,

export default {
  methods: {
     handle(){
        / / message
        this.$emit('add-success'.4)}}}Copy the code

Brother B

For example,

export default {
  props: {
    // Accept data from the parent component via props
    list: {
      type: Array.default: () = >[]}}}Copy the code

D. Through the slot

The parent component

<template>
    <son-a><button @click="handle(4)">add</button><son-a>
    <son-b :list="list"><son-b>
</template>
<script>
export defalut {
    data(){
      return {
          list: [1.2.3]}},methods: {
    handle(data){
      // Parent components communicate with child component instances
      this.list.push(data)
    }
  }
}
</script>
Copy the code

Brother A

For example,

<template>
  <div class="son-a">
    <slot></slot>
  </div>
</template>
Copy the code

Brother B

For example,

export default {
  props: {
    // Accept data from the parent component via props
    list: {
      type: Array.default: () = >[]}}}Copy the code

3. Grandparent component

A. Through father-son communication

<body>
    <div id="app">
        <grand-father></grand-father>
    </div>
</body>
<script>
// Grandpa component
Vue.component('grand-father', {
    data() {
        return {
            money: 1000}},template: Grandpa ` < div > < div > < / div > < father: money = "money" @ pay = = "money - $event" / > < / div > `
})
// Parent component
Vue.component('father', {
    props: ['money'].template: Father ` < div > < div > < / div > < son: money = "money" @ pay = "$emit (' pay, $event)" / > < / div > `
})
// Grandchild component
Vue.component('son', {
    props: ['money'].template: ` < div > < div > grandchildren - {{money}} < / div > < button @ click = "$emit (' pay ', 100)" > 100 < / button > < / div > `
})
var vm = new Vue({
    el: '#app'.data: {},methods: {},mounted(){},})Copy the code

B. by $parent

<body>
    <div id="app">
        <grand-father></grand-father>
    </div>
</body>
<script>Vue.component('grand-father', {data() {return {money: 1000}}, template: '<div>
            <div>grandpa</div>
            <father ref="father"/>
        </div>', methods: {pay(num){if(this.money>num){this.money -= num}}}}) // Vue.component('father', {template: '<div>
            <div>father</div>
            <son/>
        </div>Vue.component('son', {template: '<div>
            <div>Grandchildren -{{$parent.$parent.money}}</div>
            <! -- Yes, but don't do it.
            <! --<button @click="$parent.$parent.money-=100">-100</button>-->
            <button @click="$parent.$parent.pay(100)">- 100.</button>
        </div>
    `
})
var vm = new Vue({
    el: '#app',
    data: {
    },
    methods: {
    },
    mounted() {
    },
})
</script>
Copy the code

C. Provide and inject

<body>
    <div id="app">
        <grand-father></grand-father>
    </div>
</body>
<script>
// Grandpa component
Vue.component('grand-father', {
    data() {
        return {
            money: 1000}},provide(){
        return {
            grandFather: this}},template: '
        
Grandpa
'
.methods: {        pay(num){            if(this.money>num){                this.money -= num           }       }   } }) // Parent component Vue.component('father', {    template: '
Father
'
}) // Grandchild component Vue.component('son', {    inject: ['grandFather'].mounted(){},template: '
sun -{{grand.money}}
}) var vm = new Vue({    el: '#app'.data: {},methods: {},mounted(){},})
</script>
Copy the code

4. Irrelevant components -Vuex

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  // Define data
  state: {
    count: 0
  },
  // Synchronize the code
  mutations: {
    addCount (state) {
      state.count++
    },
    // Accept arguments
    addCountN (state, payload) {
      state.count += payload
    }
  },
  // Asynchronous code
  actions: {
    addCountSync (context) {
      setTimeout(() = > {
        context.commit('addCount')},1000)},// Accept arguments
    addCountNSync (context, payload) {
      setTimeout(() = > {
        context.commit('addCountN', payload)
      }, 1000)}},// Calculate attributes
  getters: {
    showCount (state) {
      return 'The current count value =${state.count}`
    },
    // Simplify getting state in modules
    token (state) {
      return state.user.token
    }
  },
  / / modular
  modules: {
    user: {
      // Namespace
      namespaced: true.state: {
        token: 'abc'
      },
      mutations: {
        updateToken () {
          console.log('2')}}}}})Copy the code
// state
<div>{{$store.state.count}}</div>
// mutations
<button @click="$store.commit('addCount')">+ 1</button>
// actions
<button @click="$store.dispatch('addCountSync')">+1 sync</button>
// getters
<div>{{$store.getters.showCount}}</div>


<script>
import {mapState,mapMutations,mapActions,mapGetters} from 'vuex'
export default {
  computed: {
    ...mapState(['count']),
    ...mapGetters(['showCount'])},methods: {
    ...mapMutations(['addCount'.'addCountN']),
    ...mapActions(['addCountSync'.'addCountNSync']),}}</script>
Copy the code

Custom events

The official documentation

V – model customization

Customize the usage method of the V-Model

.nativeThe modifier

You want to listen for a native event directly on the root element of a component. In this case, you can use the v-ON. Native modifier:

Core: sugar through bubbling grammar

<! -- by bubbling --> <! --<div @click="handleClick">
            <el-button></el-button>
        </div>-- > <! -- Grammar sugar --><el-button @click.native="handleClick"></el-button><! Note :.stop,.keyup,.prevent only works on DOM event objects and does not work on components communicating via $emit!! --><el-input @keyup.native.enter="handleEnter"></el-input>
    </div>
  </body>
  <script>
    Vue.component('el-button', {
      template: '
        
'
}) Vue.component('el-input', { template: ` ` }) new Vue({ el: '#app'.methods: { handleClick() { console.log('click')},handleEnter() { console.log('enter')}}})
</script>
Copy the code

Note :.stop,.keyup,.prevent only work on DOM event objects, not components communicating via $emit!!

.syncThe modifier

Usage scenario: Parent and child components send parameters to each other

Note: V-bind with the.sync modifier cannot be used with expressions (e.g. V-bind :title.sync= “doc.title + ‘! ‘” is invalid). Instead, you can only provide the name of the property you want to bind to, similar to the V-Model.

The parent component passes the child component value visible and receives the child component update: Visible event

<! -- :visible="showDialog" @update:visible="showDialog = $event"-- > <! -- Syntax sugar --> :visible. Sync ="showDialog"
Copy the code

The child component receives the value visible from the parent component and fires the parent component’s event via @update: Visible

    Vue.component('el-dialog', {
      props: ['visible'].template: ` < div v - if = "visible" > this is an elastic layer, < a @ click = "$emit (' update: visible, false)" > close < / a > < / div > `
    })
Copy the code

V-bind.sync (Multiple prop)

Note: Using v-bind.sync on a literal object, such as v-bind.sync= “{title: doc.title}”, will not work because there are many edge cases to consider when parsing a complex expression like this.

The parent component

<el-dialog v-bind.sync="info"></el-dialog>
Copy the code

Child components

    Vue.component('el-dialog', {
      props: ['visible'.'name'].template: ` < div v - if = "visible" > this is {{name}} a layer, < a @ click = "$emit (' update: visible, false)" > close < / a > < / div > `
    })
Copy the code

How components are registered

The official documentation

1. Global registration

Note: The behavior of global registration must occur before the root Vue instance (via new Vue) is created

Vue.component('component-a', { / *... * / }) 
Vue.component('component-b', { / *... * / }) 
Vue.component('component-c', { / *... * / }) 

new Vue({ el: '#app' })
Copy the code

2. Partial registration

var ComponentA = { / *... * / } 
var ComponentB = { / *... * / } 
var ComponentC = { / *... * / }

new Vue({ 
    el: '#app'.components: { 
        'component-a': ComponentA, 
        'component-b': ComponentB 
    } 
})
Copy the code

3. Register the routing component

src/router/index.js

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export const routes = [
  {
    path: '/login'.component: () = > import('@/views/login/index'),}]const router = new Router({
    routes
})

export default router
Copy the code

4. Register components in plug-in mode

Development plug-in | global registration of Vue components

src/components/index.js

This file is responsible for global registration of all common components and is exported by default

// This file is responsible for the global registration of all common components vue.use
import PageTools from './PageTools'
import UploadExcel from './UploadExcel/index'
import ImageUpload from './ImageUpload'

export default {
  install(Vue) {
    // Register the global generic bar component object
    Vue.component('PageTools', PageTools)
    // Register the file to import Excel data
    Vue.component('UploadExcel', UploadExcel)
    // Register the import upload component
    Vue.component('ImageUpload', ImageUpload)
  }
}
Copy the code

Import your plugin in main.js and register your plugin globally

import Component from '@/components'
Vue.use(Component) // Register your own plugin
Copy the code

Set up the VUE development environment

Have you built your own VUE development environment?

routing

Routing and the cords

Component and the cords

The hash and history

hash

advantages

  • Only the front end needs to configure the routing table, but the back end does not need to participate
  • Good compatibility, browser can support
  • Changes in the hash value do not send requests to the back end, but belong to front-end routes
  • Every time you change the part after #, you add a record to the browser’s history. Use the “back” button to go back to the previous position

disadvantages

  • The hash value must be preceded by a #, which is not in accordance with the URL specification and is not beautiful

history

advantages

  • Conform to url address specification, do not need #, use more beautiful

disadvantages

  • Before the user manually enters the address orA URL request is made when the page is refreshedIn the index.html page, you need to configure the case that the user cannot match the static resource. Otherwise, a 404 error occurs
  • The poor compatibility takes advantage of the new pushState() and replaceState() methods in the HTML5 History object, which require browser-specific support.

Routing guard

The official documentation

Refer to the article

Call order: Global guard — “Route exclusive Guard –” Route component internal guard

1. Global guard

Vue-router has three guards globally:

  1. Router. beforeEach Global front-guard before entering a route
  2. Router.beforeresolve Global resolution guard (2.5.0+) is called after the beforeRouteEnter call
  3. AfterEach Global post-hook after entering a route

Usage:

// import router from './router'; BeforeEach ((to, from, next) => {next(); // Import a router. }); router.beforeResolve((to, from, next) => { next(); }); Router.aftereach ((to, from) => {console.log('afterEach global afterhook '); });Copy the code

When a navigation is triggered, the global front-guard is called in the order it was created. The guard resolves asynchronously, in which case the navigation waits until all the guards resolve.

Each guard method takes three arguments:

  • To: Route: indicates the destination Route to be entered

  • From: Route: indicates the Route that the current navigation is about to leave

  • Next: Function: Be sure to call this method to resolve the hook. The execution depends on the call parameters of the next method.

    • Next () : Goes to the next hook in the pipe. If all hooks are executed, the navigation state is confirmed.

    • Next (false) : interrupts current navigation. If the browser URL changes (either manually by the user or by the browser back button), the URL is reset to the address corresponding to the FROM route.

    • Next (‘/’) or next({path: ‘/’}) : jumps to a different address. The current navigation is interrupted and a new navigation is performed. You can pass any location object to next, and you can set options like replace: True, name: ‘home’, and any options used in router-link’s to prop or router.push.

    • Next (error) : (2.4.0+) If the argument passed to Next is an error instance, the navigation is terminated and the error is passed to the callback registered with router.onerror ().

2. Route exclusive guard

Configure guards separately for some routes:

Note: The call order comes after the global front-guard, so it is not overwritten by the global guard

const router = new VueRouter({
      routes: [{path: '/foo'.component: Foo,
          beforeEnter: (to, from, next) = > { 
            // The argument usage is the same and so on. The call order is after the global front-guard, so it is not overwritten by the global guard
            // ...}}}])Copy the code

3. Internal guard of routing components

  1. BeforeRouteEnter cannot get component instance this after route exclusive guard before entering route. Component instance has not been created yet

  2. BeforeRouteUpdate (2.2) When a route is multiplexed with the same component, the call can access component instance this when the current route changes but the component is multiplexed

  3. BeforeRouteLeave is called when navigating away from the current route, when navigating away from the corresponding route of the component, and can access the component instance this

  beforeRouteEnter (to, from, next) {
    // Call no! After route exclusive guard. Can!!!! Gets component instance 'this' that has not yet been created
  },
  beforeRouteUpdate (to, from, next) {
    // The component instance 'this' is called when the current route changes but the component is being reused
    // For example, for a path /foo/:id with dynamic parameters, when jumping between /foo/1 and /foo/2,
    // Since the same Foo component will be rendered, the component instance will be reused. And the hook will be called in that case.
  },
  beforeRouteLeave (to, from, next) {
    // Called when navigating away from the corresponding route of the component to access the component instance 'this'
  }

Copy the code

Supplementary application

BeforeRouteEnter access this

Because the hook is called when the component instance has not yet been created, the component instance this cannot be retrieved; it can be accessed by passing a callback to Next.

Created and Mounted are created and created are created and mounted are created.

BeforeRouteEnter (to, from, next) {console.log(' called after routing guard exclusive '); Next (vm => {// access component instance 'this' from' VM 'after mounted,})} copy the codeCopy the code

beforeRouteLeave

Called when navigating away from the corresponding route of the component, we use it to prevent the user from leaving, for example, without saving the draft, or to destroy the setInterval before the user leaves, in case the timer is still invoked after the user leaves.

BeforeRouteLeave (to, from, next) {if (save the article) {next(); } else {next(false); // Cancel to leave}} copy codeCopy the code

Error capture of routing hook functions

If we have an error in the global guard/route exclusive guard/component route guard hook function, we can catch it like this:

Router. onError(callback => {console.log(callback, 'callback'); });Copy the code

Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.

Complete routing navigation parsing process (excluding other life cycles) :

  1. Trigger to enter other routes.
  2. Invoke the component guard to leave the routebeforeRouteLeave
  3. Call office front guard:beforeEach
  4. Called in a reused componentbeforeRouteUpdate
  5. Call route exclusive guardbeforeEnter.
  6. Parse the asynchronous routing component.
  7. Called in the incoming routing componentbeforeRouteEnter
  8. Call the global parse guardbeforeResolve
  9. Navigation confirmed.
  10. To call the global post-hookafterEachHook.
  11. Triggering DOM updates (mounted).
  12. performbeforeRouteEnterThe callback function passed to Next in the guard

The life cycle

Commonly used hook

  1. Ajax requests are best placed in Created because this is already accessible, and requests to data can be placed directly in Data.

    There have been several occasions where the interviewer has asked which lifecycle the Ajax request should be placed in.

  2. Operations on the DOM are placed in Mounted. Access to the DOM before Mounted is undefined.

  3. Do something every time you enter/leave a component, with what hook:

  • Don’t cache:

    Create and Mounted hooks are used to enter, and beforeDestory and destroyed hooks are used to leave. BeforeDestory accesses this, and destroyed does not.

  • Caches components:

    BeforeCreate, Created, beforeMount, and Mounted are not triggered for re-entering a component after it has been cached. If you want to do something every time you enter a component, you can put activated in the cache component’s hook.

    BeforeDestroy and destroyed are not triggered when leaving the cache component. Use the deactivated hook to remove the cache component instead.


vuex

Vuex modular

Vuex modular use