v-if和v-for的优先级
先说一下关于这个问题的答案:
- 在vue2中,v-for的优先级高于v-if
- 在vue3中,v-if的优先级高于v-for
有时我们可能会这样
1. 为了过滤列表中的项目
<div v-for="user in users" v-if="user.isActive">xxx</div>
在vue2中,会先执行循环,再进行判断;哪怕最终渲染的只是列表中的一小部分,但每次都要先遍历整个列表,这会比较影响性能
在vue3中,v-if先执行,它执行的时候所使用的变量还不存在,会导致问题
2. 为了避免渲染本应该被隐藏的列表
<div v-for="user in users" v-if="shouldShowUsers">xxx</div>
在vue2中,会先执行循环,再进行判断;哪怕最终渲染的只是列表中的一小部分,但每次都要先遍历整个列表,这会比较影响性能
在vue3中,这种写法虽然不会报错,但是不推荐,建议将v-if移到外层元素上去
v-if和v-show
两者都用于控制元素的显示与隐藏,但是有区别:
v-if
- 条件为真时才会渲染元素,条件为假时从 DOM 中移除,影响 DOM 结构
- 初次渲染时开销较大,适合条件变化不频繁的场景
v-show
- 条件为真时显示元素,条件为假时通过 CSS `display: none` 隐藏元素,不影响 DOM 结构
- 初次渲染较快,适合频繁切换显示的场景
computed
主要用途是基于现有数据生成新数据
特点:
- 当依赖的数据变化时,会自动重新计算
- 计算属性的结果会被缓存,只有在其依赖的数据变化时才会重新计算
- 在模板中,计算属性可以像普通属性一样使用
- 计算属性应尽量保持无副作用,避免在计算中修改其他数据
- 当需要根据数据计算出一个新值时使用,比如格式化数据、组合多个数据等
watch
是一个用于观察 Vue 实例数据变动的选项。它可以让你在特定数据变化时执行异步或开销较大的操作
特点:
- 可以通过设置 `deep: true` 监听对象内部的变化
- 可以设置 `immediate: true`,在初始化时立即调用处理函数
- 无缓存性,页面重新渲染时值不变化也会执行
v-for循环中key的作用
key的作用主要是为了高效的更新虚拟DOM
在用v-for更新已渲染的元素列表的时候,会使用就地复用的策略,也就是列表数据修改的时候,根据key值去判断某个值是否修改,如果修改了就重新渲染,否则就复用之前的元素
给每个dom元素加上key作为唯一标识,可以帮助vue高效的动态渲染页面,渲染页面时会使用diff算法,比较新旧dom,在比较时只比较同一级,不能跨级比较,key发生变化的节点销毁,并且是子节点先销毁
不绑定key会导致所有列表dom重新渲染
key也有强制刷新的作用
data为什么要定义成一个函数,而不是对象
`data` 定义为一个函数而不是对象的主要原因是为了避免共享状态
当 `data` 是一个函数时,每个 Vue 实例都会调用这个函数,返回独立的状态对象,确保不同实例之间的数据不会相互影响
如果 `data` 直接定义为一个对象,所有实例会共享同一个对象,导致数据冲突和意外修改
事件修饰符
- .stop 阻止事件冒泡
- .prevent 阻止事件默认行为
- .capture 在事件捕获阶段执行事件处理函数
- .self 只在当event.target是当前元素自身时触发处理函数
- .once 事件处理函数执行一次后解绑
- .passive 滚动事件的默认行为(即滚动行为)将会立即触发,一般与scroll连用,能够提升移动端的性能
键盘识别
- e.which === 13 表示用户按下了回车键(Enter键)
- e.ctrlKey 用于检查用户是否按下了 Ctrl 键(在 Windows 或 Linux 系统上)
- e.metaKey 用于检查用户是否按下了 Command 键(在 Mac 系统上)
diff算法
把树形结构按照层级分解,只比较同级元素,不同层级的节点只有创建和删除操作
深度优先遍历,记录差异,在实际代码中,会对新旧两棵树进行一个深度遍历,每个节点都会有一个标记,每遍历到一个节点就把该节点和新的树进行对比,如果有差异就记录到一个对象中
平层diff,只有一下4种情况:
- 节点类型变了,这个过程称为replace,直接将旧节点卸载并装载新节点,旧节点包括下面的子节点都将被卸载,如果新节点和旧节点仅仅是类型不同,但下面的所有子节点都一样时,这样做效率不高,但为了避免O(n^3)的事件复杂度,这样是值得的,这也提醒了开发者,应该避免无谓的节点类型的变化,例如运行时将div变成p没有意义
- 节点类型一样,仅仅属性或者属性值变了,这个过程称为props,此时不会触发节点卸载和装载,而是节点更新
- 文本变了,文本是一个text node,直接修改文字内容就行了,这个过程称为text
- 移动/增加/删除 子节点,这个过程称为peorder,当修改new虚拟DOM,会把newDOM和oldDOM通过diff算法比较,得出diff结果数据表(用4种变换情况表示),再把diff结果表通过DOM fragment更新到浏览器DOM中
虚拟DOM
web界面由DOM树来构建,当其中一部分发生变化时,就是对应某个DOM节点发生了变化
虚拟DOM就是为了解决浏览器性能问题而被设计出来的,若一次操作中有10次更新DOM的操作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个js对象中,最终将这个js对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量,所以,用js对象模拟DOM节点的好处是,页面的更新可以先全部反映在js对象(虚拟DOM)上,操作内存中的js对象的速度显然更快,等更新完成后,再将最终的js对象映射成真实的DOM,交由浏览器去绘制
vdom的真正意义是为了实现跨平台,服务端渲染,以及提供一个性能还不错的DOM更新策略,diff算法只是为了虚拟DOM比较替换效率更高
单页面应用
单页面应用(SPA,Single Page Application)是一种Web应用,所有必要的代码(HTML、CSS、JavaScript)在单一页面上加载,用户交互时通过异步请求更新页面内容,而不需要重新加载整个页面。
优点:
- 快速响应:仅更新部分内容,减少页面重载,提高用户体验。
- 流畅的用户体验:类似于桌面应用,减少加载时间和延迟。
- 更好的路由管理:通过 JavaScript 管理应用的状态和路由,灵活性高。
- 资源利用率高:只需加载一次大部分资源,后续操作更轻便。
缺点:
- SEO挑战:搜索引擎爬虫对动态内容的索引能力较弱,可能影响SEO。
- 初始加载时间长:需要加载较多的资源,初次访问可能较慢。
- 浏览器历史管理复杂:需要手动管理浏览器的历史记录和前进后退功能。
- JavaScript依赖性强:如果用户禁用JavaScript,应用可能无法正常工作。
总的来说,SPA适合需要快速交互和流畅体验的应用,但在SEO和初次加载方面需要额外考虑。
页面加载慢,如何分析解决
首先判断是接口慢还是页面慢,如果接口慢,后端优化
如果是前端页面慢,可以从以下几个方面进行分析:
- 看是否是因为图片等资源过大,替换尝试不同格式体积的图片
- 看 是否是某些数据处理的函数比较耗时
- 看 是否循环操作DOM,可以通过js生成DOM后再批量插入
如果页面直接卡死,就需要分析是否内存泄漏,使用chrome的任务管理器,操作页面,观察内存占用的变化,定位到是哪些操作,哪块代码导致内存占用飙升,因为js没有直接释放缓存的语法,只有靠浏览器的垃圾回收机制自动清理,我们需要做的是及时给不需要的变量赋空,定时器等闭包方法中存在内存泄漏
vue生命周期
vue实例从创建到挂载到更新,最后销毁,这整个流程叫做vue的生命周期
生命周期钩子函数
- 初始化构建阶段
beforeCreate vue实例初始化完成之前,完成了vue事件、属性的初始化,但是访问不到vue实例中的data、methods
created vue实例初始化完成,可以访问实例内部的数据和方法 - 挂载阶段
beforeMount 完成了模版的解析,但是数据没有绑定到模版上
mounted vm.$el虚拟dom替换el dom,完成了数据绑定 - 更新阶段
beforeUpdate 数据以及修改,虚拟dom也构建完毕,但是没有渲染到页面上
updated更新过后的虚拟dom节点,成功渲染到页面上 - 销毁阶段 this.$destroy()
beforeDestroy vue实例销毁之前,还可以访问实例,闭包的移除,资源的释放
destroyed vue实例上绑定的事件、监听器、子组件销毁完毕,访问不到vue实例了
vue父子组件生命周期
渲染加载过程
父组件(beforeCreate)=> 父组件(created)=> 父组件(beforeMount)=> 子组件(beforeCreate)=> 子组件(created)=> 子组件(beforeMount)=> 子组件(mounted)=> 父组件(mounted)
销毁过程
父组件(beforeDestory)=> 子组件(beforeDestory)=> 子组件(destoryed)=> 父组件(destoryed)
异步操作放在created还是mounted
异步操作通常放在 `mounted` 钩子中。因为 `mounted` 确保组件已经被挂载到 DOM 中,可以安全地进行操作,比如获取 DOM 元素或进行 API 请求。`created` 钩子在组件实例被创建时调用,但此时 DOM 还未渲染。
第一次加载页面触发的钩子函数
- beforeCreate
- created数据初始化完成,方法也调用,但是DOM未渲染
- beforeMount
- mounted DOM和数据挂载完成
vue2的缺陷
缺陷:如果为对象直接新增属性,如果为数组通过下标操作数组项,页面无法触发更新
原因:vue会在初始化实例时对property执行getter/setter转化,所以property必须在data对象上存在才能让vue将它转换为响应式的;
对策:关于对象可以通过Vue.$set(obj, key, value),组件中通过this.$set(obj, key, value)实现新增,修改属性vue可以相应更新视图;关于数组也可以通过Vue.$set(obj, key, value)
dependencies和devDependencies
dependencies
- --save放在dependencies中
- 安装的是开发环境和生产环境都使用的包,比如vue、element、vant等
devDependencies
- --save-dev放在devDependencies中
- 安装的是开发环境使用的包,比如eslint、vue-cli-serve等;
- 依赖的模块在生产环境下不会被打入包内
MVVM和MVC
MVVM(Model-View-ViewModel)和 MVC(Model-View-Controller)都是软件架构模式,但在结构和数据流方面存在一些异同
相同点:
- 都旨在将应用程序的不同部分(数据、视图)分离,以提高可维护性和可测试性
- 都包含模型(Model)、视图(View)和控制逻辑(Controller/ViewModel)
不同点:
- 数据绑定
MVVM通常支持双向数据绑定,ViewModel与View之间通过数据绑定进行同步,简化了更新操作
MVC通常采用单向数据流,View需要通过Controller来更新模型,更新视图 - 角色定义
MVVM中ViewModel充当视图和模型之间的中介,负责处理用户输入和更新模型,同时也提供视图所需的数据
MVC中:Controller负责接收用户输入,更新模型并通知视图,从而更新用户界面 - 使用场景
MVVM常用于现代前端框架(如 Vue、Angular),适合数据绑定和复杂界面的需求
MVC传统上用于服务器端应用(如 Ruby on Rails、ASP.NET MVC),更适合请求-响应模型
总结:MVVM 更适合需要频繁交互和数据更新的应用,而 MVC 更适合简单的请求-响应型应用
标签:知识点,vue,DOM,必备,渲染,组件,节点,页面 From: https://blog.csdn.net/qq_45937484/article/details/142249314