前端路由
ip地址--真实电脑的mac地址:他们两个会有一个映射关系
后端路由
JSP、ASP、PHP
前后端分离(主讲 前端路由)
现在公司的开发模式:SAP(单一页面程序) S:single P:page A:application
整个应用程序里有多个页面,home、about、category; 每个页面可以是一个组件,当我路径是/home,就渲染home组件,路径是/about,就渲染/about组件。
我前端根据不同的路径,切换不同的页面,和后端没有关系。
我实现以上操作的时候,就会有:路径--组件 的映射关系 /home--Home.vue /about--About.vue
当我路径发生改变时,我就在某个位置渲染对应的组件,具体位置需要一个占位(router-view),等我路径为/home的时候,我就把Home.vue放在占位里;
如果在浏览器地址栏,输入主要网页名,但是用户把/home输入进来,浏览器会去静态服务器 请求静态资源,但是我们不想让用户请求到静态服务器。我们希望用户在前端上,通过点击切换,来到达对应的页面。因此我们可以将/home地址设置成一个hash值:#home,就不会再向服务器请求资源的。也可以设置为history模式,也不会再请求静态服务器的静态资源了。
1.URL的hash
例子:
vue的路由原理和这个例子差不多
2.history模式
history和哈希的最大区别:history更像真实路径,哈希会有一个 # 号
go(-1):后退一步; go(1):前进一步
此方法的好处:修改了路径,但是不会再请求资源
<body>
<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');
const changeContent = () => {
console.log("-----");
switch(location.pathname) {
case "/home":
contentEl.innerHTML = "Home";
break;
case "/about":
contentEl.innerHTML = "About";
break;
default:
contentEl.innerHTML = "Default";
}
}
const aEls = document.getElementsByTagName("a");
for (let aEl of aEls) {
aEl.addEventListener("click", e => {
e.preventDefault();
const href = aEl.getAttribute("href");
// history.pushState({}, "", href);
history.replaceState({}, "", href);
changeContent();
})
}
window.addEventListener("popstate", changeContent)
</script>
</body>
认识vue-router
进入新的URL后,如果页面刷新,浏览器是会向服务器请求静态资源的。我们需要做到,进入新的URL,也不会向服务器请求静态资源。
vue-router有:path -- 组件 之间的映射
路径/home -- Home.vue组件
路由的使用
1.安装Vue Router
npm install vue-router@4
2.创建路由组件的组件
2.1新建一个pages文件夹,里面存放组件:Home.vue
<template>
<div>Home</div>
</template>
<script>
import
export default{
components:{
}
}
</script>
2.2在pages文件夹里再存放组件:About.vue
<template>
<div>About</div>
</template>
<script>
import
export default{
components:{
}
}
</script>
3.配置路由映射:组件和路径映射关系的routes数组
在src下新建router文件夹,存放路由配置
创建index.js文件
1.导入组件
import Home from '../pages/Home.vue'
import About from '../pages/Aout.vue'
4.使用路由对象和模式的前提:先导入
import {
createRouter, //有了这个函数,才能创建想要的路由对象
createWebHistory, //web端的history模式
createWebHashHistory //web端的Hash模式
} from 'vue-router'
2.存储映射关系,由于映射关系会很多,所以用数组存储
里面存放的是对象,URL书写的路径名和组件名
const routes = [
{
path:'/home',
component:Home
},
{
path:'/about',
component:About
},
];
3.通过createRouter创建路由对象,并传入routes和history模式
//5.创建一个路由对象router
const router = createRouter({
routes, //映射关系
history:createWebHashHistory() //指定模式
})
6.将 路由对象 导出出去,让别人使用路由
export default router
5.使用路由,通过<router-link>和 <router-view>
前提:在main.js
import router from './router'
const app = createApp(App)
//把当前的路由对象看做是一个插件,use安装使用插件
app.use(router)
app.mount('#app')
使用:App.vue
<template>
<div>
<h2>哈哈</h2>
//渲染出来组件的内容,全部在这里展示
<router-view/>
<div>呵呵</div>
</div>
</template>
<script>
export default{
components:{
}
}
</script>
当我后缀名是/home的时候,router-view就会显示home组件的内容,当我后缀名是/about的时候,router-view就会显示about组件的内容
点击按钮,切换路径
<template>
<div>
//router提供的一个组件,他包含 to 属性
//我点击首页的时候跳转到首页,关于跳到关于
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<router-view/>
</div>
</template>
<script>
export default{
components:{
}
}
</script>
<router-link to=".."/>本质是一个 a 元素。
我点击首页,就会显示Home.vue组件的内容,并且URL的后缀是/home,关于 也同理
路由的默认路径
我们一打开页面的时候,URL是一个 / ,所以我们希望一进来就有相应的数据显示,我们就需要进行默认路径的配置
index.js
const routes = [
多一条默认路径 / 的配置,默认显示Home组件
{path:"/",component:Home}
]
更优质的默认路径:重定向(redirect)
当我们访问默认路径的时候,我们就重定向到/home,也就意味着匹配到一个组件:Home.vue。
const routes = [
{path:"/",redirect:"/home"}
]
我们默认访问的是8080,但是会重定向到/home
router-link补充
replace属性
<router-link to="/home" replace>
Home组件写上了replace,我从/home进入到/about后,想要从/about 后退到/home页面的时候,其实已经不给后退了。他和push 相反,push可以有后退的操作
active-class属性
App.vue
它是用来激活a元素后应用的class,默认是router-link-active
<template>
<router-link to="/home" active-class="why-active">
</template>
<style>
.why-active{
color:red;
}
</style>
路由懒加载
官方推荐:所有路由的组件全部设置成懒加载;
懒加载:用到的时候才会加载
index.js
import {createRouter,createWebHistory,createWebHashHistory} from 'vue-router'
//我以前在这里还需要导入Home和About组件,使用懒加载就不用这样import导入了
const routes = [
{
//我传入的不再是组件对象,而是一个函数
path:"/home",
component:()=>{
return import("../pages/Home.vue")
}
},
{
//魔法注释,对这个东西打包的时候,告诉webpack名字
path:"/about",
component:()=>{
//在前面写(/*webpackChunkName:"自己取"*/)
return import(
/*webpackChunkName:"自己取"*/
"../pages/About.vue")
}
},
]
当我npm run build打包时,路由懒加载出来的组件就不会再次 存在于 默认包里了,这样再第一次页面渲染的时候会加速渲染效果。
关于懒加载,还有一种写法,一个意思
//写在了上方
const home = () => import("../pages/Home.vue")
const routes = [
{
path:"/home",
component:home
}
]
路由的其他属性
name:设置名字,独一无二的名称,根据名字进行跳转(用的很少)
meta:在别的地方可以拿到route对象,然后根据route.meta,可以拿到meta中存储的属性
const routes = [
{
path:"/home",
name:"home", //取名字,也可以根据名字进行跳转
component:home,
meta:{
name:"lyx",
age:18,
}
}
]
动态路由的基本匹配
我们希望,如果用户 why 登录,跳转到User.vue,那么URL标签可以显示/why。如果是lyx,那么就显示/lyx。我们曾经都是写死的/user的,通过动态路由实现此效果。
$route的具体信息
在pages中新建User.vue的用户组件
<template>
在template中获取数据不用this
<div>
User:{{$route.params.username}}
</div>
</template>
<script>
//通过引用useRoute函数,在setup中拿到$route
import {useRoute} from 'vue-router'
export default{
created(){
console.log(this.$route.params.username)
//$route里有一个params属性,里面有username属性
},
//我想在setup中拿到username
setup(){
//这里面没有this,怎么拿呢?
const route = useRoute();
//他会返回用户点击的用户对象
//点击首页,返回首页的route对象
console.log(route.params.username)
}
}
</script>
index.js
const routes = [
{
//1.路径不写死,后面写 /:username
path:"/user/:username",
component:()=>{
return import(
"../pages/User.vue"),
}
]
App.vue
<template>
<div>
//2.跳转的时候,就不能写死了
<router-link to = "/user/why">
用户
</router-link>
//3.升级版写法,动态绑定实现
<router-link :to = '/user/'+name>
</div>
</template>
<script>
export default{
setup(){
name:"why",
return{
name
}
}
}
</script>
NotFound
如果我随便输入一个路径,对应的路径是没有组件的,显示的是空白的,对于用户来说是不友好的,我们需要 给用户显示一个组件。
实质上也是一个映射关系
path:去匹配一个不存在的路径
const routes = [
//vue会先找满足条件的映射,没有的话最后才走这里
// .* 表示0-多个任意字符
path:"/:pathMatch(.*)", //完整字符串
path:"/:pathMatch(.*)*",
//多了一个*,会以数组形式存储,以/为分隔符,将输入的url字符串,存放在数组中
component:()=>import("../NotFound.vue")
]
路由的嵌套
点击首页会显示一个组件,但是我希望再点击Home的时候,再能显示一个组件,这就是路由嵌套
msg.vue
<template>
<h2>Msg组件</h2>
<ul>
<li>msg1</li>
<li>msg2</li>
<li>msg3</li>
</ul>
</template>
<script>
export default{
components:{
}
}
</script>
shops.vue
<template>
<h2>shop组件</h2>
<ul>
<li>shop1</li>
<li>shop2</li>
<li>shop3</li>
</ul>
</template>
<script>
export default{
components:{
}
}
</script>
Home.vue
<template>
<div>
<h2>Home</h2>
<ul>
<li>Home1</li>
<li>Home2</li>
<li>Home3</li>
</ul>
占位,匹配上后显示路由组件
<router-view/>
<router-link to="/msg">消息</router-link>
<router-link to="/shops">商品</router-link>
</div>
</template>
index.js
我们发现:msg和shops都是home的
const routes = [
{
path:"/home",
name:"home",
component:()=>import("/Home.vue"),
meta:{
name:"why",
age:18,
},
//此时多了一个children属性
children:[
{
//这里不用再精确写 /home/msg
//vue会从home查找,就表示一定是以/home开头的,直接写msg名称
path:"msg",
component:"Mes.vue"
},
{
path:"shops",
component:shops.vue
}
]
}
]
补充
我只给我的/home写了router-link-active,那么我的/home/shops会被匹配吗?
答案是会的,那么怎么样可以避免呢?
router-link-exact-active用来精准匹配
如果想要重定向到home组件下的子组件,那么就得写全
编程式导航(代码的页面跳转)
About.vue
取传来的query
<template>
<h2>{{$route.query.name}}</h2>
</template>
App.vue
<template>
<button @click = "jumpToAbout">
首页
</button>
</template>
<script>
//导入hook
import {useRouter} from 'vue-router'
//1.使用methods
methods:{
jumpToAbout(){
//这里router是index.js中创建的路由对象
this.$router.push("/about")
}
},
//2.使用setup,就得使用hook
setup(){
const router = useRouter();
const jumpToAbout = ()=>{
//router.push('/about')
也可以传对象
router.push({
path:"/about",
//跳转后,顺便把参数也传过去了
query:{
name:"123",
age:18
}
//URL会显示name=123&age=18
})
//router.replace("/about")
},
return{
jumpToAbout
}
}
</script>
此时点击button也是可以跳转页面的