Part six: Vue component basics

Components are reusable Vue instances. Componentized development refers to the process of taking a complete page and separating it into individual components, and ultimately, using these individual components to complete the functionality of the entire page (project). Componentized development advantage/role: reuse

1. Basic use of components (register first, then use)

1.1 Global Component Registration and use

Registering global components
Vue.component('child', {template:'

This is the child component

}) / / or <template id="one"> <div> <h1>Hello, world</h1> </div> </template> Vue.component('child', {template:'#one' }) /** * First argument: component name (component names are my-component or myComponent, converted to dash when used) Is a configuration object that is almost identical to the configuration object of the Vue instance * that is, the configuration item used in the Vue instance is almost identical to the configuration item in the component (the EL item is replaced by the template item) */ Copy the code

This step simplifies things a little bit:

  // 1. Create a component constructor object
      const cnpc = Vue.extend({
        template: '
      

I'm title

I'm content

'
}); /* 2. Register the component: Pass in the component label name and component constructor object. This registration method is a globally registered global component and can be used under multiple VUE instances Vue.component("myComponentOne", cnpc); Copy the code
Using global components
<div id="app">
      <! -- 3. Use components -->
      <my-component-one"></my-component-one>
</div>
Copy the code

1.2. Partial registration and use

Each component instance has the Components property, where we can register local components. A registered component is only valid under the scope of that instance.

      const vm = new Vue({
        el: "#app".// Syntax sugar registry component

        components: {
          "my-component-two": {
            template: '
      

I'm title

I'm content

'
,}}});Copy the code

Of course, you can separate the contents of components and define them in script tags. If the structure inside the component’s template is too complex, you can isolate it: define it outside the script.

 <div id="app">
      <my-button></my-button>
    </div>
    <template id="button">
        <div>
            {{msg}}
        </div>
    </template>
    <script>
      let myButton = {
        data() {
          return { msg: "aaa" };
        },
        template: "#button"}; vm =new Vue({
        el: "#app".data: {},
        components: {
          myButton,
        },
      });
    </script>
Copy the code

Using local components

    <div id="app"> <! --3.Using components --><my-component-two> </my-component-two>
    </div>
Copy the code

1.3 Why is component data a function?

  • Components are reusable VUE instances. Once a component is created, it can be used anywhere. However, data in components should be isolated from each other no matter how many times they are reused.
  • If the component’s data is a reference object, when the component is reused, it all points to the same heap memory, and all the reusable components operate on the same data.
  • If the component’s data is a function and the return value is an object, the component will call the data function each time to form an independent data storage space.

2. Component communication

2.1 The parent component passespropsPassing information (data) to child components

  • The child component uses props to receive data from the parent component. Properties defined in props, which operate on the component itself, can be used directly in template, computed, or Methods.
  • In father, the son tag is used to bind the data in the parent by V-bind. The data is then received through props in the instance option of the child component (SON).
    <div id="app">
      <! -- Step 1: The parent component is bound to the data component by v-bind.
      <son :father-name="name"></son>
    </div>

    <template id="son">
      <div>
        <h1>I'm a child component</h1>
        <h2>{{fatherName}}</h2>
      </div>
    </template>
    <script>
      const son = {
        template: "#son".// Step 2: The child component receives data through props
        props: ["fatherName"]};// The following component can be regarded as the parent component
      const vm = new Vue({
        el: "#app".components: {
          son,
        },
        data: {
          name: "I'm the parent component. I'm the parent component.",}});</script>
Copy the code
Props features:
  • One-way pass :Vue uses one-way data flow, meaning that changes in the parent component’s data are passed to the child component, not the other way around. This is so that the child does not inadvertently change the state of the parent.
  • If you really want to modify the props, you can save the properties in your own data.
  • There are two types of values for props, one is a string and the other is an object
/ / the first
props: ['name'.'number'.'msg']
/ / the second
props: {msg: {type:Object.default(){
                    return{}}}}Copy the code
  • Replace the props name with a dash in the template

2.2 SubComponents Pass$emit()Triggering events (and carrying data) to the parent component

  • The child emits events via $emit(), and the parent listens for custom events emitted by the child with V-on on the child’s custom tag.
  • How to bind the parent when the parent uses the child (<son @parentsay="say"></son>The parent component’s methods accept data from the child component.
  • Bind an event to a child component<button @click="sonSay">Sends an event in the child component’s event function, passing the child component’s parameters.
sonSay() {
           this.$emit("parentsay".this.msg);
         },
Copy the code

2.3 Communication between Components – Custom Events (EventBus)

Define an empty Vue instance as the central event bus (event hub) and use it to trigger events and listen for events, subtly and lightly enabling communication between any component, including parent, sibling, and cross-level. When our project was larger, we could have chosen a better state management solution, VUEX. Specific implementation methods:

var Event=newVue(); $emit(Event name, data); $on(Event name,data= > {});
Copy the code
    <div id="app">
      <my-a></my-a>
      <my-b></my-b>
    </div>
    <template id="a">
      <div>
        <h3>A component: {{name}}</h3>
        <button @click="send">Component A sends data to component B</button>
      </div>
    </template>
    <template id="b">
      <div>
        <h3>B component: {{name}}</h3>
      </div>
    </template>

    <script>
      // Step 1: Define an empty Vue instance as an event bus
      var Event = new Vue();
      var A = {
        template: "#a".data() {
          return {
            name: "tom"}; },methods: {
          send() {
            /* Step 2: send the data formed by A to B. Click send to send an event named add. The first parameter is the event name and the second parameter is the data of the current component */
            Event.$emit("add".this.name); ,}}};var B = {
        template: "#b".data() {
          return {
            name: ""}; },methods: {
          addText(name) {
            console.log(name);

            this.name = name; }},mounted() {
          // Step 3: Receive events in component B's Mounted event
          // The first argument is the event name, the second is the callback function (renamed for ease of unbundling)

          Event.$on("add".this.addText);
        },
        beforeDestroy() {
          // Step 4: Unbind events to prevent memory leaks
          Event.$off("add".this.addText); }};var vm = new Vue({
        el: "#app".components: {
          "my-a": A,
          "my-b": B,
        },
      });
    </script>
Copy the code
Step 1: Initialize EventBus directly from main.js in the project// Vue.prototype.$EventBus = new Vue()
        new Vue({
                 el: "#root".render: (h) = > h(App),
                 beforeCreate(){
                     Vue.prototype.$EventBus = this}}); Use his three methods: $on() $emit() $off() step 2: use $on() to bind events to the VM and step 3: use $emit() to distribute eventsCopy the code

3. Component lifecycle

Life cycle of a single component

BeforeMount the hook function is executed to indicate that the instance is initialized and data is available, but the root DOM element el used by the Vue instance is not initialized. BeforeMount Both data and EL are initialized, but el has no data rendered, and el is the “virtual” element node.

The mounted hook function indicates that the interface has been rendered and mounted to the instance. You can perform ajax operations such as retrieving information, binding events, and DOM manipulation.

BeforeUpdata and upDated are called only when data changes in the update phase. BeforeUpdate execution indicates that data in the EL has been upDated, and upDated indicates that data in the EL has been rendered and component DOM has been upDated.

Destroy Phase beforeDestroy The hook function represents preparation before destruction in which we can unbind custom events, destroy child components, event listeners, timers, and so on

All lifecycle hooks automatically bind this context to the instance, so you can’t use arrow functions to define a lifecycle method (e.g. Created: () => this.fetchtodos ()), which would result in this pointing to the parent.

Life cycle with parent and child components

Created Creates the parent component and then creates the child component in the instance initialization phase. In mounted rendering phase, the parent component is rendered after the child component is rendered

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

The update phase is: the parent component’s data is modified first (triggers the update), the child component is modified (triggers the update), the child component is updated (renders), the parent component says it is updated (renders).

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

