从0到Vue3企业项目实战【08.Vue路由基础】

409 阅读4分钟

这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

1.0 什么是路由?

提到路由,零基础的同学应该最先想到的是路由器,生活中的路由器是为移动设备提供网络的,会为每个设备提供不同的ip地址,生活中的路由就是设备与ip映射的关系,在后台语言如node中的路由就是接口与服务的映射关系,而Vue的路由就是路径与组件的映射关系

2.0 为何使用路由?

要知道,VueReact等前端框架实现的都是单页应用也就是SPA,一个网站中仅有一个唯一的一个HTML,所有的功能交互都在这唯一的页面中完成

相比传统的多页应用开发,SPA有如下的优势

  1. 仅在Web页面初始化时加载资源
  2. 一旦页面加载完成,用户操作不再进行重加载或者跳转,而是通过路由动态的更改组件展示,不会出现如多页应用的白屏现象
  3. 减轻服务器压力,前端专注页面渲染,后端专注API实现,利于前后端分离

所以学习Vue,路由属于必学内容

当然也有一定的缺陷

  1. 开发成本高(需要单独学习路由知识)
  2. 首次加载较慢,不利于seo

3.0 如何在Vue中使用路由?

Vue是一个渐进式框架,所以vue-router并没有默认提供,只需要我们在单独下载一下vue-router包就可以实现Vue相关的路由功能

vue-router是由Vue官方提供的路由管理器,官网地址为Vue Router (vuejs.org) 引自官网的优势为:

  • 嵌套路由映射
  • 动态路由选择
  • 模块化、基于组件的路由配置
  • 路由参数、查询、通配符
  • 展示由 Vue.js 的过渡系统提供的过渡效果
  • 细致的导航控制
  • 自动激活 CSS 类的链接
  • HTML5 history 模式或 hash 模式
  • 可定制的滚动行为
  • URL 的正确编码

4.0 使用vue-router模块

使用路由大致有如下步骤

当然可以在构建项目的时候就添加上路由,这种方式更简单,我们优先教学从0自己配置的情况

  1. 下载vue-router到当前项目
  2. main.js中引入VueRouter函数
  3. 添加到Vue.use()身上 -> 注册全局RouterLinkRouterView组件
  4. 创建路由规则数组 -> 路径与组件名的映射关系
  5. 用规则生成路由对象
  6. 把路由对象注入new Vue实例中
  7. router-view作为挂载点切换不同的路由页面

5.0 router实践

选择vue2.x默认情况

vue create routerdemo

vue.config.js中修改为

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave: false
})

添加vue-router

yarn add vue-router@3.5.1

本章版本使用的是3.5.1vue-router

image.png

在src目录下创建routerview文件夹,router文件下创建index.js文件,view中创建Dt.vue文件与Wz.vue

image.png

index.js文件下


// 引入Vue
import Vue from 'vue'
// 引入VueRouter
import VueRouter from 'vue-router'
// 页面文件
import Dt from '../view/Dt.vue'

Vue.use(VueRouter)

const routes = [
  {
    // 路径
    path: '/Dt',
    // 昵称
    name: 'Dt',
    // 组件
    component: Dt
  },
  {

    path: '/Wz',
    name: 'Wz',
    // 直接引入方式
    component: () => import('../view/Wz.vue')
  }
]
// 生成路由对象
const router = new VueRouter({
  routes // routes是固定key(传入规则数组)
})
// 导出router 在main中注入实例
export default router

main.js中引入并注入实例

import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
import router from './router'
new Vue({
  // 注入router , this可以直接访问$router与$route
  router,
  render: h => h(App),
}).$mount('#app')

Dt.vue文件与Wz.vue作为页面组件进行展示,这里就不贴详细代码了,就写个名字区分即可

<template>
  <div>文章or动态</div>
</template>

<script>
export default {

}
</script>

<style>
</style>

App.vue中通过a标签的href属性实现修改页面路径的hash值,实现路由跳转,具体代码如下

<template>
  <div>
    <div class="header">
      <a
        :class="{active: current == index,item}"
        v-for="(item,index) in list"
        :key="item.id"
        :href="item.href"
        @click="changeActive(index)"
      >{{item.name}}</a>
    </div>
    <div class="msg">
      <!-- 设置挂载点 当url的hash值切换,显示规则内对应的组件 -->
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
import ListHeader from '../../vue-life/src/components/listHeader.vue';

