Vue 路由 基本操作 路由模式 hash路由模式的实现原理
1-路由
1.1-路由的概念
- 页面访问路径和组件之间的对应关系
1.2-路由的安装
npm i vue-router -S
1.3-路由的基本使用流程
1.3.1-第一步
- 配置路由规则(数组)
import Home from './pages/Home'
import Login from './pages/Login'
const rotues=[
{
// 页面访问路径
path:'/home',
// 页面组件对象
component:Home
},
{
// 页面访问路径
path:'/login',
// 页面组件对象
component:Login
}
]
1.3.2-第二步
- 根据路由规则数组, 创建路由实例对象
import Vue from 'vue';
// 1-导入路由模块
import VueRouter from 'vue-router';
// 2-将路由模块注册成vue的插件
Vue.use(VueRouter);
// 3-创建路由实例对象
const router=new VueRouter({
// 路由规则数组
routes:routes
});
// 4-导出路由对象
1.3.3-第三步
- 将路由实例挂在到vue上
import router from './router/index';
new Vue({
el:'#app',
// 挂载路由实例
router:router
});
1.3.4-第四步
- 在根组件App.vue中添加路由占位符合路由导航链接
<template>
<!-- 必须有一个唯一的根标签 -->
<div id="app">
<!-- 导航链接 -->
<!-- to属性: 指定页面的跳转地址, 必须和路由规则数组中的path属性保持一致 -->
<router-link to="/home">首页</router-link>
<router-link to="/reg">注册</router-link>
<router-link to="/login">登录</router-link>
<hr>
<!-- 路由占位符: 访问地址匹配到的路由组件的显示位置 -->
<router-view></router-view>
</div>
</template>
1.4-路由模式
-
hash模式:
- 页面访问地址中带有
#
, 默认路由模式 hash
路由模式, 通过npm run build
打包之后, 不需要web服务器的支持
new VueRouter({ // 路由规则数组 routes, // mode可选值: hash, history mode:'hash' });
- 页面访问地址中带有
-
history模式:
- 页面访问地址中不带
#
history
路由模式, 通过npm run build
打包之后,需要web服务器的支持
new VueRouter({ // 路由规则数组 routes, // mode可选值: hash, history mode:'history' });
- 页面访问地址中不带
1.5-路由导航高亮
-
给默认的路由导航高亮类名
router-link-active
添加对应css
属性, 使其高亮显示即可 -
自定义导航链接高亮类名
new VueRouter({ // 自定义导航链接高亮类名 linkActiveClass:'' });
1.6-路由重定向
- router/index.js
// 3-定义路由规则数组
const routes=[
{
path:'/',
// component:Home
// 重定向
redirect:'/login'
}
]
1.7-命名路由
-
router/index.js
// 3-定义路由规则数组 const routes=[ { name:'index', path:'/', // component:Home // 重定向 redirect:'/login' }, { name:'home', path:'/home', component:Home }, { name:'login', path:'/login', component:Login }, { name:'reg', path:'/reg', component:Reg } ];
-
App.js
<router-link class="nav-btn" v-bind:to="{name:'home'}" tag="div">首页</router-link>
1.8-编程式导航
-
通过js的方式实现页面跳转
-
this.$router: 包含和页面跳转相关的方法
-
push(): 实现页面跳转, 追加一条访问历史
-
路由字符串
this.$router.push('/home');
-
路由对象
this.$router.push({name:'home'});
-
-
replace: 实现页面跳转, 覆盖前一次的访问历史
-
路由字符串
this.$router.replace('/home');
-
路由对象
this.$router.replace({name:'home'});
-
-
go(): 实现页面前进后者回退
- 正数: 前进
- 负数: 回退
-
forward(): 实现页面前进一步
-
back(): 实现页面回退一步
-
1.9-路由元信息
-
定义
router/index.js
// 3-定义路由规则数组 const routes=[ { name:'index', path:'/', // component:Home // 重定向 redirect:'/login' }, { name:'home', path:'/home', component:Home, // 路由元信息 meta:{ title:'网站首页' } }, { name:'login', path:'/login', component:Login, meta:{ title:'登录页面' } }, { name:'reg', path:'/reg', component:Reg, meta:{ title:'注册页面' } } ];
-
调用
- 使用路由元信息, 实现更新页面标题
- this.$route: 存储的是和路由相关的属性(包含路由元信息)
页面组件中: 通过
this.$route.meta
读取路由元信息export default { created(){ // this.$route: 存储的是和路由相关的属性(包含路由元信息) // 通过this.$route对象读取路由元信息 const title=this.$route.meta.title; // 通过操作真实dom, 实现更新页面标题 document.title=title; } }
1.10-命名视图
- 应用场景: 一个路由访问地址, 对应多个视图组件
1.10.1-配置命名视图路由规则
router/index.js
import Home from '../pages/Home';
import Aside from '../components/Aside';
// 3-定义路由规则数组
const routes=[
// 一个访问路径, 对应多个组件, 需要用到命名视图
{
name:'home',
path:'/home',
// component:Home,
components:{
// aside: 要和插入的router-view的name属性保持一致
// Aside: 组件对象
aside:Aside,
// content: 要和插入的router-view的name属性保持一致
// Home: 组件对象
content:Home
}
}
}
1.10.2-在根组件中添加命名视图
App.vue
<template>
<!-- 必须有一个唯一的根标签 -->
<div id="app" class="container">
<!-- 命名视图aside -->
<router-view name="aside"></router-view>
<div class="right">
<!-- 导航链接 -->
<router-link class="nav-btn" v-bind:to="{name:'home'}" tag="div">首页</router-link>
<router-link class="nav-btn" :to="{name:'reg'}" tag="div">注册</router-link>
<router-link class="nav-btn" to="/login" tag="div">登录</router-link>
<router-link class="nav-btn" to="/ucenter" tag="div">我的</router-link>
<hr />
<!-- 命名视图content -->
<router-view name="content"></router-view>
<!-- 默认视图: 默认路由出口 -->
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
// 组件名字
name: "App"
};
</script>
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
#app {
width: 1000px;
margin: 20px auto;
}
h1 {
margin-bottom: 10px;
}
/* 路由导航链接高亮显示 */
.nav-btn {
background: #ddd;
border: 1px solid #eee;
display: inline-block;
width: 80px;
height: 40px;
line-height: 40px;
text-align: center;
text-decoration: none;
}
/* 默认高亮类名:router-link-active */
/* 自定义导航链接高亮类名 */
.active {
background: brown;
color: #fff;
}
/* 命名视图对应样式 */
.container {
display: flex;
height: 600px;
}
.right {
flex: 1;
background: lightgreen;
}
</style>
1.11-动态路由
-
定义动态路由规则
// 3-定义路由规则数组 const routes=[ // 动态路由, id动态路由参数 { path:'/goods/:goodsId', component:Goods, // 路由元信息的定义 meta:{ title:'商品详情', // 自定义属性, auth:true,表示必须登录之后, 才能访问 auth:false } } ];
-
动态路由链接
<router-link class="nav-btn" to="/goods/100" tag="div">商品详情</router-link>
-
动态路由参数的获取
this.$route.params
1.11.1-动态路由参数的解耦
-
在路由规则对象中添加如下配置
{ path:'/goods/:goodsId', component:Home // 路由参数解耦 props:true }
-
在组件配置对象中添加如下配置
{ data(){ return {} }, props:['goodsId'] }
-
在组件视图层直接通过
goodsId
获取动态路由参数<h1>{{goodsId}}</h1> <!--完整写法--> <h1>{{$route.params.goodsId}}</h1>
1.12-通过查询字符串的方式实现路由传参
-
通过查询字符串传递数据
<router-link class="nav-btn" to="/news?newsId=1&wd=vue" tag="div">新闻详情</router-link>
-
组件内通过
this.$route.query
获取查询字符串对象this.$route.query
1.13-路由懒加载
-
作用: 提升页面渲染性能
const Home=()=>import('../pages/Home'); const Login=()=>import('../pages/Login'); const Reg=()=>import('../pages/Reg'); const Ucenter=()=>import('../pages/Ucenter'); const Goods=()=>import('../pages/Goods'); const News=()=>import('../pages/News');
1.14-路由匹配模式
- 默认是模糊匹配: 访问地址中只要包含路由对象中的path, 就认为是匹配成功(所以会自动电量对应的导航链接)
启用路由严格匹配模式
-
在路由导航链接组件上添加exact属性
<router-link exact tag="li" to="/">管理中心</router-link>
2-hash路由模式实现原理
-
监听页面锚点字符串的更新
<component :is="page"></component>
// 导入页面组件 import Home from './pages/Home'; import Reg from './pages/Reg'; import Login from './pages/Login'; export default { // 组件名字 name: "App", data(){ return { page:'Home' } }, // 注册子组件 components: {Home,Reg,Login}, created(){ window.addEventListener('hashchange',()=>{ // console.log('hashchange',location.hash.split('/')[1]); // 更新page变量的值 this.page=location.hash.split('/')[1]; }); } };
-
根据锚点字符串, 显示对应的组件
3-案例
3.1-后台管理系统
-
根组件
App.vue
<template> <div class="container"> <div class="left"> <ul class="navbar"> <!-- <li :class="page==='Main'?'active':''" @click="changePage('Main')">管理中心</li> <li :class="page==='Goods'?'active':''" @click="changePage('Goods')">商品管理</li> <li :class="page==='User'?'active':''" @click="changePage('User')">会员管理</li> <li :class="page==='Order'?'active':''" @click="changePage('Order')">订单管理</li> --> <!-- 启用路由严格匹配模式 --> <router-link exact tag="li" to="/">管理中心</router-link> <router-link tag="li" to="/goods">商品管理</router-link> <router-link tag="li" to="/user">会员管理</router-link> <router-link tag="li" to="/order">订单管理</router-link> </ul> </div> <div class="right"> <!-- 头部 --> <Header></Header> <div class="content"> <!-- <component :is="page"></component> --> <!-- 路由占位符 --> <router-view></router-view> </div> <!-- 底部 --> <Footer /> </div> </div> </template> <script> // 1-导入页组件 // import Main from "./pages/Main"; // import Goods from "./pages/Goods"; // import Order from "./pages/Order"; // import User from "./pages/User"; // 导入功能组件 import Header from "./components/Header"; import Footer from "./components/Footer"; export default { // 2-注册组件 components: { // Main, // Goods, // Order, // User, Header, Footer }, data() { return { // 页面组件名称 page: "Order" }; }, methods: { // 切换页面 changePage(page) { this.page = page; } } }; </script> <style> *{ padding: 0; margin: 0; box-sizing: border-box; } .container { background-color: #ddd; /* vh:相对单位; 100vh=屏幕的高度 1vh==1/100屏幕高度; viewport height */ height: 100vh; display: flex; } /* 左侧导航栏 */ .container .left { width: 226px; background: #00152a; } .left .navbar li { list-style: none; line-height: 50px; color: #fff; text-align: center; cursor: pointer; } .left .navbar li:hover { background: #0077b8; } .left .navbar li.active { background: #0077b8; } .container .right { flex: 1; display: flex; flex-direction: column; } .right .header { height: 60px; line-height: 60px; text-align: center; background: #fff; } .right .content { margin: 10px; background: #fff; height: 300px; text-align: center; flex: 1; } .right .footer { line-height: 60px; text-align: center; background: #fff; } </style>
-
路由文件
ruoter/index.js
// 1-导入路由模块 import Vue from 'vue' import VueRouter from 'vue-router'; // 2-注册插件 Vue.use(VueRouter); // 3-创建路由规则 // 导入页面组件 import Main from '../pages/Main'; import Goods from '../pages/Goods'; import Order from '../pages/Order'; import User from '../pages/User'; const routes=[ { // 模糊匹配: 访问地址中包含路由规则对象中的path, 那么认为匹配成功 path:'/', component:Main, meta:{ title:'管理中心' } }, { path:'/goods', component:Goods, meta:{ title:'商品管理' } }, { path:'/user', component:User, meta:{ title:'会员管理' } }, { path:'/order', component:Order, meta:{ title:'订单中心' } } ]; // 4-创建路由对象 const router=new VueRouter({ routes, mode:'hash', linkActiveClass:'active' }); // 5-导出路由实例对象 export default router;
-
项目入口文件
/main.js
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' // 导入了根组件 import App from './App' // 导入路由实例对象 import router from './router' /* eslint-disable no-new */ new Vue({ // 模板编译之后挂载的容器 el: '#app', // 挂载路由模块 router, components: { App }, // vue实例的视图模板: 使用根组件App充当默认视图 template:'<App/>' })