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

深入【虚拟列表】动态高度、缓冲、异步加载... Vue实现

前言🎀

在前文中我们了解到:

1.在某种特殊场景下,我们需要将 大量数据 使用不分页的方式渲染到列表上,这种列表叫做长列表
2.因为事件循环的机制,一次性大量的渲染耗时较长,并且渲染期间会阻塞页面交互事件,所以我们使用时间分片机制将渲染分为多次。
3.分析真实业务场景,将全部数据渲染到列表中是无用且浪费资源的行为,只需要根据用户的视窗进行部分渲染即可,所以使用到虚拟列表技术。

前文中我们根据 “无论滚动到什么位置,浏览器只需要渲染可见区域内的节点” 的思路实现了虚拟列表解决了长列表问题,但在一些细节和特殊情况的处理上还是有所欠缺,例如:

1.高度不定的列表项会导致内容出现错位、偏移等情况。
2.列表项含有异步资源,会在渲染后再次改变高度。
3.一次性大量数据的请求导致请求响应与数据处理时间过长。

在本文中我们就来一起研究这些场景,并对原版的虚拟列表做出优化 🚀

如果觉得有收获还望大家点赞、收藏 🌹

动态高度

分析

在前文的虚拟列表实现中,列表项高度itemSize都是固定的。

// template -> list-item
:style="{ height: itemSize + 'px', lineHeight: itemSize + 'px' }"// export defualt -> data
itemSize: 50, 

因此很多直接与 列表项高度itemSize 关联的属性,都很容易计算:

1.列表总高度listHeight= listData.length * itemSize
2.当前窗口偏移量currentOffset= scrollTop - (scrollTop % itemSize)
3.列表数据的开始/结束索引start/end= ~~(scrollTop / itemSize). . . . . .

但在实际情况中列表元素多为高度不固定的列表项,它可能是多行文本、图片之类的可变内容,如系统日志、微博等等。

不固定的高度会导致上述的属性无法正常计算。

对于高度不固定的列表项,我们遇到的问题如下:

1.如何获取真实高度?
2.相关的属性该如何计算?
3.列表渲染的方式有何改变?

方案

如何获取真实高度?

  • 如果能获得列表项高度数组,真实高度问题就很好解决。但在实际渲染之前是很难拿到每一项的真实高度的,所以我们采用预估一个高度渲染出真实DOM,再根据DOM的实际情况去设置真实高度。* 创建一个缓存列表,其中列表项字段为 索引、高度与定位,并预估列表项高度用于初始化缓存列表。在渲染后根据DOM实际情况更新缓存列表相关的属性该如何计算?

  • 显然以前的计算方式都无法使用了,因为那都是针对固定值设计的。* 于是我们根据缓存列表重写 计算属性、滚动回调函数,例如列表总高度的计算可以使用缓存列表最后一项的定位字段的值。列表渲染的方式有何改变?

  • 因为用于渲染页面元素的数据是根据 开始/结束索引 在 数据列表 中筛选出来的,所以只要保证索引的正确计算,那么渲染方式是无需变化的。* 对于开始索引,我们将原先的计算公式改为:在 缓存列表 中搜索第一个底部定位大于 列表垂直偏移量 的项并返回它的索引。* 对于结束索引,它是根据开始索引生成的,无需修改。实现

预估&初始化列表

先设置一个虚拟 预估高度preItemSize,用于列表初始化。

同时维护一个记录真实列表项数据的 缓存列表positions

