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

react写一个简单的3d滚轮picker组件

1. TreeDPicker.tsx文件

原理就不想赘述了, 想了解的话, 网址在:

使用vue写一个picker插件,使用3d滚轮的原理_vue3中支持3d picker选择器插件-CSDN博客

import React, { useEffect, useRef, Ref, useState } from "react";
import Animate from "../utils/animate";
import _ from "lodash";
import "./Picker.scss";
import * as ReactDOM from "react-dom";
import MyTransition from "./MyTransition";interface IProps {selected?: number | string;cuIdx: number;pickerArr: string[]|number[];isShow: boolean;setIsShow: (arg1: boolean) => void;setSelectedValue: (arg1: number|string) => void;
}interface IFinger {startY: number;startTime: number;currentMove: number;prevMove: number;
}
type ICurrentIndex = number;const a = -0.003; // 加速度
let radius = 2000; // 半径--console.log(Math.PI*2*radius/LINE_HEIGHT)=>估算最多可能多少条,有较大误差,半径2000应该够用了,不够就4000
const LINE_HEIGHT = 36; // 文字行高
const FRESH_TIME = 1000 / 60; // 动画帧刷新的频率大概是1000 / 60
// 反正切=>得到弧度再转换为度数,这个度数是单行文字所占有的。
let singleDeg = 2 * ((Math.atan(LINE_HEIGHT / 2 / radius) * 180) / Math.PI);
const REM_UNIT = 37.5; // px转化为rem需要的除数
const SCROLL_CONTENT_HEIGHT = 300; // 有效滑动内容高度const TreeDPicker = (props: IProps) => {const pxToRem = (pxNumber) => {return Number(pxNumber / REM_UNIT) + "rem";};const heightRem = pxToRem(LINE_HEIGHT); // picker的每一行的高度--单位remconst lineHeightRem = pxToRem(LINE_HEIGHT); // picker的每一行的文字行高--单位remconst radiusRem = pxToRem(radius); // 半径--单位remconst { cuIdx, pickerArr, isShow, setIsShow, setSelectedValue } = props; // 解构props, 得到需要使用来自父页面传入的数据const[pickerIsShow, setPickerIsShow] = useState(props.isShow)useEffect(() => {setPickerIsShow(isShow)
}, [isShow])// 存储手指滑动的数据const finger0 = useRef<IFinger>({startY: 0,startTime: 0, // 开始滑动时间(单位:毫秒)currentMove: 0,prevMove: 0,});const finger = _.get(finger0, "current") || {};const currentIndex = useRef<ICurrentIndex>(0);const pickerContainer = useRef() as Ref<any>;const wheel = useRef() as Ref<any>;let isInertial = useRef<boolean>(false); // 是否正在惯性滑动// col-wrapper的父元素, 限制滚动区域的高度,内容正常显示(col-wrapper多余的部分截掉不显示)const getWrapperFatherStyle = () => {return {height: pxToRem(SCROLL_CONTENT_HEIGHT),};};// class为col-wrapper的style样式: 滚轮的外包装理想样式--展示半径的内容可见,另外的半径隐藏const getWrapperStyle = () => ({height: pxToRem(2 * radius),// 居中: 1/2直径 - 1/2父页面高度transform: `translateY(-${pxToRem(radius - SCROLL_CONTENT_HEIGHT / 2)})`,});// 当父元素(class为col-wrapper), 定位是relative, 高度是直径: 2 * radius, 子页面想要居中, top: (1/2直径)-(1/2*一行文字高度)const circleTop = pxToRem(radius - LINE_HEIGHT / 2); // 很重要!!!// col-wrapper的子元素 => 3d滚轮的内容区域样式--useRef=wheel的元素样式const getListTop = () => ({top: circleTop,height: pxToRem(LINE_HEIGHT),});// col-wrapper的子元素 => 参照一般居中的做法,[50%*父页面的高度(整个圆的最大高度是直径)]-居中内容块(文本的行高)的一半高度const getCoverStyle = () => {return {backgroundSize: `100% ${circleTop}`,};};// col-wrapper的子元素 => 应该也是参照居中的做法(注意减去两条边框线)const getDividerStyle = () => ({top: `calc(${circleTop} - ${pxToRem(0)})`,height: pxToRem(LINE_HEIGHT),});const animate = new Animate();function initWheelItemDeg(index) {// 初始化时转到父页面传递的下标所对应的选中的值// 滑到父页面传的当前选中的下标cuIdx处const num = -1 * index + Number(cuIdx);const transform = getInitWheelItemTransform(num);// 当前的下标return {transform: transform,height: heightRem,lineHeight: lineHeightRem,};}/*** 1、translate3d
在浏览器中,y轴正方向垂直向下,x轴正方向水平向右,z轴正方向指向外面。
z轴越大离我们越近,即看到的物体越大。z轴说物体到屏幕的距离。* */function getInitWheelItemTransform(indexNum) {// 初始化时转到父页面传递的下标所对应的选中的值// 滑动的角度: 该行文字下标 * 一行文字对应的角度const rotate3dValue = getMoveWheelItemTransform(indexNum * LINE_HEIGHT);return `${rotate3dValue} translateZ(calc(${radiusRem} / 1))`;}function getMoveWheelItemTransform(move) {// 初始化时转到父页面传递的下标所对应的选中的值const indexNum = Math.round(move / LINE_HEIGHT);// 滑动的角度: 该行文字下标 * 一行文字对应的角度const wheelItemDeg = indexNum * singleDeg;return `rotateX(${wheelItemDeg}deg)`;}function listenerTouchStart(ev) {ev.stopPropagation();isInertial.current = false; // 初始状态没有惯性滚动finger.startY = ev.targetTouches[0].pageY; // 获取手指开始点击的位置finger.prevMove = finger.currentMove; // 保存手指上一次的滑动距离finger.startTime = Date.now(); // 保存手指开始滑动的时间}function listenerTouchMove(ev) {ev.stopPropagation();// startY: 开始滑动的touch目标的pageY: ev.targetTouches[0].pageY减去const nowStartY = ev.targetTouches[0].pageY; // 获取当前手指的位置// finger.startY - nowStart为此次滑动的距离, 再加上上一次滑动的距离finger.prevMove, 路程总长: (finger.startY - nowStartY) + finger.prevMovefinger.currentMove = finger.startY - nowStartY + finger.prevMove;let wheelDom =_.get(wheel, "current") ||document.getElementsByClassName("wheel-list")[0];if (wheelDom) {wheelDom.style.transform = getMoveWheelItemTransform(finger.currentMove);}}function listenerTouchEnd(ev) {ev.stopPropagation();const _endY = ev.changedTouches[0].pageY; // 获取结束时手指的位置const _entTime = Date.now(); // 获取结束时间const v = (finger.startY - _endY) / (_entTime - finger.startTime); // 滚动完毕求移动速度 v = (s初始-s结束) / tconst absV = Math.abs(v);isInertial.current = true; // 最好惯性滚动,才不会死板animate.start(() => inertia({ start: absV, position: Math.round(absV / v), target: 0 })); // Math.round(absV / v)=>+/-1}/**用户结束滑动,应该慢慢放慢,最终停止。从而需要 a(加速度)* @param start 开始速度(注意是正数) @param position 速度方向,值: 正负1--向上是+1,向下是-1 @param target 结束速度*/function inertia({ start, position, target }) {if (start <= target || !isInertial.current) {animate.stop();finger.prevMove = finger.currentMove;getSelectValue(finger.currentMove); // 得到选中的当前下标return;}// 这段时间走的位移 S = (+/-)vt + 1/2at^2 + s1;const move =position * start * FRESH_TIME +0.5 * a * Math.pow(FRESH_TIME, 2) +finger.currentMove;const newStart = position * start + a * FRESH_TIME; // 根据求末速度公式: v末 = (+/-)v初 + atlet actualMove = move; // 最后的滚动距离let wheelDom =_.get(wheel, "current") ||document.getElementsByClassName("wheel-list")[0];// 已经到达目标// 当滑到第一个或者最后一个picker数据的时候, 不要滑出边界// 因为在开始的时候加了父页面传递的下标,这里需要减去才能够正常使用const minIdx = 0 - cuIdx;const maxIdx = pickerArr.length - 1 - cuIdx;if (Math.abs(newStart) >= Math.abs(target)) {if (Math.round(move / LINE_HEIGHT) < minIdx) {// 让滚动在文字区域内,超出区域的滚回到边缘的第一个文本处actualMove = minIdx * LINE_HEIGHT;} else if (Math.round(move / LINE_HEIGHT) >= maxIdx) {// 让滚动在文字区域内,超出区域的滚回到边缘的最后一个文本处actualMove = maxIdx * LINE_HEIGHT;}if (wheelDom)wheelDom.style.transition ="transform 700ms cubic-bezier(0.19, 1, 0.22, 1)";}// finger.currentMove赋值是为了点击确认的时候可以使用=>获取选中的值finger.currentMove = actualMove;if (wheelDom)wheelDom.style.transform = getMoveWheelItemTransform(actualMove);animate.stop();// animate.start(() => inertia.bind({ start: newStart, position, target }));}// 滚动时及时获取最新的当前下标--因为在初始化的时候减去了,所以要加上cuIdx,否则下标会不准确function getSelectValue(move) {const idx = Math.round(move / LINE_HEIGHT) + Number(cuIdx);currentIndex.current = idx;return idx;}function sure() {// 点击确认按钮getSelectValue(finger.currentMove);setSelectedValue(pickerArr[currentIndex.current]);setTimeout(() => {close();}, 0);}function close() {setTimeout(() => {setPickerIsShow(false);// 延迟关闭, 因为MyTransition需要这段事件差执行动画效果setTimeout(() => {setIsShow(false)}, 500);}, 0);} // 点击取消按钮useEffect(() => {const dom =_.get(pickerContainer, "current") ||document.getElementsByClassName("picker-container")[0];try {dom.addEventListener("touchstart", listenerTouchStart, false);dom.addEventListener("touchmove", listenerTouchMove, false);dom.addEventListener("touchend", listenerTouchEnd, false);} catch (error) {console.log(error);}return () => {const dom =_.get(pickerContainer, "current") ||document.getElementsByClassName("picker-container")[0];dom.removeEventListener("touchstart", listenerTouchStart, false);dom.removeEventListener("touchmove", listenerTouchMove, false);dom.removeEventListener("touchend", listenerTouchEnd, false);};}, [_.get(pickerContainer, "current")]);return ReactDOM.createPortal(<div className="picker-container"><div ref={pickerContainer}>{isShow+''}<MyTransition name="myPopup" transitionShow={pickerIsShow}>{isShow && (<section className="pop-cover" onClick={close}></section>)}</MyTransition><MyTransition name="myOpacity" transitionShow={pickerIsShow}>{isShow && (<section><div className="btn-box"><button onClick={close}>取消</button><button onClick={sure}>确认</button></div><divclassName="col-wrapper-father"style={getWrapperFatherStyle()}><div className="col-wrapper" style={getWrapperStyle()}><ul className="wheel-list" style={getListTop()} ref={wheel}>{_.map(pickerArr, (item, index) => {return (<liclassName="wheel-item"style={initWheelItemDeg(index)}key={"wheel-list-"+index}>{item+''}</li>);})}</ul><div className="cover" style={getCoverStyle()}></div><div className="divider" style={getDividerStyle()}></div></div></div></section>)}</MyTransition></div></div>,document.body);
};export default TreeDPicker;

