main.js

new Vue({
    router,
    render: h= > h(App)
}).$mount('#app')
Copy the code

Question: What is the purpose of the router passed in when creating a Vue instance?

A: Two properties are injected into the Vue instance

  • $route Routing rules
  • $router Indicates the routing object

01 Dynamic Route

Method 1

{
    path: '/detail/:id'.name: 'Detail'.component: () = > import(/* webpackChunkName: "detail" */ '.. /views/Detail.vue'} $route.params.id = $route.params.idCopy the code

Way 2

{{path: '/detail/:id'.name: 'Detail'.// Enable props, which passes parameters in the URL to the component
    // Accept URL parameters in the component via props
    props: true.component: () = > import(/* webpackChunkName: "detail" */ '.. /views/Detail.vue'} Enable the props parameter in the routing ruleexport default {
    props: ['id']}Copy the code

02 Nested routines by

router.js

// Nested by
  {
    path: '/'.component: Layout,
    children: [{name: 'index'.path: ' '.component: Index
      },
      {
        name: 'detail'.path: 'detail/:id'.props: true.component: () = > import('@/views/Detail.vue')}}]Copy the code

Programmatic navigation

/ / 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

Programmatic navigation of VUE

HashHistoryPattern difference

HTML 5 History pattern

1. Differences in expression forms

  • HashModel –#
    • https://www.hnufw.com/#/playlist?id=3102961863
  • HistoryMode – Requires server cooperation
    • https://www.hnufw.com/playlist/3102961863

2. Principle difference

  • HashPatterns are based on anchor points, as wellonhashchangeThe event
  • HistoryPatterns are based onHTML5In theHistory API
    • History.pushstate () – supported only after IE10
    • history.replaceState()

The difference between pushState and push methods

When the push method is called, the path changes and a request is sent to the server;

Calling pushState does not send a request, but simply changes the address in the browser’s address bar and records that address in history

3. Use of History mode

router.js

const router = new VueRouter({
    mode: 'history'.routes: []})Copy the code
  • HistoryServer support is required
  • Because in a single page application, the server doesn’t existhttp://www.testurl.com/loginSuch an address returns the page not found
  • So the server should return single-page applications except for static resourcesindex.html


Node.js server configuration in History mode

const path = require('path')
// Import the module that handles history mode
const history = require('connect-history-api-fallback')
/ / import express
const express = require('express')

const app = express()
// Register the middleware that handles the history pattern
app.use(history())
// Static resource processing middleware, website root directory.. /web
app.use(express.static(path.join(__dirname, '.. /web')))

// Start the server on port 3000
app.listen(3000.() = > {
  console.log('Server on, port: 3000')})Copy the code

Implementation principle of Vue Router

render

  • The vue render

A build of Vue

  • Runtime version: Does not support template templates and is compiled ahead of time when packaging is required
  • The full version: contains the runtime and the compiler. It is about 10KB larger than the runtime version and converts the template into the render function when the program runs

The default for vuE-CLI creation is the runtime version

The browser console displays: [Vue WARN]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

How to solve this problem? (Do not understand the implementation of the next know!)

Vue official vue.config.js

Vue.config.js in the root directory of vue.config.js(not newly created)

module.exports = {
    runtimeCompiler: true
}
Copy the code

Hashmodel

  • https://www.hnufw.com/#/playlist?id=3102961863
  • URL#The following content is the path address
  • Listening to thehashchangeThe event
  • Find the corresponding component based on the current routing address and re-render it

Historymodel

  • https://www.hnufw.com/playlist/3102961863
  • throughhistory.pushState()Method to change the address bar
  • Listening to thepopstateThe event
    • When callingpushstatereplacestateThe event is not triggered
    • It’s triggered by moving forward and backward
  • Find the corresponding component based on the current routing address and re-render it

Analog implementation

To realize the router – the link
/ / use the render
initComponents (Vue) {
    // Create a router-link component
    Vue.component('router-link', {
      props: {
        to: String
      },
      render (h) {
        return h('a', {
          attrs: {
            href: this.to
          }
        }, [this.$slots.default])
      }
    })
  }

Copy the code
Implement the router – the view
initComponents (Vue) {
    // Create a router-link component
    Vue.component('router-link', {
      props: {
        to: String
      },
      render (h) {
        return h('a', {
          attrs: {
            href: this.to
          },
          on: {
            click: this.clickHandler
          }
        }, [this.$slots.default])
      },
      methods: {
        clickHandler (e) {
          history.pushState({}, ' '.this.to)
          this.$router.data.current = this.to
          e.preventDefault()
        }
      }
    })
    const self = this
    Vue.component('router-view', {
      render (h) {
        const component = self.routerMap[self.data.current]
        return h(component)
      }
    })
  }
Copy the code
Implement initEvent
initEvent () {
    window.addEventListener('popstate'.() = > {
      this.data.current = window.location.pathname
    })
  }
Copy the code

The complete code is as follows


let _Vue = null;

class VueRouter {
    static install (vue) {

        //1 Check whether the current plug-in is installed
        if(VueRouter.install.installed) {
            return;
        }

        VueRouter.install.installed = true;

        //2 Record the Vue constructor globally
        _Vue = vue;
        //3 Inject the Router object passed in to create the Vue instance
        // _Vue.prototype.$router = this.$options.router

        _Vue.mixin({
            beforeCreate () {
                console.log(this.$options);
                if(this.$options.router) {
                    _Vue.prototype.$router = this.$options.router
                }
            }
        });
    }

    constructor (options) {
        this.options = options;
        this.routeMap = {};

        // Observable method,
        this.data = _Vue.observable({
            // The default address is "/"
            current: '/'
        });

        this.init();
    }

    init () {
        this.createRouteMap();
        this.initComponent(_Vue);
        this.initEvent();
    }


    createRouteMap () {
        // Go through all the routing rules and parse the routing rules into key-value pairs and store them in the routeMap
        console.log(this.options);
        /** * { path: '/', name: 'Home', component: Home }, */
        this.options.routes.forEach(route= > {
            this.routeMap[route.path] = route.component
        });
    }

    initComponent (Vue) {
        // Record this of the current function
        const self = this;

        Vue.component("router-link", {
            props: {
                to: String
            },
            render (h) {
                return h("a", {
                    attrs: {
                        href: this.to
                    },
                    on: {
                        click: this.clickhander
                    }
                }, [this.$slots.default]);
            },
            methods: {
                clickhander (e) {
                    // Set the current route address to the browser address
                    history.pushState({}, ' '.this.to);

                    // Set the current route address to the current vUE setting address
                    this.$router.data.current = this.to

                    // Disables the default action for the A TAB to jump to the page
                    e.preventDefault()
                }
            }
        })

        Vue.component ('router-view', {
            render (h) {
                // Find the current route
                const cm = self.routeMap[self.data.current];
                return h(cm)
            }
        })
    }

    initEvent () {
        window.addEventListener('popstate'.() = > {
            this.data.current = window.location.pathname; }}})export default VueRouter
Copy the code