Part3-1-2 Vue Router

Posted 沿着路走到底

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Part3-1-2 Vue Router相关的知识,希望对你有一定的参考价值。

Vue Router 基础使用

router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Index from '../views/Index.vue'
// 1. 注册路由插件
Vue.use(VueRouter)

// 路由规则
const routes = [
  {
    path: '/',
    name: 'Index',
    component: Index
  },
  {
    path: '/blog',
    name: 'Blog',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "blog" */ '../views/Blog.vue')
  },
  {
    path: '/photo',
    name: 'Photo',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "photo" */ '../views/Photo.vue')
  }
]
// 2. 创建 router 对象
const router = new VueRouter({
  routes
})

export default router

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  // 3. 注册 router 对象
  router,
  render: h => h(App)
}).$mount('#app')

App.vue

<template>
  <div id="app">
    <div>
      <img src="@/assets/logo.png" alt="">
    </div>
    <div id="nav">
      <!-- 5. 创建链接 -->
      <router-link to="/">Index</router-link> |
      <router-link to="/blog">Blog</router-link> |
      <router-link to="/photo">Photo</router-link>
    </div>
    <!-- 4. 创建路由组建的占位 -->
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;
}

#nav a {
  font-weight: bold;
  color: #2c3e50;
}

#nav a.router-link-exact-active {
  color: #42b983;
}
</style>

动态路由

router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Index from '../views/Index.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Index',
    component: Index
  },
  {
    path: '/detail/:id',
    name: 'Detail',
    // 开启 props,会把 URL 中的参数传递给组件
    // 在组件中通过 props 来接收 URL 参数
    props: true,
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "detail" */ '../views/Detail.vue')
  }
]

const router = new VueRouter({
  routes
})

export default router

App.vue

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Index</router-link> |
      <router-link to="/detail/11">Detail</router-link>
    </div>
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;
}

#nav a {
  font-weight: bold;
  color: #2c3e50;
}

#nav a.router-link-exact-active {
  color: #42b983;
}
</style>

Detail.vue

<template>
  <div>
    <!-- 方式1: 通过当前路由规则,获取数据 -->
    通过当前路由规则获取:{{ $route.params.id }}

    <br>
    <!-- 方式2:路由规则中开启 props 传参 -->
    通过开启 props 获取:{{ id }}
  </div>
</template>

<script>
export default {
  name: 'Detail',
  props: ['id']
}
</script>

<style>

</style>

 

嵌套路由

router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
// 加载组件
import Layout from '@/components/Layout.vue'
import Index from '@/views/Index.vue'
import Login from '@/views/Login.vue'

Vue.use(VueRouter)

const routes = [
  {
    name: 'login',
    path: '/login',
    component: Login
  },
  // 嵌套路由
  {
    path: '/',
    component: Layout,
    children: [
      {
        name: 'index',
        path: '',
        component: Index
      },
      {
        name: 'detail',
        path: 'detail/:id',
        props: true,
        component: () => import('@/views/Detail.vue')
      }
    ]
  }
]

const router = new VueRouter({
  routes
})

export default router

App.vue

<template>
  <div id="app">
    <div id="nav">
      <router-view></router-view>
    </div>
  </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;
}

#nav a {
  font-weight: bold;
  color: #2c3e50;
}

#nav a.router-link-exact-active {
  color: #42b983;
}
</style>

components\\Layout.vue

<template>
  <div>
    <div>
      <img width="25%" src="@/assets/logo.png">
    </div>
    <div>
      <router-view></router-view>
    </div>
    <div>
      Footer
    </div>
  </div>
</template>

<script>
export default {
  name: 'layout'
}
</script>

<style scoped>
</style>

Index.vue

<template>
  <div>
    这里是首页 <br>
    <router-link to="login">登录</router-link> |

    <router-link to="detail/5">详情</router-link>
  </div>
</template>

<script>
export default {
  name: 'Index'
}
</script>

<style>

</style>

 

编程式导航

index.vue

<template>
  <div class="home">
    <div id="nav">
      <router-link to="/">Index</router-link>
    </div>
    <button @click="replace"> replace </button>

    <button @click="goDetail"> Detail </button>
  </div>
</template>

<script>
export default {
  name: 'Index',
  methods: {
    replace () {
      this.$router.replace('/login')
    },
    goDetail () {
      this.$router.push({ name: 'Detail', params: { id: 1 } })
    }
  }
}
</script>

 