The destruction stage is:

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

4. Slot Distributes content

  • Slot slots are used when a parent component wants to insert something into a child component’s label.
  • When a component tag is used, the contents of the component tag will be automatically filled in (replacing the slot position in the component template).

The basic use

The use of slots is simple in two steps:

Step 1: Write the slot label

default
in the template of the child component; Step 2: When the parent component uses the child component, write the content you want to insert in the label of the child component, such as

hello, CAI Xukun

Scope: In the parent component, the scope of the slot-distributed content (the slot pit) is the parent component, which can directly bind the methods and data in the parent component

A named slot

  • As the name implies, a named slot is a slot that has a name. If a parent component wants to distribute multiple content to its children and needs to dig multiple holes in the children, it needs to use the named slot.

Named slot usage steps:

1. If a child component uses multiple slots, name it with the name of the slot label. 2. Write the content you want to insert into the parent component, and write the outermost tag (template tag can be used) : V-slot: slot name, v-slot: can be shortened to #. For example, v-slot:header=’slotProps’

Scope slot

  • When a parent component is inserted into a child component slot, it can only access the data and methods of the parent component. If you want to access the data and methods of the child component, you need to apply to the slot.

Steps:

Step 2: The parent component sets a value with v-slot to define the name of the slot we provide: V-slot :footer=”slotProps”

Step 3: Use slotProps. User to use the data

Exclusive default slot abbreviation

When only one default slot is used and we want to pass the child’s data, we can use the child tag as the outer element, saying V-slot =’… Can ‘

Other ways of writing V-slot (deconstructing slot)

Note the way v-slot is written:

    <div id="app">
      <one v-slot="{childName}">
         {{childName}} {{name}}
     </one>
    </div>

    <template id="one">
      <div>
        <header>
          <slot :child-name="name"></slot>
          <span>I am a head</span>
        </header>
      </div>
    </template>
Copy the code
    <div id="app">
      <one v-slot="{childName:aaa}">
         {{aaa}} {{name}} 
     </one>
    </div>

    <template id="one">
      <div>
        <header>
          <slot :child-name="name"></slot>
          <span>I am a head</span>
        </header>
      </div>
    </template>
Copy the code

5. Advanced features of components

5.1 Customizing the V-Model

5.2 $nextTick () and refs

  • Vue performs asynchronous rendering for performance reasons: when data changes, dom does not render immediately, but updates the data changes to the view once the data is no longer changing.
  • When the DOM is updated, it executes this.$nextTick(()=>{})The callback function allows us to retrieve the latest DOM node after manipulating data.
  • We can combine refs to get dom nodes. Register ‘ref= XXX’ in the parent element tag, and then retrieve the DOM node via ‘this.refs’. Register ‘ref= XXX’ in the parent element tag, and then get the DOM node through ‘this.refs’. ‘ref= XXX’ is registered in the parent element tag, and the DOM node is obtained by ‘this.refs. XXX’, which is a read-only attribute.
<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <ul ref="ul1">
        <li v-for="item in list">{{item}}</li>
      </ul>
      <button @click="addItem">Add 1 item</button>
    </div>
    <script>
      vm = new Vue({
        el: "#app".data: {
          list: ["a"."b"."c"],},methods: {
          addItem() {
            this.list.push(`The ${Date.now()}`);
            this.list.push(`The ${Date.now()}`);
            this.list.push(`The ${Date.now()}`);
            // Get the DOM element
            // We can get the DOM element from this.$refs by writing ref=' XXX 'inside an element
            const ulEle = this.$refs.ul1;
            console.log(ulEle.childNodes.length); //3 does not include all of them, because the DOM does not change immediately after data changes. To get all of the dom nodes, you must use 'this.$nextTick()'
            / / is as follows:
            // 1. Render asynchronously, $nextTick will be called back after dom rendering
            // 2. Data changes will be integrated during page rendering. Multiple data changes will only be rendered once
            this.$nextTick(() = > {
              const ulEles = this.$refs.ul1;
              console.log("NextTick.", ulEles.childNodes.length);
              console.log("NextTick.", ulEles); }); ,}}});</script>
  </body>
</html>

Copy the code

5.3 Dynamic and Asynchronous Components

Dynamic components

Vue comes with a < Component > tag, which is used to dynamically display components. It has an IS attribute that selects the component to mount via the V-bind :is=” dynamic component name “attribute.

 <div id="app">
      <button @click="onChangeComponentClick(1)">To ComponentA</button>
      <button @click="onChangeComponentClick(2)">To ComponentB</button>
      <button @click="onChangeComponentClick(3)">To ComponentC</button><! -- Declared region --><component :is="componentId"></component></div> <! Define component template content --><template id="component-a">
      <div>component-a</div>
    </template>

    <template id="component-b">
      <div>component-b</div>
    </template>

    <template id="component-c">
      <div>component-c</div>
    </template>

    <script type="text/javascript">
      // Register components A/B/C
      var commponentA = {
        template: "#component-a"};var commponentB = {
        template: "#component-b"};var commponentC = {
        template: "#component-c"};var vm = new Vue({
        el: "#app".data: function () {
          return {
            componentId: commponentA,
          };
        },

        methods: {
          // A different value is passed through a click event to determine which component to mount the dynamic block
          onChangeComponentClick: function (type) {
            switch (type) {
              case 1:
                this.componentId = commponentA;
                break;
              case 2:
                this.componentId = commponentB;
                break;
              case 3:
                this.componentId = commponentC;
                break; ,}}}});</script>
Copy the code

A way to declare a component by < Component >, bind a component by V-bind :is, and change the orientation of a component to change what is displayed is called a dynamic component.

2. Every time we switch component, the template in Component will always be re-rendered, and we know that every DOM rendering is a performance-consuming operation. The

tag tells Vue to cache the rendered component if you want to avoid repeated rendering.



Asynchronous components

Take a common phenomenon in life to see what is asynchronous: you boil water, do not wait for the water to boil to brush your teeth, the water will make a sound to tell you, and then you deal with the water after boiling! It’s a bit of a leap to understand the official explanation after reading this!

In large applications, we may need to break the application into smaller code blocks and load a module from the server only when needed. For simplicity, Vue allows you to define your component as a factory function that asynchronously parses your component definition. Vue fires the factory function only when the component needs to be rendered, and caches the result for future re-rendering. One of the most important functions of asynchronous loading is to speed up page access. For example, we can make some non-first screen pages asynchronously loaded.

  <div id="app">
    <async-example></async-example>
  </div>
  
  <template id="demo">
    <div>I am an asynchronous component</div>
  </template>
   
  <script type="text/javascript">
    // Register the component
    var resCom = {
      template: "#demo"
    }
    
    Vue.component('async-example'.function(resolve, reject){
      setTimeout(function(){
        // Pass the component definition to the resolve callback
        resolve(resCom);
      }, 1000);
    });
    
    var vm = new Vue({
      el: "#app"
    })
  </script>