data() {return {. . . . . .// 预估高度preItemSize: 50,// 缓存列表positions = [// 列表项对象{index: 0,// 对应listData的索引top: 0,// 列表项顶部位置bottom: 50,// 列表项底部位置height: 50,// 列表项高度}]}
} 

在创建组件时先用preItemSizepositions进行初始化,在后续更新时再进行替换。

created() {this.initPositions(this.listData, this.positions)
},
methods: {initPositions(listData, itemSize) {this.positions = listData.map((item, index) => {return{index, top: index * itemSize, bottom: (index + 1) * itemSize,height: itemSize, }})}
} 

注:listData即数据列表,里面是每一项数据对应的内容。

列表总高度listHeight的计算方式改变为缓存列表positions最后一项的bottom

computed: {listHeight() {// return this.listData.length * this.itemSize;
+ return this.positions[this.positions.length - 1].bottom;},
} 

更新真实数据

在每次渲染后,获取真实DOM的高度去替换positions里的预估高度

updated生命周期在数据变化视图更新过后触发所以能获取到真实DOM

我们利用Vue的updated钩子来实现这一功能

期间遍历真实列表的每一个节点,对比 节点 和 列表项 生成高度差dValue判断是否需要更新:

updated() {this.$nextTick(() => {// 根据真实元素大小,修改对应的缓存列表this.updatePositions()})
},
methods: {updatePositions() {let nodes = this.$refs.items;nodes.forEach((node) => {// 获取 真实DOM高度const { height } = node.getBoundingClientRect();// 根据 元素索引 获取 缓存列表对应的列表项const index = +node.idlet oldHeight = this.positions[index].height;// dValue:真实高度与预估高度的差值 决定该列表项是否要更新let dValue = oldHeight - height;// 如果有高度差 !!dValue === trueif(dValue) {// 更新对应列表项的 bottom 和 heightthis.positions[index].bottom = this.positions[index].bottom - dValue;this.positions[index].height = height;// 依次更新positions中后续元素的 top bottomfor(let k = index + 1; k < this.positions.length; k++) {this.positions[k].top = this.positions[k-1].bottom;this.positions[k].bottom = this.positions[k].bottom - dValue;}}})}
} 

此外在更新完positions后,当前窗口偏移量currentOffset也要根据真实情况重新赋值:

updated() {this.$nextTick(() => {// 根据真实元素大小,更新对应的缓存列表this.updatePositions()// 更新完缓存列表后,重新赋值偏移量this.currentOffset = this.getCurrentOffset()})
},
methods: {updatePositions() {//. . . }getCurrentOffset() {if(this.start >= 1) {this.currentOffset = this.positions[this.start - 1].bottom} else {this.currentOffset = 0;}}
} 

重写滚动回调

滚动触发的回调函数里计算了 开始/结束索引start/end 和 当前窗口偏移量currentOffset ,现在高度不固定后都需要重新计算,而结束索引依赖于开始索引所以不需要修改。

重新计算 开始索引start

定高时我们不必建立数组(建立了也只是重复的数据),直接根据scrollTopitemSize计算索引即可

this.start = ~~(scrollTop / this.itemSize); 

但不定高时,只能带着scrollTop在列表中逐个寻找(后续使用搜索算法优化)。两个计算的最终目的都是找到当前位置对应的数据索引

列表数据开始索引start的计算方法修改为:遍历 缓存列表positions 匹配第一个大于当前滚动距离scrollTop的项,并返回该项的索引。

mounted() {. . . . . .// 绑定滚动事件let target = this.$refs.virtualListlet scrollFn = (event) => this.scrollEvent(event.target)target.addEventListener("scroll",scrollFn);
},
methods: {scrollEvent(target) {const scrollTop = target.scrollTop;// this.start = ~~(scrollTop / this.itemSize);
+ this.start = this.getStartIndex(scrollTop)this.end = this.start + this.visibleCount;this.currentOffset = scrollTop - (scrollTop % this.itemSize);},getStartIndex(scrollTop = 0) {let item = this.positions.find(item => item && item.bottom > scrollTop); return item.index;}
}, 

重新计算 窗口偏移量currentOffset

滚动后立即根据positions的预估值(此时数据还未更新)计算窗口偏移量currentOffset

scrollEvent() { . . . . . .// this.currentOffset = scrollTop - (scrollTop % this.itemSize);this.currentOffset = this.getCurrentOffset()}, 

优化

positions是遍历listData生成的,listData本是有序的,所以positions也是一个顺序数组

Array.find方法 时间复杂度 O(n)O(n)O(n),查找 索引start 效率较低 ❌

二分查找十分适合顺序存储结构 时间复杂度log2nlog_2{n}log2​n,效率较高 ✔️

<script> . . . . . .
var binarySearch = function(list, target) {    const len = list.length    let left = 0, right = len - 1let tempIndex = null    while (left <= right) {        let midIndex = (left + right) >> 1        let midVal = list[midIndex].bottom        if (midVal === target) {return midIndex} else if (midVal < target) {left = midIndex + 1} else {// list不一定存在与target相等的项,不断收缩右区间,寻找最匹配的项if(tempIndex === null || tempIndex > midIndex) {tempIndex = midIndex}right--}}// 如果没有搜索到完全匹配的项 就返回最匹配的项return tempIndex};
export default {. . . . . .methods: {. . . . . .getStartIndex(scrollTop = 0) {// let item = this.positions.find(i => i && i.bottom > scrollTop); // return item.index;
+return binarySearch(this.positions, scrollTop)}},
} </script> 

运行查看一下效果,不定高问题已经解决了

滚动缓冲

分析

上文中,为了正确计算不定高列表项,同时在 updated生命周期 和 滚动回调 中增加了额外操作,这都增加了浏览器负担

因此快速滚动列表时,我们很明显的观察到白屏闪烁的情况,即滚动后,先加载出白屏内容(没有渲染)然后迅速替换为表格内容,制造出一种闪烁的现象。

注:白屏闪烁是浏览器性能低导致的,事件循环中的渲染操作没有跟上窗口的滚动,额外操作只是加剧了这种情况。

方案

为了使页面平滑滚动,我们在原先的列表结构上再加入缓冲区,渲染区域由可视区+缓冲区共同组成,这给滚动回调和页面渲染更多处理时间。

用户在可视区滚动,脱离可视区后立即进入缓冲区,同时渲染下一部分可视区的数据。在脱离缓冲区后新的数据大概率也渲染完成了。

而缓冲区域包含多少个元素呢?

我们创建一个变量表示比例数值,这个比例数值是相对于 最大可见列表项数 的,根据这个 相对比例 和 开始/结束索引 计算上下缓冲区的大小

对渲染流程有什么影响?

列表显示数据 原先是根据索引计算,现在额外加入上下缓冲区大小重新计算,会额外渲染缓冲元素。

实现

创建一个属性代表比例值:

data: {bufferPercent: 0.5, // 即每个缓冲区只缓冲 0.5 * 最大可见列表项数 个元素
}, 

创建三个计算属性,分别代表 缓冲区标准多少个元素 + 上下缓冲区实际包含多少个元素:

computed: {bufferCount() {return this.visibleCount * this.bufferPercent >> 0; // 向下取整},// 使用索引和缓冲数量的最小值 避免缓冲不存在或者过多的数据aboveCount() {return Math.min(this.start, this.bufferCount);},belowCount() {return Math.min(this.listData.length - this.end, this.bufferCount);},
} 

重写 列表显示数据visibleData 的计算方式:

computed: {visibleData() {// return this.listData.slice(this.start, this.end);
+return this.listData.slice(this.start - this.aboveCount, this.end + this.belowCount);},
} 

因为多出了缓冲区域所以窗口偏移量currentOffset也要根据缓冲区的内容重新计算:

 getCurrentOffset() {if(this.start >= 1) {// return this.positions[this.start - 1].bottom;let size = this.positions[this.start].top - (this.positions[this.start - this.aboveCount] ? this.positions[this.start - this.aboveCount].top : 0);// 计算偏移量时包括上缓冲区的列表项return this.positions[this.start - 1].bottom - size;} else {return 0;}} 

运行看一下效果,闪烁问题已经完美解决了。

异步加载

其实在列表项中包含图片的场景,图片多为高度固定的缩略图,只需要在计算时根据图给每个列表项加一个固定高度,多于一行的图片直接省略。这样异步加载对于虚拟列表就没有影响了。

 <div v-for="item in visibleData" :key="item.id" :id="item.id" ref="items" class="list-item">{{ item.value }}<img :src="item.img" @load="updatePositions" /></div>
or
mounted() {let content = this.$refs.contentlet resizeObserver = new ResizeObserver(() => this.updatePositions())resizeObserver.observe(content)
}, 

懒加载数据

一次性请求大量数据可能会使后端处理时间增加,过大的响应体也会导致整体请求响应耗时增加,用户等待时间较长体感较差。

因此我们结合懒加载的方式,在每次滚动触底时加载部分新数据并更新positions,避免单次请求等待时间过长。

// 滚动回调scrollEvent(target) {const { scrollTop, scrollHeight, clientHeight } = target;this.start = this.getStartIndex(scrollTop);this.end = this.start + this.visibleCount;this.currentOffset = this.getCurrentOffset()// 触底if ((scrollTop +clientHeight) === scrollHeight) {// 模拟数据请求let len = this.listData.length + 1for (let i = len; i <= len + 100; i++) {this.listData.push({id: i, value: i + '字符内容'.repeat(Math.random() * 20) })}this.initPositions(this.listData, this.preItemSize)}}, 

有些同学可能会想,懒加载时初始数据量较少,会导致滚动条很短,间接给用户一种数据量很少的错觉。

对于这种情况我们需要跟后端做好协调,接口返回的数据格式大致规定为这样

data: {page: 1,size: 1000,count: 10000,list: [1...1000],updateTime: '...',. . . . . .
} 

然后使用data.count初始化positions,在后续懒加载到对应索引的数据时,替换positions里的内容。

最后

为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

相关文章:

深入【虚拟列表】动态高度、缓冲、异步加载... Vue实现

前言&#x1f380; 在前文中我们了解到&#xff1a; 1.在某种特殊场景下&#xff0c;我们需要将 大量数据 使用不分页的方式渲染到列表上&#xff0c;这种列表叫做长列表。 2.因为事件循环的机制&#xff0c;一次性大量的渲染耗时较长&#xff0c;并且渲染期间会阻塞页面交互…...

Windows 11 + WSL(ubuntu 20.04) + CLion(2022.3) 编译OpenJDK12

编译OpenJDK12 目录编译OpenJDK12前言一、下载OpenJDK源码二、编译OpenJDK参考https://openjdk.org/groups/build/doc/building.html1&#xff1a;安装编译所需的组件2&#xff1a;执行编译命令3&#xff1a;验证编译结果三、在Clion中调试OpenJDK源码1&#xff1a;Clion中配置…...

Freemarker 语法精粹

文章目录说明基本用法宏加载宏定义宏文件写法import和include区别内置方法注册全局共享变量处理空值和默认值获得hashmap的键值从map中拿对象遍历Map其它小技巧迁移事项参考说明 Freemarker 还存在我的一些老项目中&#xff0c;比起前端框架&#xff0c;自有它的简便之处&…...

使用Benchto框架对Trino进行SQL性能对比测试

有时需要对魔改源码前后的不同版本Trino引擎进行性能对比测试&#xff0c;提前发现改造前后是否有性能变差或变好的现象&#xff0c;避免影响数据业务的日常查询任务性能。而Trino社区正好提供了一个性能测试对比框架&#xff1a;GitHub - trinodb/benchto: Framework for runn…...

Redis之哨兵模式

什么是哨兵模式&#xff1f; Sentinel(哨兵)是用于监控Redis集群中Master状态的工具&#xff0c;是Redis高可用解决方案&#xff0c;哨兵可以监视一个或者多个redis master服务&#xff0c;以及这些master服务的所有从服务。 某个master服务宕机后&#xff0c;会把这个master下…...

Selenium自动化测试Python二:WebDriver基础

欢迎阅读WebDriver基础讲义。本篇讲义将会重点介绍Selenium WebDriver的环境搭建和基本使用方法。 WebDriver环境搭建 Selenium WebDriver 又称为 Selenium2。 Selenium 1 WebDriver Selenium 2 WebDriver是主流Web应用自动化测试框架&#xff0c;具有清晰面向对象 API&…...

蓝桥杯模块学习17——AT24C02存储器(深夜学习——单片机)

一、硬件电路&#xff1a;1、引脚功能&#xff1a;&#xff08;1&#xff09;A0-A2&#xff1a;决定不同设备的地址码&#xff1a;&#xff08;2&#xff09;WP&#xff1a;写保护二、通讯方式&#xff08;IIC协议&#xff09;通讯方式与PCF8591相同&#xff0c;可参考以下文章…...

netty

Netty的介绍Netty是异步的&#xff08;指定回调处理&#xff09;、基于事件驱动的网络应用框架&#xff0c;用于快速开发高性能、高可靠性的网络IO程序。Netty本质是一个NIO框架&#xff0c;适用于服务器通讯相关的多种应用场景&#xff0c;分布式节点远程调用中Netty往往作为R…...

Django项目部署-uWSGI

Django项目部署-uWSGIDjango运维部署框架整体部署架构web服务器与web应用服务器的区别部署环境准备安装python3安装mariadb安装Django和相关模块Django托管服务器uWSGI使用uWSGI配置使用Django运维部署框架 整体部署架构 操作系统: Linux 。优势&#xff1a;生态系统丰富&…...

jhipster自动生成java代码的方法

一、前言 java springboot后台项目用到了jpa查询数据库&#xff0c;还用到了jhipster&#xff0c;这个东西可以自动生成基础的Controller、Service、Dao、JavaBean等相关代码&#xff0c;减少重复开发。 在此总结下使用方法。 二、jhipster自动生成java代码的方法 1.需要先…...

LeetCode 82. 删除排序链表中的重复元素 II

原题链接 难度&#xff1a;middle\color{orange}{middle}middle 题目描述 给定一个已排序的链表的头 headheadhead &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,…...

tensorflow gpu环境安装

查看本电脑支持的最高cuda版本&#xff1a;nvidia-smi在~/.condarc修改conda 源&#xff1a;channels:- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/- https://mirrors.tuna.tsinghua.edu.cn/…...

如何在现实场景中随心放置AR虚拟对象?

随着AR的发展和电子设备的普及&#xff0c;人们在生活中使用AR技术的门槛降低&#xff0c;比如对于不方便测量的物体使用AR测量&#xff0c;方便又准确&#xff1b;遇到陌生的路段使用AR导航&#xff0c;清楚又便捷&#xff1b;网购时拿不准的物品使用AR购物&#xff0c;体验更…...

操作系统-处理机调度

1.处理机调度的概念、层次1.1调度的基本概念制定某种规则来决定处理任务的顺序。1.2调度的三个层次高级调度&#xff08;作业调度&#xff09;中级调度&#xff08;内存调度&#xff09;进程的挂起态与七状态模型低级调度&#xff08;进程调度&#xff09;小结2.进程调度的时机…...

手机截图如何提取文字?

在当今信息爆炸的时代&#xff0c;图文并茂已经成为了一个广告宣传的常用方式。然而&#xff0c;图片中的文字信息往往难以获取&#xff0c;尤其对于那些需要快速获取信息的人们来说&#xff0c;阅读图片中的文字会是一项繁琐且费时的任务。现在&#xff0c;我们有一个好消息要…...

vue中复制内容

vue中复制内容vue2vue-clipboard2依赖项在main.js引入使用vue3vue-clipboard3依赖项引入使用更新于&#xff1a;2023-02-15vue2vue-clipboard2 依赖项 “vue”: “^2.6.11” “vue-clipboard2”: “^0.3.1” 在main.js引入 import VueClipboard from vue-clipboard2 Vue.us…...

MySQL CAST()函数用法

一、语法 expr&#xff1a;源数据&#xff0c;如字符串’China’。type&#xff1a;目标数据类型&#xff0c;例如CHAR。 cast(expr AS type)二、命令说明 将任何类型的值转换为具有指定类型的值。 CAST()函数通常用于返回具有指定类型的值&#xff0c;以便在WHERE&#xff…...

【测试工程师面试】详细记录 自己的一次面试

【测试工程师面试】详细记录 自己的一次面试 目录&#xff1a;导读 Linux基础 Oracle基础 编程基础 测试的基础 面试的问题 扯闲话部分&#xff1a; 10点刚到&#xff0c;先进行笔试&#xff0c;笔试的题目很基础&#xff0c;涉及到linux&#xff0c;涉及到oracle数据库…...

Elasticsearch 安装(二)

目录前言一、Linux 安装1、下载安装包⑴、选择需要的安装包⑵、下载解压到安装目录2、查看解压后目录结构3、启动 Elasticsearch⑴、正常启动流程⑵、启动过程遇到的问题①、启动报错②、创建运行 Elasticsearch 的用户&#xff0c;启动成功&#xff0c;但无法访问③、停止Elas…...

Java基础:异常与错误(ExceptionError)

1 缘起 某天上网冲浪时&#xff0c;偶然看到一个问题&#xff0c;说Java的Error和Exception有什么区别&#xff1f; 一句话&#xff1a;不知道。并不能很清晰地描述出个中区别。 当然&#xff0c;曾经也看过Throwable相关的知识&#xff0c;但是&#xff0c;并没有通过源码及注…...

VAmPI:一个包含了OWASP Top10漏洞的REST API安全学习平台

关于VAmPI VAmPI是一个包含了OWASP Top10漏洞的REST API安全学习平台&#xff0c;该平台基于Flask开发&#xff0c;该工具的主要目的是通过一个易受攻击的API来评估针对API安全检测工具的有效性&#xff0c;并帮助广大研究人员学习和了解API安全。 功能介绍 1、基于OWASP Top…...

springboot(6)之前端传递参数的方式 普通 集合 数组

实体类传递 首先我们在后端定义一个实体类&#xff0c;通过lombok插件重写 有参 无参 get set toString 方法, 然后前端发送数据&#xff0c;后端就会自动收到&#xff0c;然后属性填写 后端代码如下 AllArgsConstructor Data NoArgsConstructor public class role …...

redis分布式锁的演变过程

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、直接添加Redis缓存二、使用setnx执行抢锁过程三、setnx获取锁+设置过期时间四、引入UUID解决误删锁问题五、引入Lua脚本来做删除六、对递归部分优化进行自旋七、添加自旋次数八、改为重入锁,使…...

leaflet 修改popup的样式,个性化弹窗(069)

第069个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中修改popup组件的样式,个性化弹窗。主要方法是更改css, 中增加custom-popup类名,style的样式要做穿透处理 >>>.具体方法请参考源代码。 直接复制下面的 vue+leaflet源代码,操作2分钟即可运行实…...

注解ConfigurationProperties、EnableConfigurationProperties的用法

1 ConfigurationProperties ConfigurationProperties主要作用就是将prefix属性指定的前缀配置项的值绑定到这个JavaBean上 &#xff0c;通过指定的前缀&#xff0c;来绑定配置文件中的配置。这样的好处是将配置数据与JOPO进行转换&#xff0c;能够管理一个类别的所有配置信息&…...

自适应布局之淘宝无限适配+rem+微信rpx自适应

一、自适应布局 所谓前端适配&#xff0c;就是为了让移动设计稿在大部分的移动设备上看起来有一致的展示效果&#xff0c;目前比较流行的方法有两种。一种是强制meta viewport宽度为设计稿宽度&#xff0c;一种是使用rem自适应布局的flexible.js。 二、当前流行的移动端自适应…...

esxi不能识别不兼容网卡解决方案

相信很多网友在安装测试VMWARE Esxi 6.0的时候&#xff0c;总会遇到无法兼容网卡的情况&#xff0c;本人也是遇到了再组装的台式机上测试ESXI 6.0的时候&#xff0c;无法识别REALTEK RTL 8111E的情况。 找了很多网友提供的博客&#xff0c;方法是正确的&#xff0c;但是不够严…...

Sizeof与Strlen的区别与联系

16年写了很多 C 与 C 相关的文章&#xff0c;但是后面从事了 Android 开发&#xff0c;就全部删掉了&#xff0c;无意中发现了这篇由还存在草稿箱&#xff0c;索性就找回来吧&#xff0c;也是追忆当年学习的青葱岁月 Sizeof与Strlen的区别与联系 一、sizeof sizeof(…)是运算…...

力扣(LeetCode)413. 等差数列划分(2023.02.15)

如果一个数列 至少有三个元素 &#xff0c;并且任意两个相邻元素之差相同&#xff0c;则称该数列为等差数列。 例如&#xff0c;[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。 给你一个整数数组 nums &#xff0c;返回数组 nums 中所有为等差数组的 子数组 个数。 …...

蓝桥杯刷题——基础篇(一)

这部分题目&#xff0c;主要面向有志参加ACM与蓝桥杯竞赛的同学而准备的&#xff0c;蓝桥杯与ACM考察内容甚至评测标准基本都一样&#xff0c;因此本训练计划提供完整的刷题顺序&#xff0c;循序渐进&#xff0c;提高代码量&#xff0c;巩固基础。因竞赛支持C语言、C、Java甚至…...

做网站推广也要营业执照吗/如何网站seo

作为一位在一所211大学的工科生&#xff0c;我就是工程力学专业的学生&#xff0c;我来回答你这个问题吧。工程力学专业的考研专业选择主要有&#xff1a;力学、工程力学、固体力学、建筑与土木工程。现在航天专业好像也比较适合学习工程力学的同学去考。工程力学的范畴很大&am…...

网站开发需要先学数据库么/网络营销在哪里学比较靠谱

1、curl仍然是最好的HTTP库&#xff0c;没有之一。 可以解决任何复杂的应用场景中的HTTP 请求2. 文件流式的HTTP请求比较适合处理简单的HTTP POST/GET请求&#xff0c;但不适用于复杂的HTTP请求3. PECL_HTTP扩展写代码更加简洁&#xff0c;省事&#xff0c; 但成熟度不好&#…...

帝国cms做门户网站/百度电脑端网页版入口

在CMakeLisits.txt里面指定编译的ARM 代码目录和DSP上代码的目录和DSP的目录&#xff0c;以及IDL文件的目录&#xff08;制定会放到DSP上执行的函数名字&#xff09; #ifndef EXAMPLE_INTERFACE_IDL #define EXAMPLE_INTERFACE_IDL #include "AEEStdDef.idl" in…...

做个商城网站要多少钱/杭州推广系统

问题截图&#xff1a; 添加#include<sys/mman.h>头文件可解决’PROT_WRITE’、‘MAP_SHARED’、未定义的问题。 现在还剩O_RDRW未定义的问题。 我再想想吧 先(~ ~) 这问题出现的原因是对应库文件的缺失&#xff0c;添加相应的库文件即可&#xff0c;但是我查了查资料后…...

国内开源建站cms/网店培训骗局

第一章 1.GUN与GPL 2.在用Linux系统centos社区版 商业版Redhat&#xff08;稳定&#xff09; 3.网络配置的文件 /etc/sysconfig/network-scripts/ifcfg-ens334.VM三种网络配置方式 第二章&#xff08;重点&#xff09; 1.用户和用户组管理  用户的增删改查 useradd userde…...

wordpress自定义文章添加标签/seo广州工作好吗

自建epel yum仓库并安装nginx1、创建 repo 文件2、yum repolist查看repolist3、安装 nginx4、验证 nginx 是否安装1、创建 repo 文件 [rootneo ~]# cat /etc/yum.repos.d/epel.repo [epel] nameepel repository baseurlhttps://epel.mirror.constant.com//7/x86_64/ gpgcheck0…...