当前位置: 首页 > news >正文

虚拟列表【vue】等高虚拟列表/非等高虚拟列表

文章目录

  • 1、等高虚拟列表
  • 2、非等高虚拟列表

1、等高虚拟列表

参考文章1
参考文章2
在这里插入图片描述
在这里插入图片描述

<!-- eslint-disable vue/multi-word-component-names -->
<template><divclass="waterfall-wrapper"ref="waterfallWrapperRef"@scroll="handleScroll"><div :style="scrollStyle"><div v-for="item in computedData.items" :key="item.userId">{{ item.username }}</div></div></div>
</template><script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { sameHighData } from "../data/index";const itemHeight = 18; //每个item的高度
let itemCount = ref(500); // 设置总共长度为500
const scrollTop = ref(0); // 滚动的高度
const wrapperHeight = ref(0); // 滚动容器的高度
const waterfallWrapperRef = ref();const list = ref([...sameHighData]);const handleScroll = (e: any) => {// 在content内容中距离content盒子的上部分的滚动距离scrollTop.value = e.target.scrollTop;// 判断是否接近底部,如果是则加载更多数据if (e.target.scrollHeight - e.target.clientHeight - scrollTop.value < 100) {getData();}
};const getData = () => {list.value = list.value.concat(list.value);itemCount.value = list.value.length;// scrollBarRef.value.style.height = itemCount.value * itemHeight + "px";console.log("发送网络请求", list.value.length);
};const scrollStyle = computed(() => ({height: `${itemHeight * (list.value.length - computedData.value.startIndex)}px`,transform: `translateY(${itemHeight * computedData.value.startIndex}px)`,
}));// 这里不使用方法的原因是以来了scrollTop 响应式数据来变更 所以使用computed更方便
const computedData = computed(() => {// 可视区域的索引const startIndex = Math.floor(scrollTop.value / itemHeight);// 设置上缓冲区为2 上缓冲区的索引const finialStartIndex = Math.max(0, startIndex - 2);// 可视区显示的数量 这里设置了item的高度为50const numVisible = Math.floor(wrapperHeight.value / itemHeight);// 设置下缓冲区的结束索引 上缓冲区也设置为2const endIndex = Math.min(itemCount.value, startIndex + numVisible + 2);// 将上缓冲区到下缓冲区的数据返回const items: any = [];// contentWrapRef.value!.style.height = finialStartIndex * itemHeight + "px";for (let i = finialStartIndex; i < endIndex; i++) {const item = {...list.value[i],top: itemHeight * i + "px",transform: `translateY(${itemHeight * i + "px"})`,};items.push(item);}console.log(startIndex);return { items, startIndex };
});onMounted(() => {// 在页面一挂载就获取滚动区域的高度if (waterfallWrapperRef.value) {wrapperHeight.value = waterfallWrapperRef.value?.clientHeight;}
});
</script><style scoped>
.waterfall-wrapper {height: 500px;overflow: hidden;overflow-y: scroll;position: relative;.scroll-bar {width: 100%;position: absolute;}
}
</style>

2、非等高虚拟列表

参考链接

非等高序列列表的实现逻辑并没有通过相对定位的方式,而是通过设置translateY来实现滚动
思路:

  • 难点1:每个元素的高度不一样,没办法直接计算出容器的高度
    • 容器高度的作用是足够大 可以让用户进行滚动,所以我们可以直接假设每一个元素的高度 需要保证预测的 item 高度尽量比真实的每一项 item 的高度要小或者接近所有 item 高度的平均值
  • 难点2: 每个元素高度不一样,top值不能通过count * index算出来
  • 难点3: 每个元素高度不一样,不能通过scrollTop * size计算出已经滚动的元素个数,很难获取可视区的起始索引
    • 难度2和难度3的解决方案是先把数据渲染到页面上 之后再通过 获取正式dom的高度 来计算
      在这里插入图片描述
<template><divclass="waterfall-wrapper"ref="waterfallWrapperRef"@scroll="handleScroll"><!-- 内容显示的区域 --><div ref="listRef" :style="scrollStyle"><div v-for="(item, index) in computedData" :key="index">{{ index }} {{ item.sentence }}</div></div></div>
</template>
  • 1、先确定预测的item高度和数据
  • 2、获取滚动区域的高度且计算容器最大容量
