【vue scrollTo 数据无限滚动 】
vue数据无限滚动
参考来源 Vue3 实现消息无限滚动的新思路 —— 林三心不学挖掘机
完整代码中项目中使用了vuetify,估div内的class会代表了对应的样式,根据需要自行删减。
功能实现主要依赖js代码部分。
鼠标悬浮停止滚动,鼠标离开恢复滚动在最后(区别就是将scroll()方法从onMounted中提取出来了)。
vue3代码
<template><div class="scroll-container" ref="scrollRef"><div v-for="(item, index) in list" :key="index" style="height: 40px; line-height: 40px;">{{ item.title }}</div></div>
</template><script setup>
import { onMounted, ref } from 'vue'
defineOptions({name: 'publicRecruitment-bountyDisplay'})// 容器的 dom 节点
const scrollRef = ref()
// 模拟列表数据
const dataSource = new Array(10).fill(0).map((_, index) => ({title: `这是一条信息${index}`
}))
const list = ref([...dataSource])// 记录原始数据的长度
const len = dataSource.length
onMounted(() => {// 滚动的距离let top = 0// 索引let index = 0const scroll = () => {// 垂直方向滚动scrollRef.value?.scrollTo({top: top++})if (top % 40 === 0) {// 哪一项滚不见了,就拿这一项 push 到列表中const target = list.value[index]if (target) list.value.push(target)if (index < (len - 1)) {// 不断递增index++} else {// 刚好滚动完一轮,重新来过,初始化数据top = 0index = 0scrollRef.value?.scrollTo({top: 0})list.value = [...dataSource]}}// 不断滚动requestAnimationFrame(scroll)}scroll()
})
</script><style lang="scss" scoped>
.scroll-container {// 防止有滚动条出现overflow: hidden;height: 150px;
}
</style>
兼容升级版本
1.如果数据长度形成的总高度少于容器高度,不设置滚动
2.如果数据长度仅高于容器高度不足一个数据单位的长度会出现抖动滚动。解决方法:将数据复制一份
删减代码

<!-- 滚动展示 -->
<template><div style="height: 100%; width: 100%;"><div class="mb-3" style="font-size: 13px; color: #666;">无缝衔接滚动</div><!-- 滚动 --><divclass="scroll-container"ref="scrollRef"style="height: calc(100% - 32px); overflow: hidden; font-size: 13px;color: #333;"><!-- 数据list --><divv-for="(item) in list":key="item.name"class="d-flex justify-space-between align-center":style="`height: ${dataItemHeight}px;`"><div class="ml-2">{{ item.name }}</div></div></div></div>
</template><script setup>
import { onMounted, ref } from 'vue'
defineOptions({name: 'publicRecruitment-bountyDisplay'})
// 滚动实现代码部分
const dataItemHeight = 40
// 容器的 dom 节点
const scrollRef = ref()
// // 模拟列表数据
let listSource = new Array(10).fill(0).map((_, index) => ({ name: `name${index}`}))
const list = ref([...listSource])// 记录原始数据的长度
let len = listSource.length
onMounted(() => {// 滚动的距离let top = 0// 索引let index = 0const scroll = () => {// 垂直方向滚动scrollRef.value?.scrollTo({top: top++,})if (top % dataItemHeight === 0) {// 哪一项滚不见了,就拿这一项 push 到列表中const target = list.value[index]if (target) list.value.push(target)if (index < len - 1) {// 不断递增index++} else {// 刚好滚动完一轮,重新来过,初始化数据top = 0index = 0scrollRef.value?.scrollTo({top: 0,})list.value = [...listSource]}}// 不断滚动requestAnimationFrame(scroll)}// 如果数据长度形成的总高度少于容器高度,不设置滚动const clientHeight = scrollRef.value?.clientHeightif (len*dataItemHeight > clientHeight) {if ((len - 1)*dataItemHeight < clientHeight) {// 如果clientHeight刚好大于len*dataItemHeight,但不满足(len+1)*dataItemHeight会出现抖动。// 解决方法:将数据复制一份listSource = listSource.concat(...Array.from({ length: 1 }, () => [...listSource]))list.value = listSourcelen = listSource.length}scroll()}
})
</script>
<style lang="scss" scoped>
.red {color: red;
}
.ellipsisText {// width: 120px;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;
}
</style>
完整代码