export default {
  components: { ListHeader },
  data () {
    return {
      current: 0,
      list: [{
        name: '动态',
        href: '#/Dt',
        id: 0
      }, {
        name: '文章',
        href: '#/Wz',
        id: 1
      }, {
        name: '专栏',
        href: '#/Wz',
        id: 2
      }, {
        name: '沸点',
        href: '#/Wz',
        id: 3
      }, {
        name: '收藏集',
        href: '#/Wz',
        id: 4
      }],
      ComList: ['DT', 'WZ', 'ZL', 'FD', 'SCJ'],
      showComName: 'DT'
    };
  },
  methods: {
    changeActive (index) {
      this.current = index
      this.showComName = this.ComList[index]
    }
  }
}
</script>

<style>
body {
  background-color: #f4f5f5;
}
.msg {
  background-color: #fff;
  width: 708px;
  height: 221px;
  margin: 0 auto;
}
.header {
  height: 49px;
  width: 708px;
  background-color: #fff;
  margin: 20px auto 0 auto;
  display: flex;
  border-radius: 0.2rem 0.2rem 0 0;
  border-bottom: 1px solid #e4e6eb;
  color: #515767;
  cursor: pointer;
}

.item:hover {
  color: #747985;
}

.item {
  font-size: 16px;
  height: 49px;
  width: 72px;
  line-height: 49px;
  text-align: center;
  color: #252933;
  font-weight: 500;
  position: relative;
  text-decoration: none; /* 去除默认的下划线 */
  color: #000; /* 去除默认的颜色和点击后变化的颜色 */
}

.active::after {
  content: '';
  position: absolute;
  width: 16px;
  height: 3px;
  border-radius: 50px;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  z-index: 10;
  background-color: #1e80ff;
}
</style>

实现的效果如下

动画.gif

至此,我们已经实现了简单的路由切换,是不是很简单呢?

6.0 声明式导航

  • vue-router为我们提供了一个全局组件router-link
  • router-link实质上最终会渲染成a标签,to属性等价于提供了href属性并且无需#
  • router-link自带高亮显示
  • to地址相同的都会进行同步高亮

如果高亮展示Vue为我们实现了那么我们就可以节省大部分的判断代码,更为精简代码结构,使用声明式导航后App.js的代码如下

<template>
  <div>
    <div class="header">
      <router-link class="item" v-for="item in list" :key="item.id" :to="item.href">{{item.name}}</router-link>
    </div>
    <div class="msg">
      <!-- 设置挂载点 当url的hash值切换,显示规则内对应的组件 -->
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
import ListHeader from '../../vue-life/src/components/listHeader.vue';

export default {
  components: { ListHeader },
  data () {
    return {
      current: 0,
      list: [{
        name: '动态',
        href: '/Dt',
        id: 0
      }, {
        name: '文章',
        href: '/Wz',
        id: 1
      }, {
        name: '专栏',
        href: '/Wz',
        id: 2
      }, {
        name: '沸点',
        href: '/Wz',
        id: 3
      }, {
        name: '收藏集',
        href: '/Wz',
        id: 4
      }],
    };
  },
  methods: {
  }
}
</script>

<style>
body {
  background-color: #f4f5f5;
}
.msg {
  background-color: #fff;
  width: 708px;
  height: 221px;
  margin: 0 auto;
}
.header {
  height: 49px;
  width: 708px;
  background-color: #fff;
  margin: 20px auto 0 auto;
  display: flex;
  border-radius: 0.2rem 0.2rem 0 0;
  border-bottom: 1px solid #e4e6eb;
  color: #515767;
  cursor: pointer;
}

.item:hover {
  color: #747985;
}

.item {
  font-size: 16px;
  height: 49px;
  width: 72px;
  line-height: 49px;
  text-align: center;
  color: #252933;
  font-weight: 500;
  position: relative;
  text-decoration: none; /* 去除默认的下划线 */
  color: #000; /* 去除默认的颜色和点击后变化的颜色 */
}

/* .active::after {
  content: '';
  position: absolute;
  width: 16px;
  height: 3px;
  border-radius: 50px;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  z-index: 10;
  background-color: #1e80ff;
} */

/* 激活后的样式 */
.header .router-link-active::after {
  content: '';
  position: absolute;
  width: 16px;
  height: 3px;
  border-radius: 50px;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  z-index: 10;
  background-color: #1e80ff;
}
</style>

