前文
今天我们来一起学习如何实现一个侧边栏弹窗并且使用GPU加速优化动画和事件委托机制优化代码
一、需求分析
平台左侧需要一个点击的出现的侧边栏
关闭状态:
打开状态:
代码实现:
xml
<template>
<!-- 侧边栏容器,捕获DOM节点 -->
<div ref="donateContentDiv" class="homeSidebar-container">
<!-- 标题栏 -->
<div class="homeSidebar-container-title" @click="toggleDonateContentDiv">
<!-- 箭头图标旋转特效 -->
<span class="container-title-text" :class="{ 'rotate-icon': isContentDivVisible }"><CaretRight /></span>
</div>
<!-- 内容栏 -->
<div class="homeSidebar-container-content" @click="itemJump">
<!-- 数据项 -->
<div class="container-content-item" v-for="item in dataArr" :key="item.url" :data-vid="item.id">{{item.title}}</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
// DOM节点引用
const donateContentDiv = ref(null);
// 控制内容栏显示与隐藏
const isContentDivVisible = ref(false);
// 数据数组
const dataArr = ref([
{ id:1, url: 'xxx', title:"xxx"},
{ id:2, url: 'xxx', title:"xxx"},
{ id:3, url: 'xxx', title:"xxx"},
{ id:4, url: 'xxx', title:"xxxx"},
{ id:5, url: 'xxx', title:"xxx"},
{ id:6, url: 'xxx', title:"xxx"},
{ id:7, url: 'xxx', title:"xxx"},
{ id:8, url: 'xxx', title:"xxx"},
{ id:9, url: 'xxx', title:"xxx"},
]);
// 切换内容栏显示与隐藏
const toggleDonateContentDiv = () => {
const leftValue = donateContentDiv.value.style.left;
donateContentDiv.value.style.left = leftValue === '0px' ? '-245px' : '0px';
isContentDivVisible.value = !isContentDivVisible.value;
};
// 处理数据项点击事件
const itemJump = (e) => {
const customIdValue = e.target.dataset.vid;
alert(customIdValue);
};
</script>
<style lang="scss" scoped>
// 必须设置hover ,否则will-change: transform;属性不会生效
.homeSidebar-container:hover {
/* GPU加速优化动画 */
-webkit-will-change: transform;
will-change: transform;
}
.homeSidebar-container {
/* 侧边栏容器样式 */
/* GPU加速优化动画 */
-webkit-transform: translateZ(0);
z-index: 3;
opacity: 1;
width: 245px;
height: 60%;
padding: 20px;
box-shadow: 0 0px 5px 2px #44cef6;
background-color: #fff;
position: fixed;
top: 20%;
left: -245px;
transition: left 0.35s ease-in-out;
// 标题栏样式
.homeSidebar-container-title {
width: 30px;
height: 60px;
background: #fff;
position: absolute;
top: 40%;
left: 246px;
// 箭头图标旋转效果
.rotate-icon {
transition: transform 1s ease-in-out;
transform: rotate(180deg);
}
.container-title-text {
/* 标题文本样式 */
margin: 15px 0 0 1px;
display: inline-block;
width: 25px;
height: 25px;
font-size: 18px;
text-align: center;
line-height: 25px;
border-radius: 100%;
color: #fff !important;
background-image: linear-gradient(120deg, #a1c4fd 0%, #c2e9fb 100%);
}
}
// 内容栏样式
.homeSidebar-container-content {
display: flex;
width: 100%;
height: 100%;
max-height: 400px;
overflow: auto;
flex-wrap: wrap;
justify-content: space-between;
// 数据项样式
.container-content-item {
padding: 20px 0 0 0;
text-align: center;
color: #fff !important;
background: #44cef6;
width: 40%;
height: 15%;
max-height: 80px;
}
}
}
</style>
二、原理分析
(1)动画部分(很简单不再赘述)
(2)GPU加速优化动画(没加之前动画会很卡)
css
.homeSidebar-container:hover {
/* GPU加速优化动画 */
-webkit-will-change: transform;
will-change: transform;
}
.homeSidebar-container {
/* 侧边栏容器样式 */
/* GPU加速优化动画 */
-webkit-transform: translateZ(0);
}
说明:
GPU加速的原理
要理解GPU加速的原理,我们需要了解浏览器渲染流程的基本概念。
1.浏览器在渲染网页时,会经历一系列的步骤,如样式计算、布局、绘制和合成。为了提高性能,浏览器会尽量避免进行不必要的计算和操作。
will-change
和-webkit-transform: translateZ(0);
的作用
will-change
的作用就是告诉浏览器某个元素将要发生的变化,从而使浏览器在渲染过程中提前分配和优化相应的资源。
例如,当我们设置了will-change: transform
时,浏览器会为该元素创建一个独立的图层,将这个图层标记为"即将变换"。这样,在进行布局和绘制时,浏览器就可以更高效地处理这个元素,而无需重新计算整个渲染树。
浏览器中图层一般包含两大类:渲染图层(普通图层)以及复合图层
怎么看图层:blog.csdn.net/Henry2Ti/ar...
渲染图层,是页面普通的文档流。我们虽然可以通过绝对定位,相对定位,浮动定位脱离文档流,但它仍然属于默认复合层(根层叠上下文),共用同一个绘图上下文对象(GraphicsContext)。 复合图层,又称图形层。它会单独分配系统资源,每个复合图层都有一个独立的GraphicsContext。(当然也会脱离普通文档流,这样一来,不管这个复合图层中怎么变化,也不会影响默认复合层里的回流重绘)
相当于,通过will-change
或者-webkit-transform: translateZ(0);
属性,提示计算机页面元素即将发生变化,需要计算机协调GPU来帮助计算,不占用CPU的资源,自然就会变得不卡顿
3.需要注意的点:
一些低版本的浏览器不支持will-change属性
这个时候需要使用-webkit-transform: translateZ(0);
属性(hack加速) 触发hack加速的元素
css
.haorooms_element {
-webkit-transform: translateZ(0);
-moz-transform: translateZ(0);
-ms-transform: translateZ(0);
-o-transform: translateZ(0);
transform: translateZ(0);
/**或者**/
transform: rotateZ(360deg);
transform: translate3d(0, 0, 0);
}
使用will-change属性
时,会消耗额外的内存,注意不要滥用will-change属性
,内存会爆炸的
使用will-change属性
时,需要在css绑定:hover这类选择器,提示计算机
错误示例:(在此,当我们通知浏览器时,已经在进行更改,从而完全抵消了will-change
属性的全部内容。 如果我们希望浏览器提前知道什么时候会发生更改,则必须在适当的时候通知它。)
css
.homeSidebar-container: {
will-change: transform;
transition: transform 0.3s;
transform: scale(1.5);
}
正确示例:
css
.homeSidebar-container:hover {
/* GPU加速优化动画 */
-webkit-will-change: transform;
will-change: transform;
}
可以看看这篇文章
(3)事件委托优化 事件委托又叫事件代理,是指利用事件冒泡的特性,将本应该注册在子元素上事件注册在父元素上,由父元素来处理子元素的事件。这样的好处是:
1.有助于降低DOM操作,提高性能。
2.增加扩展性,子元素可以随意增加,不用再做其他额外的操作,都在父元素上做事件处理操作
3.有助于代码简洁高效性,不用为每个子元素添加事件处理程序,简化了代码处理逻辑。
Html:
xml
<div class="homeSidebar-container-content" @click="itemJump">
<!-- 数据项 -->
<div class="container-content-item" v-for="item in dataArr" :key="item.url" :data-vid="item.id">{{item.title}}</div>
Js:
ini
// 处理数据项点击事件
const itemJump = (e) => {
const customIdValue = e.target.dataset.vid;
alert(customIdValue);
};
这里我设置了一个自定义属性,data-vid,点击之后,子元素通过冒泡,传递自己的id到方法中,由此可以实现指定的路由跳转