login.vue

<template>
  <div>
    用户名:<input type="text" /><br />
    密&nbsp;&nbsp;码:<input type="password" /><br />

    <button @click="push"> push </button>
  </div>
</template>

<script>
export default {
  name: 'Login',
  methods: {
    push () {
      this.$router.push('/')
      // this.$router.push({ name: 'Home' })
    }
  }
}
</script>

<style>

</style>

 

detail.vue

<template>
  <div>
    路由参数:{{ id }}

    <button @click="go"> go(-2) </button>
  </div>
</template>

<script>
export default {
  name: 'Detail',
  props: ['id'],
  methods: {
    go () {
      this.$router.go(-2)
    }
  }
}
</script>

<style>

</style>

Hash 模式和 History 模式的区别

 History 模式的使用

frontend

router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  },
  {
    path: '*',
    name: '404',
    component: () => import(/* webpackChunkName: "404" */ '../views/404.vue')
  }
]

const router = new VueRouter({
  mode: 'history',
  routes
})

export default router

backend

Node.js

const path = require('path')
// 导入处理 history 模式的模块
const history = require('connect-history-api-fallback')
// 导入 express
const express = require('express')

const app = express()
// 注册处理 history 模式的中间件
app.use(history())
// 处理静态资源的中间件,网站根目录 ../web
app.use(express.static(path.join(__dirname, '../web')))

// 开启服务器,端口是 3000
app.listen(3000, () => {
  console.log('服务器开启,端口:3000')
})

nginx

从官网下载 nginx 的压缩包
把压缩包解压到 c 盘根目录,c:\\nginx-1.18.0 文件夹

修改 conf\\nginx.conf 文件

location / {
root html;
index index.html index.htm;
#新添加内容 #尝试读取$uri(当前请求的路径),如果读取不到读取$uri/这个文件夹下的首页 #如果都获取不到返回根目录中的 index.html
try_files $uri $uri/ /index.html;
}

打开命令行,切换到目录 c:\\nginx-1.18.0

nginx 启动、重启和停止

# 启动
start nginx
# 重启
nginx -s reload # 停止
nginx -s stop

 

VueRouter 实现原理

Hash 模式

URL中 # 后面的内容作为路径地址

监听 hashchange 事件,当 hash 发生改变,会触发 hashchange 事件

在 hashchange 事件中,记录当前路由地址

根据当前路由地址找到对应组件重新渲染

 

History 模式

通过 history.pushState() 方法改变地址栏

pushState 仅仅改变地址栏,并将当前浏览器地址记录到访问历史中,但是不会向服务器发起请求

监听 popstate事件

popstate 可以监听到浏览器历史操作的变化,在popstate 处理函数中,可以记录改变后的地址

调用 pushState 或 replaceState,不会触发 popstate 事件

点击浏览器前进后退按钮,调用 history 的 back 或 forward 方法,才会触发 popstate

根据当前路由地址找到对应组件重新渲染

 

VueRouter 类图

属性:

options:记录构造函数中传入的对象 ( routes )

data:是一个对象,里面有个属性 current,用来记录当前路由地址,data对象是响应式的,因为当路由地址发生变化后,对应的组件要自动更新,使用 Vue.observable() 使 data 变成 响应式数据

routeMap:是一个对象,用来记录 路由地址和组件的对应关系,会将传入的路由规则(routes)解析到 routeMap

 

方法:

_install:静态方法,实现 Vue 的插件机制

initEvent:注册 popstate 事件,用来监听浏览器历史的变化

createRouteMap:初始化 routeMap 属性,将构造函数传入的路由规则转换成 键值对 的形式存储到 routeMap 里,键 就是 路由的地址,值 就是对应的组件

initComponents:创建 routeLink 和 routeView 这2个组件

 

Vue 的构建版本

运行时版:不支持 template 模板,需要打包的时候提前编译 

完整版:包含运行时和编译器,体积比运行时版大10K左右,程序运行的时候把模板转换成 render 函数

配置完整版:在 vue.config.js 里配置属性,runtimeCompiler

module.exports = {
  runtimeCompiler: true
}

 

 

 

 

 

1

以上是关于Part3-1-2 Vue Router的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段11——vue路由的配置

VSCode自定义代码片段11——vue路由的配置

项目集成 vue-router 和 vuex

vue知识点-$route和$router

vue-router 2.0 常用基础知识点之router-link

Vue Router 详解