2. scss文件:

@import "./common.scss";.picker-container {position: fixed;bottom: 0;left: 0;right: 0;// transition动画部分.myOpacity-enter,.myOpacity-leave-to {opacity: 0;// 因为picker滚动区域有过transform, 这里也写transform的话会导致本不该滚动的地方滚动了}.myOpacity-enter-active,.myOpacity-leave-active {opacity: 1;transition: all 0.5s ease;}.myPopup-enter,.myPopup-leave-to {transform: translateY(100px);}.myPopup-enter-active,.myPopup-leave-active {transition: all 0.5s ease;}// 透明遮罩.pop-cover {position: fixed;top: 0;left: 0;right: 0;height: 100vh;background: rgba(0, 0, 0, 0.5);z-index: -1;}// 确认 取消按钮box.btn-box {height: pxToRem(40px);background: rgb(112, 167, 99);display: flex;justify-content: space-between;font-size: pxToRem(16px);& button {background-color: rgba(0, 0, 0, 0);border: none;color: #fff;}}.col-wrapper-father {overflow: hidden;}//overflow: hidden=>截掉多余的部分,显示弹窗内容部分ul,li {list-style: none;padding: 0;margin: 0;}// 为了方便掌握重点样式,简单的就直接一行展示,其他的换行展示,方便理解.col-wrapper {position: relative;border: 1px solid #ccc;text-align: center;background: #fff;&>.wheel-list {position: absolute;width: 100%;transform-style: preserve-3d;transform: rotate3d(1, 0, 0, 0deg);.wheel-item {backface-visibility: hidden;position: absolute;left: 0;top: 0;width: 100%;border: 1px solid #eee;font-size: pxToRem(16px);}}&>.cover {position: absolute;left: 0;top: 0;right: 0;bottom: 0;background: linear-gradient(0deg, rgba(white, 0.6), rgba(white, 0.6)), linear-gradient(0deg,rgba(white, 0.6),rgba(white, 0.6));background-position: top, bottom;background-repeat: no-repeat;}&>.divider {position: absolute;width: 100%;left: 0;border-top: 1px solid #ccc;border-bottom: 1px solid #ccc;}}
}

