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:
node
The node’sv-model
Or an interpolated symbol. Such asv-model="name"
.exp
isname
; - cbIs:
Watcher
Binding 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 first
let value = this.vm.data[this.exp];
To get the latest data, - And then I’m going to compare it to before
get()
The old data obtained is compared, and if different, the update function is calledcb
Update.
- Through the first
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. through
modelUpdater
Method 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. through
attr.name
To get the click,attr.value
Get Handel and register the corresponding event function for the current node
- If it isv-model=’name’, you need to bind data. through
-
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></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
.native
The 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!!
.sync
The 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 or
A URL request is made when the page is refreshed
In 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:
- Router. beforeEach Global front-guard before entering a route
- Router.beforeresolve Global resolution guard (2.5.0+) is called after the beforeRouteEnter call
- 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
-
BeforeRouteEnter cannot get component instance this after route exclusive guard before entering route. Component instance has not been created yet
-
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
-
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) :
- Trigger to enter other routes.
- Invoke the component guard to leave the route
beforeRouteLeave
- Call office front guard:
beforeEach
- Called in a reused component
beforeRouteUpdate
- Call route exclusive guard
beforeEnter
. - Parse the asynchronous routing component.
- Called in the incoming routing component
beforeRouteEnter
- Call the global parse guard
beforeResolve
- Navigation confirmed.
- To call the global post-hook
afterEach
Hook. - Triggering DOM updates (
mounted
). - perform
beforeRouteEnter
The callback function passed to Next in the guard
The life cycle
Commonly used hook
-
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.
-
Operations on the DOM are placed in Mounted. Access to the DOM before Mounted is undefined.
-
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