网站内容优化方案(Vue工厂函数的方式定义你的组件定义,下官网)
优采云 发布时间: 2022-04-09 01:27网站内容优化方案(Vue工厂函数的方式定义你的组件定义,下官网)
随着互联网的发展,越来越多的公司在使用Vue。但是随着项目越来越大,必然会带来一系列的性能问题。笔者也因为这些问题而头疼。学习Vue的性能优化,已经避免了项目初期的性能问题,避免了不必要的返工。
为了以后能够快速找到相关的学习内容,我在此做个记录,方便以后查看。同时,我也想总结一下这些内容,希望能帮助更多的小伙伴一起学习成长。战斗~
这时候很多小伙伴可能会说,现在Vue3.0即将发布,为什么要优化2.0的项目呢?因为公司80%的项目都是Vue2.0项目,迁移成本太高,只能优化调整性能。事不宜迟,让我们开始吧。
利用异步组件
Vue-cli打包的时候会把所有依赖的文件打包成一个大的js文件。用户在浏览网页时需要拉取整个js文件,这会导致页面在初始化时出现。在长白屏的情况下,这个问题确实比较棘手。
想象一下,如果页面上有很*敏*感*词*点,每个功能点对应一个不同的功能弹窗或表单。首先,第一点页面有很*敏*感*词*。我们不知道用户想要使用哪个功能,需要弹出哪个功能。对于弹窗或者表单,在异步组件的情况下,Vue-cli在打包的时候会将异步组件打包成一个单独的文件,js文件的内容只有在用户使用的时候才会加载,这样第一个屏幕的渲染起着重要作用。一些优化。
看看官网对异步组件的描述:
在大型应用程序中,我们可能需要将应用程序拆分为更小的代码块,并且仅在需要时从服务器加载模块。为简单起见,Vue 允许您将组件定义为异步解析组件定义的工厂函数。Vue 仅在组件需要渲染时触发工厂函数,并将结果缓存起来以备将来重新渲染。
// 代码截取自Vue官网
Vue.component('async-webpack-example',
() => import('./my-async-component')
)
为了解决组件加载等待时间过长的问题,Vue 官方提供了异步组件用于异步组件加载:
// 代码截取自Vue官网
const AsyncComponent = () => ({
// 需要加载的组件 (应该是一个 `Promise` 对象)
component: import('./MyComponent.vue'),
// 异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时时间且组件加载也超时了,
// 则使用加载失败时使用的组件。默认值是:`Infinity`
timeout: 3000
})
使用异步组件时需要注意以下几点:
如果只是需要异步加载一些组件,先加载part,再加载part,那么按照vue官网的方式直接使用setTimeOut也不是不行。如果点击加载,一定要写v-if,否则会报错,说测试组件没有注册。v-if 是惰性的,只会在第一个值为 true 时开始初始化。
初始化减少 DOM 渲染
还是上面说的情况。页面的功能点很多,但是弹窗很多。其实在这些弹窗一开始的时候,所有弹窗只考虑一个弹窗,是为了节省页面初始化的渲染,但是在实际开发过程中,虽然出现了一些问题已经解决了,看来发展进程并不那么乐观。弹窗出现大量v-if和v-show,维护难度太大。
我也想过使用组件,但可以想象压力不是一点点。但是这个问题仍然存在,需要解决。在没办法的情况下,最后用两个flag来控制弹窗的显示和隐藏。
Render Dialog
export default {
data:() => ({
isRenderDialog:false,
isShowDialog:false
}),
methods: {
onShowDialog(){
!this.isRenderDialog && (this.isRenderDialog = true);
this.$nextTick(() => {
this.isShowDialog = true;
})
}
}
}
上面代码中,使用了两个标志值来控制Dialog,一个是控制Dialog的渲染,一个是控制Dialog的显示。当用户第一次进入页面时,对话框元素不会被渲染。当用户单击按钮时,将呈现相应的 Dialog。out,当 Dialog 的 DOM 渲染是使用正在使用的 Display Dialog 完成时。
注意:对话框显示在$nextTick中,以保证对话框的*敏*感*词*效果。如果不使用$nextTick,对话框会直接出现。
在组件内部请求数据
在做生意的时候,可能会出现这样的情况。单击按钮时,需要获取数据的详细信息并在弹出窗口或侧滑中进行渲染。这种情况一定很少见。开始做这个的时候,我点击的时候直接获取了被点击元素的详细数据,当数据返回的时候,我把数据放到数据缓存中,然后传给组件。
这不是不可能的,也是可能的。这将面临一个问题。第一点是当弹窗中要渲染的元素过多时,滑动或弹窗的*敏*感*词*效果会很卡顿。有的一动不动,瞬间就消失了。
最后经过反复实验,将数据放入弹窗内部组件请求,保证弹窗或侧滑出现时内置元素较少。当没有请求回数据时,需要隐藏弹出框组件中的所有元素。不是加载,而是在弹窗或侧滑关闭时,需要销毁显示的组件,以保证释放内部数据占用的内存,有利于整体优化。
模板计数更少
由于业务情况的复杂性,难免要在某个地方添加各种渲染条件,比如:v-if="isHide && selectList.length && (isA || isB)",这里只是一个简单的可能在实际开发过程中远比这个复杂的例子。虽然这个表达式看起来是可以维护的,但是长此以往会暴露问题,不利于维护。
在这种情况下,可以适当地使用方法或计算方法将其封装到方法中。其实这样做的好处是我们可以判断同一个表达式。如果其他元素有类似的要求,我们可以直接使用这种方法。
v-for && v-绑定:键
在使用v-for循环的过程中,使用诸如:key="item.id"这样的代码对代码的性能是非常不友好的,因为在更新数据数据的时候,会比较新的状态值和旧的状态值状态值。相比之下,Vue 在使用多种 diff 算法时可以更快地定位虚拟 DOM 的元素。
其实有必要解释一下key在vue中的作用。key属性其实是vue的一个优化。上面说了,就是更准确高效的定位虚拟DOM,相当于使用key。数组中的预算绑定在一起。如果该key对应的数据发生变化,则可以直接更新对应的DOM。
简而言之,可以直接使用 index 作为 key。但是,如果列表很大,最好不要使用索引作为键。例如,如果从数组中删除一个元素,那么这个元素后面的元素的下标都向前移动了一个位置,那么前一个key对应的数据和DOM就会乱七八糟。除非重新匹配密钥,否则很容易出错。如果重新匹配了key,就相当于重新渲染了一遍,违背了使用key优化更新DOM的初衷。但是如果你是一个非常会玩Vue的学生,你可以忽略这个。
对象冻结
如果你对Vue有一定的了解,都知道Vue使用Object.defineProperty来保存数据,最终实现视图响应数据的变化,但是在实际开发过程中,页面的某些部分可能不需要双向binding ,只做简单的渲染。数据绑定后,在不需要做任何更改的情况下,可以使用 Object.freeze 解绑数据。
首先介绍Object.freeze的以下内置函数,用于对接对象。被冻结的对象不会再被修改。无法向该对象添加新属性,无法删除现有属性,也无法修改对象现有属性的可枚举属性。属性、可配置性和可写性。另外,冻结对象后,不能修改对象的原型。
当数据量很大时,这可以显着减少组件的初始化时间。这里要注意的一点是,一旦对象被冻结,就不能再对其进行修改。但是这里有一个需要注意的问题是,废话,废话,废话,废话!敲黑板!敲黑板!
虽然 Object.freeze 可以在一定程度上帮助我们提升一些数据性能,但还是需要谨慎使用。避免导致数据无响应的问题。如果再次使用 Object.freeze 属性赋值给它的对象属性,会抛出错误 cannot be assigned to a read-only property of an object*。
如果数据量很小,就感觉不到使用这种方法来提高性能。只有当数据量很大时,才会感受到数据的明显变化。
预渲染
渲染数据时,后端返回的数据与UI设计图中要求的数据格式不一致。比如列表中需要显示一个时间,但是后端返回的是时间戳,所以前端需要修正这部分。数据被处理。一般来说,有一些方法可以处理这种情况,使用函数,使用过滤器,以及在渲染之前处理数据。
笔者这里建议在渲染前对所有数据进行处理。为什么?数据渲染完成后,会执行里面的函数或过滤器,这会给页面渲染带来很大的额外负担。如果知道Vue3.0,就可以知道Vue3.0中已经去掉了过滤功能。推荐使用computed来达到同样的效果。
猜猜内容:你可能已经发现,过滤器给页面渲染带来的额外负担对提升页面性能并没有太大的作用。
功能性的
没有多少功能组件需要方法。在 Vue 中,为了指示模板应该被编译成功能组件,在模板中添加了功能属性。如果项目中使用的组件不是有状态组件,那么您可以使用功能属性将组件转换为功能组件。
函数式组件(不要与 Vue 的渲染函数混淆)是一个不收录状态和实例的组件。功能组件是没有状态或实例的组件。由于功能组件没有状态,因此不需要对 Vue 的数据响应之类的事情进行初始化操作。功能组件仍然会响应传入和传出 props 等数据更新,但功能组件本身由于不维护自己的状态,因此无法知道其数据是否已更改。在大型项目中使用功能组件后,DOM 渲染有了显着改进。
由于功能组件没有状态,因此像 Vue 的反应式系统这样的东西不需要额外的初始化。当新的 props 被传入时,功能组件仍然会对变化做出反应,但在组件本身内部,由于它不维护自己的状态,它无法知道数据何时发生变化。
在许多情况下,功能组件可能不合适。毕竟,使用 JavaScript 框架的目的是构建更具反应性的应用程序。在 Vue 中,如果没有适当的反应系统,您将无法做到这一点。
假设我们的组件接受一个 prop.user,它是一个收录 firstName 和 lastName 的对象,并且我们想要呈现一个显示用户全名的模板。在函数式组件中,我们可以通过在组件定义上提供一个方法,然后使用 Vue 提供的 $options 属性来访问我们的特殊方法来做到这一点:
{{ $options.userFullName(props.user) }}
export default {
props: {
user: Object
},
userFullName(user) {
return `${user.firstName} ${user.lastName}`
}
}
处理子组件中的业务
页面上也会有很多列表,列表中也会出现各种复杂的情况。这时候,一些繁重的业务处理就可以存放在它的子组件中了。
代码对比:
{{ heavy() }}
export default {
props: ['number'],
methods: {
heavy () {
const n = 100000
let result = 0
for (let i = 0; i < n; i++) {
result += Math.sqrt(Math.cos(Math.sin(42)))
}
return result
},
},
}
优化:
export default {
props: ['number'],
components: {
ChildComp: {
methods: {
heavy () { /* 长任务在子组件里。 */ }
},
render (h) {
return h('div', this.heavy())
}
}
}
}
当组件补丁用 props:number 更改重新渲染时,繁重的 long 任务也会重新执行。但是如果与父组件不相互依赖的元素可以拆分成一个组件,当父组件需要重新渲染时,因为子组件不依赖父组件,不会重新渲染,响应性能也可以提高。
局部范围
开发过程中经常使用一些计算属性或 Util 函数。如果我们在循环过程中不断地使用 this.*** 调用一个计算属性,那么每次调用该值都会计算一次计算属性。但是,这个值是一个固定值,造成了极大的性能浪费。
如果当我们使用这些属性时,最好的方法是取出对应的值,然后使用它。
{{ result }}
export default {
props: ['start'],
computed: {
base () {
return 42
},
result ({ base, start }) {
let result = start
for (let i = 0; i < 1000; i++) {
result += Math.sqrt(Math.cos(Math.sin(base))) + base * base + base + base * 2 + base * 3
}
return result
},
},
}
总结
以上是我通过调查资料和个人项目中的一些小经验得出的一些Vue性能优化的解决方案。文章 中的一些见解可能存在一些问题。欢迎大家在评论区指出,一起学习,一起进步。