脚本宝典收集整理的这篇文章主要介绍了「offer来了」从基础到进阶原理,从vue2到vue3,48个知识点保姆级带你巩固vuejs知识体系,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
对于前端来说, vuejs
是一大常考点。基本上只要候选人的简历上有涉及到 vue
的内容,那么面试官一般都会考察。那么,对于 vue
来说,我们需要从 vue2
到 vue3
来做一个基本的学习,以更好的应对面试官的各种刁难问题。
在下面的这篇文章中,将从 vue2
的基础知识,到 vue2
的原理知识,再到 vue3
的基础知识和原理知识做一个归纳和总结。同时,周一也将整理出相关的面试题,以供大家可以有一个更好的参考。
下面开始进入本文的讲解~
在了解常见的面试题之前,需要先对 vue
的基础知识有一个体系的了解。详细见下图👇
关于以上内容,已整理成博文,戳下方链接进入学习👇
原文:万字总结vue的基本使用和高级特性,周边插件vuex和vue-router
链接:https://juejin.cn/post/6976040670939054093
基于以上知识点,我们将其细分为面试中的常考题。详细见下图👇
接下来对这些题进行一一解答。
├── assets 放置静态资源
├── components 放组件
├── router 定义路由的相关配置
├── views 视图
├── app.vue 应用主组件
├── main.js 入口文件
如何使用:
components
目录新建你的组件文件( smithButton.vue
);import smithButton from '../components/smithButton.vue'
;vue
的子组件的 components
属性上,components:{smithButton}
template
视图 view
中使用;会遇到的问题:
smithButton
命名,使用的时候需要用 smith-button
,在创建时常用到驼峰命名,但在使用时需把驼峰转换为 -
表示;
vue 组件解决什么问题?
vue
组件可以提升整个项目的开发效率。能够页面抽象成多个相对独立的模块,解决了我们传统项目开发效率低、难维护、复用性等等问题。
v-show
通过 css
中的 display
来控制显示和隐藏;v-if
组件是真正的渲染和销毁,而不是显示和隐藏;v-show
,否则用 v-if
。key
,且不能是 index
和 random
;vue
的 diff
算法中,通过对 tag
和 key
来判断是否为相同节点 sameNode
,如果是相同节点,则会尽可能的复用原有的 DOM
节点。key
的好处是:减少渲染次数,提升渲染性能。一般来说,组件生命周期的执行顺序为:挂载阶段 → 更新阶段 → 销毁阶段。下面给出常用组件生命周期的解析。
生命周期钩子 | 介绍 |
---|---|
beforeCreate | 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。 |
created | 页面还没有渲染,但是vue的实例已经初始化结束。 |
beforeMount | 在挂载开始之前被调用:相关的 render 函数首次被调用。 |
mounted | 页面已经渲染完毕。 |
beforeUpdate | 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。 |
updated | 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。 |
activated | keep-alive 组件激活时调用。 |
deactivated | keep-alive 组件停用时调用。 |
beforeDestroy | 实例销毁之前调用。在这一步,实例仍然完全可用。常用场景有: 自定义事件的绑定要解除、setTimeout等定时任务需要销毁、自己绑定的window或者document事件需要销毁。 |
destroyed | Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 |
加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程
父beforeUpdate->父updated
销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
vue
组件常见的通讯方式有以下三种:
props
和 this.$emit
;event.$no
、 event.$off
和 event.$emit
;vuex
。关于组件的渲染和更新过程,需要了解以下这张图。大家可以从 1-6
依次按顺序地对下图的整个过程进行细化和解读。
vuex
进行配置,将 vuex
的状态储存到 localStorage
中;localStorage
里的状态信息;vuex
里的信息保存到 localStorage
里;vuex
里的信息使用 computed
接收。input
元素的 value = this.name
;
绑定 input
事件 this.name = $event.target.value
;
data
更新后触发重新渲染 re-render
;
最核心问题:了解 v-model
在模板编译之后,产生的内容是什么。
具有缓存功能,当 data
不变时不会进行计算;
有效地提高性能。
export
看似是一个对象,但是 .vue
文件编译出来后是一个类;
在每一个地方( data
, method
……)等等进行使用就是对 class
进行实例化;
我们在实例化的时候执行 data
;
如果这个 data
不是函数的话,那每一个组件的实例数据就都一样了,就共享了;
因此需要让它在闭包之中。
mounted
表示整个渲染完成, dom
也加载完成,因此 ajax
请求应该放在 mounted
生命周期中;
本质上 js
是单线程的,并且 ajax
是异步获取数据,是异步加载的一个机制;
如果将其放在 mounted
之前是没有用的,这样做只会让逻辑更加混乱;
原因在于,如果在 mounted
之前放 ajax
请求,那么这个时候 js
还没有渲染完成。且又因为 ajax
请求的数据还是异步的,因此即使是在 mounted
之前也不能加载,也不会有提前加载的效果。
父组件通过 $props
的而方式将自己的属性传递给子组件;
之后子组件通过 <User v-bind = "$props" />
这种方式去接收父组件传递过来的参数。
注: 细节知识点,优先级不高
第一步,我们先定义一个子组件,名字叫 CustomVModel.vue
,具体代码如下:
<template>
<!-- $emit是子组件往父组件传递数据 -->
<input type="text"
:value="text1"
@input="$emit('change1', $event.target.value)"
>
<!--
1. 上面的 input 使用了 :value 来绑定数据,而不是使用 v-model
2. 上面的 change1 和 model.event 要对应起来
3. 上面的 text1 与下面props的 text1 属性对应起来
-->
</template>
<script>
export default {
model: {
prop: 'text1', // 对应下面 props 的 text1
event: 'change1'
},
props: {
text1: String,
default() {
return ''
}
}
}
</script>
第二步,我们在父组件中使用上面的这个子组件:
<template>
<div>
<p>vue 高级特性</p>
<hr>
<!-- 自定义 v-model -->
<p>{{name}}</p>
<CustomVModel v-model="name"/>
</div>
</template>
<script>
import CustomVModel from './CustomVModel'
export default {
components: {
CustomVModel
},
data() {
return {
name: 'Monday'
}
}
}
</script>
通过上面的代码我们可以发现,通过绑定 value
属性和 input
事件这两个语法糖,最终实现数据的双向绑定。
此时我们看下浏览器的显示效果。
通过上图我们自己发现,结果跟实际的 v-model
结果是一样的。至此,我们就实现了自定义的 v-model
,以此来操作数据的双向绑定。
在 vue2.x
中,当多个组件有相同的逻辑时,可以使用 mixin
来进行逻辑抽离;
值得注意的是, mixin
存在有以下问题:
mixin
可能会造成命名冲突。mixin
和组件可能出现多对多的关系,复杂度较高。因此,要慎用 mixin
,且 vue3.x
已经出了 Composition API
,来解决 vue2.x
中存在的这些问题。
当加载大组件时,需要用到异步组件;
当 vue-router
路由要进行异步加载时,需要用到异步组件;
异步组件可以达到优化性能的效果。
keep-alive
可以缓存组件,使得组件不需要重复渲染;
比如像多个静态 tab
页的切换;
keep-alive
可以达到优化性能的效果。
当解绑自定义事件 event.$off
时,需使用 beforeDestory
来对事件进行销毁操作;
当使用定时器绑定时间时,在定时器操作结束时,需要清除定时器;
解绑自定义的 DOM
事件,如 window scroll
等,需要在 beforeDestory
生命周期来对其进行事件解绑。
注意: 如果以上三者不做的话,很容易造成内存泄漏。
action
中可以处理异步, mutation
不可以;
mutation
做原子操作,即做一个操作,比较原子的;
action
可以整合多个 mutation
,可以理解为整理多个原子操作的集合。
hash
默认
H5 history
(需要服务端支持)
已将路由模式整理成博客,具体戳下方链接👇
原文:浅谈前端路由原理
链接:https://juejin.cn/post/6993840419041706014
vue-router
中,使用 import
来实现异步加载。(1)scoped的实现原理:
DOM
节点加一个不重复的属性 data-v-5db9451a
来标志唯一性。(2)vue中scoped的作用:
style
样式属性只属于当前模块,不污染全局。(3)谨慎使用:
scoped
属性,子组件带有 scoped
,父组件是无法操作子组件的。scoped
属性,子组件无 scoped
。父组件也无法设置子组件样式。因为父组件的所有标签都会带有 data-v-5db9451a
唯一标志,但子组件不会带有这个唯一标志属性。v-show
和 v-if
computed
v-for
时加 key
,以及避免和 v-if
同时使用DOM
事件及时销毁keep-alive
data
层级不要太深,尽量扁平vue-loader
在开发环境做模板编译(预编译)keep-alive
webpack
层面的优化SSR
在了解常见的面试题之前,需要先对 vue2.x
的原理知识有一个体系的了解。详细见下图👇
关于以上内容,已整理成博文,戳下方链接进入学习👇
原文1:手把手教你剖析vue响应式原理,监听数据不再迷茫
链接1:https://juejin.cn/post/6978278417951096839
原文2:面试中的网红虚拟DOM,你知多少呢?深入解读diff算法
链接2:https://juejin.cn/post/6978621084862005285
原文3:模板编译template的背后,究竟发生了什么事?带你了解template的纸短情长
链接3:https://juejin.cn/post/6978965732633608222
基于以上知识点,我们将其细分为面试中的常考题。详细见下图👇
接下来对这些题目进行一一解答。
所谓 MVVM
,即 Model-View-ViewModel 。
View 即 视图 ,也就是 DOM
。
Model 即 模型 ,可以理解为 Vue
中组件里面的 data
。
那么这两者之间,就通过 ViewModel 来做关联。而 ViewModel
可以做的事情有很多,比如说像监听事件,监听指令等。当 Model
层的数据发生修改时,就可以通过 ViewModel
,来把数据渲染到 View
视图层上。反之,当 View
层触发 DOM
事件时,就可以通过 ViewModel
,从而使得 Model
层实现数据的修改。
这就是 Vue
中的数据驱动视图,通过修改 Model
层的数据,来驱动到 View
的视图中来。
vue
的响应式,即组件 data
的数据一旦变化,就会立刻触发视图的更新。实现数据驱动视图的第一步,需要了解实现响应式的一个核心 API
,即 Object.defineProperty
。Object.defineProperty
,我们可以实现对数据进行 get
和 set
操作,即获取数据和修改数据的操作,从而达到对数据进行响应式的监听。要想让 Object.defineProperty()
这个 API
拥有监听数组的能力,我们可以这么做。具体代码如下:
// 触发更新视图
function updateView() {
console.log('视图更新')
}
// 重新定义数组原型
const oldArrayProperty = Array.prototype
// 创建新对象,原型指向 oldArrayProperty ,再扩展新的方法不会影响原型
const arrProto = Object.create(oldArrayProperty);
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {
arrProto[methodName] = function () {
updateView() // 触发视图更新
oldArrayProperty[methodName].call(this, ...arguments)
// Array.prototype.push.call(this, ...arguments)
}
})
// 重新定义属性,监听起来
function defineReactive(target, key, value) {
// 深度监听
observer(value)
// 核心 API
Object.defineProperty(target, key, {
get() {
return value
},
set(newValue) {
if (newValue !== value) {
// 深度监听
observer(newValue)
// 设置新值
// 注意,value 一直在闭包中,此处设置完之后,再 get 时也是会获取最新的值
value = newValue
// 触发更新视图
updateView()
}
}
})
}
// 监听对象属性
function observer(target) {
if (typeof target !== 'object' || target === null) {
// 不是对象或数组
return target
}
// 污染全局的 Array 原型(如果直接定义在这里面,会直接污染全局)
// Array.prototype.push = function () {
// updateView()
// ...
// }
if (Array.isArray(target)) {
target.__proto__ = arrProto
}
// 重新定义各个属性(for in 也可以遍历数组)
for (let key in target) {
defineReactive(target, key, target[key])
}
}
// 准备数据
const data = {
name: 'monday',
age: 20,
info: {
address: '深圳' // 需要深度监听
},
nums: ['打篮球', '出来玩', '打乒乓球']
}
// 监听数据
observer(data)
// 测试
data.info.address = '上海' // 深度监听
data.nums.push('神游') // 监听数组
复制代码
此时浏览器的打印效果如下:
我们可以看到,两个数据对应的视图都更新了。通过对数组原型的重新定义,我们就让 Object.defineProperty()
实现了监听数组的能力。
Vue
组件都会生成一个 render
函数。render
函数会生成一个 vnode
。render
函数的时候会触发 data
里面的 getter
,触发后则会生成依赖。data
触发到哪个变量,就会将哪一个变量观察起来。setter
进行数据修改;如果不是,则直接进行监听操作;re-render
重新渲染操作,并且进行 patch(vnode, newVnode)
。根据下方的 html
代码,用 v-node
模拟出该 html
代码的 DOM
结构。
html代码:
<div id="div1" class="container">
<p>
vdom
</p>
<ul style="font-size:20px;">
<li>a</li>
</ul>
</div>
复制代码
用JS模拟出以上代码的DOM结构:
{
tag: 'div',
props:{
className: 'container',
id: 'div1'
},
children: [
{
tag: 'p',
chindren: 'vdom'
},
{
tag: 'ul',
props:{ style: 'font-size: 20px' },
children: [
{
tag: 'li',
children: 'a'
}
// ....
]
}
]
}
vdom
节点,那这个优化过程其实我们所说的 diff
算法。diff
算法的时间复杂度为 O(n)
。patchVnode
,判断如何对该节点的子节点进行处理,先判断一方有子节点一方没有子节点的情况(如果新的 children
没有子节点,则将旧的子节点移除);updateChildren
,判断如何对这些新老节点的子节点进行操作( diff
核心)。注意: 在 diff
中,只对同层的子节点进行比较,放弃跨级的节点比较,使得时间复杂从 O(n^3)
降低值 O(n)
,也就是说,只有当新旧 children
都为多个子节点时才需要用核心的 diff
算法进行同层级比较。
vue
在进行模板编译之后,会先转化成一个 render
函数,之后继续执行 render
函数,执行完成之后返回一个 vnode
;vnode
之后,基于 vnode
的基础上,再执行 patch
和 diff
。vue
是组件级更新,一旦当前组件里的数据变了,那么它就会去更新这个组件。nextTick
, $nextTick
可以在 DOM
更新完之后,再触发回调。SPA,即单页面应用(Single Page Application)。所谓单页 Web
应用,就是只有一张 Web
页面的应用。单页应用程序 (SPA) 是加载单个 HTML
页面并在用户与应用程序交互时动态更新该页面的 Web
应用程序。浏览器一开始会加载必需的 HTML
、 CSS
和 JavaScript
,所有的操作都在这张页面上完成,都由 JavaScript
来控制。
现如今,为了配合单页面 Web
应用快速发展的节奏,各类前端组件化技术栈层出不穷。近几年来,通过不断的版本迭代, vue
和 react
两大技术栈脱颖而出,成为当下最受欢迎的两大技术栈。
hash
可以改变 url
,但是不会触发页面重新加载(hash的改变是记录在 window.history
中),即不会刷新页面。也就是说,所有页面的跳转都是在客户端进行操作。因此,这并不算是一次 http
请求,所以这种模式不利于 SEO
优化。hash
只能修改 #
后面的部分,所以只能跳转到与当前 url
同文档的 url
。hash
通过 window.onhashchange
的方式,来监听 hash
的改变,借此实现无刷新跳转的功能。hash
永远不会提交到 server
端(可以理解为只在前端自生自灭)。url
可以是与当前 url
同源的任意 url
,也可以是与当前 url
一样的地址,但是这样会导致的一个问题是,会把重复的这一次操作记录到栈当中。history.state
,添加任意类型的数据到记录中。title
属性,以便后续使用。pushState
、 replaceState
来实现无刷新跳转的功能。history
模式时,在对当前的页面进行刷新时,此时浏览器会重新发起请求。如果 nginx
没有匹配得到当前的 url
,就会出现 404
的页面。hash
模式来说, 它虽然看着是改变了 url
,但不会被包括在 http
请求中。所以,它算是被用来指导浏览器的动作,并不影响服务器端。因此,改变 hash
并没有真正地改变 url
,所以页面路径还是之前的路径, nginx
也就不会拦截。history
模式时,需要通过服务端来允许地址可访问,如果没有设置,就很容易导致出现 404
的局面。to B
的系统推荐用 hash
,相对简单且容易使用,且因为 hash
对 url
规范不敏感;to C
的系统,可以考虑选择 H5 history
,但是需要服务端支持;关于 vue3
模块,我将把基础知识和原理的内容结合在一起进行整理。详细见下图👇
关于以上内容,已整理成博文,戳下方链接进入学习👇
原文1: 一文了解vue3基础新特性
链接1: https://juejin.cn/post/6976400439793172487
原文2: 敲黑板!vue3重点!一文了解Composition API新特性:ref、toRef、toRefs
链接2: https://juejin.cn/post/6976679225239535629
原文3: 一文get一波 vue3.x 进阶新特性
链接3: https://juejin.cn/post/6976040670939054093
原文4: vue2的响应式原理学“废”了吗?继续观摩vue3响应式原理Proxy
链接4: https://juejin.cn/post/6979368550225936392
基于以上知识点,我们将其细分为面试中的常考题。详细见下图👇
接下来对这些题进行一一解答。
vue3
比 vue2
来说,性能上更好,代码体积更小,并且有更好的ts支持。vue3
有更好的代码组织能力,有更好的逻辑抽离能力,并且还有更多各式各样的新功能。Composition API
和 Options API
。以下给出 Vue2
与 Vue3
生命周期的对比。
Vue2生命周期(Options API) | Vue3生命周期(Composition API) | 含义 |
---|---|---|
beforeCreate | setup | 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用 |
created | setup | 页面还没有渲染,但是vue的实例已经初始化结束。 |
beforeMount | onBeforeMount | 在挂载开始之前被调用:相关的 render 函数首次被调用。 |
mounted | onMounted | 页面已经渲染完毕。 |
beforeUpdate | onBeforeUpdate | 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。 |
updated | onUpdated | 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。 |
beforeDestory | onBeforeUnmount | 实例销毁之前调用。在这一步,实例仍然完全可用。 |
destroy | onUnmounted | Vue 实例销毁后调用。 |
对于 Composition API
和 Options API
的使用,主要有以下几点建议:
Options API
;Composition API
,相较于 Options API
来说, Composition API
对大型项目更好一些,逻辑的抽离,代码的复用,使得大型项目得以更好的维护。ref
是可以生成 值类型
(即基本数据类型) 的响应式数据;ref
可以用于模板和reactive;ref
通过 .value
来修改值(一定要记得加上 .value
);ref
不仅可以用于响应式,还可以用于模板的 DOM
元素。toRef
可以响应对象 Object
,其针对的是某一个响应式对象( reactive
封装)的属性 prop
。
toRef
和对象 Object
两者保持引用关系,即一个改完另外一个也跟着改。
toRef
如果用于普通对象(非响应式对象),产出的结果不具备响应式。如下代码所示:
//普通对象
const state = {
age: 20,
name: 'monday'
}
//响应式对象
const state = reactive({
age: 20,
name: 'monday'
})
toRef
不一样的是, toRefs
是针对整个对象的所有属性,目标在于将响应式对象( reactive
封装)转换为普通对象。prop
都对应一个 ref
。toRefs
和对象 Object
两者保持引用关系,即一个改完另外一个也跟着改。.sync
composition API
通过把代码的逻辑抽离出来进行封装,并把封装的内容直接引用到生命周期里面,已达到代码的逻辑复用效果。reactive
注册响应式对象,对函数返回值进行操作。Proxy
劫持数据的 get
, set
, deleteProperty
, has
, own
。WeakMap
, Map
, Set
来实现依赖收集。ES6
新增特性,旧版本浏览器兼容性差。data
属性变化;watch
需要明确监听哪个属性;watchEffect
会根据其中的属性,自动监听其变化。在 vue2
中, Options API
可以使用 this
来获取组件的实例,但是到现在的 vue3
,已经被摒弃掉了。在 setup
和其他 Composition API
中没有 this
,但是它提供了一个 getCurrentInstance
来获取当前的实例。
vite
是一个前端的打包工具,是 vue
作者发起的一个项目;vite
借助 vue
的影响力,发展较快,和 webpack
有着一定的竞争关系;vite
使得程序在开发环境下无需打包,且启动非常快速。setup
只会被调用一次,而后者函数会被多次调用。useMemo
和 useCallback
(即缓存数据和缓存函数),因为 setup
只调用一次。hooks
的顺序一致。reactive+ref
比后者的 useState
,要难理解。从 vue2.x
的基础知识,再到 vue2.x
的原理知识,最后到 vue3.x
的新特性和原理知识学习,全文贯穿着 vue
的知识要点及相关知识点所涉及到的一些面试题。
最后,关于这部分内容已整理成 PDF
,获取方式放在彩蛋里面,有需要的小伙伴自取o!
vue2.x
和 vue3.x
的原理学习,累计博文输出 11
篇,以下是相关专栏文章~
面试专栏 pdf
版本:
微信搜索 星期一研究室
并关注,回复关键词 vue面试pdf
获取相关资料~
回复 面试大全pdf
可获取全系列资料!
更新地址:
以上是脚本宝典为你收集整理的「offer来了」从基础到进阶原理,从vue2到vue3,48个知识点保姆级带你巩固vuejs知识体系全部内容,希望文章能够帮你解决「offer来了」从基础到进阶原理,从vue2到vue3,48个知识点保姆级带你巩固vuejs知识体系所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。