onMounted(async () => {// 在页面一挂载就获取滚动区域的高度if (waterfallWrapperRef.value) {wrapperHeight.value = waterfallWrapperRef.value?.clientHeight;// 预测容器最多显示多少个元素maxCount.value = Math.ceil(wrapperHeight.value / estimatedHeight) + 1;await nextTick();// 先把数据显示再页面上initData();setItemHeight();}
});
  • 3、引用一个新的变量来存放实际的dom和预测结果和实际的偏差高度
interface IPosInfo {// 当前pos对应的元素索引index: number;// 元素顶部所处位置top: number;// 元素底部所处位置bottom: number;// 元素高度height: number;// 自身对比高度差:判断是否需要更新dHeight: number;
}

在这里插入图片描述

  • 4、初始化预测的dom

参考逻辑

function initPosition() {const pos: IPosInfo[] = [];//  将获取到的数据全部进行初始化for(let i = 0; i < props.dataSource.length; i++) {pos.push({index: item.id,height: props.estimatedHeight, // 使用预测高度先填充 positionstop: item.id * props.estimatedHeight,bottom: (item.id + 1) * props.estimatedHeight,dHeight: 0,})}positions.value = pos;
}

实际代码

// 初始化数据
const initData = () => {const items: IPosInfo[] = [];// 获取需要更新位置的dom长度 即新增加的数据const len = list.value.length - preLen.value;// 已经处理好位置的长度const currentLen = initList.value.length;// 可以用三元运算符是因为初始化的时候initList的数值是空的const preTop = initList.value[currentLen - 1]? initList.value[currentLen - 1].top: 0;const preBottom = initList.value[currentLen - 1]? initList.value[currentLen - 1].bottom: 0;for (let i = 0; i < len; i++) {const currentIndex = preLen.value + i;// 获取当前要初始化的itemconst item: DiffHigh = list.value[currentIndex];items.push({id: item.id,height: estimatedHeight, // 刚开始不知道他高度 所以暂时先设置为预置的高度top: preTop? preTop + i * estimatedHeight: currentIndex * estimatedHeight,// 元素底部所处位置 这里获取的是底部的位置 所以需要+1bottom: preBottom? preBottom + (i + 1) * estimatedHeight: (currentIndex + 1) * estimatedHeight,// 高度差:判断是否需要更新dHeight: 0,});}initList.value = [...initList.value, ...items];preLen.value = list.value.length;
};
  • 5、更新实际的数据,拿到实际的数据高度
    • 通过 ref 获取到 list DOM,进而获取到它的 children
    • 遍历 children,针对于每一个 DOM item 获取其高度信息,通过其 id 属性找到 positions 中对应的 item,更新该 item 信息
// 数据渲染之后更新item的真实高度
const setItemHeight = () => {const nodes = listRef.value.children;if (!nodes.length) return;//  Array.from(nodes): 使用 Array.from() 方法,其中 nodes 是一个类数组对象。// [...nodes]: 使用数组解构语法,其中 nodes 是一个可迭代对象,例如 NodeList。// 1、遍历节点并获取位置信息// 2、更新节点高度和位置信息:// 这里只更新了视图上的bottom 没有更新top的数值 而且只更新视图上面显示的,并没有更新整个列表,因为height发生了改变视图以外的数据也发生了变化 需要同步修改[...nodes].forEach((node: Element, index: number) => {const rect = node.getBoundingClientRect();const item = initList.value[startIndex.value + index];const dHeight = item?.height - rect?.height;if (dHeight) {item.height = rect.height;item.bottom = item.bottom - dHeight;item.dHeight = dHeight;}});// 3、将当前 item 的 dHeight 进行累计,之后再重置为 0 (更新后就不再存在高度差了)const len = initList.value.length;let startHeight = initList.value[startIndex.value]?.dHeight;if (startHeight) {initList.value[startIndex.value].dHeight = 0;}// 从渲染视图的第二个开始处理// 实际上第一项的 top 值为 0,bottom 值在上轮也更新过了,所以遍历的时候我们从第二项开始for (let i = startIndex.value + 1; i < len; i++) {const item = initList.value[i];item.top = initList.value[i - 1].bottom;item.bottom = item.bottom - startHeight;if (item.dHeight !== 0) {startHeight += item.dHeight;item.dHeight = 0;}}// 设置 list 高度listHeight.value = initList.value[len - 1].bottom;
};
  • 6、设置滚动

