先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
正文
q
u
e
r
y
.
n
a
m
e
和
t
h
i
s
.
router.query.name 和 this.
router.query.name和this.router.params.name。url 地址显⽰:query 更加类似于我们 ajax 中 get 传参,params 则类似于 post,说的再简单⼀点,前者在浏览器地址栏中显⽰参数,后者则不显⽰
注意点:query 刷新不会丢失 query ⾥⾯的数据 params 刷新会丢失 params ⾥⾯的数据
49、vue mock 数据
在项⽬中尝试了 mockjs,mock 数据,实现前后端分离开发。关于 mockjs,官⽹描述的是
-
- 前后端分离
-
- 不需要修改既有代码,就可以拦截 Ajax 请求,返回模拟的响应数据。
-
- 数据类型丰富
-
- 通过随机数据,模拟各种场景。
总结:在后端接⼝没有开发完成之前,前端可以⽤已有的接⼝⽂档,在真实的请求上拦截 ajax,并根据 mockjs 的 mock 数据的规则,模拟真实接⼝返回的数据,并将随机的模拟数据返回参与相应的数据交互处理,这样真正实现了前后台的分离开发。
与以往的⾃⼰模拟的假数据不同,mockjs 可以带给我们的是:在后台接⼝未开发完成之前模拟数据,并返回,完成前台的交互;在后台数据完成之后,你所做的只是去掉 mockjs:停⽌拦截真实的 ajax,仅此⽽已。
50、vue 初始化页⾯闪动问题
使⽤ vue 开发时,在 vue 初始化之前,由于 div 是不会 vue 管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于 {{message}} 的字样,虽然⼀般情况下这个时间很短暂,但是我们还是有必要解决这个问题的。
⾸先:在 css ⾥加上 [v-cloak]{display:none;},如果没有彻底解决问题,则在根元素加上 style=“display:none;” :style=“{display:block}”
51、vue 更新数组时触发视图更新的⽅法
push();pop();shift();unshift();splice();sort();reverse()
52、vue 常⽤的 UI 组件库
Mint UI,element,VUX
53、mint-ui 是什么?怎么使⽤?说出⾄少三个组件使⽤⽅法?
基于 vue 的前端组件库。npm 安装,然后 import 样式和 js,vue.use(mintUi)全局引⼊。在单个组件局部引⼊:import {Toast} from ‘mint-ui’。
- 组件⼀:Toast(‘登录成功’);
- 组件⼆:mint-header;
- 组件三:mint-swiper
54、Vue ⾥⾯ router-link 在电脑上有⽤,在安卓上没反应怎么解决?
Vue 路由在 Android 机上有问题,babel 问题,安装 babel polypill 插件解决
55、Vue2 中注册在 router-link 上事件⽆效解决⽅法
使⽤ @click.native。原因:router-link 会阻⽌ click 事件,.native 指直接监听⼀个原⽣事件。
56、简述 MVVM 框架
Model: 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑。
View: 代表 UI 组件,它负责将数据模型转化成 UI 展现出来。
ViewModel: 监听数据模型的改变和控制视图行为、处理用户交互,简单理解就是一个同步 View 和 Model 的对象,连接 Model 和 View。
57、vue2 和 vue3 区别
- 写法上的区别: vue2 使用的是
options(选项)Api
,vue3 的是composition Api
(当然 vue3 也兼容composition api
)。options Api
中methods,compute,data
等 api 都是分散的。而composition api
中的代码是根据逻辑功能来组织的, 我们可以将一个功能所定义的methods,compute,data
等 api 会放在一起, 让我们可以更灵活地组合组件逻辑。 - vue2 将响应式数据放到 data 函数中, 而 vue3 则是使用
ref
和reactive
将数据声明为响应式 - 响应式实现方式: vue2 中是通过
Object.defineProperty
对数据劫持实现的, vue3 中则是使用Proxy
对数据代理实现的。 - 生命周期区别: vue3 中将
beforeCreate
和created
合并到了setup
函数中 - 根节点: vue3 组件允许多个根节点, 而 vue2 只允许一个
- 内置组件: vue3 新增了传送组件
Teleport
和异步依赖处理组件Suspense
58、v-if 和 v-show
v-if
表示一个 dom 元素是否被创建,而v-show
则是控制这个 dom 元素的display
属性是否为none
- 一般在频繁切换状态的地方使用
v-show
,v-if
则更适合条件不经常改变的场景,因为它切换开销相对较大
59、v-for 和 v-if 优先级
- 开发过程中一般不建议同时将 v-for 和 v-if 放在一个标签中使用
- Vue2 中 v-for 的优先级会更高,所以会先执行循环,再进行 v-if 判断,所以这样就会导致无论需不需展示这个元素,都会先遍历整个列表
- 在 Vue3 中 v-if 的优先级会更高,但是当我们遍历一个数组的时候,根据数组中的某个元素进行 v-if 判断的时候就会报错,因为 v-if 会先执行此时还没有拿到这个数组。所以 Vue3 中会报错
60、介绍 Vue 插槽用法
插槽slot
可以理解为占坑,当使用一个组件的时候,在组件标签里的对应的内容就会替换掉这个组件中的slot
标签。
插槽分为默认插槽
,具名插槽
,作用域插槽
。
默认插槽子组件中用slot
标签来确定渲染位置,父组件使用它时直接在子组件的标签内写入内容即可
//子组件
<template>
<slot />
</template>
//父组件
<Child>
<div>默认插槽</div>
</Child>
具名插槽
顾名思义就是具有名字的插槽,子组件中可以用name
熟悉对slot
命名,父组件在使用的时候通过template
中的v-slot:name
或者#name
来定义这个插槽中的内容
//子组件
<template>
<slot ></slot>
</template>
//父组件
<Child>
<template v-slot:content>具名插槽内容</template>
</Child>
作用域插槽
子组件中的slot
可以通过类似组件属性传递的方式将子组件的值传递给父组件中这个子组件的插槽内容中
(子组件标签内),在父组件使用子组件的时候要用v-slot
的值进行接收这些参数,默认插槽可以将其直接写在子组件标签上,具名插槽则写在template
上。而传过来的值只能在子组件标签中或者template
标签中使用。所以在父组件作用域中获取到了子组件作用域中的变量,可以认为作用域插槽延伸了子组件数据的作用范围,因此叫做作用域插槽
61、过滤器的作用,如何实现一个过滤器
过滤器是用来过滤数据的,在 Vue 中使用 filters 来过滤数据,filters 不会修改数据,而是过滤数据,改变用户看到的输出
使用场景:
- 需要格式化数据的情况,比如需要处理时间、价格等数据格式的输出 / 显示。
- 比如后端返回一个 年月日的日期字符串,前端需要展示为 多少天前 的数据格式,此时就可以用 fliters 过滤器来处理数据。
过滤器是一个函数,它会把表达式中的值始终当作函数的第一个参数。过滤器用在插值表达式 {{}} 和 v-bind 表达式 中,然后放在操作符 “ | ” 后面进行指示
<li>商品价格:{{item.price | filterPrice}}</li>
filters: { filterPrice (price) { return price ? ('¥' + price) : '--' } }
注意 vue3 已经移除了过滤器
62、常见的事件修饰符及其作用
- .stop:等同于 JavaScript 中的 event.stopPropagation() ,防止事件冒泡;
- .prevent :等同于 JavaScript 中的 event.preventDefault() ,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);
- .capture :将事件改成捕获模式, 由外到内触发
- .self :只会触发自己范围内的事件,不包含子元素;
- .once :只会触发一次。
63、v-model 如何实现的
v-model 其实是一个语法糖, 比如
<input v-model="message" />
等同于
<input
:value="message"
@input="message=$event.target.value"
>
63、Vue2 中给 data 中的对象属性添加一个新的属性时会发生什么?如何解决?
Vue2 中对象添加新属性绑定的视图不会更新, 因为 Vue2 中 Object.defineProperty 劫持不到 data 对象中新增的属性, 可以使用this.$set(this.obj, 'b', 'obj.b')
解决
$set() 方法相当于手动的去把 obj.b 处理成一个响应式的属性,此时视图也会跟着改变了。
64、Vue 插件用法
面试一般会问你如何写一个 vue 插件, 所以没写过 vue 插件的最好去亲自体验一下
回答:
vue
实例会有一个use
函数, 它接受的是一个带有install
函数的对象和一个可选的选项对象, 当我们使用 vue.use(plugin)
或者app.use(plugin)
会调用我们插件的install
属性的函数, 并且将当前组件的实例传进来. 所以在插件中就可以对这个实例进行一些操作来实现我们插件的功能
65、Vue 自定义指令
vue 官方提供了 v-text、v-for、v-model、v-if 等常用的指令。除此之外 vue 还允许开发者自定义指令。面试经常会问什么是自定义指令? 你用自定义指令做过哪些功能?
回答 1: 什么是自定义指令?
- 自定义指令包含局部指令和全局指令, 在模板中使用指令前必须先使用
directives
选项注册。局部指令指在某个组件中注册, 而全局则是将指令注册到全局, 通常在 main.js 中注册。 - 自定义指令由一个包含类似组件生命周期钩子的对象来定义。它的生命周期钩子包含
created
,beforeMount
,mounted
,beforeUpdate
,updated
,beforeUnmount
,unmounted
, - 常用的钩子为
mounted
和updated
, 它接受el
,binding
等参数.binding
参数的值一般包含绑定到这个元素上的信息, 比如下面这个指令
<div v-example:foo.bar="baz">
它的 binding 会是这个对象
{
arg: 'foo',
modifiers: { bar: true },
value: /* `baz` 的值 */,
oldValue: /* 上一次更新时 `baz` 的值 */
}
回答 2: 你用自定义指令做过哪些功能?
- 数据埋点, 通过绑定自定义事件传入点击当前元素需要埋点的事件名, 在指令中监听当前元素的点击事件后调用后台接口将事件名传入
- 权限控制, 通过绑定自定义事件传入控制当前元素的权限字段, 在指令中获取到当前元素根据权限字段来控制该元素的状态 (显示, 隐藏等)
66、computed 和 watch
- computed 是计算属性, 依赖其它属性值, 用于解决模板中放入过多的逻辑会让模板过重且难以维护的问题.watch 是侦听器, 当我们需要根据一个属性的变化而做出一些处理的时候, 可以使用 watch 来对这个属性进行监听
- computed 具有缓存的特点, 即当它所依赖的属性发生改变的时候它才会重新执行内部逻辑. 如下代码
<template>
<div>{{ addSum }}</div>
<div>{{ addSum }}</div>
<div>{{ addSum }}</div>
</template>
<script setup>
import { computed, ref, watch } from "vue";
const a = ref(1)
const b = ref(2)
let addSum = computed(() => {
console.log('内部逻辑执行')
return a.value + b.value
})
</script>
页面多次使用addSum
, 但是只会打印一次 “内部逻辑执行”
- watch 在页面首次加载的时候默认不会执行, 需要设置
immediate:true
首次才会执行监听 - watch 默认只监听一层数据, 不监听多层数据里属性的变化, 需要设置
deep:true
才会进行深度监听
67、vue 生命周期
Vue2(选项式 API) | Vue3(setup) | 描述 |
---|---|---|
beforeCreate | - | 实例创建前 |
created | - | 实例创建后 |
beforeMount | onBeforeMount | DOM 挂载前调用 |
mounted | onMounted | DOM 挂载完成调用 |
beforeUpdate | onBeforeUpdate | 数据更新之前被调用 |
updated | onUpdated | 数据更新之后被调用 |
beforeDestroy | onBeforeUnmount | 组件销毁前调用 |
destroyed | onUnmounted | 组件销毁完成调用 |
68、vue 父子组件生命周期执行顺序
这个相对于上一个问题稍微复杂一点, 可以试着理解记忆或者直接记住吧
渲染过程
#mermaid-svg-czhhfdPqQmB0CYtp {font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-czhhfdPqQmB0CYtp .error-icon{fill:#552222;}#mermaid-svg-czhhfdPqQmB0CYtp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-czhhfdPqQmB0CYtp .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-czhhfdPqQmB0CYtp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-czhhfdPqQmB0CYtp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-czhhfdPqQmB0CYtp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-czhhfdPqQmB0CYtp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-czhhfdPqQmB0CYtp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-czhhfdPqQmB0CYtp .marker.cross{stroke:#333333;}#mermaid-svg-czhhfdPqQmB0CYtp svg{font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-czhhfdPqQmB0CYtp .label{font-family:“trebuchet ms”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-czhhfdPqQmB0CYtp .cluster-label text{fill:#333;}#mermaid-svg-czhhfdPqQmB0CYtp .cluster-label span{color:#333;}#mermaid-svg-czhhfdPqQmB0CYtp .label text,#mermaid-svg-czhhfdPqQmB0CYtp span{fill:#333;color:#333;}#mermaid-svg-czhhfdPqQmB0CYtp .node rect,#mermaid-svg-czhhfdPqQmB0CYtp .node circle,#mermaid-svg-czhhfdPqQmB0CYtp .node ellipse,#mermaid-svg-czhhfdPqQmB0CYtp .node polygon,#mermaid-svg-czhhfdPqQmB0CYtp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-czhhfdPqQmB0CYtp .node .label{text-align:center;}#mermaid-svg-czhhfdPqQmB0CYtp .node.clickable{cursor:pointer;}#mermaid-svg-czhhfdPqQmB0CYtp .arrowheadPath{fill:#333333;}#mermaid-svg-czhhfdPqQmB0CYtp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-czhhfdPqQmB0CYtp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-czhhfdPqQmB0CYtp .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-czhhfdPqQmB0CYtp .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-czhhfdPqQmB0CYtp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-czhhfdPqQmB0CYtp .cluster text{fill:#333;}#mermaid-svg-czhhfdPqQmB0CYtp .cluster span{color:#333;}#mermaid-svg-czhhfdPqQmB0CYtp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-czhhfdPqQmB0CYtp :root{–mermaid-font-family:“trebuchet ms”,verdana,arial,sans-serif;}
父beforeCreate
父created
父beforeMount
子beforeCreate
子created
子beforeMount
子mounted
父mounted
更新过程
#mermaid-svg-dU9lCSZuMx8fiJaw {font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-dU9lCSZuMx8fiJaw .error-icon{fill:#552222;}#mermaid-svg-dU9lCSZuMx8fiJaw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dU9lCSZuMx8fiJaw .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-dU9lCSZuMx8fiJaw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dU9lCSZuMx8fiJaw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dU9lCSZuMx8fiJaw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dU9lCSZuMx8fiJaw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dU9lCSZuMx8fiJaw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dU9lCSZuMx8fiJaw .marker.cross{stroke:#333333;}#mermaid-svg-dU9lCSZuMx8fiJaw svg{font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dU9lCSZuMx8fiJaw .label{font-family:“trebuchet ms”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-dU9lCSZuMx8fiJaw .cluster-label text{fill:#333;}#mermaid-svg-dU9lCSZuMx8fiJaw .cluster-label span{color:#333;}#mermaid-svg-dU9lCSZuMx8fiJaw .label text,#mermaid-svg-dU9lCSZuMx8fiJaw span{fill:#333;color:#333;}#mermaid-svg-dU9lCSZuMx8fiJaw .node rect,#mermaid-svg-dU9lCSZuMx8fiJaw .node circle,#mermaid-svg-dU9lCSZuMx8fiJaw .node ellipse,#mermaid-svg-dU9lCSZuMx8fiJaw .node polygon,#mermaid-svg-dU9lCSZuMx8fiJaw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dU9lCSZuMx8fiJaw .node .label{text-align:center;}#mermaid-svg-dU9lCSZuMx8fiJaw .node.clickable{cursor:pointer;}#mermaid-svg-dU9lCSZuMx8fiJaw .arrowheadPath{fill:#333333;}#mermaid-svg-dU9lCSZuMx8fiJaw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dU9lCSZuMx8fiJaw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dU9lCSZuMx8fiJaw .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-dU9lCSZuMx8fiJaw .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-dU9lCSZuMx8fiJaw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dU9lCSZuMx8fiJaw .cluster text{fill:#333;}#mermaid-svg-dU9lCSZuMx8fiJaw .cluster span{color:#333;}#mermaid-svg-dU9lCSZuMx8fiJaw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dU9lCSZuMx8fiJaw :root{–mermaid-font-family:“trebuchet ms”,verdana,arial,sans-serif;}
父beforeUpdate
子beforeUpdate
子updated
父updated
销毁过程
#mermaid-svg-ZdXs7utVab0XZIpe {font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ZdXs7utVab0XZIpe .error-icon{fill:#552222;}#mermaid-svg-ZdXs7utVab0XZIpe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZdXs7utVab0XZIpe .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-ZdXs7utVab0XZIpe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZdXs7utVab0XZIpe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZdXs7utVab0XZIpe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZdXs7utVab0XZIpe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZdXs7utVab0XZIpe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZdXs7utVab0XZIpe .marker.cross{stroke:#333333;}#mermaid-svg-ZdXs7utVab0XZIpe svg{font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZdXs7utVab0XZIpe .label{font-family:“trebuchet ms”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZdXs7utVab0XZIpe .cluster-label text{fill:#333;}#mermaid-svg-ZdXs7utVab0XZIpe .cluster-label span{color:#333;}#mermaid-svg-ZdXs7utVab0XZIpe .label text,#mermaid-svg-ZdXs7utVab0XZIpe span{fill:#333;color:#333;}#mermaid-svg-ZdXs7utVab0XZIpe .node rect,#mermaid-svg-ZdXs7utVab0XZIpe .node circle,#mermaid-svg-ZdXs7utVab0XZIpe .node ellipse,#mermaid-svg-ZdXs7utVab0XZIpe .node polygon,#mermaid-svg-ZdXs7utVab0XZIpe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZdXs7utVab0XZIpe .node .label{text-align:center;}#mermaid-svg-ZdXs7utVab0XZIpe .node.clickable{cursor:pointer;}#mermaid-svg-ZdXs7utVab0XZIpe .arrowheadPath{fill:#333333;}#mermaid-svg-ZdXs7utVab0XZIpe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZdXs7utVab0XZIpe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZdXs7utVab0XZIpe .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-ZdXs7utVab0XZIpe .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-ZdXs7utVab0XZIpe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZdXs7utVab0XZIpe .cluster text{fill:#333;}#mermaid-svg-ZdXs7utVab0XZIpe .cluster span{color:#333;}#mermaid-svg-ZdXs7utVab0XZIpe div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZdXs7utVab0XZIpe :root{–mermaid-font-family:“trebuchet ms”,verdana,arial,sans-serif;}
父beforeDestroy
子beforeDestroy
子destroyed
父destroyed
注意如果子组件是异步组件的话它们的执行顺序会发生改变,会先执行完父组件的生命周期然后再执行子组件的生命周期
69、vue 导航 (路由守卫)
路由守卫分为全局路由守卫,路由独享守卫,组件路由守卫
- 全局路由守卫
beforeEach
, 接收to、from、next
三个参数,每个路由跳转前都会触发,登录验证时用的比较多beforeResolve
,和beforeEach
类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后调用- afterEach,在路由跳转完成后调用,接收 to、from 两个参数
- 路由独享守卫
beforeEnter
, 一般配置在路由配置文件中(router/index.js),对进入某个路由之前进行相关操作
- 组件路由守卫
接收
to、from、next
三个参数
beforeRouteEnter
, 进入该组件之前调用,无法获取到 vue 实例beforeRouteUpdate
,在当前路由改变,但是该组件被复用时调用beforeRouteLeave
, 在离开当前组件时调用
70、Vue-Router 的懒加载如何实现
使用箭头函数 + import 动态加载
const router = new VueRouter({
routes: [{ path: "/list", component: () => import("@/components/list.vue") }],
});
71、路由的 hash 和 history 模式的区别
Vue-Router 有两种模式:hash 模式和 history 模式。默认的路由模式是 hash 模式。
- hash 模式
简介: hash 模式是开发中默认的模式,它的 URL 带着一个 #,例如:www.abc.com/#/vue,它的 hash 值就是 #/vue。
特点:hash 值会出现在 URL 里面,但是不会出现在 HTTP 请求中,对后端完全没有影响。所以改变 hash 值,不会重新加载页面。这种模式的浏览器支持度很好,低版本的 IE 浏览器也支持这种模式。hash 路由被称为是前端路由,已经成为 SPA(单页面应用)的标配。
原理: hash 模式的主要原理就是 onhashchange() 事件:
window.onhashchange = function (event) {
console.log(event.oldURL, event.newURL);
let hash = location.hash.slice(1);
};
- history 模式
简介: history 模式的 URL 中没有 #,它使用的是传统的路由分发模式,即用户在输入一个 URL 时,服务器会接收这个请求,并解析这个 URL,然后做出相应的逻辑处理。 特点: 当使用 history 模式时,URL 就像这样:abc.com/user/id。相比 hash 模式更加好看。但是,history 模式需要后台配置支持。如果后台没有正确配置,访问时会返回 404。 API: history api 可以分为两大部分,切换历史状态和修改历史状态:
修改历史状态:包括了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法,这两个方法应用于浏览器的历史记录栈,提供了对历史记录进行修改的功能。只是当他们进行修改时,虽然修改了 url,但浏览器不会立即向后端发送请求。如果要做到改变 url 但又不刷新页面的效果,就需要前端用上这两个 API。
切换历史状态: 包括 forward()、back()、go() 三个方法,对应浏览器的前进,后退,跳转操作。
虽然 history 模式丢弃了丑陋的 #。但是,它也有自己的缺点,就是在刷新页面的时候,如果没有相应的路由或资源,就会刷出 404 来。
如果想要切换到 history 模式,需要后端进行一些配置:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的根页面
Apache
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
nginx
location / {
try_files $uri $uri/ /index.html;
}
72、nexttick 原理
关于 nextTick 会问到它的用法, 然后是它的原理, 然后还可能问到 JS 的时间循环机制。
问题 1:vue 中的 nextTick 是干什么用的?
这个其实比较简单, 用过都知道它是干嘛的, vue 官方的解释是:
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
这是什么意思呢, 其实 vue 中修改 data 不会立刻触发 dom 更新; 而是把需要更新的 Watcher 加入到 queueWatcher 队列中, 然后在合适的时机在 nextTick 中调用这些 Watcher 的更新函数进行 dom 更新, 所以在 data 刚被修改的时候, 我们是获取不到更新后的 dom 的, 这时候便需要调用 nextTick 函数在它的回调函数中获取到变化后的 dom
问题 2:nextTick 原理
- nextTick 原理是借助浏览器事件循环来完成的, 因为每次事件循环之间都有一次视图渲染, nextTick 尽量在视图渲染之前完成 dom 更新, 所以 nextTick 优先使用的是 promise(微任务) 实现
- 每次执行 nextTick 时会将传入的回调函数放入一个队列中 (callbacks 数组), 然后当在本次事件循环的同步代码执行完毕后开启一个微任务(promise 或者 MutationObserver) 去依次执行这个 callbacks 中的回调函数。
- 但是当浏览器不支持 promise 的时候在 vue2 中会进行进行降级处理, 依次使用
setImmediate
、setTimeout
开启一个宏任务执行 callbacks - 当一个 data 数据更新时对应的 watcher 便会调用一次 nextTick, 将它对应的 dom 更新操作作为回调函数放入 callbacks 中, 所以当我们想获取这个 data 更新后的 dom 需要在其值变化后也调用 nextTick 将回调函数传入排在上个更新 dom 的回调函数后面, 所以我们可以在这个 nextTick 的回调函数中获取到更新后的 data
73、Vue 组件传参
这里我大概归纳了一下 vue2 和 vue3 的传参方式
方式 | Vue2 | Vue3 |
---|---|---|
父传子 | props | props |
子传父 | $emit | emits |
专业技能
一般来说,面试官会根据你的简历内容去提问,但是技术基础还有需要自己去准备分类,形成自己的知识体系的。简单列一下我自己遇到的一些题
-
HTML+CSS
-
JavaScript
-
前端框架
-
前端性能优化
-
前端监控
-
模块化+项目构建
-
代码管理
-
信息安全
-
网络协议
-
浏览器
-
算法与数据结构
-
团队管理
最近得空把之前遇到的面试题做了一个整理,包括我本人自己去面试遇到的,还有其他人员去面试遇到的,还有网上刷到的,我都统一的整理了一下,希望对大家有用。
其中包含HTML、CSS、JavaScript、服务端与网络、Vue、浏览器等等
由于文章篇幅有限,仅展示部分内容
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
e2 中会进行进行降级处理, 依次使用setImmediate
、setTimeout
开启一个宏任务执行 callbacks
4. 当一个 data 数据更新时对应的 watcher 便会调用一次 nextTick, 将它对应的 dom 更新操作作为回调函数放入 callbacks 中, 所以当我们想获取这个 data 更新后的 dom 需要在其值变化后也调用 nextTick 将回调函数传入排在上个更新 dom 的回调函数后面, 所以我们可以在这个 nextTick 的回调函数中获取到更新后的 data
73、Vue 组件传参
这里我大概归纳了一下 vue2 和 vue3 的传参方式
方式 | Vue2 | Vue3 |
---|---|---|
父传子 | props | props |
子传父 | $emit | emits |
专业技能
一般来说,面试官会根据你的简历内容去提问,但是技术基础还有需要自己去准备分类,形成自己的知识体系的。简单列一下我自己遇到的一些题
-
HTML+CSS
-
JavaScript
-
前端框架
-
前端性能优化
-
前端监控
-
模块化+项目构建
-
代码管理
-
信息安全
-
网络协议
-
浏览器
-
算法与数据结构
-
团队管理
最近得空把之前遇到的面试题做了一个整理,包括我本人自己去面试遇到的,还有其他人员去面试遇到的,还有网上刷到的,我都统一的整理了一下,希望对大家有用。
其中包含HTML、CSS、JavaScript、服务端与网络、Vue、浏览器等等
由于文章篇幅有限,仅展示部分内容
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-PontHpNj-1713018809508)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!