设备和ip的映射关系
接口和服务的映射关系
路径和组件的映射关系
在一个页面里,切换业务场景
vue单页面应用(SPA):所有的功能在一个html页面上实现
优点:
缺点:
vue集成路由
https://router.vuejs.org/zh/guide/
vue-router模块包,它和vue.js深度集成
定义映射规则—模块化—提供2个内置的全局组件
.vue组件分两类,一个页面组件,一个复用组件
.vue文件本质无区别
src/views(pages)文件夹 —页面组件 —配合路由使用
src/components 文件夹 —复用组件(展示数据—复用)
总结:views下的页面组件,配合路由切换;components下的一般引入到views下的vue中复用展示数据
npm i [email protected]
在vue2项目中要使用3.xx的vue-router
在vue3项目中要使用4.xx的vue-router
src下创建router/index.js
import Vue from 'vue'
// 1. 导入路由
import VueRouter from "vue-router"
// 引入组件
import Home from '../views/Home'
import Login from '../views/Login'
import Register from '../views/Register'
// 2. 使用路由插件
// 在vue中,使用vue插件,需要调用Vue.use()
Vue.use(VueRouter)
// 3. 创建路由规则
const routes = [
// 路径和组件的映射关系
{
path: '/',
component: Home,
},
{
path: '/login',
component: Login,
},
{
path: '/register',
component: Register,
}
]
// 4. 创建路由对象,传入规则
const router = new VueRouter({
// routes: routes,
routes,
})
// 导出路由对象
export default router
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
App.vue
每次全部引入所有组件会导致性能问题
使用路由懒加载,当匹配到路由路径时才引入
import Vue from 'vue'
// 1. 导入路由
import VueRouter from "vue-router"
// 引入组件
// import Home from '../views/Home'
// import Login from '../views/Login'
// import Register from '../views/Register'
// 2. 使用路由插件
// 在vue中,使用vue插件,需要调用Vue.use()
Vue.use(VueRouter)
// 3. 创建路由规则
const routes = [
// 路径和组件的映射关系
{
path: '/',
// component: Home,
// 路由懒加载
component: () => import('../views/Home'),
},
{
path: '/login',
// component: Login,
component: () => import('../views/Login')
},
{
path: '/register',
// component: Register,
component: () => import('../views/Register')
}
]
// 4. 创建路由对象,传入规则
const router = new VueRouter({
// routes: routes,
routes,
})
// 导出路由对象
export default router
使用全局组件 router-link 来替代 a 标签
<template>
<div>
<div class="nav">
<router-link to="/">首页</router-link>
<router-link to="/login">登录</router-link>
<router-link to="/register">注册</router-link>
</div>
<router-view></router-view>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.nav {
display: flex;
justify-content: space-around;
}
.router-link-exact-active {
color: red;
}
</style>
在跳转路由时,进行传参
to="/path?参数名=值&参数名2=值"
//页面组件接收传递过来的值
$route.query.参数名
注意
/detail/:word
表示必须要传参数,如果不传参数,也希望匹配,可以加个可选符 “?”
{
path:"/detail/:word?",
component:Detail
}
router-link 自带的2个类名的区别是什么?
router-link-active
(模糊匹配) url中 hash 值,包含 href属性值这个路径
------to = “/my” 可以匹配 /my/a /my/b …
router-link-exact-active
(精确匹配) url中 hash 值路径,与 href属性值完全相同,设置此类名
------to = “/my” 只能匹配 /my…
自定义类名
linkActiveClass:
--------模糊匹配类名
linkExactActiveClass:
--------精确匹配类名
const router = new VueRouter({
// routes: routes,
routes,
linkActiveClass: 'active',
linkExactActiveClass: 'exactActive',
})
强制切换到目标path上
需求:网页默认打开,,匹配路由 ‘/’ 强制切换到 '/home’上
const routes = [
{
path: '/',
redirect: '/home', // 重定向到 /home
},
// 路径和组件的映射关系
{
path: '/',
// component: Home,
// 路由懒加载
component: () => import('../views/Home'),
},
{
path: '/login',
// component: Login,
component: () => import('../views/Login')
},
{
path: '/register',
// component: Register,
component: () => import('../views/Register')
},
// 写在最后
{
path: '*',
redirect: '/home',
},
]
总结:强制重定向后,还会重新来数组中匹配一次规则
如果路由hash值没有和数组里规则匹配
默认给一个404页面
路由最后,path*匹配任意路径—前面都不匹配,就匹配最后这个,显示对应的组件
<template>
<div>
404
</div>
</template>
<script>
export default {
}
</script>
<style scoped></style>
const routes = [
{
path: '/',
redirect: '/home', // 重定向到 /home
},
// 路径和组件的映射关系
{
path: '/home',
// component: Home,
// 路由懒加载
component: () => import('../views/Home'),
},
{
path: '/login',
// component: Login,
component: () => import('../views/Login')
},
{
path: '/register',
// component: Register,
component: () => import('../views/Register')
},
// // 写在最后
// {
// path: '*',
// redirect: '/home',
// },
{
path: '*',
component: () => import('../views/NotFound')
}
]
如果路由未命中任何规则,给出一个兜底的404页面
hash 模式是一种把前端路由的路径用 # 拼接在真实 url 后面的模式,地址栏url中的 # 符号 http://localhost:8080/#/home,通过 hashchange 事件监听 hash 值的改变来渲染页面对应的组件。hash 模式不会向后端发送 http 请求,所有的 hash 值操作都与后端无关。改变hash不会重新加载页面
使用 location.hash
获取 hash 值:
location 是 window.location
或者 document.location
的简写模式。
以 url 地址:http://localhost:8080/#/about?name=she&age=16
示例:
属性 | 解释 | 值 |
---|---|---|
hash | 设置或返回从#开始的锚点信息 | #/about?name=she&age=16 |
host | 设置或返回主机名+端口号 | localhost:8080 |
hostname | 设置或返回主机名 | localhost |
port | 设置或返回端口号 | 8080 |
href | 设置或返回完整的 URL | http://localhost:8080/#/about?name=she&age=16 |
origin | 设置或返回协议+主机+端口 | http://localhost:8080 |
pathname | 设置或返回当前 URL 的路径 | /(hash 值不算在路径里面,此处返回的是#之前的斜杠) |
protocol | 设置或返回当前协议 | http: |
search | 设置或返回从?开始的查询字符串 | ?name=she&age=16 |
location 常用方法:
方法名 | 解释 | 语法 |
---|---|---|
assign() | 加载并显示指定的 URL 的内容 | location.assign(url); |
reload() | 刷新当前页面,就像刷新按钮一样 | location.reload(); |
replace() | 以给定的 URL 来替换当前的资源 | location.replace(url); |
调用 location.replace() 方法后,当前页面不会保存到会话历史中(session History),这样,用户点击回退按钮时,将不会再跳转到该页面。
当 URL 的片段标识符(hash 值)更改时,将触发 hashchange 事件 (跟在#符号后面的 URL 部分,包括#符号)。
window.addEventListener('hashchange', function() {
console.log('hash值被修改了')
}, false);
function locationHashChanged() {
if (location.hash === '#/about') {
console.log("欢迎进入about页面");
}
}
window.onhashchange = locationHashChanged;
测试 hashchage 事件:
window.addEventListener('hashchange', function () {
console.log('hashchage 事件被触发了');
});
// hash值的改变也会触发 window.onpopstate事件,onpopstate事件在 history模式中再做介绍
window.addEventListener("popstate", () => {
console.log("popstate 事件被触发了");
})
直接修改浏览器url地址,添加 hash 值 #/about。可以看出,修改 hash 值会优先触发 popstate 事件,然后再触发 hashchange 事件
history 是 HTML5 提供的新特性,允许开发者直接更改前端路由,也就是更改 url 地址而无需向后端发送 http 请求。
history 是 window.history
的简写模式,是 History 构造函数的实例化对象。
History 接口允许操作浏览器的曾经在标签页或者框架里访问的会话历史记录。
也就是说 History 里面保存着当前标签页的所有浏览页面的访问记录。
1.实例化对象属性
属性 | 解释 | 值 |
---|---|---|
length | 会话历史记录中元素的数目,包括当前加载的页面 Integer | (整型数值) |
scrollRestoration | 设置浏览器的默认滚动行为 | auto(默认值,浏览器自动滚动) / manual(关闭浏览器自动滚动) |
state | 返回一个表示历史堆栈顶部的状态的任意值 | any(任意值) |
2.实例化对象方法
属性 | 解释 | 值 |
---|---|---|
back() | 在会话历史记录中向后移动一页。如果没有上一页,则此方法调用不执行任何操作 | window.history.back() |
forward() | auto(默认值,浏览器自动滚动) / manual(关闭浏览器自动滚动) | window.history.forward(); |
go() | go方法从会话历史记录中加载特定页面 | window.history.go(-1); 负值表示向后移动back(),正值表示向前移动forward(); 值为0或不传时重新加载当前页面 |
pushState() | 向当前浏览器历史中添加记录 | history.pushState(state, title[, url]) |
replaceState() | 修改当前历史记录实体,可以更新 state 对象以及 URL 地址。 | history.replaceState(stateObj, title[, url]); |
3.history.pushState()的使用
history.pushState() 方法接收三个参数:
4.history.replaceState()的使用
history.replaceState()
方法接收的参数与 history.pushState()
方法相同,唯一的不同是,使用 replaceState 会更新当前页面的记录,包括 state 对象和 URL 地址。
举个例子,使用 pushState
添加 a.html b.html c.html
三个记录,然后使用 replaceState
添加 d.html
,最后查看历史记录栈中收录了几条历史记录。
历史记录栈中只存有三条记录,即 ["a.html", "b.html", "d.html"]
。原因就是 replaceState
将 c.html
替换为了 d.html
。
所以使用 history.back()
会返回 b.html
。
使用 history.forward()
也只会显示 d.html
:
window.onpopstate 事件是用来监听浏览历史记录变化的。
调用 history.pushState()
或者 history.replaceState()
不会触发 popstate 事件。popstate 事件只会在浏览器某些行为下触发,比如点击前进、后退按钮(或者在 JavaScript 中调用 history.back()
、history.forward()
、 history.go()
方法)。即,在同一文档的两个历史记录条目之间导航会触发该事件。
window.addEventListener('popstate', function(event) {
console.log(event);
}, false);
function historyStateChanged(event) {
console.log(event);
}
window.onpopstate= historyStateChanged;
测试,使用 popstate 监听记录栈的改变:
window.addEventListener("popstate", (event) => {
console.log(event);
})
使用 pushState 以及 replaceState 并未触发 popstate 事件
使用 history.back() ,触发了 popstate 事件并打印了参数 event,** event事件对象中保存着 state 对象。**
http://localhost:8080/home(需要服务器支持,否则找的是文件夹)
利用了HTML5新增的pushState() 和 replaceState()方法
// 4. 创建路由对象,传入规则
const router = new VueRouter({
// routes: routes,
routes,
mode: 'history', // 默认是hash
})
在 history 下,你可以自由的修改 path,但刷新页面时,如果服务器中没有相应的响应或者资源,则会出现404页面,因为刷新页面会发送 http 请求。也就是说,使用 history 路由模式,需要通过服务端来允许地址可访问,后端也必须配置了当前资源路径地址才行。
如果后台部署使用了 nginx,可以对 nginx 进行如下配置来解决页面刷新问题(摘录):
server {
listen 8080;
server_name localhost;
location / {
root 'E:\dist';
index /index.html;
try_files $uri $uri/ /index.html;
}
}
编程式导航:用js代码实现跳转
声明式导航:router-link实现跳转
语法:
this.$router.push({
path:"路由路径",
})
this.$router.push({
name:"路由名",
})
router/index.js路由规则里,给路由起名字
const routes = [
{
path: '/',
redirect: '/home', // 重定向到 /home
},
// 路径和组件的映射关系
{
path: '/home',
name: 'home',
component: () => import('../views/Home'),
},
{
path: '/login',
name: 'login',
component: () => import('../views/Login')
},
{
path: '/register',
name: 'register',
component: () => import('../views/Register')
},
App.vue中router-link换成span,配合js的编程式导航跳转
<template>
<div>
<div class="nav">
<span @click="goto('/home', 'home')">首页</span>
<span @click="goto('/login', 'login')">登录</span>
<span @click="goto('/register', 'register')">注册</span>
</div>
<router-view></router-view>
</div>
</template>
<script>
/*
编程式导航:js方式实现跳转路由
语法:
this.$router.push({path:"路由路径"})
this.$router.push({name:"路由名"})
注意:
虽然用name跳转,但是url的hash值还是切换path路径值
使用场景:
使用name跳转,方便修改,(name路由名在页面上看不到,随便修改)适合路径比较长的时候
使用path跳转,可以在url的hash值看到,要尽量符合组件内规范
*/
export default {
methods: {
goto(targetPath, targetName) {
this.$router.push({
// path: targetPath
name: targetName
})
}
},
}
</script>
<style scoped>
.nav {
display: flex;
justify-content: space-around;
}
.router-link-exact-active {
color: red;
}
</style>
编程式导航:js方式实现跳转路由
语法:
this.$router.push({path:"路由路径"})
this.$router.push({name:"路由名"})
注意:
虽然用name跳转,但是url的hash值还是切换path路径值
使用场景:
使用name跳转,方便修改,(name路由名在页面上看不到,随便修改)适合路径比较长的时候
使用path跳转,可以在url的hash值看到,要尽量符合组件内规范
两种传参方式:查询传参 + 动态路由传参
两种跳转方式,对两种传参方式都支持
methods: {
// 查询参数
goSearch() {
// this.$router.push(`/search?key=${this.iptValue}`)
this.$router.push({
path: '/search',
query: {
key: this.iptValue
}
})
}
},
methods: {
// 动态路由传参
// 一定要先在路由规则中配置动态路由 path: '/detail/:word?',
goSearch() {
// this.$router.push(`/detail/${this.iptValue}`)
this.$router.push({
path: `/detail/${this.iptValue}`
})
}
},
methods: {
goSearch() {
// 命名路由
// 查询传参
this.$router.push({
name: 'search',
query: {
key: this.iptValue
}
})
}
}
methods: {
goSearch() {
// 命名路由
// 动态路由传参 ==> 一定要先在路由规则中配置动态路由 ==> path: '/detail/:word?',
this.$router.push({
name: 'detail',
params: {
word: this.iptValue
}
})
}
}
在现有的一级路由下,再嵌套二级路由
// 3. 创建路由规则
const routes = [
{
path: '/',
redirect: '/find'
},
{
path: '/find',
redict:'/find/recommend',
component: () => import('../views/Find'),
children: [
{
path: 'recommend',
component: () => import('../views/Second/Recommend')
},
{
path: 'ranking',
component: () => import('../views/Second/Ranking')
},
{
path: 'songlist',
component: () => import('../views/Second/SongList')
},
]
},
{
path: '/my',
component: () => import('../views/My')
},
{
path: '*',
component: () => import('../views/NotFound')
},
]
App.vue 的 router-view 负责发现音乐 和 我的音乐 页面切换
<template>
<div>
<div class="nav">
<router-link to="/find">发现音乐</router-link>
<router-link to="/my">我的音乐</router-link>
</div>
<router-view></router-view>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.nav {
display: flex;
width: 400px;
justify-content: space-around;
}
</style>
Find.vue的 router-view 负责发现音乐下的三个页面切换
<template>
<div>
<div class="nav_main">
<router-link to="/find/recommend">推荐</router-link>
<router-link to="/find/ranking">排行榜</router-link>
<router-link to="/find/songlist">歌单</router-link>
</div>
<router-view></router-view>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.nav_main {
display: flex;
justify-content: space-around;
width: 400px;
background-color: red;
border-radius: 7px;
}
.nav_main a {
text-decoration: none;
}
.nav_main .router-link-exact-active {
background-color: brown;
border-radius: 5px;
}
</style>
解决方法:
在路由规则给find一级路由添加重定向redict:'/find/recommend'
嵌套路由找准在哪个页面里写router-view 和 对应的规则里写 children
从面经 点到详情 又点返回 数据重新加载了-----》希望回到原来的位置
原因:路由跳转后,组件被销毁了,返回回来的组件又重新创建,所以数据重新被加载了
keep-alive 是什么
keep-alive是Vue的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁他们
keep-alive是一个抽象组件,它自身不会渲染成一个dom元素,也不会出现在父组件链中
优点:
在组件切换过程中,吧切换出去的组件保留在内存中,防止重复渲染dom
减少加载时间以及性能消耗,提高用户体验
功能行为 :
使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。
const router = new Router({
mode: "history",
routes: routes,
scrollBehavior(to, from, savedPosition) {
console.log(savedPosition)
if(savedPosition) {
return savedPosition
} else {
return {
x: 0,
y: 0
}
}
}
});
注意:该功能只能在history的路由模式下有效,对于某些页面操作可能会影响上一个页面的展示,那么上一个页面就不应该做滚动处理,这个时候就可以根据路由的来源和去向来判断是否需要滚动了。
如果是hash模式的路由,那么就只能靠方式间接实现滚动状态保持了…