// 已经滚动的距离
const offsetDis = computed(() =>startIndex.value > 0 ? initList.value[startIndex.value - 1]?.bottom : 0
);const scrollStyle = computed(() => ({height: `${listHeight.value - offsetDis.value}px`,transform: `translateY(${offsetDis.value}px)`,
}));

在这里插入图片描述

  • 7、滚动事件和 startIndex 计算
    • 如何判断一个 item 滚出视图?这个问题在最早就提到过了,只需要看它的 bottom <= scrollTop
    • 现在就好办了,我们可以遍历 positions 数组找到第一个 item.bottom >= scrollTop 的 item,它就是 startIndex 所对应的 item,那 startIndex 就拿到了
    • 这里再补充一个细节,在 initList 数组中 item.bottom 一定是递增的,而我们现在想要做的是查找操作,有序递增 + 查找 = 二分查找
// 二分查找 找到可视区域的索引startIndex
const getStartIndex = (list: any, value: number) => {let left = 0,right = list.length - 1,templateIndex = -1;while (left < right) {const mid = Math.floor((left + right) / 2);const midValue = list[mid].bottom;// 如果找到了就用找到的索引 + 1 作为 startIndex,因为找到的 item 是它的 bottom 与 scrollTop 相等,即该 item 已经滚出去了if (midValue === value) return mid + 1;else if (midValue < value) left = mid + 1;else if (midValue > value) {if (templateIndex == -1 || templateIndex > mid) {templateIndex = mid;}right = mid;}}return templateIndex;
};
  • 8、每次 startIndex 改变,不仅会改变 renderList 的计算,我们还需要重新计算 item 信息
watch(() => startIndex.value,() => {setItemHeight();}
);
<!-- eslint-disable vue/multi-word-component-names -->
<template><divclass="waterfall-wrapper"ref="waterfallWrapperRef"@scroll="handleScroll"><!-- 内容显示的区域 --><div ref="listRef" :style="scrollStyle"><div v-for="(item, index) in computedData" :key="index">{{ index }} {{ item.sentence }}</div></div></div>
</template><script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch } from "vue";
import { sameDiffData } from "../data/index";interface IPosInfo {// 当前pos对应的元素索引id: number;// 元素顶部所处位置top: number;// 元素底部所处位置bottom: number;// 元素高度height: number;// 高度差:判断是否需要更新dHeight: number;
}interface DiffHigh {id: number;sentence: string;
}const waterfallWrapperRef = ref();
const listRef = ref();const estimatedHeight = 60; // 设置预估的高度为100
let itemCount = ref(500); // 设置总共长度为500
const scrollTop = ref(0); // 滚动的高度
const wrapperHeight = ref(0); // 滚动容器的高度
const preLen = ref(0); // 因为每次处理数值的时候都需要处理全部数据 这个用来记录已经处理的数据const list = ref<DiffHigh[]>([...sameDiffData]);
const initList = ref<IPosInfo[]>([]); // 用来存放已经处理好位置的数据
const listHeight = ref(0); // 列表的高度const startIndex = ref(0);
const maxCount = ref(0);const endIndex = computed(() =>Math.min(list.value.length, startIndex.value + maxCount.value + 2)
);const computedData = computed(() =>list.value.slice(Math.max(0, startIndex.value - 2), endIndex.value)
);// 已经滚动的距离
const offsetDis = computed(() =>startIndex.value > 0 ? initList.value[startIndex.value - 1]?.bottom : 0
);const scrollStyle = computed(() => ({height: `${listHeight.value - offsetDis.value}px`,transform: `translateY(${offsetDis.value}px)`,
}));const handleScroll = (e: any) => {scrollTop.value = e.target.scrollTop;// 在content内容中距离content盒子的上部分的滚动距离// 在开始滚动之后获取startIndexstartIndex.value = getStartIndex(initList.value, scrollTop.value);console.log(startIndex.value, "-0-");// 判断是否接近底部,如果是则加载更多数据if (e.target.scrollHeight - e.target.clientHeight - scrollTop.value < 100) {getMoreData();}
};watch(() => startIndex.value,() => {setItemHeight();}
);const getMoreData = async () => {list.value = list.value.concat(list.value);await nextTick();initData();setItemHeight();
};// 二分查找 找到可视区域的索引startIndex
const getStartIndex = (list: any, value: number) => {let left = 0,right = list.length - 1,templateIndex = -1;while (left < right) {const mid = Math.floor((left + right) / 2);const midValue = list[mid].bottom;if (midValue === value) return mid + 1;else if (midValue < value) left = mid + 1;else if (midValue > value) {if (templateIndex == -1 || templateIndex > mid) {templateIndex = mid;}right = mid;}}return templateIndex;
};// 初始化数据
const initData = () => {const items: IPosInfo[] = [];// 获取需要更新位置的dom长度const len = list.value.length - preLen.value;// 已经处理好位置的长度const currentLen = initList.value.length;// 可以用三元运算符是因为初始化的时候initList的数值是空的const preTop = initList.value[currentLen - 1]? initList.value[currentLen - 1].top: 0;const preBottom = initList.value[currentLen - 1]? initList.value[currentLen - 1].bottom: 0;for (let i = 0; i < len; i++) {const currentIndex = preLen.value + i;// 获取当前要初始化的itemconst item: DiffHigh = list.value[currentIndex];items.push({id: item.id,height: estimatedHeight, // 刚开始不知道他高度 所以暂时先设置为预置的高度top: preTop? preTop + i * estimatedHeight: currentIndex * estimatedHeight,// 元素底部所处位置 这里获取的是底部的位置 所以需要+1bottom: preBottom? preBottom + (i + 1) * estimatedHeight: (currentIndex + 1) * estimatedHeight,// 高度差:判断是否需要更新dHeight: 0,});}initList.value = [...initList.value, ...items];preLen.value = list.value.length;
};// 数据渲染之后更新item的真实高度
const setItemHeight = () => {const nodes = listRef.value.children;if (!nodes.length) return;//  Array.from(nodes): 使用 Array.from() 方法,其中 nodes 是一个类数组对象。// [...nodes]: 使用数组解构语法,其中 nodes 是一个可迭代对象,例如 NodeList。// 1、遍历节点并获取位置信息// 2、更新节点高度和位置信息:[...nodes].forEach((node: Element, index: number) => {const rect = node.getBoundingClientRect();const item = initList.value[startIndex.value + index];const dHeight = item?.height - rect?.height;if (dHeight) {item.height = rect.height;item.bottom = item.bottom - dHeight;item.dHeight = dHeight;}});// 3、将当前 item 的 dHeight 进行累计,之后再重置为 0 (更新后就不再存在高度差了)const len = initList.value.length;let startHeight = initList.value[startIndex.value]?.dHeight;if (startHeight) {initList.value[startIndex.value].dHeight = 0;}for (let i = startIndex.value + 1; i < len; i++) {const item = initList.value[i];item.top = initList.value[i - 1].bottom;item.bottom = item.bottom - startHeight;if (item.dHeight !== 0) {startHeight += item.dHeight;item.dHeight = 0;}}// 设置 list 高度listHeight.value = initList.value[len - 1].bottom;
};onMounted(async () => {// 在页面一挂载就获取滚动区域的高度if (waterfallWrapperRef.value) {wrapperHeight.value = waterfallWrapperRef.value?.clientHeight;// 预测容器最多显示多少个元素maxCount.value = Math.ceil(wrapperHeight.value / estimatedHeight) + 1;await nextTick();// 先把数据显示再页面上initData();setItemHeight();}
});
</script><style scoped>
.waterfall-wrapper {height: 300px;/* overflow: hidden; */overflow-y: scroll;/* position: relative; */.scroll-bar {width: 100%;}
}
</style>