效果如图

动画.gif

6.1.0 声明式导航跳转传参

6.1.1 第一种方法
  • to属性传值 语法为 /path?属性名=值
  • 对应页面组件接受传递过来的值 $router.query.参数名

我们尝试将Wz.组件进行修改这样实现每点击一个标签跳转后展示各自的名称

<template>
  <div>{{$route.query.name}}</div>
</template>

<script>
export default {
  mounted () {
  }
}
</script>

<style>
</style>

只需要将App.vue文件中的to方法修改就可以实现展示个标签的名称了

 :to="item.href + `?name=${item.name}`"

实现效果如图,需要注意:取得时候用的是$route不是$router 动画.gif

6.1.2 第二种方法
  • 路由规则上 定义/path:参数名称
  • router-linkto="path/值"
  • 组件上通过 $route.params.参数名接受

这样用数组循环下来缺陷动态的路径将也会被修改,读取不到原本的动态页面了 我们看看实践

App.vue文件下的代码如下

<template>
  <div>
    <div class="header">
      <router-link class="item" v-for="item in list" :key="item.id" :to="item.href">{{item.name}}</router-link>
    </div>
    <div class="msg">
      <!-- 设置挂载点 当url的hash值切换,显示规则内对应的组件 -->
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
import ListHeader from '../../vue-life/src/components/listHeader.vue';

export default {
  components: { ListHeader },
  data () {
    return {
      current: 0,
      list: [{
        name: '动态',
        href: '/Dt',
        id: 0
      }, {
        name: '文章',
        href: '/Wz',
        id: 1
      }, {
        name: '专栏',
        href: '/Wz',
        id: 2
      }, {
        name: '沸点',
        href: '/Wz',
        id: 3
      }, {
        name: '收藏集',
        href: '/Wz',
        id: 4
      }],
    };
  },
  methods: {
  }
}
</script>

<style>
body {
  background-color: #f4f5f5;
}
.msg {
  background-color: #fff;
  width: 708px;
  height: 221px;
  margin: 0 auto;
}
.header {
  height: 49px;
  width: 708px;
  background-color: #fff;
  margin: 20px auto 0 auto;
  display: flex;
  border-radius: 0.2rem 0.2rem 0 0;
  border-bottom: 1px solid #e4e6eb;
  color: #515767;
  cursor: pointer;
}

.item:hover {
  color: #747985;
}

.item {
  font-size: 16px;
  height: 49px;
  width: 72px;
  line-height: 49px;
  text-align: center;
  color: #252933;
  font-weight: 500;
  position: relative;
  text-decoration: none; /* 去除默认的下划线 */
  color: #000; /* 去除默认的颜色和点击后变化的颜色 */
}

/* .active::after {
  content: '';
  position: absolute;
  width: 16px;
  height: 3px;
  border-radius: 50px;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  z-index: 10;
  background-color: #1e80ff;
} */

/* 激活后的样式 */
.header .router-link-active::after {
  content: '';
  position: absolute;
  width: 16px;
  height: 3px;
  border-radius: 50px;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  z-index: 10;
  background-color: #1e80ff;
}
</style>

Wz.vue文件做简单的修改即可

  <div>{{$route.params.name}}</div>

实现效果如下

动画.gif

来看看我的其他章节吧,正在长更中

从0到Vue3企业项目实战【01.Vue的基本概念与学习指南】 - 掘金 (juejin.cn)

从0到Vue3企业项目实战【02.了解并理解Vue指令以及虚拟Dom】 - 掘金 (juejin.cn)

从0到Vue3企业项目实战【03.vue基本api入门】 - 掘金 (juejin.cn)

从0到Vue3企业项目实战【04.从vue组件通讯到eventBus以及vuex(附mock接口与axios简单实践)】 - 掘金 (juejin.cn)

从0到Vue3企业项目实战【05.vue生命周期】 - 掘金 (juejin.cn)

从0到Vue3企业项目实战【06.refref与nextTick使用】 - 掘金 (juejin.cn)

从0到Vue3企业项目实战【07.vue动态组件,组件缓存,组件插槽,子组件直接修改props,自定义指令看这一篇就够了】 - 掘金 (juejin.cn)

从0到Vue3企业项目实战【08.Vue路由基础】 - 掘金 (juejin.cn)

从0到Vue3企业项目实战【09.Vue路由进阶】 - 掘金 (juejin.cn)