关于Vue
关于Vue
1 什么是MVVM
MVVM的核心是数据驱动
即ViewModel,ViewModel是View和Model的关系映射
。MVVM本质就是基于操作数据
来操作视图
进而操作DOM
,借助于MVVM无需直接操作DOM,开发者只需编写ViewModel中有业务,使得View完全实现自动化
。
2 什么是SPA单页面,以及优缺点
2.1 SPA
SPA( single-page application )即一个web项目就只有一个页面(即一个HTML文件,HTML 内容的变换是利用路由机制实现的。
仅在 Web 页面初始化
时加载
相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转
;取而代之的是利用路由
机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载
。
2.2 SPA的优点
- 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
- 基于上面一点,SPA 相对对服务器压力小;
- 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;
2.3 SPA的缺点
- 初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;
- 前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
- SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。
- seo是一种网站优化技术,也被叫做搜索引擎优化,可以利用搜索规则提高网站上有关搜索的自然排名,主要表现为微博热搜控榜等。
3 Vue生命周期
3.1 基本概念
3.1.1 什么是生命周期
Vue 实例从创建到销毁的过程,就是生命周期。
3.1.2 生命周期的8个钩子函数 ⭐️
**注意:**浏览器有8个钩子,但是node中做服务端渲染的时候只有beforeCreate和created
- beforeCreate是new Vue()之后触发的第一个钩子,在当前阶段data、methods、computed以及watch上的数据和方法
都不能
被访 - created在实例创建完成后发生,当前阶段已经完成了
数据观测
,也就是可以使用数据,更改数据,在这里更改数据不会触发updated函数
。可以做一些初始数据的获取,在当前阶段无法与Dom进行交互
,如果非要想,可以通过vm.$nextTick
来访问Dom。 - beforeMount发生在
挂载之前
,在这之前template模板已导入渲染函数编译。而当前阶段虚拟Dom
已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触
发updated。- 挂载Mount(没有找到准确定义):React.js 将组件渲染,并且构造 DOM 元素然后塞入页面的过程;挂载是渲染过程的一步,挂载主要是建立虚拟DOM与HTML的联系
- mounted在
挂载完成后
发生,在当前阶段,真实的Dom挂载完毕
,数据完成双向绑定,可以访问到Dom节点
,使用$refs属性对Dom进行操作。 - beforeUpdate发生在
更新之前
,也就是响应式数据发生更新,虚拟dom重新渲染之前
被触发,你可以在当前阶段进行更改数据,不会造成重渲染。 - updated发生在
更新完成之后
,当前阶段组件Dom已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环
的更新。 - beforeDestroy发生在
实例销毁之前
,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器,销毁父组件对子组件的重复监听。beforeDestroy(){Bus.$off(“saveTheme”)} - destroyed发生在
实例销毁之后
,这个时候只剩下了dom空壳
。组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。
速记:Create => Mount => Update => Destroy
3.2 生命周期调用顺序
- 组件的
调用
顺序:先父后子 渲染完成的
顺序:先子后父- 组件的
销毁
操作:先父后子 销毁完成
的顺序:先子后父
加载渲染过程: 父beforeCreate -> 父created -> 父beforeMount
-> 子beforeCreate
-> 子created -> 子beforeMount -> 子mounted -> 父mounted
子组件更新过程: 父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
父组件更新过程: 父 beforeUpdate -> 父 updated
销毁过程: 父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
3.3 生命周期的作用⭐️
生命周期中的多个事件钩子,让控制Vue实例的过程更加清晰。
3.4 第一次页面加载会触发哪几个钩子?
第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子
3.5 每个周期具体适合哪些场景?
beforecreate
: 可以在这加个loading事件,在加载实例时触发created
: 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用mounted
: 挂载元素,获取到DOM节点updated
: 如果对数据统一处理,在这里写上相应函数beforeDestroy
: 可以清除定时器nextTick
: 更新数据后立即操作dom- 在下次 DOM 更新循环结束之后执行延迟回调。在这里里面的代码会等到dom更新以后再执行。
3.6 异步请求适合在哪个生命周期调用?
官方实例的异步请求是在mounted
生命周期中调用的,而实际上也可以在created生命周期中调用。
博文作者推荐在 created 钩子函数中调用异步请求,有以下优点:
- 能更快获取到服务端数据,减少页面 loading 时间;
- ssr 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性;
4 SSR 服务端渲染
4.1 什么是SSR
SSR也就是服务端渲染
(后端渲染),也就是将Vue在客户端把标签渲染成HTML
的工作放在服务端完成,然后再把HTML直接返回
给客户端。
⭐️ 服务端渲染只支持 beforCreate
和 created
两个钩子函数。
4.2 SSR的优点
- 更好的 SEO: 因为 SPA 页面的内容是通过 Ajax 获取,而搜索引擎爬取工具并不会等待 Ajax 异步完成后再抓取页面内容,所以在 SPA 中是抓取不到页面通过 Ajax 获取到的内容;而 SSR 是直接由服务端返回已经渲染好的页面(数据已经包含在页面中),所以搜索引擎爬取工具可以抓取渲染好的页面;
- 更快的内容到达时间(首屏加载更快): SPA 会等待所有 Vue 编译后的 js 文件都下载完成后,才开始进行页面的渲染,文件下载等需要一定的时间等,所以首屏渲染需要一定的时间;SSR 直接由服务端渲染好页面直接返回显示,无需等待下载 js 文件及再去渲染等,所以 SSR 有更快的内容到达时间;
4.3 SSR的缺点
- 更多的开发条件限制: 例如服务端渲染只支持
beforCreate
和created
两个钩子函数,这会导致一些外部扩展库需要特殊处理
才能在服务端渲染应用程序中运行;并且与可以部署在任何静态文件服务器上的完全静态单页面应用程序 SPA 不同,服务端渲染应用程序,需要处于 Node.js server 运行环境
; - 更多的服务器负载: 在 Node.js 中渲染完整的应用程序,显然会比仅仅提供静态文件的 server 更加大量占用CPU 资源 (CPU-intensive - CPU 密集),因此如果你预料在高流量环境 ( high traffic ) 下使用,请准备相应的服务器负载,并明智地采用缓存策略。
5 v-show 与 v-if 的区别
5.1 v-if
是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器
和子组件
适当地被销毁和重建;
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
5.2 v-show
不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。
5.3 结论
v-if 适用于在运行时很少改变条件
,不需要频繁切换
条件的场景;
v-show 则适用于需要非常频繁切换条件的场景。
6 你有对Vue项目进行那些优化?
6.1 代码层面的优化
- ✔️ v-if 和 v-show 区分使用场景
- computed 和 watch 区分使用场景
- ✔️ v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
- 长列表性能优化
- ✔️ 事件的销毁
- ✔️ 图片资源懒加载
- 路由懒加载
- 第三方插件的按需引入
- 优化无限列表性能
- 服务端渲染 SSR or 预渲染
6.2 Webpack 层面的优化
- Webpack 对图片进行压缩:先引入npm install image-webpack-loader --save-dev,然后在 webpack.config.js 中配置
- 减少 ES6 转为 ES5 的冗余代码
- 提取公共代码
- 模板预编译
- 提取组件的 CSS
- 优化 SourceMap
- 构建结果输出分析
- Vue 项目的编译优化
6.3 基础的 Web 技术的优化
- 开启 gzip 压缩
- ✔️ 浏览器缓存
- CDN 的使用
- 使用 Chrome Performance 查找性能瓶颈
7 Vue响应式原理⭐️
7.1 Vue2.x响应式数据原理
Vue在初始化数据时,会使用Object.defineProperty
重新定义data中的所有属性,当页面使用对应属性时,首先会进行依赖收集
(收集当前组件的watcher)如果属性发生变化
会通知相关依赖
进行更新操作(发布订阅)
vue2.x中如何监测数组变化
使用了函数劫持
的方式,重写了数组的方法,Vue将data中的数组进行了原型链重写
,指向了自己定义的数组原型方法
。这样当调用数组api时,可以通知依赖更新
。如果数组中包含着引用类型,会对数组中的引用类型再次递归遍历
进行监控。这样就实现了监测数组变化。
7.2 Vue3.x响应式数据原理
Vue3.x改用Proxy
替代Object.defineProperty。因为Proxy可以直接监听对象和数组
的变化,并且有多达13种拦截方法
。并且作为新标准将受到浏览器厂商重点持续的性能优化
。
Proxy只会代理对象的第一层,那么Vue3又是怎样处理这个问题的呢?
判断当前Reflect.get的返回值是否为Object,如果是则再通过reactive方法做代理, 这样就实现了深度观测。
监测数组的时候可能触发多次get/set,那么如何防止触发多次呢?
我们可以判断key是否为当前被代理对象target自身属性,也可以判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger。
简述虚拟DOM + diff算法
vue中Computed、Methods、Watch区别
什么是vuex?
Vue-router共有几种模式?默认是哪种?
history模式 hash模式
默认 hash模式