相关文章:

虚拟列表【vue】等高虚拟列表/非等高虚拟列表

文章目录 1、等高虚拟列表2、非等高虚拟列表 1、等高虚拟列表 参考文章1 参考文章2 <!-- eslint-disable vue/multi-word-component-names --> <template><divclass"waterfall-wrapper"ref"waterfallWrapperRef"scroll"handleScro…...

【MySQL】如何理解索引(高频面试点)

一、前言 首先这个博客会介绍一些关于MySQL中索引的基本内容以及一些基本的语法&#xff0c;当然里面也会有些常见的面试题的解答。 二、关于索引 1、概念 索引是一种能够帮助MySQL高效的去磁盘检索数据的一种数据结构。在MySQL的Innodb存储引擎中呢&#xff0c;采用的是B树的…...

NXP实战笔记(四):S32K3xx如何产生中心对称三相六路波形

目录 1、概述 1.1、理论基础 2、RTD实现 2.1、Emios时基配置 2.1.1、EmiosMcl 2.1.2、EmiosCommon 2.2、Emios PWM配置 2.3、TRGMUX 2.4、LCU 2.5、外设信号配置 3、代码实现 4、测试结果 1、概述 电机控制中需要产生三相六路SVPWM进行占空比与周期调制,怎么通过RT…...

