路由
1.当给vue 注入router的时候,router会给vue注入$route 和$router两个属性$route是一个路由规则,存储了当前的路由的路劲(如有参数,也会包含有的)$router就是VueRouter的一个实例对象,它包含了当前实例的一些信息。可以调用一些方法,比如push2.我们给路由注册组件的时候不用整个组件全部加载,可以使用路由懒加载来实现,如果我们用户不访问,这个组件不会创建的component:()=>import(/*webpackChunkName:"detail"*/ '../views/Detail.vue');3.动态的路由我们在路由规则那里配置路由为true的时候可以获取路由的相关的参数。const routes =[{path:'/detail/:id',name:"Detail",//开启props,会把URL中的参数传递给组件//在组件通过props 来接受URL的参数·props:true,component:()=>import(/*webpackChunkName:"detail"*/ '../views/Detail.vue');}]//=================================================================================<template>//<div>{{$route.params.id}}</div><div>{{id}}</div> // props:['id']</template>4.路由跳转 this.$router.push('/') 或者this.$router.push({name:'Home'}) //必须在路由规则那里配置name属性。 this.$router.replace('/') //跟push 功能一样,不会记录历史的 左上角的后退不行的,但是push是记录历史的
Hash 和History区别
不管那种模式,前端路由都是客户端路由的实现方式,也就是当路径发生改变时,不会向服务器发送请求,是利用js监听路径的变化。然后根据不同的地址渲染不同的内容,如果需要服务器内容,会发送ajax请求来获取。
表现形式的区别
hash 模式https://music.163.com/#/discover/toplist 地址中会存在 # 号history 模式https://music.163.com/discover/toplist 地址中没有# 类似于普通的地址,但是需要服务端配置支持
原理的区别
hash 模式是基于瞄点,以及onhashchange事件history 模式是基于HTML5中的History APIhistory.pushState() IE10以后才支持history.replaceState()
History 模式的使用
History 需要服务器的支持单页面应用中,如果刷新页面,会像服务器发送请求,而服务器不存在这样的地址就会返回找不到该页面从而出现404在服务端应该除了静态资源外都返回单页应用的index.html
node 环境下支持history
在node环境下,启用对history模式的支持可以通过connect-history-api-fallback 这个中间件来完成
// 导入处理 history 模式的模块const history = require('connect-history-api-fallback')// 导入 expressconst express = require('express')const app = express()// 注册处理 history 模式的中间件app.use(history())
Nginx 下支持history
- 从官网下载 nginx 的压缩包
- 把压缩包解压到 c 盘根目录,c:\nginx-1.18.0 文件夹
- 修改 conf\nginx.conf 文件
运行nginx服务器基本指令
启动start nginx重启nginx -s reload停止nginx -s stop
- 修改 conf\nginx.conf 文件
```javascript
location / {
root html;
index index.html index.htm;
新添加内容
尝试读取$uri(当前请求的路径),如果读取不到读取$uri/这个文件夹下的首页
如果都获取不到返回根目录中的 index.html
try_files $uri $uri/ /index.html; }
<a name="Sbk3f"></a>## Vue Router 实现原理```javascriptVue Router 有两种模式,一种hash模式,一种history模式。需要使用 插件 混入 vue.observable() 插槽 render函数 运行时和完整的vue原理:Hash模式 是把URL中#后面的内容作为路劲地址,通过localtion.url来切换路由的地址,如果只改变URL中#号后面的地址,浏览器不会向服务器请求这个地址,但是会把这个地址记录在访问历史中,当hash改变了,会监听hashchange这个事件,我们会记录路由地址并找到对应的组件进行渲染history 路劲就是普通的url,通过history.pushState()方法改变地址栏,这个方法仅仅改变地址栏,并把当前地址记录在访问地址中,并不会跳转到指定的路劲,也就是浏览器不会向服务器发送请求,通过监听popstate 事件,可以监听到浏览器历史操作的变化,当地址改变的时候,根据当前路由地址找到对应的组件进行重新渲染!vue.use(Object || Funtinon) 如果传入一个对象 会调用一个install的方法
实现思路

VueRouter-install 方法实现
要实现install方法,首先先分析一下该方法要做的事情:
- 判断当前插件是否已经被安装
- 把Vue构造函数记录到全局变量
- 把创建Vue实例时候传入的router对象注入到所有的Vue实例上
添加 VueRouter 的constructor
添加 VueRouter 的constructorVueRouter 的构造函数要初始化三个属性,分别是: options、data、routeMap。
options 是路由的构造配置对象
data 应该是一个响应式的对象,其中有一个属性 current 用来记录当前我们的路由地址,这里我们该如何才能创建一个响应式的对象呢?可以使用Vue的observable方法
routeMap 中记录了 options里的rules,rules解析出来 会以键值对的形式存在 routeMap中 ,key 就是路由地址,value 就是路由组件
createRouterMap
接下来我们来实现VueRouter类中 createRouterMap 这个方法,它的作用就是把 options 中rules 路由规则解析出来以键值对的形式存储在routeMap上
initComponents
下一步,来创建initComponents 方法,这个方法里我们要创建两个组件。分别是:RouterLink 和 RouterView
routerlink中添加点击事件,修改地址为了能够让链接成功完成跳转展示组件,我们需要对routerlink中的a标签添加点击事件
并且要在点击的时候,把最新的path更新到router实例的current上.
我们借助于history的pushState方法 该方法会修改浏览器地址栏中的地址,但不会向服务器发起请求,并且还可以将新地址记录在历史中
initEvent
现在功能基本上已经差不多了,但是还存在一个小问题,就是当我们点击浏览器的前进或者后退按钮的时候,组件不能实现切换展示,主要思路就是通过添加popstate监听地址变化
let _Vue;export default class VueRouter {static install(Vue) {// 1. 判断当前插件是否已经被安装if (VueRouter.install.installed) returnVueRouter.install.installed = true// 2. 把Vue构造函数记录到全局变量_Vue = Vue// 3. 把创建Vue实例时候传入的router对象注入到所有的Vue实例上// 利用混入让所有的vue实例加载router_Vue.mixin({beforeCreate() {// this.$options.name用来获取vue实例 data以外的属性// new Vue( { router } )if (this.$options.router) {_Vue.prototype.$router = this.$options.routerconsole.log(this.$options.router.init);this.$options.router.init()}}})}constructor(options) {this.options = optionsthis.routeMap = {}this.data = _Vue.observable({current: '/'})}createRouterMap() {this.options.routes.forEach(route => this.routeMap[route.path] = route.component)}initComponents(Vue) {// 创建RouterLink组件Vue.component('router-link', {props: {'to': { type: String }},render(h) {return h('a', {attrs: { href: this.to },on: { click: this.clickHandle }}, [this.$slots.default])},methods: {clickHandle(e) {history.pushState({}, "", this.to)// 把点击的链接地址 更新到 current 上this.$router.data.current = this.toe.preventDefault()}}// template: `<a :href="to"><slot></slot></a>`})let self = thisVue.component('router-view', {render(h) {// routeMap以key value形式记录了path和component// data.current 记录了当前页面的pathreturn h(self.routeMap[self.data.current])}})}init() {this.createRouterMap()this.initComponents(_Vue)this.initEvent()}initEvent() {//window.addEventListener("popstate", () => {this.data.current = window.location.pathname})}}