<!-- 滚动展示 -->
<template><div style="height: 100%; width: 100%;"><div class="mb-3" style="font-size: 13px; color: #666;">最近30天已有<span class="red">68人</span>提现成功,累计提现<span class="red">¥9450</span></div><!-- 滚动 --><divclass="scroll-container"ref="scrollRef"style="height: calc(100% - 32px); overflow: hidden; font-size: 13px;color: #333;"><!-- 数据list --><divv-for="(item) in list":key="item[keyText] || item.name"class="d-flex justify-space-between align-center":style="`height: ${dataItemHeight}px;`"><!-- 头像、用户名 --><div class="d-flex align-center"><v-avatar size="30" :image="item.avatar || 'https://minio.citupro.com/dev/menduner/7.png'"></v-avatar><div class="ml-2">{{ formatName(item.name) }}</div><!-- <div class="ml-2">{{ item.name }}</div> --></div><div class="d-flex" style="width: calc(100% - 65px);"><!-- 内容 --><div class="d-flex ellipsisText mx-4" style="flex: 1;"><div>推荐到</div><div class="ellipsisText ml-1" style="max-width: 100px;">{{ item.company }}</div><div class="ellipsisText ml-1" style="max-width: 60px;">{{ item.job }}</div></div><!-- 赏金 --><div>提现¥<span class="red">{{ item.money }}</span></div></div></div></div></div>
</template><script setup>
import { onMounted, ref } from 'vue'defineOptions({name: 'publicRecruitment-bountyDisplay'})
defineProps({keyText: {type: String,default: 'id'}
})
const avatarList = ['https://img0.baidu.com/it/u=230622178,1565949306&fm=253&fmt=auto&app=138&f=JPEG?w=449&h=300','https://img0.baidu.com/it/u=1401084042,2724457850&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=726','https://img1.baidu.com/it/u=3995643348,1848098846&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=800','https://img0.baidu.com/it/u=230622178,1565949306&fm=253&fmt=auto&app=138&f=JPEG?w=449&h=300','https://img0.baidu.com/it/u=1401084042,2724457850&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=726','https://img1.baidu.com/it/u=3995643348,1848098846&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=800','https://img0.baidu.com/it/u=230622178,1565949306&fm=253&fmt=auto&app=138&f=JPEG?w=449&h=300',
]
let listSource = []
for (let index = 0; index < 68; index++) {const obj = {id: 'id' + (index+1),name: '用户' + (index+1),// name: (index+1),avatar: avatarList[index % 7],company: '某某公司' + (index+1),job: '某某职位' + (index+1),money: index*index*(100 - index) || 100,}listSource.push(obj)
}// 用户名加*号
const formatName = (name) => {if (!name.length) {return name} else if (name.length === 1) { return name // 如果名字只有一个字,则直接返回该字 } else if (name.length === 2) { return name.charAt(0) + '*' // 如果名字有两个字,则返回第一个字后跟一个星号 } else { return name.charAt(0) + '**' // 如果名字有多于两个字,则返回第一个字后跟两个星号 }
}// 滚动实现代码部分
const dataItemHeight = 40
// 容器的 dom 节点
const scrollRef = ref()
// // 模拟列表数据
// const listSource = new Array(10).fill(0).map((_, index) => ({ title: `这是一条信息${index}`}))
const list = ref([...listSource])// 记录原始数据的长度
let len = listSource.length
onMounted(() => {// 滚动的距离let top = 0// 索引let index = 0const scroll = () => {// 垂直方向滚动scrollRef.value?.scrollTo({top: top++,})if (top % dataItemHeight === 0) {// 哪一项滚不见了,就拿这一项 push 到列表中const target = list.value[index]if (target) list.value.push(target)if (index < len - 1) {// 不断递增index++} else {// 刚好滚动完一轮,重新来过,初始化数据top = 0index = 0scrollRef.value?.scrollTo({top: 0,})list.value = [...listSource]}}// 不断滚动requestAnimationFrame(scroll)}// 如果数据长度形成的总高度少于容器高度,不设置滚动const clientHeight = scrollRef.value?.clientHeightif (len*dataItemHeight > clientHeight) {if ((len - 1)*dataItemHeight < clientHeight) {// 如果clientHeight刚好大于len*dataItemHeight,但不满足(len+1)*dataItemHeight会出现抖动。// 解决方法:将数据复制一份listSource = listSource.concat(...Array.from({ length: 1 }, () => [...listSource]))list.value = listSourcelen = listSource.length}scroll()}
})
</script>
<style lang="scss" scoped>
.red {color: red;
}
.ellipsisText {// width: 120px;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;
}
</style>
完整代码二(鼠标悬浮停止滚动,鼠标离开恢复滚动)
<!-- 滚动展示 -->
<template><div style="height: 100%; width: 100%;" @mouseover="handleMouseover" @mouseleave="handleMouseleave"><div class="mb-3" style="font-size: 13px; color: #666;">最近30天已有<span class="red">68人</span>提现成功,累计提现<span class="red">¥9450</span></div><!-- 滚动 --><divclass="scroll-container"ref="scrollRef"style="height: calc(100% - 32px); overflow: hidden; font-size: 13px;color: #333;"><!-- 数据list --><divv-for="(item) in list":key="item[keyText] || item.name"class="d-flex justify-space-between align-center":style="`height: ${dataItemHeight}px;`"><!-- 头像、用户名 --><div class="d-flex align-center"><v-avatar size="30" :image="item.avatar || 'https://minio.citupro.com/dev/menduner/7.png'"></v-avatar><div class="ml-2">{{ formatName(item.name) }}</div></div><div class="d-flex" style="width: calc(100% - 65px);"><!-- 内容 --><div class="d-flex ellipsisText mx-4" style="flex: 1;"><div>推荐到</div><div class="ellipsisText ml-1" style="max-width: 100px;">{{ item.company }}</div><div class="ellipsisText ml-1" style="max-width: 60px;">{{ item.job }}</div></div><!-- 赏金 --><div>提现¥<span class="red">{{ item.money }}</span></div></div></div></div></div>
</template><script setup>
import { onMounted, ref } from 'vue'defineOptions({name: 'publicRecruitment-bountyDisplay'})
defineProps({keyText: {type: String,default: 'id'}
})
const avatarList = ['https://img0.baidu.com/it/u=230622178,1565949306&fm=253&fmt=auto&app=138&f=JPEG?w=449&h=300','https://img0.baidu.com/it/u=1401084042,2724457850&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=726','https://q7.itc.cn/q_70/images03/20240423/6d236fae5c8f44ed9b60d977f32debb7.jpeg','https://q1.itc.cn/q_70/images03/20240609/1c1be14298be4dbe978e55bde6e958b0.jpeg','https://q4.itc.cn/q_70/images03/20240528/298d4abda5e4469d98fa77e7cde46525.jpeg','https://q5.itc.cn/q_70/images03/20240520/ceb0d77d1be24eea8cd3826994eac1c1.jpeg','https://img1.baidu.com/it/u=3995643348,1848098846&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=800',
]
let listSource = []
for (let index = 0; index < 68; index++) {const obj = {id: 'id' + (index+1),name: '用户' + (index+1),avatar: avatarList[index % 7],company: '某某公司' + (index+1),job: '某某职位' + (index+1),money: index*index*(100 - index) || 100,}listSource.push(obj)
}// 用户名加*号
const formatName = (name) => {if (!name.length) {return name} else if (name.length === 1) { return name // 如果名字只有一个字,则直接返回该字 } else if (name.length === 2) { return name.charAt(0) + '*' // 如果名字有两个字,则返回第一个字后跟一个星号 } else { return name.charAt(0) + '**' // 如果名字有多于两个字,则返回第一个字后跟两个星号 }
}// 滚动实现代码部分
const dataItemHeight = 40 // 单位高度
const scrollRef = ref() // 容器的 dom 节点
const list = ref([...listSource]) // 滚动数据列表
let len = listSource.length // 记录原始数据的长度
const scrollItem = ref(null)
let top = 0 // 滚动的距离
let index = 0 // 索引
const scroll = () => {// 垂直方向滚动scrollRef.value?.scrollTo({top: top++,})if (top % dataItemHeight === 0) {// 哪一项滚不见了,就拿这一项 push 到列表中const target = list.value[index]if (target) list.value.push(target)if (index < len - 1) {// 不断递增index++} else {// 刚好滚动完一轮,重新来过,初始化数据top = 0index = 0scrollRef.value?.scrollTo({top: 0,})list.value = [...listSource]}}// 不断滚动scrollItem.value = requestAnimationFrame(scroll)// setTimeout(() => { scrollItem.value = requestAnimationFrame(scroll) }, 20) // 延迟滚动-> 20 : 1px。即:1秒滚动50px
}
const handleMouseover = () => { cancelAnimationFrame(scrollItem.value) } //暂停滚动
const handleMouseleave = () => { scroll() } // 恢复滚动
onMounted(() => {// 如果数据长度形成的总高度少于容器高度,不设置滚动const clientHeight = scrollRef.value?.clientHeightif (len*dataItemHeight > clientHeight) {if ((len - 1)*dataItemHeight < clientHeight) {// 如果clientHeight刚好大于len*dataItemHeight,但不满足(len+1)*dataItemHeight会出现抖动。// 解决方法:将数据复制一份listSource = listSource.concat(...Array.from({ length: 1 }, () => [...listSource]))list.value = listSourcelen = listSource.length}scroll() // 启动滚动}
})
</script>
<style lang="scss" scoped>
.red {color: red;
}
.ellipsisText {// width: 120px;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;
}
</style>相关文章:
【vue scrollTo 数据无限滚动 】
vue数据无限滚动 参考来源 Vue3 实现消息无限滚动的新思路 —— 林三心不学挖掘机 完整代码中项目中使用了vuetify,估div内的class会代表了对应的样式,根据需要自行删减。 功能实现主要依赖js代码部分。 鼠标悬浮停止滚动,鼠标离开恢复滚动在…...
MinIO在Linux环境中的使用
MinIO 是一个高性能的对象存储服务,兼容 Amazon S3 API。它设计用于大规模数据存储,可以很好地处理大数据集和高并发请求。如果你想在 Linux 系统上安装 MinIO,并开放必要的端口以便外部访问。 Vmware下载安装和linux安装这里就不在赘述了&a…...
免费内网穿透工具 ,快解析内网穿透解决方案
在IPv4公网IP严重不足的环境下,内网穿透技术越来越多的被人们所使用,使用内网穿透技术的好处有很多。 1:无需公网ip 物以稀为贵,由于可用的公网IP地址越来越少,价格也是水涨船高,一个固定公网IP一年的成本…...
踩坑——VS添加相对路径
需求:我需要将模型放到程序里面。 过程:附加包含目录添加目录,发现找不到onnx模型文件。我就想是不是相对路径不对,该来搞去都不对。 解决办法: 相对路径值得是运行程序的当下环境,什么是运行程序呢&…...
HTML【介绍】
HTML【介绍】 一、Web认知 1.网页组成 文字、图片、音频、视频、超链接 2.五大浏览器 IE浏览器、火狐浏览器(Firefox)、谷歌浏览器(Chrome)、Safari浏览器、欧朋浏览器(Opera) 3.Web标准的构成 HTML…...
网络安全:Web 安全 面试题.(XSS)
网络安全:Web 安全 面试题.(XSS) 网络安全面试是指在招聘过程中,面试官会针对应聘者的网络安全相关知识和技能进行评估和考察。这种面试通常包括以下几个方面: (1)基础知识:包括网络基础知识、操作系统知…...
Ubuntu网络管理命令:netstat
安装Ubuntu桌面系统(虚拟机)_虚拟机安装ubuntu桌面版-CSDN博客 顾名思义,netstat命令不是用来配置网络的,而是用来查看各种网络信息的,包括网络连接、路由表以及网络接口的各种统计数据等。 netstat命令的基本语法如…...
CV预测:快速使用DenseNet神经网络
AI预测相关目录 AI预测流程,包括ETL、算法策略、算法模型、模型评估、可视化等相关内容 最好有基础的python算法预测经验 EEMD策略及踩坑VMD-CNN-LSTM时序预测对双向LSTM等模型添加自注意力机制K折叠交叉验证optuna超参数优化框架多任务学习-模型融合策略Transform…...
竞赛选题 python 机器视觉 车牌识别 - opencv 深度学习 机器学习
1 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 基于python 机器视觉 的车牌识别系统 🥇学长这里给一个题目综合评分(每项满分5分) 难度系数:3分工作量:3分创新点:3分 🧿 更多资…...
zerotier-one自建根服务器方法二
一、简介 zerotier-one免费账户有25设备的限制,如果自己的设备多了就需要付费。不过zerotier-one是开源软件,我们可以自己建立根服务器,不用付费速度还很快。 由于时间关系上一篇文章没有写完,今天继续。 二、准备工作 准备一…...
【论文通读】SeeClick: Harnessing GUI Grounding for Advanced Visual GUI Agents
SeeClick: Harnessing GUI Grounding for Advanced Visual GUI Agents 前言AbstractMotivationMethodGUI grounding for LVLMsData ConstructionTraining Details ScreenSpotExperimentsGUI Grounding on ScreenSpotVisual GUI Agent TasksMiniWobAITWMind2WebOther experiment…...
Ubuntu20.04离线安装Docker
1.下载3个docker离线安装包,下载网址: https://download.docker.com/linux/ubuntu/dists/xenial/pool/stable/amd64/ 2.把3个离线安装包拷贝到ubuntu本地执行以下命令 sudo dpkg -i containerd.io_1.4.6-1_amd64.deb sudo dpkg -i docker-ce-cli_20.1…...
AI大模型战争:通用与垂直,谁将领跑未来?
文章目录 📑引言一、通用大模型:广泛适用,实力不容小觑1.1 强大的泛化能力1.2 广泛的适用场景 二、垂直大模型:专注深度,精准解决问题2.1 深度专注,精准度高2.2 快速落地与普及 三、通用与垂直:…...
计算机网络之TCP的三次握手和四次挥手
一.有关TCP协议的几个概念 1.1TCP协议的基本概念: TCP协议是传输层的一个协议,它支持全双工通信,是主机对主机之间数据的可靠传输,是一个连接导向的协议。 1.2连接: 连接是通信双方的一个约定,它的目的是让…...
JupyterLab使用指南(八):更改JupterLab左侧默认打开目录
在JupyterLab中,默认打开路径通常是由其配置文件中的root_dir设置决定的。如果你没有特意设置这个配置项,JupyterLab可能会使用当前用户的主目录或者上一次关闭时的路径作为默认打开路径。 更改JupyterLab默认路径的操作在不同操作系统下大体相似&…...
Android SurfaceFlinger——HWC Adapter初始化(五)
上一篇文章对 HWC 硬件加载流程进行了分析,在加载完成后开始创建 HAL 实例时,首先需要对 hwc2_device_t 的适配器进行初始化,这里我们主要分析 HWC Adapter 的创建流程。 一、创建HWC Adapter 在创建 HAL 实例之前,我们先来看一下 HWC Adapter 的创建。 1、createHalWith…...
泛微开发修炼之旅--17基于Ecology短信平台,实现后端自定义二开短信发送方案及代码示例
文章链接:17基于Ecology短信平台,实现后端自定义二开短信发送方案及代码示例...
SpringMVC系列二: 请求方式介绍
RequestMapping 💞基本使用💞RequestMapping注解其它使用方式可以修饰类和方法可以指定请求方式可以指定params和headers支持简单表达式支持Ant 风格资源地址配合PathVariable 映射 URL 绑定的占位符注意事项和使用细节课后作业 上一讲, 我们学习的是Spr…...
大学湖北中医药大学法医学试题及答案,分享几个实用搜题和学习工具 #微信#学习方法#职场发展
今天分享拥有拍照搜题、文字搜题、语音搜题、多重搜题等搜题模式,可以快速查找问题解析,加深对题目答案的理解。 1.快练题 这是一个网站 找题的网站海量题库,在线搜题,快速刷题~为您提供百万优质题库,直接搜索题库名称,支持多种刷题模式:顺序练习、语…...
C# 关于通讯观察线程(1) -- 开启通讯线程
通讯观察线程是个有意思,又是非常实用的功能。 具体怎么实现呢,我们来看看主要过程的伪代码。对于高手这也许很简单,但是要用好也是需要实践到通讯的流程正确,同时应对好网络故障等。 先在合适的地方启动观察线程: …...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...
云原生周刊:k0s 成为 CNCF 沙箱项目
开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...

