Vue2
1. v-show 和 v-if的区别
- v-show 通过CSS display控制显示和隐藏
- v-if组件真正的渲染和销毁,而不是显示和隐藏
- 频繁切换显示状态用v-show,否则用v-if
2. 为何v-for中要用key
- 必须用key,且不能是index和random
- diff算法中通过tag和key来判断,是否是sameNode
- 减少渲染次数,提升渲染性能
3. 描述Vue组件生命周期(有父子组件的情况)
-
单个组件
- 挂载阶段
- 更新阶段
- 销毁阶段
-
父子组件
- 挂载阶段
-
- 父 beforeCreate
-
- 父 created
-
- 父 beforeMount
-
- 子 beforeCreate
-
- 子 created
-
- 子 beforeMount
-
- 子 mounted
-
- 父 mounted
-
- 更新阶段
-
- 父 beforeUpdate
-
- 子 beforeUpdate
-
- 子 updated
-
- 父 updated
-
- 销毁阶段
-
- 父 beforeDestroy
-
- 子 beforeDestroy
-
- 子 destroyed
-
- 父 destroyed
-
- 挂载阶段
4. Vue组件如何通讯
- props 和 this.$emit 父子组件(父传子->属性直接传值,子传父-> 自定义事件触发)
event.$onevent.$emitevent.$off兄弟组件(event:Vue实例;beforeDestroy生命周期上进行销毁,否则可能造成内存泄漏)- vuex
5. 描述组件渲染和更新的过程
6. 双向数据绑定v-model的实现原理
- input元素的value = this.name
- 绑定input事件 this.name = $event.target.value
- data 更新触发 re-render
7. 自定义v-model
8. $nextTick
- Vue是异步渲染
- data改变之后,DOM不会立刻渲染
- $nextTick会在DOM渲染之后被触发,以获取最新DOM节点
9. slot
-
父组件往子组件插入一段内容
-
作用域插槽
- 子组件
<slot :xxx="yyy"></slot>向父组件传递一段内容<template v-slot="xxx"></template>
- 子组件
-
具名插槽
10. 动态组件
<component :is="component-name"></component>- 需要根据数据,动态渲染的场景。即组件类型不确定
11. 异步组件
- import()函数
- 按需加载,异步加载大组件
12. keep-alive
- 缓存组件
- 频繁切换,不需要重复渲染
13. mixin
- 多个组件有相同的逻辑,抽离出来
- mixin并不是完美的解决方案,会有一些问题
- 变量来源不明确,不利于阅读
- 多mixin 可能会造成命名冲突
- mixin和组件可能会出现多对多的关系,复杂度较高
- Vue3提出的Composition API旨在解决这些问题
14. vuex
- state
- action
- mutation
- getters
15. vue-router
- 路由模式(hash、H5 history)
- hash模式(默认) 如abc.com/#/user/10
- H5 history模式 如abc.com/user/10
- history模式需要server端支持,因此无特殊需求可选择前者
- 路由配置(动态路由、懒加载)
vue原理
1. 组件化基础
-
传统组件,只是静态渲染,更新还要依赖于操作DOM
-
数据驱动视图 - Vue MVVM
2. Vue响应式
-
组件data的数据一旦变化,立刻触发视图的更新
-
核心API - Obejct.defineProperty
- 监听对象,监听数组
- 复杂对象,深度监听
-
Object.definePropery的一些缺点(Vue3 启用了 Proxy)
- 深度监听,需要递归到底,一次性计算量大
- 无法监听新增属性/删除属性(Vue.set Vue.delete)
- 无法原生监听数组,需要特殊处理
-
响应式:监听data属性 getter setter(包括数组)
3. 虚拟DOM(vdom) 和 diff算法
- vdom是实现Vue的重要基石
- diff算法是vdom中最核心、最关键的部分
- DOM操作非常耗费性能
- 以前用jQuery,可以自定控制DOM操作的时机,手动调整
- Vue是数据驱动视图,如何有效控制DOM操作?
- 解决方案 - vdom
- 有了一定复杂度,想减少计算次数比较难
- 能不能把计算,更多的转移为JS计算?因为JS执行速度很快(比起操作DOM)
- vdom - 用JS模拟DOM结构,计算出最小的变更,操作DOM
- 用JS模拟DOM结构(vnode)
- 新旧vnode对比,得出最小的更新范围,最后更新DOM
- 数据驱动视图的模式下,有效控制DOM操作
- vdom:patch(elem, vnode) 和 patch(vnode, newVnode)
- 解决方案 - vdom
- diff算法
- 日常使用vue中的体现(如key)
3. 模板编辑
- 模板到render函数,再到vnode
4. 渲染和更新
5. 异步渲染
6. computed有何特点
- 缓存,data不变不会重新计算
- 提高性能
7. 为何组件data必须是一个函数?
- 每一个vue文件实例化后,函数内形成一个闭包,各个vue文件之间的变量不会相互影响
8. ajax请求放在哪个生命周期?
- mounted
- JS是单线程的,ajax异步获取数据
- 放在mounted之前没有用,只会让逻辑更加混乱
9. 如何将组件所有的props传递给子组件
- $props
<User v-bind='$props' />
10. 多个组件有相同的逻辑,如何抽离?
- mixin
- mixin的一些缺点
11. 何时使用异步组件?
- 加载大组件
- 路由异步加载
- 优化性能
12. 何时使用keep-alive?
- 缓存组件,不需要重复渲染
- 如多个静态tab页的切换
- 优化性能
- 有自己独立的生命周期钩子 activited(组件被激活时调用)、deactivited(组件被销毁时调用);同时,beforeDestroy和destroyed不会触发了,因为组件不会真正销毁
- 当组件被换掉时,会被缓存到内存中,触发deactivate钩子;当组件被切回来时,再去缓存里找这个组件,触发特定钩子
13. 何时需要使用beforeDestroy?
- 解除自定义事件 event.$off
- 清除定时器
- 解绑自定义的DOM事件,如window scroll等,否则可能会造成内存泄漏
14. 什么是作用域插槽?
15. vuex中action和mutation有何区别?
- action中处理异步,mutation不可以
- mutation中做单个操作
- action可以整合多个mutation
16. Vue-router常用的路由模式
- hash 默认
- H5 history(需要服务端支持)
17. 如何配置vue-router 异步加载?
18. 请用vnode描述一个DOM结构
19. 监听data变化的核心API是什么?
- Object.defineProperty
- 深度监听、监听数组
- 有何缺点?
20. Vue如何监听数组变化?
- Object.defineProperty 不能监听数组变化
- 重新定义,重写push pop等方法,实现监听
- vue3 Proxy可以原生支持监听数组的变化
21. 请描述响应式原理
- 监听data变化
- 组件渲染和更新的流程
22. 简述diff算法过程
23. Vue为何是异步渲染,$nextTick有何用?
- 异步渲染(以及合并data修改),以提高渲染性能
- $nextTick在DOM更新完之后,触发回调
24. Vue常见性能优化方式?
- 合理使用v-show和v-if
- 合理使用computed
- v-for时加key,以及避免和v-if同时使用(v-for优先级大于v-if,每次遍历时,做v-if,消耗性能)
- 自定义事件(eventBus)、自定义DOM事件及时销毁(会造成内存泄漏,页面越来越卡)
- 合理使用异步组件
- 合理使用keep-alive
- data层级不要太深(数据设计尽量扁平化)
- 前端通用的性能优化,如图片懒加载、使用CDN等
- webpack层面的优化
- 使用SSR
Vue3
1. Vue3比Vue2有什么优势?
- 性能更好
- 体积更小
- 更好的ts支持
- 更好的代码组织
- 更好的逻辑抽离
- 更多新功能
2. Vue3的生命周期
-
Options API生命周期
- beforeDestroy 改为 beforeUnmount
- destroyed 改为 unMounted
- 其他沿用Vue2的生命周期
-
Composition API 声明周期
- vue2生命周期前加on
- beforeCreate created整合到setup中
3.Composition API 对比 Options API
- Compositon API 带来了什么
- 更好的代码组织
- 更好的逻辑复用
- 更好的类型推导(没有this了)
- 如何选择?
- 不建议共用,会引起混乱
- 小型项目、业务逻辑简单,用Options API
- 中大型项目、业务逻辑复杂,用Composition API
4. 如何理解ref toRef toRefs?
- ref reactive使用原则
- 若需要一个基本类型的响应式数据,必须使用ref
- 若需要一个响应式对象,层级不深,ref、reactive都可以
- 若需要一个响应式对象,且层级较深,推荐使用reactive
- reactive
- 一般用来做对象的响应式
- hook函数返回响应式对象式,可以使用toRefs进行包裹,如toRefs(state)
- ref
-
一般用来做基本类型的响应式
-
生成值类型的响应式数据
-
可用于模板和reactive
-
通过.value修改值
-
为何需要ref?
- 直接返回值类型,会丢失响应式
- 在setup、computed、hook函数,都有可能返回值类型
- Vue如果不定义ref,用户将自造ref,反而混乱
-
为何需要.value?
- ref是一个对象(不丢失响应式),value存储值
- 通过.value属性的get和set实现响应式
- computed 返回一个类似于ref的对象,也需要.value
- 用于模板、reactive时,不需要.value,其他情况都需要
-
- toRefs
- 通过toRefs将reactive对象中的n个属性批量取出,且依然保持响应式的能力
- 用于对reactive的解构
- 为何需要toRef和toRefs?
- 初衷:不丢失响应式的情况下,把对象数据 解构
- 前提:针对的是响应式对象(reactive封装的)非普通对象
- 注意: 不创造响应式,而是延续响应式
5. Vue3升级了哪些重要功能?
6. Composition API 事项逻辑复用(hook)
- 抽离逻辑代码到一个函数
- 函数命名约定为useXxx格式
- 在setup函数中引用useXxx函数
- 组件中使用: const {x, y} = useMousePosition()
7. Vue3如何实现响应式?
- 回顾 vue2 Object.defineProperty
- vue3 Proxy 实现响应式
-
基本使用
-
Reflect
- 和Proxy能一一对应
- 标准化、规范化、函数式
- 替代掉Object上的工具函数
-
实现响应式
-
优点(Proxy能规避Object.defineProperty的问题)
- 深度监听,性能更好(类似按需递归,需要哪个数据时,递归哪一个)
- 可监听 新增/删除 属性
- 可监听 数组变化
-
缺点
- Proxy无法兼容所有浏览器,无法polyfill
-
8. watch和watchEffect的区别
- 两者都可以监听data属性变化
- watch需要明确监听哪个属性
- watchEffect会根据其中的属性,自动监听其变化。初始化时,一定会执行一次(收集要监听的数据)
9. setup中如何获取组件实例?
10. Vue3 为什么比 Vue2 快?
- Proxy响应式
- PatchFlag
- 编译模版时,动态节点做标记
- 标记,分为不同的类型,如TEXT PROPS CLASS
- diff算法时,可以区分静态节点,以及不同类型的动态节点
- hoistStatic
-
cacheHandler
- 缓存事件
-
SSR优化
- 静态节点直接输出,绕过了vdom
- 动态节点,还是需要动态渲染
-
tree shaking
- 按需引入
- 编译时,根据不同的情况,引入不同的API
11. Vite为何启动快?
- 开发环境使用ES6 Module,无需打包 —— 非常快
- 生产环境使用rollup,并不会快很多
12. Composition API 和 React Hooks 有什么区别?
- 前者setup只会被调用1次,而后者函数会多次调用
- 前者无需useMemo useCallback,因为setup只调用1次
- 前者无需考虑调用顺序,而后者需要保证hooks的顺序一致
- 前者 reactive + ref比后者 useState,要难理解
13. Vue3 script setup语法糖
-
基本使用
- 顶级变量、自定义组件,可以直接用于模板
- 可正常使用ref reactive computed 等
-
属性和事件
- 定义属性defineProps
- 定义事件defineEmits
-
暴露数据给父组件
- defineExpose
14. 前端为什么要进行打包和构建?
- 体积更小(Tree-Shaking、压缩、合并),加载更快
- 编译高级语言或语法(TS、ES6+、模块化、scss)
- 兼容性和错误检查(Polyfill、postcss、eslint)
- 统一、高效的开发环境
- 统一的构建流程和产出标准
- 集成公司构建规范(提测、上线等)
15. webpack优化构建速度
16. vue3和vue2有什么区别?
-
用组合式api替换选项式api,方便逻辑更加的聚合
-
一些细节使用点改变
- 组合式api,没有this
- 生命周期没有create,setup等同于create,卸载改成unmount
- vue3中v-if优先级高于v-for
- 根实例的创建从new app 变成了createApp方法
- 一些全局注册,比如mixin、注册全局组件、use改成了用app实例调用,而不是vue类调用
- 新增了传送门teleport组件
- template模板可以不包在一个根div里
-
原理方面
- 响应式原理改成了用proxy,解决了数组无法通过下标修改,无法监听到对象的属性的新增和删除的问题。也提升了响应式的效率。
- 可以额外叙述vue3并不是完全抛弃了defineProperty,通过reactive定义的响应式数据使用proxy包装出来,而ref还是用defineProperty去给一个空对象,定义了一个value属性来做的响应式
- 组合式api的写法下,源码改成了函数式编程,方便按需引入,因为tree-shaking功能必须配合按需引入写法。所以vue3更好地配合tree-shaking能让打包体积更小
- 性能优化,增加了静态节点标记。会标记静态节点,不对静态节点进行比对。从而增加效率
-
进阶操作方面
- vue3不推荐使用mixin进行复用逻辑提取,而是推荐使用hook
- v-model应用于组件时,监听的事件和传递的值改变
- vue2 value 监听 change/input事件
- vue3 modelValue 监听update:modelValue
- ts更好地配合
17. axios封装
- 基本封装部分
- 基本全局配置 如baseUrl,超时时间等
- Token,秘钥等 出于权限和安全考虑的秘钥设置到请求头
- 响应的统一基本处理 主要针对于错误的情况进行全局统一处理
- 封装请求方法 把对接口的请求封装为一个方法
前端组件和状态设计
1. 考察重点
2. Vue实现购物车
- data 数据结构设计
- 用数据描述所有的内容
- 数据要结构化,易于程序操作(遍历、查找)
- 数据要可扩展,以便增加新的功能
- 组件设计和组件通讯
- 从功能上拆分层次
- 尽量让组件原子化
- 容器组件(只管理数据)& UI组件(只显示视图)