Copy the code
  • In the above code, we first declare a variable resCom and give it a template pointing to async-Example, which is exactly what we did when we declared the local component.
  • Vue.component(‘async-example’, function (resolve, reject){} creates a factory function that takes resolve and reject. These parameters represent two callback methods. We can use resolve(resCom) to asynchronously load the defined resCom component, or reject(‘ load failure description ‘). To indicate a load failure. Here setTimeout is used only to simulate asynchronous operations. Of course, the above code can also be used as a local component:
var vm = new Vue({
    el: '#app'.components: {
        'async-example': function (resolve, reject) {
            setTimeout(function () {
                resolve(resCom);
                // reject(' load failure description ');
            }, 1000); }}});Copy the code

Modify:

// Register the component
    var resCom = {
      template: "#async-example"
    };
    
    var promise = new Promise(function(resolve, reject){
      setTimeout(function(){
        resolve(resCom)
      }, 1000);
    });
    
    var vm = new Vue({
      el: "#app".components: {'async-example':function(){
          return promise
        }
      }
    })

Copy the code

In Webpack you can build like this:

// Global registration
Vue.component(
  'async-webpack-example'.// The 'import' function returns a 'Promise' object.
  () = > import('./my-async-component'))// Local registration
new Vue({
  // ...
  components: {
    'my-component': () = > import('./my-async-component')}})Copy the code

Advanced asynchronous registration:

  <script type="text/javascript">
    // Register the component
    var resCom = {
      template: "#async-example"
    };
    
    var promise = new Promise(function(resolve, reject){
      setTimeout(function(){
        resolve(resCom)
      }, 2000);
    });
    
    var LoadingComponent = {
      template: '
      
Component shown under load
'
}; var ErrorComponent = { template: '
Asynchronous component load failed
'
}; const AsyncComponent = function(){ return { // The component to load (should be a 'Promise' object) component: promise, // The component used when the asynchronous component is loaded loading: LoadingComponent, // The component used when loading failed error: ErrorComponent, // Display the component delay time when loading. The default is 200 (ms) delay: 200.// If a timeout is provided and the component loads time out, // Use the component used when the load failed. The default value is' Infinity ' // PS: component loading timeout. If the timeout indicates that the loading fails, ErrorComponent will be displayed. For example, when we change the Promise setTimeout to 4000, ErrorComponent is displayed timeout: 3000}}var vm = new Vue({ el: "#app".// Notice the difference here because we are taking this method out and assigning it to the AsyncComponent variable components: {'async-example': AsyncComponent } }) </script> Copy the code

Register asynchronous components by registering the route method:

// Register the route with a statement that registers the asynchronous component,
// The 'import' function returns a 'Promise' object
// Use asynchronous components with webpack's code-splitting feature
component: () = > import(/* webpackChunkName: "index" */ './views/Index.vue')
Copy the code

5.4 Keep-alive Cache Component

1, What is keep-alive?
  • Keep-alive is a built-in component of Vue that caches inactive component instances when wrapping dynamic components rather than destroying them (The main goal is to preserve component state and avoid re-rendering). Like Transition, keep-Alive is an abstract component: it does not render itself as a DOM element, nor does it appear in the parent component chain.

Take a look at the specific usage scenario:

  • In the first common scenario, when we go from the home page – > list page – > Business page – > back, the list page should be keep-alive.
  • Second, when we go from the home page – > list page – > business page – > return to the list page (cache required) – > return to the home page (cache required) – > return to the list page (no cache required), this is the keep-alive control of the page on demand.
2. Keep – Props of the alive
  • Include – a string or regular expression. Only components with matching names are cached.
  • Exclude – a string or regular expression. Any component with a matching name will not be cached.
  • Max – Numbers. Maximum number of component instances can be cached.
3. Life cycle functions

In a keep-alive wrapped component or route, there are two additional hook functions: activated and deactivated. When a component is switched internally, its activated and deactivated lifecycle hook functions are executed accordingly. If exclude is used, both hook functions will not be called even if wrapped in keep-alive. In addition, this hook function is not called during server-side rendering.

  • 1. Activated: this hook function is called when the keep-alive component is activated. This hook function is not called during server-side rendering.
  • If keep-alive is used, data is stored in memory. To obtain the latest data each time a page is entered, data needs to be obtained in the Activated phase, which is responsible for obtaining data in the original Created hook function.
  • 2. Deactivated: This hook is called when the keep-Alive component is disabled. This hook is not called during server-side rendering
Application in dynamic components
<keep-alive :include="whiteList" :exclude="blackList" :max="amount">
     <component :is="currentComponent"></component>
</keep-alive>
Copy the code
Application in VUe-Router
Cache all pages (in app.vue)
<template>
  <div id="app">
  	<keep-alive>
      <router-view/>
    </keep-alive>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>
Copy the code
Caching pages based on criteria (in app.vue)
//include defines the cache whitelist. Keep-alive caches hit components.
//exclude defines a blacklist. Matching components will not be cached.
// Max defines the upper limit of the cache component, beyond which LRU's policy is used to replace the cache data.
<template>
  <div id="app">// 1. Cache the component named test<keep-alive include='test'>
      <router-view/>
    </keep-alive>// 2. Use the cache component whose name is A or B with the dynamic component<keep-alive include='a,b'>
  	  <router-view/>
	</keep-alive>// 3. To use regular expressions, use v-bind<keep-alive :include='/a|b/'>
  	  <router-view/>
	</keep-alive>// 5<keep-alive :include='includedComponents'>
  	  <router-view/>
	</keep-alive>// 5. The component named test will not be cached<keep-alive exclude='test'>
  	  <router-view/>
	</keep-alive>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>
Copy the code
With the Router, cache some pages (in the index.js file in the Router directory)

Using the meta object provided by vue-Router, add a field to the cache such as the home page, list page, and business details to determine whether the user is going forward or backward and whether the user needs keep-alive

import Vue from 'vue'
import Router from 'vue-router'
const Home = resolve= > require(['@/components/home/home'], resolve)
const Goods = resolve= > require(['@/components/home/goods'], resolve)
const Ratings = resolve= > require(['@/components/home/ratings'], resolve)
const Seller = resolve= > require(['@/components/home/seller'], resolve)

Vue.use(Router)

export default new Router({
  mode: 'history'.routes: [{path: '/'.name: 'home'.component: Home,
      redirect: 'goods'.children: [{path: 'goods'.name: 'goods'.component: Goods,
          meta: {
        	keepAlive: false // No caching is required}}, {path: 'ratings'.name: 'ratings'.component: Ratings,
          meta: {
        	keepAlive: true  // Cache is required}}, {path: 'seller'.name: 'seller'.component: Seller,
          meta: {
        	keepAlive: true  // Cache is required}}]}})Copy the code
In app.vue ($route.meta. KeepAlive)
<template>
  <div id="app">
  	<keep-alive>
      <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
    <router-view v-if=! "" $route.meta.keepAlive"></router-view>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>
Copy the code
Now set up the component cache on demand for the scenario

router.js

 / / home page
  {
    path: The '*'.name: 'Home'.// Route lazy loading:
    component: () = > import(/* webpackPreload: true */ '@/views/home'),
    meta: {
      keepAlive: true.deepth: 1}},// List of items
  {
    path: '/product'.name: 'Product'.component: () = > import('@/views/product'),
    meta: {
      keepAlive: true.deepth: 2}},// Product details
  {
    path: '/detail'.name: 'Detail'.component: () = > import('@/views/detail'),
    meta: {
      keepAlive: true.deepth: 3}},Copy the code

App. Under the vue

<template>
  <div id="app">
    <keep-alive :include="include">
      <router-view v-if="$route.meta.keepAlive" />
    </keep-alive>
    <router-view v-if=! "" $route.meta.keepAlive" />
  </div>
</template>


export default {
  data() {
    return {
      include: []}; },watch: {
    $route(to, from) {
      // If the page to be entered requires a keepAlive cache, push the name into the include array
      if (to.meta.keepAlive) {
        !this.include.includes(to.name) && this.include.push(to.name);
      }
      // If the page to form from is keepAlive cached,
      // Go back or forward according to deepth
      // If it is a backstep:
      if (from.meta.keepAlive && to.meta.deepth < from.meta.deepth) {
        const index = this.include.indexOf(from.name); index ! = = -1 && this.include.splice(index, 1); }}}};Copy the code
Use meta. KeeAlive and key values

First of all, we will definitely use the meta. KeeAlive field to determine, but we don’t need to define the deepth depth.

When we enter the app.vue page, we add a key to

. This key is just like what we defined with the V-for loop.

<template>
  <div id="app">
    <keep-alive>
      <router-view v-if="$route.meta.keepAlive" :key="key" />
    </keep-alive>
    <router-view v-if=! "" $route.meta.keepAlive" :key="key" />
  </div>
</template>

<script>
  export default {
    computed: {
      key() {
        return this.$route.fullPath; }}};</script>
Copy the code
// Then we add a timestamp to the page parameter that needs to be forcibly refreshed, so that we can implement keep-alive on demand.
  onClick() {
      this.$router.push({
        path: '/product'.query: {
          t: +new Date()}})}Copy the code

5.5 Mixin components disassociate common logic

Mixins provide a very flexible way to distribute reusable functionality in Vue components. A mixin object can contain any component option. When a component uses mixin, all mixin options are “blended” into the component’s own options.

  • 1. When a component uses mixin, all mixin options are “blended” into the component’s own options;
  • 2. The data objects are internally recursively merged, and in case of a conflict, the component data takes precedence. The hook function of the same name is merged into an array, so both will be called. In addition, hooks mixed with objects are called before the component’s own hooks;
  • 3. The options that are values for objects, such as Methods, Components, and directives, will be combined into the same object. When two object key names conflict, the key value pair of the component object is taken;
  • 4. Use global mixin with caution, as it affects each individually created Vue instance (including third-party components).
The basic use

Step 1: SRC /mixin/demo.js

export default {
    data(){
      return {
        msg:"This is mixin's data.".mixinMsg:"This is mixin's data.",}},created(){
      console.log(123)},methods: {onClick(){
        console.log('Triggered onClick in mixin')}}}Copy the code

Step 2: Introduce and use mixins in components where only mixins are used.

<template>
  <div class='container'>
    <div>{{msg}}</div>
    <div>{{mixinMsg}}</div>
    <div @click="onClick">click</div>
  </div>
</template>

<script>
import mixin from '@/mixin/demo.js';
export default {
  mixins:[mixin],
  //1. The attribute in data takes precedence over the data in the component in case of key-value conflicts
   data () {
    return {
      msg: 'Data in component'}},//2. The hook functions of the same name will be merged into an array and will be called sequentially. The hook functions of mixed objects will be called before the component spawses hook functions
  created(){
    console.log('Created within components')},//3. The options that are values for objects, such as Methods, Components, and directives, will be combined into the same object. When two object key names conflict, the component object's key takes precedence.
  methods: {
    onClick(){
      console.log('Triggered onClick in component')}}}</script>
Copy the code
Global component mixing

Call vue.mixin () for global mixing before initializing Vue, which can be used in main.js:

Vue.mixin({
  data(){
    return {
      $_globalMsg:"Global mixin data"}},created(){
    console.log('Trigger the creation of global mixins')},methods:{
    $_globalMixin(){
      console.log('$_globalMixin')}}})Copy the code
Case – mix in lazy loading images

Add lazy loading to all images in the component

Step 1: SRC /mixin/demo.js

import logo from '@/assets/logo.png'
export default {
  data() {
    return {
      baseImg: logo,
      $_timer: null}},mounted() {
    // First screen lazy load once
    this.$_lazyLoadImage();
    // Listen for croll events
    window.addEventListener('scroll'.this.$_handelScroll);
    // Remove the croll event
    this.$on('hook:beforeDestroy'.() = > {
      window.removeEventListener('scroll'.this.$_handelScroll)
    })
  },
  methods: {
    $_handelScroll() {
      clearTimeout(this.$_timer);
      this.$_timer = setTimeout(() = > {
        this.$_lazyLoadImage();
      }, 20);
    },
    // lazy loading of images
    $_lazyLoadImage() {
      const imgList = this.$_getNeedLoadingImg();
      if(imgList.length <= 0 ) return;
      // Check whether the image is displayed
      imgList.forEach(img= > {
        if (this.$_imgInView(img)) {
          this.$_showImg(img)
        }
      })
    },
    // Get the image to load
    $_getNeedLoadingImg() {
      let images = Array.from(document.querySelectorAll('img[data_src]'));
      images = images.filter(ele= > {
        return! ele.getAttribute('isloaded')})return images
    },
    // Calculate the position of the image to determine whether the image is displayed
    $_imgInView(img) {
      return window.innerHeight + document.documentElement.scrollTop >= img.offsetTop
    },
    // Display the image
    $_showImg(img) {
      const image = new Image();
      const src = img.getAttribute('data_src')
      image.src = src;
      image.onload = () = > {
        img.src = src;
        // The tag is loaded
        img.setAttribute('isloaded'.true); }}}}Copy the code

Step 2: Use in required components

<template>
  <div class='container'>
    <div><img :src="baseImg" alt=""></div>
    <div v-for="(item,index) in imgSrc" :key="index" ><img :src="baseImg" :data_src="item" alt=""></div>
  </div>
</template>

<script>
import mixin from '@/mixin/demo.js';
export default {
  mixins:[mixin],
  data(){
    return {
      imgSrc: ['Play image link']}}}</script>

<style lang="scss" scoped>
img{
  width: 200px;
  height: 200px;
}
</style>
Copy the code

Part 7: Custom directives and filters

Custom instruction (V-XXX)

In Vue, in addition to the core functionality of the default built-in directives (V-model and V-show), Vue also allows the registration of custom directives. Use custom instructions to perform low-level operations on ordinary DOM elements for reuse purposes.

Registration instructions are divided into global registration and local registration

Custom global directives

It is usually registered directly in the main.js file and can be used in the component

// pseudo-code:
vue.directive('Custom instruction name', {lifecycle name:function (el) {instruction business logic code}});// Example: v-color
 Vue.directive("color", {
        // Where el is the element to which the directive is bound
        bind: function (el) {
            el.style.color = "red"; }});<p v-color>I am a paragraph</p>
Copy the code
Custom local directives
  • Add directives to the object passed when creating the Vue instance
  • Can only be used in the custom Vue instance
 let vm= new Vue({
        el: '#app'.directives: {
            "color": {
                bind: function (el, obj) { el.style.color = obj.value; }}}});Copy the code

Custom instruction lifecycle hook functions

bind

The directive is executed when it is bound to a DOM element, and since it is bound only once, it is executed only once, where one-time initialization is possible.

inserted

Called when the bound element is inserted into the parent (the parent is guaranteed to exist, but not necessarily inserted into the document)

update

Called when the component’s VNode is updated, but may occur before its child VNodes are updated. The value of the instruction may or may not have changed. But you can ignore unnecessary template updates by comparing the values before and after the update.

componentUpdated

Called after the VNode of the component where the directive resides and its child VNodes are all updated.

unbind

Called when the directive is unbound from a DOM element (the bound DOM element is removed by Vue) and only once.

#### 3. Customize command parameter transmission

  • For example: v-model=”name”, we can also pass pass in our custom directive.
  • When you execute the method that corresponds to the custom instruction, in addition to passing us an EL, you’re also passing us an object that holds the parameters that the instruction passed to you.
<div id="app">
    <p v-color="curColor">I am a paragraph</p>
</div>
<script>
    Vue.directive("color", {
        // Where el is the element to which the directive is bound
        bind: function (el, obj) { el.style.color = obj.value; }});let vue = new Vue({
        el: '#app'.data: {
            curColor: 'green'
        },
        methods: {}});</script>
Copy the code

The filter

  • Vue.js allows you to customize filters that can be used for some common text formatting. Filters can be used in two places: double curly brace interpolation and v-bind expressions (the latter supported as of 2.1.0+). Filters should be added to the end of JavaScript expressions, indicated by the “pipe” symbol:
  • Filters and functions are used to process data as well as computed properties, but filters are generally used to format inserted text data.
// The values on the left are passed to the filters on the right<! - in a pair of curly braces - > {{message | capitalize}} <! -`v-bind`-- - ><div v-bind:id="rawId | formatId"></div>
Copy the code
  • By default, functions that process data take one parameter, the current data to be processed, and the filter can be used continuously.
    <div id="app">
      <! Vue will pass the name to the specified filter, and then insert the result into the specified element to render.

      <p>{{name | formartStr2}}</p>
    </div>
    <script>
      Vue.filter("formartStr2".function (value) {
        console.log(value); // Tsinghua University, MIT, Imperial College London
        // The regular expression '/ university /g' matches colleges globally and then replaces colleges
        value = value.replace(/ g/university."College");
        console.log(value); // Tsinghua Wudaokou Institute, MIT, Imperial College London, Shrek College
        return value;
      });
      let vue = new Vue({
        el: "#app".data: {
          name: "Tsinghua Wudaokou University, MIT, Imperial College London, Shrek University.",}});</script>
Copy the code

Part 8: Rendering functions and JSX syntax

1. The virtual DOM

  • The virtual DOM is described as the ==DOM == element using ordinary JavaScript objects. In a Vue, each virtual node is an instance of a VNode. The high performance of vue. js is due to the virtual DOM mechanism.
  • A virtual DOM object is a normal JavaScript object. Accessing a JavaScript object is much faster than accessing the real DOM. Vue compares the differences in the virtual DOM structure before and after updating the real DOM. The difference is then updated to the real DOM using an asynchronous update queue.

Real DOM structure:

<div id="app">
    <h1>Hello, vue</h1>
</div>
Copy the code

Vue. Js virtual DOM creates JavaScript objects:

    var vNode = {
        tag:'div'.data: {attrs: {id:'app'}},children: {/ / h1 node}}Copy the code

2. The render function

Concept:

  • Vue provides the render() function that lets you programmatically generate HTML templates using JavaScript. In most cases, we use the template template in the Vue instance to build the HTML.
  • The render function, like template, is used to create HTML templates, but can be used in scenarios where template is verbose and repetitive.

Parameters:

  • The Render function takes a function parameter createElement.
  • The return value of the Render () function must be the createElement() method, which creates a virtual node.

CreateElement () takes three arguments:

  • 1. The first argument is an HTML tag string, component option object, or an async asynchronous function that parses any of the above. Type: {String | Object | Function}.A necessity.
  • 2. The second argument is a data object that contains attributes related to the template. You can use these attributes in the template. Type: {Object}. Optional. A simple point is the set of attributes of an element (including general attributes, PORp, event attributes, custom instructions, etc.).
  • The third argument is the child node information, which is printed as an array. If the element has only text child nodes, it is given as a string. If there are other child elements, createElement is called.
  • All VNodes in the component tree must be unique, and if you want to repeat elements/components many times, you can do this using factory functions.
render: function (createElement) {
  return createElement('div'.Array.apply(null, { length: 20 }).map(function () {
      return createElement('p'.'hi')}}))Copy the code
  • JavaScript replaces template functionality

When we used templates to build HTML earlier, we could use directives. These instructions are not available when creating templates with the Render function, so we have to write our own JavaScript to implement them.

/ / v - if and v - for
<ul v-if="items.length">
  <li v-for="item in items">{{ item.name }}</li>
</ul>
Copy the code

To build the above HTML page using the Render function, the process is as follows:

props: ['items'].render: function (createElement) {
  if (this.items.length) {
    return createElement('ul'.this.items.map(function (item) {
      return createElement('li', item.name)
    }))
  } else {
    return createElement('p'.'No items found.')}}// Check the length of item. If the length is 0, return a p label. If the length is not 0, return a ul label, and loop to create li child nodes
Copy the code
  • v-model

The essence of the V-Model is to use the value of value as a prop and listen for input events, and the above code is implemented according to the logic of the V-Model.

props: ['value'].render: function (createElement) {
  var self = this
  return createElement('input', {
    domProps: {
      value: self.value
    },
    on: {
      input: function (event) {
        self.$emit('input', event.target.value)
      }
    }
  })
}
Copy the code

3.render:h => h(App)

  • The render function renders a view and then provides it to the EL to mount
  • 1. The render method of the Vue instance option object takes the argument h function as a function and returns the result of the function call to h(App).
  • 2. Second, when Vue creates a Vue instance, it renders the DOM tree of the instance by calling the Render method.
  • 3. Finally, when Vue calls the render method, it passes in a createElement function as an argument, and createElement is called with APP as an argument.
render: h= >H (App) is short for:render: function (createElement) {
    return createElement(App);
Copy the code

4.JSX

The Render function solved our problem, but it was too much work. That’s why there’s a Babel plug-in for using JSX syntax in Vue, which brings us back to a more template-like syntax.

import AnchoredHeading from './AnchoredHeading.vue'

new Vue({
  el: '#demo'.render: function (h) {
    return (
      <AnchoredHeading level={1}>
        <span>Hello</span> world!
      </AnchoredHeading>)}})Copy the code

Part nine: Transitions in Vue

  • In the Vue project, we can use the TRANSITION component wrapped in Vue to add transitions and animations to arbitrary elements and components
  • It is used with v-if, V-show, dynamic components, and the root node of components. V-if, V-show add animation when displaying hidden components; Component switch page switch, add transition animation, fade in and out effect to enhance user experience.

Includes the following tools:

  • Automatically apply class to CSS transitions and animations
  • You can use third-party CSS animation libraries, such as animation.css
  • Use JavaScript to manipulate the DOM directly in transitional hook functions
  • You can use a third-party JavaScript animation library, such as velocity.js

1. Name of the transition class

Animation entry:

  • V-enter: The initial state before the animation enters. It takes effect before the element is inserted and is removed the next frame after the element is inserted.
  • V-enter -to: Indicates the end state after the animation enters. The next frame takes effect after the element is inserted (the V-enter is removed at the same time) and removed after the transition/animation is complete.
  • V-enter-active: indicates the period during which the animation enters. Applied throughout the transition phase, before the element is inserted and removed after the transition/animation is complete. This class can be used to define the process time, delay, and curve functions that enter the transition.

PS: The first and second are time points; The third is the time period. Animation away:

  • V-leave: The initial state before the animation leaves. Immediately after the exit transition is triggered, the next frame is removed.
  • V-leave-to: Indicates the end state after the animation leaves. The next frame takes effect after the exit transition is triggered (and the V-leave is deleted at the same time), and is removed after the transition/animation is complete.
  • V-leave-active: indicates the period during which the animation leaves. Applies throughout the exit transition phase, takes effect immediately when the exit transition is triggered, and removes after the transition/animation is complete. This class can be used to define exit transition process time, delay and curve functions.

PS: The first and second are time points; The third is the time period.

Note that v- is the default prefix for class names that are switched in transition if you use an unnamed
. If you use
then v-Enter will be replaced with my-transition-Enter.

Principle description:

  • 1. The first and most basic thing is that if you want to animate a transition within a single element/component, you need to wrap a tag around the element/component’s HTML tag, which is used for both transitions and animations.
  • 2. As mentioned above, when an element/component is wrapped in a tag, Vue will automatically build an animation process, that is, automatically add/remove corresponding CSS class names at a certain point in time. Vue actually provides six corresponding class names, as shown in the figure above.

2. The transition

Specific implementation process:

<style>
/* You can set different entry and exit animations */

/* Sets the duration and animation function */
.v-enter{
  transform: translateX(10px);
  opacity: 0;
}
.v-enter-active {
  transition: all .3s ease;
}
/*v-enter-to is the same thing as V -leave and you can just write one or you can omit it, just write v-enter and V -leave-to and the entry and exit functions */
.v-enter-to{}
.v-leave{}

.v-leave-active {
  transition: all .8s cubic-bezier(1.0.0.5.0.8.1.0);
}
.v-leave-to{
  transform: translateX(10px);
  opacity: 0;
}
</style>

<transition>
    <p v-if="show">hello</p>
</transition>
Copy the code

To:

  • Before the transition begins, the P tag is added to class V-enter -active, class V-Enter; When the transition begins, class V-Enter is removed and class V-enter to is added. After the transition is complete, class V-enter -active and class V-Enter -to are removed.

Leave:

  • Class V-leave-active and class V-leave will theoretically be added before leaving. At the beginning of the transition, class V-leave is removed and class V-leave-to is added. Theoretically, class V-leave is added and removed instantaneously, so I did not observe it. Based on the actual effect, I don’t think v-leave is working.

3. The CSS animations

// Step 1: write the keyframe function
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.5);
  }
  100% {
    transform: scale(1); }}// Step 2: Write the entry and exit states
.v-enter-active {
  animation: bounce-in .5s;
}
.v-leave-active {
  animation: bounce-in .5s reverse;
}
// Step 3: use in style
<transition >
    <p v-if="show">Lorem ipsum dolor sit amet</p>
</transition>
Copy the code

4. Transition-group list transition

Transition-group generates a real DOM node, which defaults to span and can be switched by tag=”ul”. Transition-group must have a key value.

5. CSS animation: Animate. CSS library

The Animate. CSS base address

1.1 Import the Animate. CSS library

NPM install animate. CSS -- Save<head>
  <link
    rel="stylesheet"
    href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
  />
</head>
Copy the code

1.2 Bind required class names to properties during execution

<h1 class="animate__animated animate__bounce">An animated element</h1>

//或者
.my-element {
  display: inline-block;
  margin: 0 0.5rem;

  animation: bounce; /* referring directly to the animation's @keyframe declaration */
  animation-duration: 2s; /* don't forget to set a duration! */
}
Copy the code

Part 10: Vue-Router

  • The single-page application of VUE is based on routing and components, which are used to set access paths and map paths to components. The traditional page application uses some hyperlinks to realize the page switch and jump. In vue-Router single-page applications, the switch between paths is actually a component switch. Routing is the path manager for SPA (single page application).
  • Implementing routing in VUE is relatively simple. Because everything on our page is componentized, we just need to map the path to the component and render the component in the page.

Vue Router is the official route manager of vue.js. Its deep integration with vue.js core makes building single-page applications a breeze. The features included are:

  • Nested routing/view chart
  • Modular, component-based routing configuration
  • Route parameters, queries, and wildcards
  • View transition effect based on vue. js transition system
  • Fine-grained navigation controls with links to automatically activated CSS classes
  • HTML5 historical mode or Hash mode is automatically degraded in IE9
  • Custom scroll bar behavior

1. How to use vue-router?

  • Step 1: Install vue-Router
npm install vue-router -S
Copy the code
  • Step 2: Load the VueRouter plugin from the router file index.js using vue.use ()
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
Copy the code
  • Step 3: Configure the route (define the route and instantiate the route object)
//1. Define routing rules
const routes = [
  {
    path: '/'.name: 'Home'.component: Home
  },
  {
    path: '/about'.name: 'About'.component: () = > import(/* webpackChunkName: "about" */ '.. /views/About.vue')}]//2. Instantiate the routing object
const router = new VueRouter({
  routes
})
//3. Export the route instance object
export default router
Copy the code
  • Step 4: Mount the route instance object to the root instance (main.js)
import App from './App.vue'
import router from './router'

new Vue({
  router,
  render: h= > h(App)
}).$mount('#app')
Copy the code
  • Step 5: Set up jump navigation

Click to jump to the corresponding routing component (represented by a change in URL)

<template>
  <div id="app">
    <div id="nav">
    <! -- Jump navigation -->
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <router-view/>
  </div>
</template>
Copy the code
  • Step 6: The root component template sets up routing outlets (using routes)

Displays the current routing component content based on the URL path

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
     <! -- Route exit -->
    <router-view/>
  </div>
</template>
Copy the code

2. Routing mode (hash H5 history)

Front-end routing: It is to match a special URL for each view presentation form in SPA while ensuring only one HTML page and not refreshing or jumping pages when interacting with users. Refresh, forward, backward, and SEO are all done through this particular URL. To achieve this goal, we need to do the following two things:

  • Change the URL and prevent the browser from sending requests to the server.
  • You can listen for url changes

Vue-router models have two modes: hash mode and history mode.

Hash pattern

  • Hash mode is used by the browser to render the specified component by changing the value after #. Vue uses Hash mode by default.

Description:

  • Here the hash is the hash after the URL and the character after it.
  • Window. The location. The hash.
  • In hash mode, only the content before the hash symbol is included in the request. Changing the hash value does not cause the browser to send the request to the server.
  • Whenever the hash changes, the URL is logged by the browser so that you can use the browser’s back.
  • Changing the hash (forward and back of the browser) does not reload the page and triggers the Hashchange event.
Apis used in hash mode:
window.location.hash = 'Hash string'; // Set the hash value

let hash = window.location.hash; // Get the current hash value

// Listen for hash changes, triggered by clicking the browser's forward and back
window.addEventListener('hashchange'.function(event){ 
    let newURL = event.newURL; // Hash the new URL
    let oldURL = event.oldURL; // Hash the old URL before changing it
},false)
Copy the code

Browsers had history objects before HTML5. But in the early days of History, you could only use multiple page jumps: History — takes advantage of the new pushState() and replaceState() methods in the HTML5 History Interface. (Browser-specific support required) These two methods apply to the browser’s history stack and provide the ability to modify the history in addition to the existing back, Forward, and Go methods. It’s just that when they make changes that change the current URL, the browser doesn’t immediately send requests to the back end.

The history mode

The History mode uses the pushState() method to modify the browser’s History without asking the back end to render it. However, it is recommended to use the history mode for the actual project.

const router = new VueRouter({
  mode: 'history'.// If not, the route uses hash mode by default
  routes: [...]. })Copy the code

Browsers had history objects before HTML5. But in the early days of History it could only be used for multi-page jumps:

history.go(-1);       // Go back one page
history.go(2);        // Proceed two pages
history.forward();     // Move forward one page
history.back();      // Go back one page
Copy the code

In the HTML5 specification, History adds the following apis:

window.history.pushState(state, title, url)
/* // Add a new state to the history stack. State: data that needs to be saved. This is a valid Javascript object. When the popState event is triggered, the title can be obtained in the event. The origin of the new URL must be the same as the origin of the current URL, otherwise an error will be thrown. A URL can be an absolute path or a relative path. If the current url is https://www.baidu.com/a/, execution history. PushState (null, null, '/'/qq), as https://www.baidu.com/a/qq/, Execution history. PushState (null, null, '/ qq /), is turned into https://www.baidu.com/qq/ * /

window.history.replaceState(state, title, url)
/* // Replacing the current state with a new state replaces the current page history in history with the URL. Basically the same as pushState, except that it modifies the current history, while pushState creates a new history */

window.addEventListener(" popState ", function() {// returns the current state object // listens for browser forward and backward events, pushState and replaceState methods do not trigger});Copy the code

HTML5 introduces history.pushState() and history.replacestate () methods, which can add and modify history entries, respectively. These methods are usually used in conjunction with window.onpopState. Since history.pushState() and history.replacestate () can change urls without refreshing the page, histroy in HTML5 has the ability to implement front-end routing.

History changes do not trigger any events, so we cannot directly listen for history changes to make changes accordingly. Therefore, we need to think differently. We can list all the possible situations that can trigger history changes and intercept these ways one by one to monitor history changes in a disguised way. For the history mode of a single-page application, url changes can only be caused by one of the following four ways:

  • Click your browser’s forward or back buttons
  • Click on the A TAB
  • Trigger history.pushState in the JS code
  • Trigger the history.replaceState function in your JS code

Conclusion:

  • The pushState() method changes the URL without sending a request, and the replaceState() method reads the history stack and makes changes to the browser record. These two methods apply to the browser’s history stack and provide the ability to modify the history in addition to the existing back, Forward, and Go methods. It’s just that when they make changes that change the current URL, the browser doesn’t immediately send requests to the back end.
  • Under History, you are free to modify the path, and when refreshed, if there is no response or resource on the server, the 404 page will be refreshed. The way history mode changes the URL causes the browser to send a request to the server, which is not what we want to see, and we need to do it on the server side: if no static resource matches, the same HTML page should always be returned.

3. Dynamic route matching

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:

3.1 params refs

const User = {
// Step 3: Use parameters in the current component
  template: '<div>{{$route.params.name}}</div>'
}

const router = new VueRouter({
  routes: [
    // Step 1: Dynamic path parameters start with a colon
    { path: '/user/:name'.component: User }
  ]
})

// In a routing link
<router-link to="/user/:jack"> user < / router - the link >$route.params = $route.params = $route.params For example: {name: 'jack'}
Copy the code
 <router-link :to="{name:'User',params:{name:' CAI Xukun ',age:10}}"> user < / router - the link >Copy the code

3.2 query Configure parameter transmission

Const User = {// Step 3: Use the template: 'parameter in the current component.<div>{{this.$route.query.id}}</div>} const router = new VueRouter({routes: [// routes:]) {path: '/user', component: User}]}) // Pass in a routing link, starting with a question mark<router-link to="/ user? id=111">The user</router-link>
Copy the code

Vue-route automatically links? The following id=foo is encapsulated in this.route.query. At this point, in the component this.route.query. At this point, in the component this.route.query. In this case, the value of this.route.query.id in the component is ‘foo’. == In addition to the router-link to attribute, query can also be passed as an argument == via programmatic navigation as described below

3.3 The listening route is changed

  • After dynamic routes are configured, all routes correspond to the same component. For example, user/: ID is configured for:, and route forward is configured for:/user/foo 和 /user/barWhen routing parameters are used, the User component is reused. The component’s lifecycle hook is no longer called. If you want to do some initialization when switching paths, you can use the following two solutions:
  • Watch (monitor changes) $route object within component:
const User = {
 template: '... '.watch: {
   '$route' (to, from) {
     // Respond to routing changes...}}}Copy the code
  • Or. BeforeRouteUpdate Navigation guard if the destination is the same as the current route, only the parameters are changed (e.g. from one user profile to another /users/1 -> /users/2), You need to use beforeRouteUpdate to respond to this change (such as fetching user information).
const User = {
  template: '... ',
  beforeRouteUpdate (to, from, next) {
	// react to route changes...
	// don't forget to call next()}}Copy the code

Router,routes,route

  • 1. Router: Generally refers to a router instance. Such as $router.
  • 2. Routes: indicates the Routes API of the router routing instance. Used to configure multiple route routing objects.
  • 3. Route: refers to the route object. For example; $route refers to the current routing object.

4.1 The Router provides methods for programmatic navigation

Router: Router object that contains functions that manipulate routes for programmatic navigation. This generally refers to accessing routes within any component. Such as:

Routing programmatic navigation $router.push()

The argument to this method can be a string path or an object describing the address. Such as:

/ / string
router.push('home')

/ / object
router.push({ path: 'home' })

// Named route
router.push({ name: 'user'.params: { userId: '123' }})

// With query parameters, change to /register? plan=private
router.push({ path: 'register'.query: { plan: 'private' }})
Copy the code

Note: If path is provided, params will be ignored. You will need to provide either the name of the route or a handwritten path with arguments:

const userId = '123'
router.push({ name: 'user'.params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// Params does not work here
router.push({ path: '/user'.params: { userId }}) // -> /user
Copy the code
The router. The replace method

Router. replace is similar to router.push. Push adds a new record to history. Replace simply replaces the current browser history! What are the immediate consequences? Here’s an example:

  • Using the push method, page 1 goes to page 2, and you go back to page 1 using the browser
  • With the replace method, page 1 is replaced with page 2, and you use the browser’s back, and you can’t go back to page 1, you can only go back to page 0, the page before page 1.

So when do you use replace?

  • This is common when you don’t want the user to go back to the previous page, and then you don’t want the user to go back to the login page to authenticate again.
The router. The go (n) method

The argument to this method is an integer that means how many steps forward or backward in the history. Something like window.history.go(n). This controls how many steps the page moves forward or backward.

4.2 routes

Routes Creates the configuration item of the vue-router routing instance. Used to configure multiple Route routing objects

4.3 the route

5. Set routine by

A corresponding representation is a component, so there are two main points to implement nested routines:

  • Define child routes in routing objects (nested child routes)
  • In the component<router-view/>The use of.
// Step 1: Define child routes in the routing object (nested child routes)
 {
    path: "/user".component: User,
    name: "user".// Nested routines are written as routes in the children configuration.
    children: [{path: "".// Let it be displayed in user view by default
        component: UserDefault,
        name: "default"}, {path: "foo".component: UserFoo, name: "foo" },
      // Write the child path directly. In this case, path is equal to '/user/foo'. The child path inherits the parent path.],},// Step 2: use 
       within the component.
<template>
  <div>
    <div>The user component</div>
    <router-link to>The default user</router-link>
    <router-link to="/user/foo">User foo</router-link>
    <router-view></router-view>
  </div>
</template>
Copy the code

6. Named view (the way is displayed by the same normal component in the rule)

We know that clicking the current route path jump link will display the corresponding routing component, but if we want to make it jump and also display its brother non-routing component, we need to add a named routing outlet in the place of the default routing outlet of the same level, for the non-routing component of the same level to display. Just look at the picture.

7. Route redirection and alias

7.1 Route Redirection

Redirection means intercepting the path through a route and redirecting the URL to the route specified by the redirect. Redirection is done using the Routes configuration,

// Redirect from /a to /b
const router = new VueRouter({
	routes:[
		{path:'/a'.redirect:'/b'}]})/// Redirect from /a to a route named 'foo'
const router = new VueRouter({
  routes: [{path: '/a'.redirect: { name: 'foo'}}}])// Even a method that dynamically returns the redirected target:
const router = new VueRouter({
  routes: [{path: '/a'.redirect: to= > {
      // The method receives the destination route as an argument
      // Return redirects the string path/path object
	  const { hash, params, query } = to
	  // This uses ES6 deconstruction, which corresponds to the hash mode,params, and query parameters respectively. I'm not going to go into deconstruction here.
        if (query.to === 'foo') {
          return { path: '/foo'.query: null}}if (hash === '#baz') {
          return { name: 'baz'.hash: ' '}}if (params.id) {
          return '/with-params/:id'
        } else {
          return '/bar'}}}}])Copy the code

7.2 the alias

  • “Redirect” means that when the user accesses /a, the URL will be replaced with /b, and then the route will be matched with /b. What is the “alias”?
  • The alias for /a is /b, which means that when a user accesses /b, the URL remains /b, but the route matches/A, just as if the user accesses /a.
  • The alias is a route with two paths. Both paths can jump to this route.
// Alias is configured in the rutes alias:
const router = new VueRouter({
  routes: [{path: '/a'.component: A, alias: '/b'}]})// Use an alias
  <router-link to="/b">About</router-link>|
Copy the code

8. Route components send parameters

  • Route parameters can be passed through params and Query described earlier. However, these two methods of parameter passing are essentially putting parameters on the URL and changing the URL. This results in a high degree of coupling between parameters and components.
  • If I want to pass in parameters, I can be a little bit more free, not tied to the URL. This can be decoupled using rute’s props. Improved component reuse without changing urls.
//1. Component receive
const Hello = {
  props: ['name'].// If rute props is used to pass a parameter, the component must add props to receive the parameter
  template: '< div > Hello {{$route. The params}} and {{this. The name}} < / div >'
  // If this.name has a value, then name has been successfully passed as a component property
}

//2.
const router = new VueRouter({
mode: 'history'.routes: [
  // No parameter is passed so the component gets nothing
    { path: '/'.component: Hello }, 
  // If Boolean mode: props is set to true, route.params (name here) will be set to the component property.
    { path: '/hello/:name'.component: Hello, props: true }, 
  // Object mode: this has nothing to do with Params. The name is passed directly to the Hello component. Note: The props must be static!
    { path: '/static'.component: Hello, props: { name: 'world' }}, 
 /* Function mode: 1, this function can take a single argument, the current route object by default. 2, this function returns an object. 3, in this function, you can process static values and routing-related values. */ 
    { path: '/dynamic/:years'.component: Hello, props: dynamicPropsFn }, 
    { path: '/attrs'.component: Hello, props: { name: 'attrs'}}}])function dynamicPropsFn (route) {
  return {
    name: (new Date().getFullYear() + parseInt(route.params.years)) + '! '}}new Vue({
  router,
  el: '#app'}) <! - HTML part -- -- ><div id="app">
      <h1>Route props</h1>
      <ul>
        <li><router-link to="/">/</router-link></li>
        <li><router-link to="/hello/you">/hello/you</router-link></li>
        <li><router-link to="/static">/static</router-link></li>
        <li><router-link to="/dynamic/1">/dynamic/1</router-link></li>
        <li><router-link to="/attrs">/attrs</router-link></li>
      </ul>
      <router-view></router-view>
    </div>
Copy the code

9. Lazy route loading

  • Vue is mainly used for single-page applications. In this case, Webpack will pack a large number of files. As a result, the home page needs to load too many resources and the first screen takes too long, giving users an unfriendly experience.
  • If you use route lazy loading, load the page only when your route jumps. This way the home page loads less stuff and the first screen time is reduced.
  • VueRouter’s lazy loading mainly relies on Vue’s asynchronous component and Webpack’s code segmentation function, which can easily realize lazy loading of routing components. Just bring in the component as a promise.
  {
    path: "/about".name: "About".alias: "/a1111".component: () = > import(".. /views/About.vue"),}, orconst Foo = () = > import('./Foo.vue')
   routes: [{path: '/foo'.component: Foo 
     }
]

// Or group components into blocks
const Foo = () = > import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () = > import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () = > import(/* webpackChunkName: "group-foo" */ './Baz.vue')
Copy the code

10. Navigation Guard (Routing hook)

Route navigation guard, in layman’s terms, is a route hook. It also acts like a lifecycle hook, controlling operations during a route jump. Route guards are used for authentication of route hops, such as login authentication (you cannot enter the personal center page without login), etc

10.1 Navigation Guard classification

  • 1. Global front guardbeforeEach: 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.
//1. The configuration can be done in main.js or in a separate routing configuration file, router.js
	router.beforeEach((to, from, next) = >{... next(); });//2, which can also be set inside the component
	this.$router.beforeEach((to, from, next) = >{... next(); });//3, detailed instructions for the function and next()
    router.beforeEach((to, from, next) = > {
      next();// Do not omit next!! To go directly to the next hook.
	//next(false) interrupts current navigation
	//next('/path path ') or object next({path:'/path path '}) jumps to path routing address
	//next({path:'/shotcat',name:'shotCat',replace:true,query:{logoin:true}... } router-link to prop and router.push Replace :true is used to replace the current route address, which is used to modify the route after permission judgment.
	// Next (error) (2.4.0+)
    }).catch(() = >{
  // Jump to the failed page
  next({ path: '/error'.replace: true.query: { back: false}})})Router.onerror () router.onError() router.onError()
router.onError(callback= > { 
      console.log('Wrong! ', callback);
    });
Copy the code
  • 2. Global parse guardbeforeResolveThe parse guard is called before the navigation is confirmed and after all the intra-component guards and asynchronous routing components have been parsed.
  • AfterEach: These hooks do not accept the next function and do not change the navigation itself:
  • 4. Route exclusive guard: You can define beforeEnter guard directly on route configuration:
const router = new VueRouter({
  routes: [{path: '/foo'.component: Foo,
      beforeEnter: (to, from, next) = > {
        // ...
        // Use the same method as beforeEach above}}}])Copy the code
  • 5. Guards within components:beforeRouteEnter,BeforeRouteUpdate (2.2 New),beforeRouteLeaveYou can define the route navigation guard directly within the route component:
const Foo = {
  template: `... `.beforeRouteEnter(to, from, next) {
    // called before the corresponding route to render the component is confirmed
    / / no! Can!!!! Get component instance 'this'
    // Because the component instance has not been created before the guard executes
    // However, you can access component instances by passing a callback to next. The callback is executed when the navigation is validated, and the component instance is taken as an argument to the callback method.
     next(vm= > {
    // Access component instances through 'VM'})},beforeRouteUpdate(to, from, next) {
    // 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.
    // Access component instance 'this'
    this.name = to.params.name
  },
  
  
  
  beforeRouteLeave(to, from, next) {
    // called when navigating away from the component's corresponding route
    // Exit the current route, this time can be used to save data, or data initialization, or turn off the timer, etc
    // Access component instance 'this'
    const answer = window.confirm('Do you really want to leave? you have unsaved changes! ')
    if (answer) {
         next()
    } else {
         next(false)}}}Copy the code

10.2 Complete navigation parsing process

Navigation is triggered. Call the beforeRouteLeave guard in the deactivated component. Call the global beforeEach guard. Call the beforeRouteUpdate guard (2.2+) in the reused component. Call beforeEnter in routing configuration. Parse the asynchronous routing component. Call beforeRouteEnter in the activated component. Call the global beforeResolve guard (2.5+). Navigation confirmed. Call the global afterEach hook. Trigger a DOM update. Call the callback passed to Next in the beforeRouteEnter guard, and the created component instance is passed in as an argument to the callback.Copy the code

10.3 Navigation Guard Parameters

Each guard method takes three arguments:

  • To: Route: indicates the destination Route to be entered
  • From: Route: Indicates the Route object that the current navigation is leaving
  • 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 ().

11. Route meta information

During route configuration, add a custom meta object to each route. You can set some states in the meta object to perform some operations. It’s perfect for login verification. To gracefully and implicitly convey information, use meta objects!

const router = new VueRouter({
  routes: [{path: '/foo'.component: Foo,
      children: [{path: 'bar'.component: Bar,
          // a meta field
          meta: { requiresAuth: true}}]}})Copy the code
/* * matched: an array containing all nested path fragments of the current route */
router.beforeEach((to, from, next) = > {
  if (to.matched.some(record= > record.meta.requiresAuth)) {
	// Array some method, which returns true if meta. RequiresAuth is true. In this case, you need to check whether the user has logged in before entering the route
    if(! auth.loggedIn()) {// If you are not logged in, jump to the login page
      next({
        path: '/login'.query: { redirect: to.fullPath }  // This is a nice little detail in the official example. Query saves the route path to jump to. After login, you can get the path directly and jump to the route to go to before login})}else {
      next()
    }
  } else {
    next() // Be sure to call next()}})Copy the code
  • We can determine whether login authentication is required based on the status set in the meta. If requiresAuth in the meta is true, you need to check whether you are logged in and jump to the login page if you are not. If you have logged in, continue to jump.
  • Path, Params, and Query can store information as status markers for login authentication. Indeed, they can achieve the same effect. If you have a small number of individual validations, using them is not a problem.
  • But what if there are multiple routes that require login authentication? Path, Params, and Query explicitly store information in urls. And multiple paths add the same state information to the URL. This makes urls less simple and less elegant.

So to convey information gracefully and implicitly, use meta objects!

Take you to Vue (1)portal

See the next article: VueX and VUUE – CLI

Part 11: VueX

Basic concepts of VueX

state

mutation

getter

action

Used for Vue components

dispatch

commit

mapState

mapGetters

mapActions

mapMutations

Part twelve: Vue- CLI