最后
你要问前端开发难不难,我就得说计算机领域里常说的一句话,这句话就是『难的不会,会的不难』,对于不熟悉某领域技术的人来说,因为不了解所以产生神秘感,神秘感就会让人感觉很难,也就是『难的不会』;当学会这项技术之后,知道什么什么技术能做到什么做不到,只是做起来花多少时间的问题而已,没啥难的,所以就是『会的不难』。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
我特地针对初学者整理一套前端学习资料
关于
.home {
color: red;
}
**exact-active-class属性(下面路由嵌套时会讲解)**:
>
> 链接精准激活时,应用于渲染的 <a> 的 class,默认class是`router-link-exact-active`;
>
>
>
---
### 懒加载分包处理
**当打包构建应用时,JavaScript 包会变得非常大,影响页面加载**:
>
> 如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效;
>
>
> 也可以提高首屏的渲染效率;
>
>
>
**其实这里还是我们前面讲到过的webpack的分包知识,而Vue Router默认就支持动态来导入组件**:
>
> 这是因为component可以传入一个组件,也可以接收一个函数,该函数 需要放回一个Promise;
>
>
> 而import函数就是返回一个Promise;
>
>
>
// 使用import函数, 打包时会进行分包处理
routes: [
{
path: “/”,
redirect: “/home”
},
{
path: “/home”,
component: () => import(“…/views/Home.vue”)
},
{
path: “/about”,
component: () => import(“…/views/About.vue”)
}
]
>
> 打包效果如下
>
>
>
![在这里插入图片描述](https://img-blog.csdnimg.cn/f6b3c3733c134e6cb4cdc81b88cd3ea0.png#pic_center)
>
> 但是我们发现, 打包之后虽然分包了, 但是我们无法分清楚哪一个打包的文件是Home, 哪一个打包的文件是About
>
>
> 其实webpack从3.x开始支持对分包进行命名(chunk name)
>
>
>
routes: [
// 添加一个映射关系, 设置默认的展示页面
{
path: “/”,
redirect: “/home”
},
{
path: “/home”,
component: () => import(/* webpackChunkName: ‘home’ */“…/views/Home.vue”)
},
{
path: “/about”,
component: () => import(/* webpackChunkName: ‘about’*/“…/views/About.vue”)
}
]
>
> 我们再来看一下打包效果
>
>
>
![在这里插入图片描述](https://img-blog.csdnimg.cn/c67c000edb7f42a6b1258c272b4b8d26.png#pic_center)
**注意: 在开发中我们使用路由, 一般都是会使用它的懒加载的**
---
### 路由的其他属性
>
> 前面我使用了路由中的path属性和component属性
>
>
> 其实路由中还有name属性和meta属性
>
>
>
**name属性**
>
> 记录路由独一无二的名称, 在页面跳转的时候也是可以指定name的(用的不多);
>
>
>
routes: [
// 添加一个映射关系, 设置默认的展示页面
{
// name要是独一无二, 唯一的
name: “home”,
path: “/”,
redirect: “/home”
}
]
**meta属性**
>
> meta属性放一些额外的, 自定义的数据
>
>
> 这个自定义数据是可以在其他地方拿到的 (后面用到时在和大家介绍)
>
>
>
{
path: “/”,
redirect: “/home”,
// 自定义的一些数据
meta: {
name: “chenyq”,
age: 18,
height: 1.88
}
}
---
### 动态路由的使用
#### 🍟动态路由基本匹配
**很多时候我们需要将给定匹配模式的路由映射到同一个组件**:
>
> 例如,我们可能有一个 User 组件,它应该对所有用户进行渲染,我们url需要拼接上用户的ID,但是用户的ID是不同的,意味着我们路径是不能写死的;
>
>
> 在Vue Router中,我们可以在路径中使用一个动态字段来实现,我们称之为路径参数;
>
>
>
routes: [
{
// 拼接时上:id表示路径不是写死的, 会有用户传入的id
path: “/user/:id”,
component: () => import(“…/views/User.vue”)
}
]
**在router-link中进行如下跳转**:
用户:123
用户:321
#### 🍟获取动态路由的值
>
> 上面代码中, 我们虽然实现了/user拼接不同的id显式同一个页面
>
>
> 但是我们页面中展示的效果是相同的, 我们需要在User组件中根据不同的用户, 获取到不同的id进行展示
>
>
>
**那么在User中如何获取到对应的值呢?**
>
> 在template中,直接通过 $route.params获取值;
>
>
> 在created中,通过 this.$route.params获取值;
>
>
> 在setup中,我们要使用 vue-router库给我们提供的一个hook useRoute;
>
>
> * 该Hook会返回一个Route对象,对象中保存着当前路由相关的值;
>
>
>
* **在template模板中,通过 `$route.params`获取值**
User{{ $route.params.id }}
* 在Options API 的 created中,通过 this.$route.params获取值
* **在setup中,我们要使用 vue-router库给我们提供的一个hook `useRoute`;**
#### 🍟NotFound
**对于哪些没有匹配到的路由,我们通常会匹配到固定的某个页面**
>
> 比如NotFound的错误页面中,这个时候我们可`编写一个动态路由用于匹配所有的页面`;
>
>
> 在vue中, 我们可以通过`/:pathMatch(.*)`匹配所有的路径
>
>
>
routes: [
{
path: “/”,
redirect: “/home”
},
{
path: “/home”,
component: () => import(“…/views/Home.vue”)
},
{
path: “/about”,
component: () => import(“…/views/About.vue”)
},
{
path: “/user/:id”,
component: () => import(“…/views/User.vue”)
},
{
// *匹配所有路由的路径
path: “/:pathMatch(.*)”,
component: () => import(“…/views/NotFound.vue”)
}
]
* **当我们匹配不到前面路径的时候, 就会匹配最后一个路径, 显式NotFoun组件**
![在这里插入图片描述](https://img-blog.csdnimg.cn/b8b2af45cf824365bca588fdeb9c9549.png#pic_center)
>
> 如果我们想要提示用户的什么路径不正确
>
>
> 我们可以通过 `$route.params.pathMatch`获取到传入的参数:
>
>
>
Not Found: 您的路径 {{ $route.params.pathMatch }} 不正确,请检查路径是否正确
---
#### 🍟匹配规则加 \*
**刚刚我们通过`/:pathMatch(.*)`匹配所有的路径, 这里还有另一种写法**:
>
> 注意:我在`/:pathMatch(.*)`后面又加了一个 `*`;
>
>
>
{
// 匹配所有路由的路径
path: “/:pathMatch(.*)*”,
component: () => import(“…/views/NotFound.vue”)
}
>
> **它们的区别在于解析的时候,是否解析 /**
>
>
>
* 当没有加 \* 号时
{
// 没有加 * 号
path: “/:pathMatch(.*)”,
component: () => import(“…/views/NotFound.vue”)
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/884d5737433748548f5895b42cff4e58.png#pic_center)
* 当加了 \* 号时
{
// 加了 * 号
path: “/:pathMatch(.*)*”,
component: () => import(“…/views/NotFound.vue”)
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/c08f6c6d0c3244a6950a176618aca900.png#pic_center)
### 路由嵌套的使用
**什么是路由的嵌套呢**?
>
> 目前我们匹配的Home、About、User等都`属于第一层路由`,我们在它们之间可以来回进行切换;
>
>
>
**但是呢,我们Home页面本身,也可能会在多个组件之间来回切换**:
>
> 比如Home中包括Product、Message,它们可以在Home内部来回切换;
>
>
> 这个时候我们就需要使用嵌套路由,在Home中也使用 router-view 来占位之后需要渲染的组件;
>
>
>
**使用嵌套路由, 首先我们需要配置嵌套路由**
>
> 在我们要配置嵌套路由的映射关系中, 添加children属性
>
>
> 下面我用Home组件举例
>
>
>
{
path: “/home”,
component: () => import(“…/views/Home.vue”),
// children中配置home的二级路由
children: [
// 定义默认展示路由
{
path: “/home”,
redirect: “/home/product”
},
{
// 配置HomeProduct组件路由, 二级路径直接写子路径即可
path: “product”, // 相当于: /home/product
component: () => import(“…/views/HomeProduct.vue”)
},
{
// 配置HomeMessage组件路由
path: “message”,
component: () => import(“…/views/HomeMessage.vue”)
}
]
}
* 在Home组件中定义router-view展示二级路由
Home
商品 信息<!-- 使用router-view站位 -->
<router-view></router-view>
---
**前面我们有说过会在嵌套路由和大家讲解exact-active-class属性**
>
> exact-active-class属性的默认class是`router-link-exact-active`
>
>
>
>
> 我们知道active-class属性会匹配当前选中的<router-view>标签
>
>
> 而exact-active-class是`精准匹配`当前选中的标签, 这个精准匹配怎么理解呢, 我给大家画一幅图展示
>
>
>
**当上面代码中我们选中首页下面商品的时候**:
>
> 此时首页和商品都是当前被选中的<router-link>标签, 都会添加上`active-class`属性的默认class`router-link-active`
>
>
> 而商品这个<router-link>标签还会额外添加, `exact-active-class`属性的`router-link-exact-active`
>
>
>
![在这里插入图片描述](https://img-blog.csdnimg.cn/bf4b9aac6bb34171876deac0b245a8c2.png#pic_center)
### 代码的页面跳转
>
> 前面我们路由的页面跳转都是通过<router-link>标签完成的
>
>
> 但是有时候我们希望通过代码来完成页面的跳转,比如点击的是一个按钮, 点击一个span等等其他元素也实现页面跳转
>
>
>
**如下, 我想通过点击span和button代替刚刚Home组件中的两个<router-link>标签, 那么我可以分别监听span元素和button元素的点击, 在代码中实现页面跳转的功能**
<span @click=“homeSpanClick”>商品
<button @click=“btnClick”>信息
**使用push的特点是压入一个新的页面,那么在用户点击返回时,上一个页面还可以回退,但是如果我们希望当前页面是没有历史记录的,那么可以使用replace**:
**push中也可以传入一个对象, 对象的写法就可以通过query属性传递参数**
function homeSpanClick() {
router.push({
path: “/home/product”,
// 通过query传递参数
query: {
name: “chenyq”,
age: 18
}
})
}
**在界面中通过 $route.query 来获取参数**
{{ $route.query.name }} - {{ $route.query.age }}
---
**页面的前进后退**
**router的go方法**
// 导入函数useRouter
import { useRouter } from “vue-router”
// 通过函数useRouter拿到路由对象
const router = useRouter()
function goClick() {
// 向前移动一条记录
router.go(1)
// 返回一条记录
// router.go(-1)
/// 向前三条记录
// router.go(3)
// 如果没有name多条记录, 静默失败
// router.go(100)
// router.go(-100)
}
**router也有back**:
>
> 通过调用 history.back() 回溯历史。相当于 router.go(-1);
>
>
>
// 导入函数useRouter
import { useRouter } from “vue-router”
// 通过函数useRouter拿到路由对象
const router = useRouter()
function btnClick() {
router.back()
}
**router也有forward**:
>
> 通过调用 history.forward() 在历史中前进。相当于 router.go(1);
>
>
>
// 导入函数useRouter
import { useRouter } from “vue-router”
// 通过函数useRouter拿到路由对象
const router = useRouter()
function btnClick() {
router.forward()
}
### 动态添加路由
**某些情况下我们可能需要动态的来添加路由**:
>
> 比如有一个后台管理系统, 我们需要根据用户不同的权限,注册不同的路由, 来显示符合用户权限的操作菜单;
>
>
> 这个时候我们可以使用一个方法 `addRoute`;
>
>
>
**例如我们定义一个变量isAdmin用于判断用户是否是管理员 (真实开发这个用于判断的变量是来自网络请求的)**
>
> 如果isAdmin为true, 那么说明是管理员, 就为管理员注册路由可以进入管理员界面
>
>
> 如果不是管理员, 那么就不会注册管理员界面的路由, 没有注册路由管理员界面就不会展示出来
>
>
>
// 定义一个变量用于判断是否是管理员
let admine = false
if (admine) {
// 使用addRoute方法添加一级路由
router.addRoute({
path: “/admin”,
component: () => import(“…/views/Admin.vue”)
})
}
**上面是动态添加了一个一级路由, 那么能不能动态添加二级路由呢? 答案是肯定的**
// 定义一个变量用于判断是否是管理员
let admine = true
if (admine) {
// 动态添加二级路由, 第一个参数, 父路由的name值
router.addRoute(“home”, {
path: “vip”,
component: () => import(“…/views/HomeVip.vue”)
})
}
---
**动态管理路由的其他方法(了解)**
**删除路由有以下三种方式**:
>
> 方式一:添加一个name相同的路由, 由于name是唯一的, 所以新添加的路由会把原来的路由覆盖掉;
>
>
> 方式二:通过`removeRoute(name值)`的方法,传入路由的名称;
>
>
> 方式三:通过addRoute方法的返回值回调;
>
>
>
// 方式一
router.addRoute({ name: “about”, path: “/about”, component: About })
// 由于name相同, 新添加的会覆盖掉之前的路由
router.addRoute({ name: “about”, path: “/home”, component: Home })
// 方式二
router.addRoute({ name: “about”, path: “/about”, component: About })
// 通过removeRoute方法删除
router.removeRoute(“about”)
// 方式三
const remove = router.addRoute({ path: “/about”, component: About })
// 调用addRoute方法会有一个返回值, 调用返回值可以删除路由
remove()
**路由的其他方法补充**:
>
> `router.hasRoute(name值)`:检查路由是否存在。
>
>
>
console.log(router.hasRoute(“home”)) // true
>
> `router.getRoutes()`:获取一个包含所有路由记录的数组。
>
>
>
console.log(router.getRoutes())
---
### 路由导航守卫
#### 🍚beforeEach守卫函数
>
> **在开发中我们使用最多的就是beforeEach守卫函数**
>
>
>
**vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航, 那么什么是导航守卫呢**?
>
> 在home页面跳转到about页面的这个过程, 我们称之为导航
>
>
> 在跳转这个过程的中间环节, 我们称之为导航守卫, 我们可以在这个环节对跳转进行拦截, 进行逻辑判断
>
>
>
**全局的前置守卫beforeEach是在导航触发时会被回调的**:
**beforeEach传入一个函数, 传入的函数都会被回调, 且传入的函数有两个参数**:
>
> `to`:即将进入的路由Route对象;
>
>
> `from`:即将离开的路由Route对象;
>
>
>
**beforeEach有返回值**:
>
> 返回false:取消当前导航;
>
>
> 不返回或者undefined:进行默认导航;
>
>
> 明确返回一个路由地址, 页面会跳转到返回的地址上去:
>
>
> * 可以是一个string类型的路径;
> * 可以是一个对象,对象中包含path、query、params等信息;
>
>
>
**可选的第三个参数:next(不推荐使用)**
>
> 在Vue2中我们是通过next函数来决定如何进行跳转的;
>
>
> 但是在Vue3中我们是通过返回值来控制的,不再推荐使用next函数,这是因为开发中很容易调用多次next;
>
>
>
**比如我们完成如下一个功能**:
>
> **现在我们有一个订单页面: 在订单页面我们主要实现两个逻辑**:
>
>
> 1. 判断用户是否登录
> 2. 根据逻辑进行不同的处理
>
>
> 用户已经登录, 进入订单页面
>
>
> 用户没有登录, 进入登录页面, 等到用户登录成功, 进入首页(或者订单页)
>
>
>
**路由配置中的逻辑**:
// 路由导航守卫
router.beforeEach((to, from) => {
const token = localStorage.getItem(“token”)
// 判断用户是否登录, 是否去order页面
if (!token && to.path === “/order”) {
return “/login”
}
})
**order中的登录逻辑**
import { useRouter } from “vue-router”
const router = useRouter()
function loginClick() {
// 模拟向服务器发生请求, 服务器会返回token
localStorage.setItem(“token”, “chenyq”)
// 登录成功跳转会order页面
router.push(“/order”)
}
---
#### 🍚其他导航守卫(了解)
**Vue还提供了很多的其他守卫函数,目的都是在某一个时刻给予我们回调,让我们可以更好的控制程序的流程或者功能**:[文档链接](https://bbs.csdn.net/topics/618166371):https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html
**我们一起来看一下官方给出的完整的导航解析流程**:
1. 导航被触发。
2. 在失活的组件里调用 beforeRouteLeave 守卫。
>
> 也就是说在我们离开的组件调用
>
>
>
3. 调用全局的 beforeEach 守卫。
4. 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
>
> 比如/user/123 -> /user/321, 类似这种才会调用beforeRouteUpdate
>
>
>
### 最后
除了简历做到位,面试题也必不可少,整理了些题目,前面有117道汇总的面试到的题目,后面包括了HTML、CSS、JS、ES6、vue、微信小程序、项目类问题、笔试编程类题等专题。
* **[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**
![](https://i-blog.csdnimg.cn/blog_migrate/a387da353ac569d57df9855956d26714.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f03426adfe9ca77f2cfcd26f86dafdc2.png)
})
order中的登录逻辑
import { useRouter } from "vue-router"
const router = useRouter()
function loginClick() {
// 模拟向服务器发生请求, 服务器会返回token
localStorage.setItem("token", "chenyq")
// 登录成功跳转会order页面
router.push("/order")
}
🍚其他导航守卫(了解)
Vue还提供了很多的其他守卫函数,目的都是在某一个时刻给予我们回调,让我们可以更好的控制程序的流程或者功能:文档链接:https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html
我们一起来看一下官方给出的完整的导航解析流程:
- 导航被触发。
- 在失活的组件里调用 beforeRouteLeave 守卫。
也就是说在我们离开的组件调用
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
比如/user/123 -> /user/321, 类似这种才会调用beforeRouteUpdate
最后
除了简历做到位,面试题也必不可少,整理了些题目,前面有117道汇总的面试到的题目,后面包括了HTML、CSS、JS、ES6、vue、微信小程序、项目类问题、笔试编程类题等专题。