关于uniapp H5应用无法在触摸屏正常显示的处理办法

关于uniapp H5应用无法在触摸屏正常显示的处理办法 1、问题2、处理3、建议 1、问题 前几天&#xff0c; 客户反馈在安卓触摸大屏上无法正确打开web系统&#xff08;uni-app vue3开发的h5 应用&#xff09;&#xff0c;有些页面显示不出内容。该应用在 pc 端和手机端都可以正常…...

Stable Diffusion 3 发布,AI生图效果,再次到达全新里程碑!

AI生图效果&#xff0c;再次到达全新里程碑&#xff01; Prompt&#xff1a;Epic anime artwork of a wizard atop a mountain at night casting a cosmic spell into the dark sky that says "Stable Diffusion 3" made out of colorful energy 提示&#xff08;意译…...

单例模式怎样实现单例(独例)?

在类定义中加入私有属性 __init__flag Ture,在随后的初始化处理中&#xff0c;判断该属性为真时进行相应的初始化操作&#xff0c;否则&#xff0c;跳过相应的初始化操作。这个机制&#xff0c;保证在进行后续的调用时&#xff0c;不再占用额外的内存开销。 当然了&#xff0c…...

MySQL——基础内容

目录 第01章_数据库概述 关系型数据库(RDBMS)——表、关系模型 非关系型数据库(非RDBMS) 表、记录、字段 表的关联关系 一对一关联 一对多关系 多对多 自我引用 第02章_MySQL环境搭建 登录命令 常用命令 show databases; create database use 数据库名 show tables 第03章…...

node 之 初步认识

思考&#xff1a;为什么JavaScript可以在浏览器中被执行 代执行的js代码——JavaScript解析引擎 不同的浏览器使用不同的JavaScript解析引擎 Chrome 浏览器 》 V8 Firefox浏览器 》OdinMonkey(奥丁猴&#xff09; Safri浏览器 》JSCore IE浏览器 》Chakra(查克拉&#xff09; e…...

css复习

盒模型相关&#xff1a; border&#xff1a;1px solid red (没有顺序) 单元格的border会发生重叠&#xff0c;如果不想要重叠设置 border-collapse:collapse (表示相邻边框合并在一起) padding padding影响盒子大小的好处使用 margin应用&#xff1a; 行内或行内块元素水…...

HTML5和CSS3提高

一、HTML5的新特性 增加了一些新的标签&#xff0c;新的表单&#xff0c;新的表单属性&#xff0c;IE9以上版本的浏览器才支持 注意&#xff1a; 这些语义化标准主要针对搜索引擎的 新标签可以使用多次 在IE9中需要把这些元素转化为块级元素 新增的多媒体标签 主要包含两个…...

感受2024生物发酵展示会-明章机械