3. transition组件(之前写了一篇文章有提到):

react简单写一个transition动画组件然后在modal组件中应用-CSDN博客

相关文章:

react写一个简单的3d滚轮picker组件

1. TreeDPicker.tsx文件 原理就不想赘述了, 想了解的话, 网址在: 使用vue写一个picker插件,使用3d滚轮的原理_vue3中支持3d picker选择器插件-CSDN博客 import React, { useEffect, useRef, Ref, useState } from "react"; import Animate from "../utils/an…...

Compose竖向列表LazyColumn

基础列表一 LazyColumn组件中用items加载数据&#xff0c;rememberLazyListState()结合rememberCoroutineScope()实现返回顶部。 /*** 基础列表一*/ Composable fun Items() {Box(modifier Modifier.fillMaxSize()) {val context LocalContext.currentval dataList arrayLi…...

6.自定义相机控制器

愿你出走半生,归来仍是少年&#xff01; Cesium For Unity自带的Dynamic Camera,拥有优秀的动态展示效果&#xff0c;但是其对于场景的交互方式用起来不是很舒服。 通过模仿Cesium JS 的交互方式&#xff0c;实现在Unity中的交互&#xff1a; 通过鼠标左键拖拽实现场景平移通过…...

一文带你GO语言入门

什么是go语言? Go语言(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。Go语言的主要特点包括:- 简洁和简单 - 语法简单明快,易于学习和使用 特点 高效 编译速度快,执行效率高 并发支持 原生支持并发,利用goroutine实现高效的并发…...

前后端小项目链接

1.vue的创建 vue的项目创建 1.1 vue create vue_name 1.2 Babel Router(路由) CSS Pre-processors 路由可通过&#xff1a;npm i vue-router3.5.2 -S 下载 1.3less 1.4 In dedicated config files 1.5 启动命令&#xff1a;npm run serve 端口号在vue.config。js中配置 devS…...

编辑器功能:用一个快捷键来【锁定】或【解开】Inspector面板

一、需求 我有一个脚本&#xff0c;上面暴露了许多参数&#xff0c;我要在场景中拖物体给它进行配置。 如果不锁定Inspector面板的话&#xff0c;每次点击物体后&#xff0c;Inspector的内容就是刚点击的物体的内容&#xff0c;而不是挂载脚本的参数面板。 二、 解决 &…...

Vue 网络处理 - axios 异步请求的使用,请求响应拦截器(最佳实践)

目录 一、axiox 1.1、axios 简介 1.2、axios 基本使用 1.2.1、下载核心 js 文件. 1.2.2、发送 GET 异步请求 1.2.3、发送 POST 异步请求 1.2.4、发送 GET、POST 请求最佳实践 1.3、请求响应拦截器 1.3.1、拦截器解释 1.3.2、请求拦截器的使用 1.3.3、响应拦截器的使…...

关于W5500网卡使用过程的部分问题记录

某个项目中用到了W5500这种自带网络协议栈的网卡芯片&#xff0c;由于该项目开发时间很紧&#xff0c;就临时网上买了一些模块拼凑到了一套系统&#xff0c;经过验证果真这种拼积木的方法只能用在学生实验开发中&#xff0c;真不能拿来做工程应用&#xff0c;硬件太不稳定很容易…...

Unity DOTS World Entity ArchType Component EntityManager System概述

最近DOTS终于发布了正式的版本, 我们来分享以下DOTS里面地几个关键概念&#xff0c;方便大家上手学习掌握Unity DOTS开发。 Unity DOTS 中所有的Entities 都是被放到World世界中。每个Entity在它所在的World里面有唯一不同的ID号来区分。DOTS项目中可以同时有多个World。每个W…...

最详细STM32,cubeMX 点亮 led

这篇文章将详细介绍 如何在 stm32103 板子上点亮一个LED. 文章目录 前言一、开发环境搭建。二、LED 原理图解读三、什么是 GPIO四、cubeMX 配置工程五、解读 cubeMX 生成的代码六、延时函数七、控制引脚状态函数点亮 LED 八、GPIO 的工作模式九、为什么使用推挽输出驱动 LED总结…...

论文阅读:Image-to-Lidar Self-Supervised Distillation for Autonomous Driving Data

目录 摘要 Motivation 整体架构流程 技术细节 雷达和图像数据的同步 小结 论文地址: [2203.16258] Image-to-Lidar Self-Supervised Distillation for Autonomous Driving Data (arxiv.org) 论文代码&#xff1a;GitHub - valeoai/SLidR: Official PyTorch implementati…...

前端版本控制工具,常见的Git 和SVN

目录 前言GitGit简介Git的优势Git常用指令常见的Git服务 SVN (Subversion)SVN简介SVN的优势SVN常用指令SVN与Git的区别 &#x1f44d; 点赞&#xff0c;你的认可是我创作的动力&#xff01; ⭐️ 收藏&#xff0c;你的青睐是我努力的方向&#xff01; ✏️ 评论&#xff0c;你…...

C++ —— Tinyxml2在Vs2017下相关使用2(较文1更复杂,附源码)

相关链接 C —— Tinyxml2在Vs2017下相关使用1&#xff08;附源码&#xff09; tinyxml2简介 TinyXML2是一个简单&#xff0c;小巧&#xff0c;高效&#xff0c;CXML解析器&#xff0c;可以很容易地集成到其他程序中。TinyXML-2解析一个XML文档&#xff0c;并从中构建一个 可以…...

阿里内推强推的并发编程学习笔记,原理+实战+面试题,面面俱到!

并发编程 谈到并发编程&#xff0c;可能很多人都有过经验&#xff0c;甚至比我了解的更多。 那么并发与并行的区别又是什么&#xff1f; 并发编程是编程中的核心问题&#xff0c;实践中&#xff0c;当人们希望利用计算机处理一些现实世界问题&#xff0c;以及希望同时处理多…...

域名注册查询流程

域名注册查询怎么查域名是否被注册?域名注册查询如何查域名的过期时间和注册商?域名注册查询用什么工具?下面是关于域名注册查询流程介绍。 1、域名注册查询可以用什么工具? 这里可以使用聚查工具&#xff0c;聚查包括&#xff1a;whois 查询、建站历史查询、反链查询、P…...

【Linux学习笔记】代码编辑工具vim

1. vim工具基本模式的转换2. vim命令模式下的各种编辑命令2.1. 光标行定位2.2. 光标自由定位2.3. 复制粘贴2.4. 删除2.5. 文本的大小写替换2.6. 文本的替换2.7. 文本的前删后删2.8. 撤销操作 3. vim底行模式下的命令3.1. 设置行号与取消设置行号3.2. 分屏操作3.3. 在不退出vim的…...

Android Boring SSL

前期设置 SSLContext.getInstance(“TLS”)SSLContext.init()SSLContext.getSocketFactory()SSLSocketFactory.createSocket()NativeSsl.newInstance()BioWrapper 的创建ConscryptEngineSocket.startHandshake() TLS协商 state_start_connect(TLS)state_enter_early_data(TLS)s…...

中国人民大学与加拿大女王大学金融硕士项目:开启你的金融精英之路

在全球化的今天&#xff0c;金融行业的发展日新月异&#xff0c;对金融人才的需求也日益增长。为了满足这一需求&#xff0c;中国人民大学与加拿大女王大学联合推出了金融硕士项目&#xff0c;旨在培养具有国际视野、专业素养和创新能力的金融精英。 这一开创性的项目将两大世…...

HashSet编程小案例,控制生日和姓名。重写HashCode

Java编程&#xff1a; 定义员工Employee类&#xff0c;该类包含&#xff1a;private成员属性name&#xff0c;sal&#xff0c;birthday(MyDate类型)&#xff0c; 其中birthday为MyDate类型(属性包括&#xff1a;year&#xff0c;month&#xff0c;day)&#xff0c; 要求&…...

虚幻阴影整理

虚拟阴影贴图&#xff08;VSM&#xff09;是一种全新的阴影贴图方法&#xff0c;可以提供稳定的高分辨率阴影。通过与虚幻引擎5的Nanite虚拟几何体、Lumen全局光照和反射以及世界分区功能结合使用&#xff0c;它能够实现电影级的品质效果&#xff0c;为大型开放场景提供光照。 …...

MySQL数据库(一)

数据库 —— 基础 1. 数据库 DataBase 数据库管理系统 2. SQL语言2.1 DDL数据定义语言2.1.1 数据库基础操作2.1.2 数据表基础操作2.1.3 字段基础操作 2.2 DML表记录管理2.2.1 插入数据INSERT2.2.2 更新数据UPDATE2.2.3 删除数据DELETE 3. SQL数据类型3.1 数值类型3.1.1 整数类型…...

C++11 新特性

C11 新特性 C11 新特性统一的列表初始化声明auto 关键字decltype 关键字nullptr 关键字 关键字 using使用 using 在子类中引用基类的成员使用 using 关键字定义类型别名 范围-based for 循环右值引用和移动语义左值引用和右值引用右值引用使用场景和意义完美转发 lambda表达式移…...

排查手机应用app微信登录问题不跳转失败原因汇总及其解决方案

经过最近我发的文章,我个人觉得解决了不少小问题,因为最近很小白的问题已经没有人私聊问我了,我总结了一下排查手机应用app微信登录问题不跳转失败的原因汇总及其解决方案在这篇文章中,分析微信登录不跳转的原因,并提供解决方案。希望通过这篇文章,能够帮助大家顺利解决这…...

软考高级系统架构设计师系列之:数学与经济管理

软考高级系统架构设计师系列之:数学与经济管理 一、数学与经济管理二、图论应用-最小生成树三、图论应用-最短路径四、图论应用-网络与最大流量五、运筹方法-线性规划六、运筹方法-动态规划七、运筹方法-转移矩阵八、运筹方法-排队论九、运筹方法-决策-不确定决策十、运筹方法…...

基于Scrapyd与Gerapy部署scrapy爬虫方案【可用于分布式爬虫部署】

scrapyd部署爬虫 Scrapyd 是一个基于 Scrapy 的开源项目&#xff0c;它提供了一个简单的方式来部署、运行和监控 Scrapy 爬虫。它是一个用于集成 Scrapy 爬虫到分布式架构中的工具&#xff0c;允许您在分布式环境中运行爬虫&#xff0c;并提供了一组 Web API&#xff0c;用于管…...

ST-SSL:基于自监督学习的交通流预测模型

文章信息 文章题为“Spatio-Temporal Self-Supervised Learning for Traffic Flow Prediction”&#xff0c;是一篇发表于The Thirty-Seventh AAAI Conference on Artificial Intelligence (AAAI-23)的一篇论文。该论文主要针对交通流预测任务&#xff0c;结合自监督学习&#…...

如何处理C++中的字符串编码和国际化?

在C中处理字符串编码和国际化的常用方式如下&#xff1a; 字符串编码&#xff1a; 使用UTF-8编码&#xff1a;UTF-8是一种可变字节长度的编码方式&#xff0c;广泛用于表示 Unicode 字符。C中的字符串类型std::string默认使用的是UTF-8编码。可以通过使用宽字符类型std::wstrin…...

DH48WK 温控器参数设置

北京东昊力伟科技有限责任公司 温控仪、温度控制器 产品特点&#xff1a; 可外接温度传感器Pt100、Cu50、K、E、J、N、T、R、S、B兼容输入&#xff1b;PID控制输出、位式控制输出、继电器报警输出&#xff1b;控温能满足设定温度值的0.2℃&#xff1b;既可用于加热控制、也可…...

【文档智能】多模态预训练模型及相关数据集汇总

前言 大模型时代&#xff0c;在现实场景中或者企业私域数据中&#xff0c;大多数数据都以文档的形式存在&#xff0c;如何更好的解析获取文档数据显得尤为重要。文档智能也从以前的目标检测&#xff08;版面分析&#xff09;阶段转向多模态预训练阶段&#xff0c;本文将介绍目…...

超全整理,性能测试——数据库索引问题定位+分析(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、数据库服务器添…...