前端路由
当浏览器地址发生改变时,此时我们不希望地址一改变就去服务器请求静态资源。因此我们可以使用url的hash和history。
url的hash
url的hash也就是锚点(#)本质是改变window.location的href属性。hash的优势是兼容性更好,但是缺点有一个#,显得不像一个真实路径。 vue hash路由实现原理是监听hashchange事件,知道hash发生了哪些变化,根据hash变化实现更新部分页面的操作 简单hash实现原理
<div id="app">
<a href="#/home">home</a>
<a href="#/about">about</a>
<div class="content">default</div>
</div>
<script>
const contentEl = document.querySelector('.content');
window.addEventListener("hashchange", () => {
switch(location.hash) {
case '#/home':
contentEl.innerHTML = "home";
break;
case '#/about':
contentEl.innerHTML = "about";
break;
default:
contentEl.innerHTML = "Default";
}
// console.log(location.hash)
})
</script>
html的history
history的接口是html5新增的,他有六种模式改变url而不刷新页面:
- replaceState:替换原来的路径;
- pushState:使用新的路径
- popState:路径的回退
- go:向前或向后改变路径
- forword:向前改变路径
- back:向后改变路径
histor路由的简单实现
<div id="app">
<a href="/home">home</a>
<a href="/about">about</a>
<div class="content">default</div>
</div>
<script>
// 要在liveserve中打开,否则使用history方法会报错
const contentEl = document.querySelector('.content');
const aEls = document.getElementsByTagName("a");
for(let aEl of aEls) {
aEl.addEventListener("click", e => {
e.preventDefault(); //阻止默认行为,不会跳转去请求新资源
const href = aEl.getAttribute("href");
history.replaceState({}, "", href);
// console.log(location.pathname)
switch(location.pathname) {
case '/home':
contentEl.innerHTML = 'Home';
break;
case '/about':
contentEl.innerHTML = 'About';
break;
default:
contentEl.innerHTML = 'default';
}
})
}
</script>
pushState: 有历史记录,可以返回 replaceState: 无历史记录
vue-router使用
下载vue-router
npm install vue-router@4
创建一个js文件用于导出router对象
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import Home from '../pages/Home.vue'
import About from '../pages/About.vue'
//配置映射对象
const routes = [
{path: '/', redirect: '/home'}, //重定向
{path: '/home', component: Home},
{path: '/about', component: About},
]
//创建一个路由对象
const router = createRouter({
routes,
history: createWebHashHistory(),
})
export default router;
在main.js中引入导入
import { createApp } from 'vue'
import App from './App.vue'
import router from '@/router'
const app = createApp(App)
app.use(router)
app.mount('#app')
使用占位符表示路由所显示的位置
<template>
<router-view/>
</template>
在浏览器中输入/home即可展示 可以通过router-link实现跳转
<router-link to="home">首页</router-link>
route还有name和meta属性
vue-router懒加载
/* webpackChunkName: "home-chunk" */指定打包的名字
//配置映射对象
const routes = [
{path: '/', redirect: '/home'},
{path: '/home', component: () => import(/* webpackChunkName: "home-chunk" */'../pages/Home.vue')},
{path: '/about', component: () => import('../pages/About.vue')},
]
动态路由匹配
动态路由使得浏览器路劲不能写死,此时可以使用动态路由
const routes = [
{path: '/user/:name/id/:id', component: () => import('../pages/User.vue')},
]
<div><router-link to="user/kobe/id/111">用户</router-link></div>
可以根据需要将值变为动态的 可以通过this.$route获得:name的值 如果在setup中使用,可以使用vue-router提供的函数
<script>
import { useRoute } from 'vue-router'
export default {
setup() {
const route = useRoute();
console.log(route)
}
}
</script>
匹配不存在路劲
当用户输入不存在路劲时,页面不会发生变化,此时应在router中设置不存在路劲所匹配的路由
const routes = [
{path: '/:pathMatch(.*)', component: () =>import('../components/HelloWorld.vue')},
]
路由嵌套
在需要嵌套的路由中
<template>
<div>
<h2>home</h2>
<router-view/>
<router-link to="home/message">消息</router-link>
</div>
</template>
在route中设置
{
path: '/home',
component: () => import(/* webpackChunkName: "home-chunk" */'../pages/Home.vue'),
children: [
{
path: 'message',
component: () => import('../pages/HomeMessage.vue')
}]
},
编程式导航
可以取到this的情况下使用:
this.$router.push('/about')
在setup中使用:
<script>
import { useRoute } from 'vue-router'
export default {
setup() {
const router = useRoute();
const jump = () => {
router.push('/about)
}
return {
jump
}
}
}
</script>
router.push中可以传入对象
router.push({
query: {
name: 'juju'
}
})
query会显示在浏览器的url地址上 使用this.$router.query取到
router-link的内置插槽
<router-link to="home">
<button>首页</button>
</router-link>
在router-link组件下写元素,则占据默认插槽。内部也可以写一个组件。 也可以通过v-slot取得router-link to的路劲
<router-link to="home" v-slot="props">
<a>{{props.href}}</a>
</router-link>
props.href为"/home" props中也有route属性
<router-link to="home" v-slot="props" custom>
<button @click="props.navigate">我是v-slot跳转</button>
</router-link>
自定义插槽通过navgate函数跳转
router-view的插槽
router-view一般是作为占位使用,但如果想要在页面切换直接使用过渡效果,可以在rouetr-view中使用transtion组件
<router-view v-slot="props">
<transition name="juju">
<component :is="props.Component"></component>
</transition>
</router-view>
<style>
.juju-enter-from,
.juju-leave-to {
opacity: 0;
}
.juju-enter-active,
.juju-leave-active {
transition: opacity 1s ease;
}
</style>
也可以使用keep-alive对组件进行缓存
<router-view v-slot="props">
<transition name="juju">
<keep-alive>
<component :is="props.Component"></component>
<keep-alive>
</transition>
</router-view>
动态添加路由
const categoryRoute = {
path: '/cate',
component: () => import('../pages/Category.vue')
}
router.addRoute(categoryRoute);
动态添加二级路由
router.addRoute("home", {
path: 'moment',
component: () => import('../pages/moment.vue')
})
第一个参数对于的是route的name属性
动态删除路由
- 通过removeRoute方法,传入路由名称.如removeRoute("home")
- 通过daaRoute方法返回值回调
const remove = router.addRoute(categoryRoute);
remove();
路由导航守卫
beforeEach在路由跳转之前调用,可以用来在路由跳转时有无权限,如果登录信息过期跳转到登录页。
// to: route对象,即将跳转到的路由对象
// from: 从哪一个路由对象来到的
/**
* 返回值:1.false不进行导航
* 2.undefined或者不写:进行默认导航
* 3.字符串:路劲,跳转到对应的路径中
* 4.对象。类似于route.push({path: '/home', query})
* */
router.beforeEach((to, from) => {
})