基础回顾

  • 基本使用
    • 创建路由组件
    • vue.use()注册vue-router
    • 注册router-view
    • 创建链接 router-link
  • 动态路由

    • $route.params.id

      1. const routes = [
      2. {
      3. name: 'detail',
      4. // 路径中携带参数
      5. path: '/detail/:id',
      6. component: detail
      7. }
      8. ]
      9. // detail 组件中接收路由参数
      10. $route.params.id
    • props:true ——推荐

      1. const routes = [
      2. {
      3. name: 'detail',
      4. // 路径中携带参数
      5. path: '/detail/:id',
      6. component: detail,
      7. props: true
      8. }
      9. ]
      10. // detail 组件中接收路由参数
      11. const detail = {
      12. props: ['id'],
      13. template: '<div>Detail ID: {{ id }}</div>'
      14. }
  • 路由嵌套

index组件和details组件嵌套layout组件

  1. {
  2. path: '/',
  3. component: layout,
  4. children: [
  5. {
  6. name: 'index',
  7. path: '/',
  8. component: index
  9. },
  10. {
  11. name: 'details',
  12. path: '/details/:id',
  13. component: details
  14. }
  15. ]
  16. }
  • 编程式导航

    1. // 跳转到指定路径
    2. router.push('/login')
    3. // 命名的路由
    4. router.push({ name: 'user', params: { id: '5' }})
    5. router.replace()
    6. router.go()
  • Hash模式和History模式的区别

    • Hash带#
      • 基于锚点以及onhashchange事件
      • 后面的内容作为路径地址

      • 根据当前路由地址找到对应组件重现渲染
    • history
      • 基于HTML5 API
        • history.pushState()改变地址栏 IE10以后才支持
        • history.replaceState()
        • 监听popstate事件
      • 开启History模式
        1. const router = new VueRouter({
        2. // mode: 'hash',
        3. mode: 'history',
        4. routes
        5. })
  • HTML5 HIstory模式的使用

    • History需要服务器的支持
    • 单应用中,服务端不存在http://www.testurl.com/login这样的地址会返回找不到该页面
    • 在服务端应除了静态资源外都返回单页应用的 index.html
    • Node.js环境
      • const history = require('connect-history-api-fall-back')
      • app.use(history())
    • nginx中配置

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

        1. location / {
        2. root html;
        3. index index.html index.htm;
        4. #新添加内容
        5. #尝试读取$uri(当前请求的路径),如果读取不到读取$uri/这个文件夹下的首页
        6. #如果都获取不到返回根目录中的 index.html
        7. try_files $uri $uri/ /index.html;
        8. }
      • 打开命令行,切换到目录c:\nginx-1.18.0

      • nginx启动、重启和停止
        1. # 启动
        2. start nginx
        3. # 重启
        4. nginx -s reload
        5. # 停止
        6. nginx -s stop

        Vue Router模拟实现

        前置知识:插件、solt插槽、混入、render函数、运行时和完整版的Vue

        实现思路

  • 创建VueRouter插件,静态方法install

    • 判断插件是否已经被加载
    • 当Vue加载的时候把传入的router对象挂载到Vue实例上(注意:只执行一次)
  • 创建VueRouter类

    • 初始化、options、routeMap、app(简化操作,创建Vue实例作为响应式数据记录当前路径)
    • initRouteMap()遍历所有路由信息,把组件和路由的映射记录到routeMap对象中
    • 注册popstate事件,当路由地址发生变化,重新记录当前的路径
    • 创建router-link和router-view组件
    • 当路径改变的时候通过当前路径在routerMap对象中找到对应的组件,渲染router-view

      代码实现

  • 创建VueRouter插件

    1. export default class VueRouter {
    2. static install (Vue) {
    3. // 如果插件已经安装直接返回
    4. if (VueRouter.install.installed && _Vue === Vue) return
    5. VueRouter.install.installed = true
    6. _Vue = Vue
    7. Vue.mixin({
    8. beforeCreate () {
    9. // 判断 router 对象是否已经挂载了 Vue 实例上
    10. if (this.$options.router) {
    11. // 把 router 对象注入到 Vue 实例上
    12. _Vue.prototype.$router = this.$options.router
    13. }
    14. }
    15. })
    16. }
    17. }
  • 实现VueRouter类-构造函数

    1. constructor (options) {
    2. this.options = options
    3. // 记录路径和对应的组件
    4. this.routeMap = {}
    5. this.app = new _Vue({
    6. data: {
    7. // 当前的默认路径
    8. current: '/'
    9. }
    10. })
    11. }
  • 实现VueRouter类-initRouteMap()

    1. initRouteMap () {
    2. // routes => [{ name: '', path: '', component: }]
    3. // 遍历所有的路由信息,记录路径和组件的映射
    4. this.options.routes.forEach(route => {
    5. // 记录路径和组件的映射关系
    6. this.routeMap[route.path] = route.component
    7. })
    8. }
  • 实现VueRouter类-注册事件

    1. initEvents () {
    2. // 当路径变化之后,重新获取当前路径并记录到 current
    3. window.addEventListener('hashchange', this.onHashChange.bind(this))
    4. window.addEventListener('load', this.onHashChange.bind(this))
    5. }
    6. onHashChange () {
    7. this.app.current = window.location.hash.substr(1) || '/'
    8. }
  • 实现VueRouter类-router-link和router-view组件

    1. initComponents () {
    2. _Vue.component('RouterLink', {
    3. props: {
    4. to: String
    5. },
    6. // 需要带编译器版本的 Vue.js
    7. // template: "<a :href='\"#\" + to'><slot></slot></a>"
    8. // 使用运行时版本的 Vue.js
    9. render (h) {
    10. return h('a', {
    11. attrs: {
    12. href: '#' + this.to
    13. }
    14. }, [this.$slots.default])
    15. }
    16. })
    17. const self = this
    18. _Vue.component('RouterView', {
    19. render (h) {
    20. // 根据当前路径找到对应的组件,注意 this 的问题
    21. const component = self.routeMap[self.app.current]
    22. return h(component)
    23. }
    24. })
    25. }
  • 注意:

    • vue-cli创建的项目默认使用的是运行版本的Vue.js
    • 如果想切换成带编译器版本的Vue.js,需要修改vue-cli配置
      • 项目根目录创建vue.config.js文件,添加runtimeCompiler
        1. modele.exports = {
        2. runtimeCompile:true
        3. }
  • 实现VueRouter类-init()

    1. init () {
    2. this.initRouteMap()
    3. this.initEvents()
    4. this.initComponents()
    5. }
    6. // 插件的 install() 方法中调用 init() 初始化
    7. if (this.$options.router) {
    8. _Vue.prototype.$router = this.$options.router
    9. // 初始化插件的时候,调用 init
    10. this.$options.router.init()
    11. }