Vue
2021-03-24 15:04:27 0 举报
AI智能生成
前端面试_Vue
作者其他创作
大纲/内容
Vue 使用
Vue 基本使用
指令、插值
插值、表达式
指令、动态属性
v-html:有 XSS 风险,会覆盖子组件
指令、动态属性
v-html:有 XSS 风险,会覆盖子组件
computed 和 watch
computed
computed 有缓存,data 不变则不会重新计算
v-model(双向数据绑定)如果绑定 computed 里的计算属性,一定要有 get 和 set,否则会报错
watch
watch 如何深度监听? handler, deep: true
watch 监听引用类型,拿不到 oldVal。因为指针相同,此时已经指向了新的 val
class 和 style
使用动态属性
使用驼峰式写法
使用驼峰式写法
条件渲染
`
v-if v-else的用法,可使用变量,也可使用 === 表达式
v-if 和 v-show 的区别?
v-if 只渲染满足条件的,v-show 元素总是会被渲染,只切换元素的 CSS display 属性;
v-if 有更高的切换开销, v-show 有更高的初始渲染开销
v-if 只渲染满足条件的,v-show 元素总是会被渲染,只切换元素的 CSS display 属性;
v-if 有更高的切换开销, v-show 有更高的初始渲染开销
v-if 和 v-show 的使用场景
一次性或更新不频繁使用v-if,切换比较频繁使用v-show
一次性或更新不频繁使用v-if,切换比较频繁使用v-show
循环(列表)渲染
如何遍历对象? v-for
key 的重要性,key 不能乱写(如 random 或 index)
高效更新虚拟 DOM:如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
高效更新虚拟 DOM:如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
v-for 和 v-if 不能一起使用
v-for 的计算优先级高于 v-if,一起使用会先进行 for 循环再分别进行 if 判断
v-for 的计算优先级高于 v-if,一起使用会先进行 for 循环再分别进行 if 判断
事件
修饰符
事件修饰符
按键修饰符
表单
- v-model
- 常见表单项 textarea checkbox radio select
- 修饰符 lazy number trim
Vue 父子组件如何通讯
props, $emit:
props 父组件向子组件 传递一个数据
$emit 子组件向父组件 传递一个事件
props 父组件向子组件 传递一个数据
$emit 子组件向父组件 传递一个事件
Index 父组件
Input 子组件
如何用自定义事件进行 Vue 组件通讯
List 子组件
event 是 vue 的一个实例
event.$emit 触发一个自定义事件
event.$on 绑定一个自定义事件
event.$off 销毁一个自定义事件(及时销毁,否则可能造成内存泄露)
beforeDestory 的使用场景之一:及时解绑自定义事件
Vue 组件生命周期
生命周期图示
挂载阶段:(beforeCreate,created;beforeMount,mounted)
更新阶段:(beforeUpdate,updated)
销毁阶段:(beforeDestroy,destroyed)
更新阶段:(beforeUpdate,updated)
销毁阶段:(beforeDestroy,destroyed)
created 和 mounted 的区别?
created:vue 的实例已经初始化完成,但页面还没有开始渲染
mounted:页面已经渲染完了,大部分操作(ajax 获取信息、绑定事件等)都在 mounted 里面完成
created:vue 的实例已经初始化完成,但页面还没有开始渲染
mounted:页面已经渲染完了,大部分操作(ajax 获取信息、绑定事件等)都在 mounted 里面完成
beforeDestroy 里可能要做什么?
解除绑定,销毁子组件以及事件监听器
例如:自定义事件的绑定要解除;setTimeout 定时任务要销毁;自己绑定的 window 或 document 事件要销毁
总之,该销毁的销毁,不要遗留在内存中
解除绑定,销毁子组件以及事件监听器
例如:自定义事件的绑定要解除;setTimeout 定时任务要销毁;自己绑定的 window 或 document 事件要销毁
总之,该销毁的销毁,不要遗留在内存中
Vue 父子组件生命周期调用顺序
挂载阶段:创建初始化实例是从外到内的,但是渲染是从内到外的
父 beforeCreate
父 created
父 beforeMount
子 beforeCreate
子 created
子 beforeMount
子 mounted
父 mounted
父 beforeCreate
父 created
父 beforeMount
子 beforeCreate
子 created
子 beforeMount
子 mounted
父 mounted
更新阶段:
父 beforeUpdate
子 beforeUpdate
子 updated
父 updated
父 beforeUpdate
子 beforeUpdate
子 updated
父 updated
销毁阶段:
父 beforeDestroy
子 beforeDestroy
子 destroyed
父 destroyed
父 beforeDestroy
子 beforeDestroy
子 destroyed
父 destroyed
面试官会考察哪些 Vue 高级特性
自定义 v-model
$nextTick
refs
slot(插槽)
动态、异步组件(很多面试者不知道)
keep-alive (缓存、提升性能)
mixin(项目复杂、多个组件之间有重复逻辑时使用)
$nextTick
refs
slot(插槽)
动态、异步组件(很多面试者不知道)
keep-alive (缓存、提升性能)
mixin(项目复杂、多个组件之间有重复逻辑时使用)
Vue 如何自己实现 v-model
使用场景
如:颜色选择器
一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用来避免这样的冲突
Vue 组件更新之后如何获取最新 DOM
$nextTick
使用场景
Vue 组件更新后获取最新 DOM
基本使用
Vue 是异步渲染(React 也是)
data 改变之后,DOM 不会立刻渲染
$nextTick 会在 DOM 渲染之后被触发,以获取最新 DOM 节点
data 改变之后,DOM 不会立刻渲染
$nextTick 会在 DOM 渲染之后被触发,以获取最新 DOM 节点
异步渲染,$nextTick 待 DOM 渲染完成再回调
页面渲染时会将 data 的修改进行合并,多次 data 修改只会渲染一次
页面渲染时会将 data 的修改进行合并,多次 data 修改只会渲染一次
$refs 获取dom节点:
给相应的元素加 ref="name", 然后通过 this.$refs.name 获取到该元素
给相应的元素加 ref="name", 然后通过 this.$refs.name 获取到该元素
slot 是什么
基本使用
slot 插槽作用:让父组件可以往子组件中插入一段内容(不一定是字符串,可以是其它的组件,只要是符合 Vue 标准的组件或者标签都可以)
如果父组件不插入内容,就会使用子组件 slot 标签中默认内容
如果父组件不插入内容,就会使用子组件 slot 标签中默认内容
作用域插槽
作用域插槽的作用:让父组件可以访问到子组件的数据(不是很常用,但要知道)
具名插槽
Vue 的动态组件是什么
使用场景
需要根据数据动态渲染组件的场景,比如:新闻落地页,图文视频组件的不同排列组合。
基本使用
<component :is="component-name">
Vue 如何异步加载组件
异步组件
使用场景
按需加载,异步加载大组件(Vue 常见性能优化)
基本使用
import CustomVModel from './CustomVModel'
这种引入方式为同步加载,打包时也是打一个包出来
这种引入方式为同步加载,打包时也是打一个包出来
import() 函数
异步组件引入方式:
直接在 components 中注册
FormDemo: () => import('../BaseUse/FormDemo')
直接在 components 中注册
FormDemo: () => import('../BaseUse/FormDemo')
异步组件只有在用到的时候才会加载,且会把结果缓存起来供未来重渲染
Vue 如何缓存组件
keep-alive
使用场景
缓存组件
频繁切换,不需要重复渲染(如 tab 切换)
Vue 常见性能优化
频繁切换,不需要重复渲染(如 tab 切换)
Vue 常见性能优化
基本使用
如果去掉 keep-alive,切换 tab 时,会先销毁当前组件,再挂载新组件
keep-alive 、v-show、v-if 的区别
v-if:通过销毁 DOM 和重构 DOM 控制显示隐藏 DOM
v-show:通过 CSS 的 display 控制显示隐藏 DOM
keep-alive:是 Vue 框架层级进行的 js 对象的渲染(一个组件就是一个 js 对象)
v-show:通过 CSS 的 display 控制显示隐藏 DOM
keep-alive:是 Vue 框架层级进行的 js 对象的渲染(一个组件就是一个 js 对象)
Vue 组件如何抽离公用逻辑
mixin
使用场景
多个组件有相同的逻辑,抽离出来
基本使用
mixin 可以添加多个,会自动合起来
mixin 的问题
变量来源不明确,不利于阅读(mixin中的变量或者方法在当前组件是查不到的)
多mixin可能会造成命名冲突(如data变量,方法名称,只要是有名称的都有可能冲突,但是像mounted函数不会冲突,这是vue特有的生命周期,里面的代码会合并
mixin和组件可能出现多对多的关系,复杂度较高(一个组件引多个mixin,多个组件引用一个mixin)
Vue 3 提出的 Composition API 旨在解决这些问题
Vue 高级特性知识点小结
相关面试技巧
可以不太深入,但必须知道
熟悉基本用法,了解使用场景
结合项目经验
熟悉基本用法,了解使用场景
结合项目经验
Vuex 知识点串讲
Vuex 使用
面试考点并不多(因为熟悉 Vue 之后,Vuex 没有难度)
但基本概念、基本使用和 API 必须要掌握
可能会考察 state 的数据结构设计
但基本概念、基本使用和 API 必须要掌握
可能会考察 state 的数据结构设计
Vuex 基本概念
state
getters
action
mutation
getters
action
mutation
用于 Vue 组件
dispatch
commit
mapState
mapGetters
mapActions
mapMutations
commit
mapState
mapGetters
mapActions
mapMutations
Vuex 图示
actions 里面才能做异步操作,常用的就是 ajax 请求后端 API
actions 还会整合多个mutations原子操作
actions 还会整合多个mutations原子操作
mutation 里是原子操作,力求原子、最小、同步
vue-router 知识点串讲
vue-router 使用
面试考点并不多(前提是熟悉 Vue)
路由模式(hash、H5 history)
路由配置(动态配置、懒加载)
路由模式(hash、H5 history)
路由配置(动态配置、懒加载)
vue-router 路由模式
hash 模式(默认),如 http://abc.com/#/user/10
H5 history 模式,如 http://abc.com/user/20(需要server端支持,因此无特殊要求可选择 hash 模式)
H5 history 模式的配置
vue-router 路由配置
动态配置
懒加载
Vue 使用考点总结
v-if 和 v-show 的区别
v-if 通过销毁 DOM 和重构 DOM 控制显示隐藏 DOM
v-show 通过 CSS 的 display 控制显示隐藏 DOM
更新不频繁使用 v-if,切换比较频繁使用 v-show
v-show 通过 CSS 的 display 控制显示隐藏 DOM
更新不频繁使用 v-if,切换比较频繁使用 v-show
为何 v-for 中要用 key
key 主要用来做 dom diff 算法用的
key 需要使用与业务相关的唯一 id,不要使用 index
key 需要使用与业务相关的唯一 id,不要使用 index
描述 Vue 组件的生命周期(有父子组件的情况)
Vue 组件如何通讯
1.父子组件,使用属性和触发事件
2.组件之间无关或者层级较深时,使用自定义事件
3.Vuex通讯
2.组件之间无关或者层级较深时,使用自定义事件
3.Vuex通讯
Vue 原理
组件化和 MVVM
组件化
传统组件:只是静态渲染,更新还要依赖于操作 DOM
数据驱动视图:不直接操作 DOM,通过修改数据重新渲染视图(Vue MVVM、React setState)
MVVM:Model-View-ViewModel
View:视图,就是 DOM
Model:模型,就是 Vue 组件里的 data,或 Vuex 里的数据
ViewModel:View 和 Model 通过 ViewModel 来做关联,像监听事件、监听指令
Model:模型,就是 Vue 组件里的 data,或 Vuex 里的数据
ViewModel:View 和 Model 通过 ViewModel 来做关联,像监听事件、监听指令
响应式
组件 data 的数据一旦变化,立刻触发视图的更新
监听 data 变化的核心 API:Object.defineProperty
基本用法
如何深度监听 data 变化
示例
深度监听,递归到底
Vue 如何监听数组变化
示例
重新定义数组原型:先获取数组原型,然后创建一个新的对象指向数组原型(仅是指向,再扩展新的方法不会影响原型)
Object.create 隔离原型链指向
忌:污染全局的 Array 原型
Object.defineProperty 缺点
- 深度监听,需要递归到底,一次性计算量大
- 无法监听新增属性/删除属性(Vue.set Vue.delete)
- 无法原生监听数组,需要特殊处理
Vue3.0 启用 Proxy,但 Proxy 兼容性不太好,且无法用 polyfill
vdom 和 diff
虚拟 DOM (Virtual DOM)
vdom 是实现 Vue 和 React 的基石
背景
- DOM 操作非常耗费性能
- 以前用 jQuery,可以自行控制 DOM 操作的时机,手动调整
- Vue 和 React 是数据驱动视图,如何有效控制 DOM 操作
解决方案
- 有了一定复杂度,想减少计算次数比较难。DOM 的改变很耗时。
- 能不能把计算,更多的转移为 JS 计算? JS 执行速度很快
- vdom 用 JS 模拟 DOM 结构,计算出最小的变更,操作 DOM
用 JS 模拟 DOM 结构
snabbdom
- 简洁强大的 vdom 库,易学易用
- Vue 参考它实现的 vdom 和 diff
- https://github.com/snabbdom/snabbdom
Vue3.0重写了vdom的代码,优化了性能
代码演示
h 函数
vnode 数据结构
patch 函数
vnode 数据结构
patch 函数
h 函数:接受三个参数(选择器,属性,子节点数组),返回一个 vnode 结构
vnode 数据结构
patch(container, vnode) 初次渲染
patch(vnode, newVnode) DOM 更新
patch(vnode, newVnode) DOM 更新
vdom 总结
- 用 JS 模拟 DOM 结构(vnode)
- 新旧 vnode 对比,得出最小的更新范围,最后更新 DOM
- 数据驱动视图的模式下,有效控制 DOM 操作
diff 算法
diff 算法是 vdom 中最核心、最关键的部分
diff 算法概述
- diff 即对比,是一个广泛的概念,如 linux diff 命令、git diff 等
- 两个 js 对象也可以做 diff,如 https://github.com/cujojs/jiff
- 两棵树做 diff,如这里的 vdom diff
树 diff 的时间复杂度 O(n^3)
遍历 tree1;遍历 tree2;排序
1000个节点,要计算1亿次,算法不可用
1000个节点,要计算1亿次,算法不可用
优化时间复杂度到 O(n)
- 只比较同一层级,不跨级比较
- tag 不相同,则直接删掉重建,不再深度比较
- tag 和 key,两者都相同,则认为是相同节点,不再深度比较
深入 diff 算法源码
看源码,不用过于关注细节
找到核心函数,查看其参数、返回值、主要逻辑
找到核心函数,查看其参数、返回值、主要逻辑
生成 vnode
h 函数
参数:选择器,属性,子节点数组
返回值:通过 vnode 函数返回 vnode 结构
返回值:通过 vnode 函数返回 vnode 结构
vnode 函数
返回 vnode 结构
patch 函数
参数:oldVnode,vnode
第一个参数不是 vnode,则创建一个空的 vnode,关联到 这个 DOM 元素
相同的 vnode(key 和 selector 都相等),执行 patchVnode 函数
如果都没有传 key,则 undefined === undefined true
不相同的 vnode,直接删掉重建
patchVnode 函数
vnode 对比
参数:oldVnode,vnode
设置 vnode.elem,赋值成旧的 elem
patch 逻辑:
1. 新 text 无值(children 有值)
(1)新旧都有 children --> 执行 updateChildren 函数
(2)新 children 有,旧 children 无(旧 text 有)--> 清空 text ,并添加 children
(3)新 children 无,旧 children 有 --> 移除 children
(4)旧 text 有 --> 清空 text
2. 新 text 有值(children 无值),且新 text 不等于 旧 text,--> 移除旧 children,并设置新 text
1. 新 text 无值(children 有值)
(1)新旧都有 children --> 执行 updateChildren 函数
(2)新 children 有,旧 children 无(旧 text 有)--> 清空 text ,并添加 children
(3)新 children 无,旧 children 有 --> 移除 children
(4)旧 text 有 --> 清空 text
2. 新 text 有值(children 无值),且新 text 不等于 旧 text,--> 移除旧 children,并设置新 text
updateChildren 函数(key 的重要性)
1. 开始和开始对比,如果命中(sameVnode true),则执行 patchVnode 函数
2. 结束和结束对比,同上;
3. 开始和结束对比,同上;
4. 结束和结束对比,同上;
5. 以上都未命中,拿新节点 key ,能否对应上 oldCh 中的某个节点的 key:
(1)没对应上 --> 插入新节点
(2)对应上了,判断 sel 是否相等(sameVnode 的条件)
1)sel 不相等 --> 插入新节点
2)sel 相等且 key 相等 --> 执行 patchVnode 函数
以上细节不必深究
2. 结束和结束对比,同上;
3. 开始和结束对比,同上;
4. 结束和结束对比,同上;
5. 以上都未命中,拿新节点 key ,能否对应上 oldCh 中的某个节点的 key:
(1)没对应上 --> 插入新节点
(2)对应上了,判断 sel 是否相等(sameVnode 的条件)
1)sel 不相等 --> 插入新节点
2)sel 相等且 key 相等 --> 执行 patchVnode 函数
以上细节不必深究
模板编译
渲染过程
前端路由
Vue 面试真题演练
Vue 使用
Vue 基本使用
指令、插值
插值、表达式
指令、动态属性
v-html:有 XSS 风险,会覆盖子组件
指令、动态属性
v-html:有 XSS 风险,会覆盖子组件
computed 和 watch
computed
computed 有缓存,data 不变则不会重新计算
v-model(双向数据绑定)如果绑定 computed 里的计算属性,一定要有 get 和 set,否则会报错
watch
watch 如何深度监听? handler, deep: true
watch 监听引用类型,拿不到 oldVal。因为指针相同,此时已经指向了新的 val
class 和 style
使用动态属性
使用驼峰式写法
使用驼峰式写法
条件渲染
`
v-if v-else的用法,可使用变量,也可使用 === 表达式
v-if 和 v-show 的区别?
v-if 只渲染满足条件的,v-show 元素总是会被渲染,只切换元素的 CSS display 属性;
v-if 有更高的切换开销, v-show 有更高的初始渲染开销
v-if 只渲染满足条件的,v-show 元素总是会被渲染,只切换元素的 CSS display 属性;
v-if 有更高的切换开销, v-show 有更高的初始渲染开销
v-if 和 v-show 的使用场景
一次性或更新不频繁使用v-if,切换比较频繁使用v-show
一次性或更新不频繁使用v-if,切换比较频繁使用v-show
循环(列表)渲染
如何遍历对象? v-for
key 的重要性,key 不能乱写(如 random 或 index)
高效更新虚拟 DOM:如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
高效更新虚拟 DOM:如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
v-for 和 v-if 不能一起使用
v-for 的计算优先级高于 v-if,一起使用会先进行 for 循环再分别进行 if 判断
v-for 的计算优先级高于 v-if,一起使用会先进行 for 循环再分别进行 if 判断
事件
修饰符
事件修饰符
按键修饰符
表单
- v-model
- 常见表单项 textarea checkbox radio select
- 修饰符 lazy number trim
Vue 父子组件如何通讯
props, $emit:
props 父组件向子组件 传递一个数据
$emit 子组件向父组件 传递一个事件
props 父组件向子组件 传递一个数据
$emit 子组件向父组件 传递一个事件
Index 父组件
Input 子组件
如何用自定义事件进行 Vue 组件通讯
List 子组件
event 是 vue 的一个实例
event.$emit 触发一个自定义事件
event.$on 绑定一个自定义事件
event.$off 销毁一个自定义事件(及时销毁,否则可能造成内存泄露)
beforeDestory 的使用场景之一:及时解绑自定义事件
Vue 组件生命周期
生命周期图示
挂载阶段:(beforeCreate,created;beforeMount,mounted)
更新阶段:(beforeUpdate,updated)
销毁阶段:(beforeDestroy,destroyed)
更新阶段:(beforeUpdate,updated)
销毁阶段:(beforeDestroy,destroyed)
created 和 mounted 的区别?
created:vue 的实例已经初始化完成,但页面还没有开始渲染
mounted:页面已经渲染完了,大部分操作(ajax 获取信息、绑定事件等)都在 mounted 里面完成
created:vue 的实例已经初始化完成,但页面还没有开始渲染
mounted:页面已经渲染完了,大部分操作(ajax 获取信息、绑定事件等)都在 mounted 里面完成
beforeDestroy 里可能要做什么?
解除绑定,销毁子组件以及事件监听器
例如:自定义事件的绑定要解除;setTimeout 定时任务要销毁;自己绑定的 window 或 document 事件要销毁
总之,该销毁的销毁,不要遗留在内存中
解除绑定,销毁子组件以及事件监听器
例如:自定义事件的绑定要解除;setTimeout 定时任务要销毁;自己绑定的 window 或 document 事件要销毁
总之,该销毁的销毁,不要遗留在内存中
Vue 父子组件生命周期调用顺序
挂载阶段:创建初始化实例是从外到内的,但是渲染是从内到外的
父 beforeCreate
父 created
父 beforeMount
子 beforeCreate
子 created
子 beforeMount
子 mounted
父 mounted
父 beforeCreate
父 created
父 beforeMount
子 beforeCreate
子 created
子 beforeMount
子 mounted
父 mounted
更新阶段:
父 beforeUpdate
子 beforeUpdate
子 updated
父 updated
父 beforeUpdate
子 beforeUpdate
子 updated
父 updated
销毁阶段:
父 beforeDestroy
子 beforeDestroy
子 destroyed
父 destroyed
父 beforeDestroy
子 beforeDestroy
子 destroyed
父 destroyed
面试官会考察哪些 Vue 高级特性
自定义 v-model
$nextTick
refs
slot(插槽)
动态、异步组件(很多面试者不知道)
keep-alive (缓存、提升性能)
mixin(项目复杂、多个组件之间有重复逻辑时使用)
$nextTick
refs
slot(插槽)
动态、异步组件(很多面试者不知道)
keep-alive (缓存、提升性能)
mixin(项目复杂、多个组件之间有重复逻辑时使用)
Vue 如何自己实现 v-model
使用场景
如:颜色选择器
一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用来避免这样的冲突
Vue 组件更新之后如何获取最新 DOM
$nextTick
使用场景
Vue 组件更新后获取最新 DOM
基本使用
Vue 是异步渲染(React 也是)
data 改变之后,DOM 不会立刻渲染
$nextTick 会在 DOM 渲染之后被触发,以获取最新 DOM 节点
data 改变之后,DOM 不会立刻渲染
$nextTick 会在 DOM 渲染之后被触发,以获取最新 DOM 节点
异步渲染,$nextTick 待 DOM 渲染完成再回调
页面渲染时会将 data 的修改进行合并,多次 data 修改只会渲染一次
页面渲染时会将 data 的修改进行合并,多次 data 修改只会渲染一次
$refs 获取dom节点:
给相应的元素加 ref="name", 然后通过 this.$refs.name 获取到该元素
给相应的元素加 ref="name", 然后通过 this.$refs.name 获取到该元素
slot 是什么
基本使用
slot 插槽作用:让父组件可以往子组件中插入一段内容(不一定是字符串,可以是其它的组件,只要是符合 Vue 标准的组件或者标签都可以)
如果父组件不插入内容,就会使用子组件 slot 标签中默认内容
如果父组件不插入内容,就会使用子组件 slot 标签中默认内容
作用域插槽
作用域插槽的作用:让父组件可以访问到子组件的数据(不是很常用,但要知道)
具名插槽
Vue 的动态组件是什么
使用场景
需要根据数据动态渲染组件的场景,比如:新闻落地页,图文视频组件的不同排列组合。
基本使用
<component :is="component-name">
Vue 如何异步加载组件
异步组件
使用场景
按需加载,异步加载大组件(Vue 常见性能优化)
基本使用
import CustomVModel from './CustomVModel'
这种引入方式为同步加载,打包时也是打一个包出来
这种引入方式为同步加载,打包时也是打一个包出来
import() 函数
异步组件引入方式:
直接在 components 中注册
FormDemo: () => import('../BaseUse/FormDemo')
直接在 components 中注册
FormDemo: () => import('../BaseUse/FormDemo')
异步组件只有在用到的时候才会加载,且会把结果缓存起来供未来重渲染
Vue 如何缓存组件
keep-alive
使用场景
缓存组件
频繁切换,不需要重复渲染(如 tab 切换)
Vue 常见性能优化
频繁切换,不需要重复渲染(如 tab 切换)
Vue 常见性能优化
基本使用
如果去掉 keep-alive,切换 tab 时,会先销毁当前组件,再挂载新组件
keep-alive 、v-show、v-if 的区别
v-if:通过销毁 DOM 和重构 DOM 控制显示隐藏 DOM
v-show:通过 CSS 的 display 控制显示隐藏 DOM
keep-alive:是 Vue 框架层级进行的 js 对象的渲染(一个组件就是一个 js 对象)
v-show:通过 CSS 的 display 控制显示隐藏 DOM
keep-alive:是 Vue 框架层级进行的 js 对象的渲染(一个组件就是一个 js 对象)
Vue 组件如何抽离公用逻辑
mixin
使用场景
多个组件有相同的逻辑,抽离出来
基本使用
mixin 可以添加多个,会自动合起来
mixin 的问题
变量来源不明确,不利于阅读(mixin中的变量或者方法在当前组件是查不到的)
多mixin可能会造成命名冲突(如data变量,方法名称,只要是有名称的都有可能冲突,但是像mounted函数不会冲突,这是vue特有的生命周期,里面的代码会合并
mixin和组件可能出现多对多的关系,复杂度较高(一个组件引多个mixin,多个组件引用一个mixin)
Vue 3 提出的 Composition API 旨在解决这些问题
Vue 高级特性知识点小结
相关面试技巧
可以不太深入,但必须知道
熟悉基本用法,了解使用场景
结合项目经验
熟悉基本用法,了解使用场景
结合项目经验
Vuex 知识点串讲
Vuex 使用
面试考点并不多(因为熟悉 Vue 之后,Vuex 没有难度)
但基本概念、基本使用和 API 必须要掌握
可能会考察 state 的数据结构设计
但基本概念、基本使用和 API 必须要掌握
可能会考察 state 的数据结构设计
Vuex 基本概念
state
getters
action
mutation
getters
action
mutation
用于 Vue 组件
dispatch
commit
mapState
mapGetters
mapActions
mapMutations
commit
mapState
mapGetters
mapActions
mapMutations
Vuex 图示
actions 里面才能做异步操作,常用的就是 ajax 请求后端 API
actions 还会整合多个mutations原子操作
actions 还会整合多个mutations原子操作
mutation 里是原子操作,力求原子、最小、同步
vue-router 知识点串讲
vue-router 使用
面试考点并不多(前提是熟悉 Vue)
路由模式(hash、H5 history)
路由配置(动态配置、懒加载)
路由模式(hash、H5 history)
路由配置(动态配置、懒加载)
vue-router 路由模式
hash 模式(默认),如 http://abc.com/#/user/10
H5 history 模式,如 http://abc.com/user/20(需要server端支持,因此无特殊要求可选择 hash 模式)
H5 history 模式的配置
vue-router 路由配置
动态配置
懒加载
Vue 使用考点总结
v-if 和 v-show 的区别
v-if 通过销毁 DOM 和重构 DOM 控制显示隐藏 DOM
v-show 通过 CSS 的 display 控制显示隐藏 DOM
更新不频繁使用 v-if,切换比较频繁使用 v-show
v-show 通过 CSS 的 display 控制显示隐藏 DOM
更新不频繁使用 v-if,切换比较频繁使用 v-show
为何 v-for 中要用 key
key 主要用来做 dom diff 算法用的
key 需要使用与业务相关的唯一 id,不要使用 index
key 需要使用与业务相关的唯一 id,不要使用 index
描述 Vue 组件的生命周期(有父子组件的情况)
Vue 组件如何通讯
1.父子组件,使用属性和触发事件
2.组件之间无关或者层级较深时,使用自定义事件
3.Vuex通讯
2.组件之间无关或者层级较深时,使用自定义事件
3.Vuex通讯
Vue 原理
组件化和 MVVM
组件化
传统组件:只是静态渲染,更新还要依赖于操作 DOM
数据驱动视图:不直接操作 DOM,通过修改数据重新渲染视图(Vue MVVM、React setState)
MVVM:Model-View-ViewModel
View:视图,就是 DOM
Model:模型,就是 Vue 组件里的 data,或 Vuex 里的数据
ViewModel:View 和 Model 通过 ViewModel 来做关联,像监听事件、监听指令
Model:模型,就是 Vue 组件里的 data,或 Vuex 里的数据
ViewModel:View 和 Model 通过 ViewModel 来做关联,像监听事件、监听指令
响应式
组件 data 的数据一旦变化,立刻触发视图的更新
监听 data 变化的核心 API:Object.defineProperty
基本用法
如何深度监听 data 变化
示例
深度监听,递归到底
Vue 如何监听数组变化
示例
重新定义数组原型:先获取数组原型,然后创建一个新的对象指向数组原型(仅是指向,再扩展新的方法不会影响原型)
Object.create 隔离原型链指向
忌:污染全局的 Array 原型
Object.defineProperty 缺点
- 深度监听,需要递归到底,一次性计算量大
- 无法监听新增属性/删除属性(Vue.set Vue.delete)
- 无法原生监听数组,需要特殊处理
Vue3.0 启用 Proxy,但 Proxy 兼容性不太好,且无法用 polyfill
vdom 和 diff
虚拟 DOM (Virtual DOM)
vdom 是实现 Vue 和 React 的基石
背景
- DOM 操作非常耗费性能
- 以前用 jQuery,可以自行控制 DOM 操作的时机,手动调整
- Vue 和 React 是数据驱动视图,如何有效控制 DOM 操作
解决方案
- 有了一定复杂度,想减少计算次数比较难。DOM 的改变很耗时。
- 能不能把计算,更多的转移为 JS 计算? JS 执行速度很快
- vdom 用 JS 模拟 DOM 结构,计算出最小的变更,操作 DOM
用 JS 模拟 DOM 结构
snabbdom
- 简洁强大的 vdom 库,易学易用
- Vue 参考它实现的 vdom 和 diff
- https://github.com/snabbdom/snabbdom
Vue3.0重写了vdom的代码,优化了性能
代码演示
h 函数
vnode 数据结构
patch 函数
vnode 数据结构
patch 函数
h 函数:接受三个参数(选择器,属性,子节点数组),返回一个 vnode 结构
vnode 数据结构
patch(container, vnode) 初次渲染
patch(vnode, newVnode) DOM 更新
patch(vnode, newVnode) DOM 更新
vdom 总结
- 用 JS 模拟 DOM 结构(vnode)
- 新旧 vnode 对比,得出最小的更新范围,最后更新 DOM
- 数据驱动视图的模式下,有效控制 DOM 操作
diff 算法
diff 算法是 vdom 中最核心、最关键的部分
diff 算法概述
- diff 即对比,是一个广泛的概念,如 linux diff 命令、git diff 等
- 两个 js 对象也可以做 diff,如 https://github.com/cujojs/jiff
- 两棵树做 diff,如这里的 vdom diff
树 diff 的时间复杂度 O(n^3)
遍历 tree1;遍历 tree2;排序
1000个节点,要计算1亿次,算法不可用
1000个节点,要计算1亿次,算法不可用
优化时间复杂度到 O(n)
- 只比较同一层级,不跨级比较
- tag 不相同,则直接删掉重建,不再深度比较
- tag 和 key,两者都相同,则认为是相同节点,不再深度比较
深入 diff 算法源码
看源码,不用过于关注细节
找到核心函数,查看其参数、返回值、主要逻辑
找到核心函数,查看其参数、返回值、主要逻辑
生成 vnode
h 函数
参数:选择器,属性,子节点数组
返回值:通过 vnode 函数返回 vnode 结构
返回值:通过 vnode 函数返回 vnode 结构
vnode 函数
返回 vnode 结构
patch 函数
参数:oldVnode,vnode
第一个参数不是 vnode,则创建一个空的 vnode,关联到 这个 DOM 元素
相同的 vnode(key 和 selector 都相等),执行 patchVnode 函数
如果都没有传 key,则 undefined === undefined true
不相同的 vnode,直接删掉重建
patchVnode 函数
vnode 对比
参数:oldVnode,vnode
设置 vnode.elem,赋值成旧的 elem
patch 逻辑:
1. 新 text 无值(children 有值)
(1)新旧都有 children --> 执行 updateChildren 函数
(2)新 children 有,旧 children 无(旧 text 有)--> 清空 text ,并添加 children
(3)新 children 无,旧 children 有 --> 移除 children
(4)旧 text 有 --> 清空 text
2. 新 text 有值(children 无值),且新 text 不等于 旧 text,--> 移除旧 children,并设置新 text
1. 新 text 无值(children 有值)
(1)新旧都有 children --> 执行 updateChildren 函数
(2)新 children 有,旧 children 无(旧 text 有)--> 清空 text ,并添加 children
(3)新 children 无,旧 children 有 --> 移除 children
(4)旧 text 有 --> 清空 text
2. 新 text 有值(children 无值),且新 text 不等于 旧 text,--> 移除旧 children,并设置新 text
updateChildren 函数(key 的重要性)
1. 开始和开始对比,如果命中(sameVnode true),则执行 patchVnode 函数
2. 结束和结束对比,同上;
3. 开始和结束对比,同上;
4. 结束和结束对比,同上;
5. 以上都未命中,拿新节点 key ,能否对应上 oldCh 中的某个节点的 key:
(1)没对应上 --> 插入新节点
(2)对应上了,判断 sel 是否相等(sameVnode 的条件)
1)sel 不相等 --> 插入新节点
2)sel 相等且 key 相等 --> 执行 patchVnode 函数
以上细节不必深究
2. 结束和结束对比,同上;
3. 开始和结束对比,同上;
4. 结束和结束对比,同上;
5. 以上都未命中,拿新节点 key ,能否对应上 oldCh 中的某个节点的 key:
(1)没对应上 --> 插入新节点
(2)对应上了,判断 sel 是否相等(sameVnode 的条件)
1)sel 不相等 --> 插入新节点
2)sel 相等且 key 相等 --> 执行 patchVnode 函数
以上细节不必深究
模板编译
渲染过程
前端路由
0 条评论
下一页