参展企业介绍 温州明章机械有限公司是一家专业从事搅拌传动装置机械密封&#xff0c;减速机&#xff0c;机架&#xff0c;联轴器及相关配件。设计、开发及生产的服务型高新技术企业公司&#xff0c;座落于浙江省温州市瓯海区娄桥镇高新工业园区豪新路42号&#xff0c;交通位置…...

算法打卡day1|数组篇|Leetcode 704.二分查找、27.移除元素

数组理论基础 数组是存放在连续内存空间上的相同类型数据的集合&#xff0c;可以方便的通过下标索引的方式获取到下标下对应的数据。 1.数组下标都是从0开始的。 2.数组内存空间的地址是连续的。 正是因为数组的在内存空间的地址是连续的&#xff0c;所以我们在删除或者增添…...

什么是高阶组件

高阶组件&#xff08;HOC&#xff09;是 React 中用于复用组件逻辑的一种高级技巧。简单来说&#xff0c;高阶组件就是一个函数&#xff0c;该函数接受一个组件作为参数&#xff0c;并返回一个新的组件。这个新的组件会使用你传给它的组件作为子组件。 高阶组件并不是真的组件…...

python实现裂区试验方差分析

方差分析&#xff08;Analysis of Variance&#xff0c;ANOVA&#xff09;是一种统计方法&#xff0c;用于比较三个或三个以上组别的平均值是否存在显著差异。它通过比较组内变异和组间变异的大小来判断组别间的平均值是否有显著差异。 方差分析通常用于以下情况&#xff1a; …...

Vue v-for、v-if、v-show常见问题

vue使用v-for遍历对象时&#xff0c;是按照什么顺序遍历的&#xff1f;如何保证顺序&#xff1f; 会先判断对象是否存在iterator接口&#xff0c;如果有循环执行next()方法。 没有iterator的情况下&#xff0c;会调用Object.Keys()方法&#xff0c;在不同的浏览器中&#xff…...

GPT技术在学术研究中的革命性应用:开启论文创作新篇章

在学术界&#xff0c;撰写高质量的论文一直是一个挑战性的任务&#xff0c;它不仅需要深厚的专业知识&#xff0c;还要求良好的文献综述能力、数据分析技巧以及清晰的表达能力。近年来&#xff0c;随着人工智能技术的飞速发展&#xff0c;尤其是生成式预训练变换器&#xff08;…...

【K8s】-- 描述容器中 pod 的状态

命令&#xff1a;kubectl describe pod -n 你的namespace名称 pod 名称 举例&#xff1a;kubectl describe pod -n my-flink --context prod-5 test-record-all-new-mc-taskmanager-1-1 Name: test-record-all-new-mc-taskmanager-1-1 Namespace: ky-flink Pri…...

使用yolo-seg模型实现自定义自动动态抠图

yolov8导航 如果大家想要了解关于yolov8的其他任务和相关内容可以点击这个链接&#xff0c;我这边整理了许多其他任务的说明博文&#xff0c;后续也会持续更新&#xff0c;包括yolov8模型优化、sam等等的相关内容。 YOLOv8&#xff08;附带各种任务详细说明链接&#xff09; …...

FairyGUI × Cocos Creator 3.x 场景切换

前言 前文提要&#xff1a; FariyGUI Cocos Creator 入门 FairyGUI Cocos Creator 3.x 使用方式 个人demo&#xff1a;https://gitcode.net/qq_36286039/fgui_cocos_demo_dust 个人demo可能会更新其他代码&#xff0c;还请读者阅读本文内容&#xff0c;自行理解并实现。 官…...

【Java程序设计】【C00288】基于Springboot的篮球竞赛预约平台(有论文)

基于Springboot的篮球竞赛预约平台&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的篮球竞赛预约平台 本系统分为前台功能模块、管理员功能模块以及用户功能模块。 前台功能模块&#xff1a;用户进入到平台首页&a…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

Python 包管理器 uv 介绍

Python 包管理器 uv 全面介绍 uv 是由 Astral&#xff08;热门工具 Ruff 的开发者&#xff09;推出的下一代高性能 Python 包管理器和构建工具&#xff0c;用 Rust 编写。它旨在解决传统工具&#xff08;如 pip、virtualenv、pip-tools&#xff09;的性能瓶颈&#xff0c;同时…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...