首页/新闻资讯/正文详情

从零手写 Vue3 通用分页组件:状态管理与页码计算全解析

发布时间:2026/9/24 21:30:08 来源:云帆数科 栏目:资讯中心
从零手写 Vue3 通用分页组件:状态管理与页码计算全解析
分页组件是后台管理系统里出现频率最高的组件之一但很多项目写着写着就乱套了新页面复制一份老代码改一改参数再遇到地方就再复制一份。等到后端接口从 currentPage 变成 pageNum前端就得满项目找人肉替换。这篇文章我以 Vue 3 为例从零手写一个通用分页组件把状态管理、页码计算、事件抛发、数据请求协同这些核心环节全部拆开讲清楚顺便把我在真实项目中踩过的坑一并整理出来。不管你是刚接触前端封装还是已经写过若干组件想梳理一下设计思路这份实践记录应该都能给你一些参考。1. 先搞清楚分页组件到底在解决什么问题1.1 从业务痛点说起分页的本质是把数据分块展示但它背后牵扯的东西其实不少当前页码、每页条数、总条数、总页数这四个状态是分页的四件套。除此之外还有页码列表如何生成、点击页码时如何通知外部、跨页选择每页条数之后要不要自动回退页码等等问题。很多新手第一次写分页就是在页面里堆代码const page ref(1) const pageSize ref(10) const total ref(0) function loadData() { api.getList({ page: page.value, pageSize: pageSize.value }).then(res { data.value res.data.list total.value res.data.total }) } function changePage(p) { page.value p loadData() }三个页面复制三份这类代码本身并不可怕。可怕的是当项目膨胀每页条数变化、排序字段变化、搜索条件变化都开始影响加载逻辑时散落在各个页面的重复代码会变成维护的噩梦。封装分页组件本质上就是把分页状态管理和页码UI渲染这两件事从业务代码中剥离出来让业务方只关心数据加载这一个动作。1.2 封装前先想清楚的三个问题动手写组件之前有三件事必须想明白。第一组件是受控还是非受控。受控意味着当前页码由父组件传入组件内部只是展示非受控则是组件自己维护页码状态。我用下来更推荐折中方案组件自己维护内部状态但同时暴露 setPage、setPageSize 这类方法供外部干预再通过事件把变化告诉父组件。第二组件要不要内置请求逻辑。这是争议最大的点。有的封装风格是分页组件 usePagination 组合式函数完全解耦组件管 UI函数管请求有的则是父组件把加载函数传给子组件子组件内部自己调用。我的建议是分页组件本身不直接发请求但请求逻辑必须有一个独立的可复用层否则组件绑定具体接口换个项目就废了。第三边界条件如何处理。没有数据、只有一页、总数为 0、接口返回异常、最后一页删除数据后页码越界……这些问题不提前想好上线之后就会出现明明有数据但页面不显示的诡异 bug。封装分页组件时这些边界场景要在一开始就规划进设计里而不是每个页面各自打补丁。2. 分页组件的核心设计思路2.1 组件要管什么状态、交互、数据流先看状态。分页组件的核心状态是四个状态类型说明currentPagenumber当前页码从 1 开始pageSizenumber每页条数默认 10totalnumber数据总条数由父组件或者数据请求层写入totalPagesnumber总页数由 total 和 pageSize 计算得出这四个状态中totalPages 是派生状态不用单独维护每次渲染时计算就行。这里有一个容易踩的坑很多人习惯在组件里监听 total 变化后手动计算 totalPages但其实在 computed 里做派生计算就够了省掉一大半同步逻辑。再看交互。分页组件的交互可以拆成三块。页码切换点击数字页码、上一页、下一页触发 currentPage 改变。快速跳转输入页码回车跳转需要控制输入范围。每页条数切换改变 pageSize触发数据重新加载并且需要判断当前页码是否需要回退。数据流的走向上我的设计原则是单向数据流 事件回传。组件内部维护的 currentPage 和 pageSize 变化时不直接通知父组件去改数据而是抛出一个 change 事件事件参数包含最新的 page 和 pageSize。父组件在 change 回调里重新拉数据拿到最新 total 后再通过 prop 回传给组件。这样组件始终处于数据驱动的状态不会出现组件和父组件互相抢状态的死锁问题。2.2 参数与事件设计接口稳定才是关键组件封装得不好最大的感受就是用起来很别扭。我现在设计组件参数时会以使用方最少认知负担为准则能用默认值的绝不强制传入命名和业务习惯保持一致。以下是我在项目里沉淀出来的一套参数表// 输入参数props { total: { type: Number, default: 0 }, page: { type: Number, default: 1 }, pageSize: { type: Number, default: 10 }, pageSizes: { type: Array, default: () [10, 20, 50, 100] }, disabled: { type: Boolean, default: false } } // 事件emits { change: (page: number, pageSize: number) void, update:page: (page: number) void, update:pageSize: (pageSize: number) void }change 事件是主事件update:page 和 update:pageSize 是为了兼容 v-model:page、v-model:pageSize 这种双向绑定写法。真实的项目中有的团队喜欢 v-model有的喜欢事件回调两种写法都支持可以让组件兼容更多场景。参数设计里还有个容易被忽略的点pageSizes 数组。有的组件把每页条数选择项写死成 [10, 20, 30, 50]但实际业务中不同页面的数据密度差异很大列表页可能用 20 条报表页可能需要 100 条。pageSizes 设置成可配置的参数一行就能适配不同场景。3. 从零手写一个通用分页组件3.1 基础功能实现我用 Vue 3 TypeScript 写了核心实现。先说模板部分template div classpagination :class{ is-disabled: disabled } button classpagination__btn :disableddisabled || currentPage 1 clickhandleChangePage(currentPage - 1) 上一页 /button template v-forp in visiblePages :keyp button v-ifp ! ... classpagination__btn :class{ is-active: p currentPage } :disableddisabled clickhandleChangePage(p) {{ p }} /button span v-else classpagination__ellipsis.../span /template button classpagination__btn :disableddisabled || currentPage totalPages clickhandleChangePage(currentPage 1) 下一页 /button span classpagination__info 共 {{ total }} 条 /span select v-modelcurrentPageSize classpagination__size-select :disableddisabled option v-forsize in pageSizes :keysize :valuesize {{ size }} 条/页 /option /select /div /template这段模板里最需要注意的就是visiblePages也就是页码列表的生成逻辑。这个逻辑可以说是分页组件的灵魂后面的3.2会专门拆开讲。3.2 页码计算的核心逻辑为什么这么写页码计算的基本要求有两点。第一能展示完整的首尾页保证用户能快速跳转第二中间区域要显示当前页附近的部分页码避免页码过多导致按钮挤成一团。我采用的设计是首尾固定 当前页为中心的窗口模式同时用省略号收拢中间大段页码。计算逻辑如下const visiblePages computedArraynumber | ...(() { const total totalPages.value const current currentPage.value const range 2 // 当前页前后各展示 2 个页码 if (total 7) { // 页数少的时候全部展开不做省略 return Array.from({ length: total }, (_, i) i 1) } const pages: Arraynumber | ... [] const left Math.max(1, current - range) const right Math.min(total, current range) if (left 1) { pages.push(1) if (left 2) pages.push(...) } for (let i left; i right; i) { pages.push(i) } if (right total) { if (right total - 1) pages.push(...) pages.push(total) } return pages })为什么用总页数小于等于 7 时全部展开这个条件因为 7 个以内的页码按钮加上前后翻页按钮在常见的 1200px 以下容器里布局刚好合适不需要为了收拢空间而去掉有效点击目标。当总页数超过 7就要把首尾页和当前页周边逻辑分层处理1 和 total 永远保留中间部分形成一个以当前页为圆心、半径为 2 的滑动窗口。这个方案比简单的每页显示固定 10 个页码更贴合用户习惯因为用户翻到第 30 页时能在前后各看到 2 页的上下文知道自己大概在什么位置。直接展示第 27、28、29、30、31、32、33 页视觉上不会太碎又保留了关键路径。这个方案里有一处细节省略号的判断用的是left 2而不是left 1。因为当 left 等于 2 时页码序列就是[1, 2, 3, ...]此时不需要再插入一个省略号否则会看到1 ... 2 3 4这种奇怪的断档。右边同理右边区域用right total - 1判断。3.3 交互事件与状态同步组件内部真正的心脏是handleChangePage和currentPageSize的监听逻辑。这两处处理不好分页组件的联动就会各种别扭。const emit defineEmits([change, update:page, update:pageSize]) const props defineProps({ total: { type: Number, default: 0 }, page: { type: Number, default: 1 }, pageSize: { type: Number, default: 10 }, pageSizes: { type: Array, default: () [10, 20, 50, 100] }, disabled: { type: Boolean, default: false } }) const internalPage ref(props.page || 1) const internalPageSize ref(props.pageSize || 10) // 总页数由 total 和 pageSize 派生 const totalPages computed(() { return Math.max(1, Math.ceil(props.total / internalPageSize.value)) }) // 当外部传入的 page 变化时同步内部状态 watch(() props.page, (val) { if (val val ! internalPage.value) { internalPage.value val } }) // 当外部传入的 pageSize 变化时同步内部状态 watch(() props.pageSize, (val) { if (val val ! internalPageSize.value) { internalPageSize.value val } }) function handleChangePage(p: number) { if (props.disabled || p 1 || p totalPages.value) return if (p internalPage.value) return internalPage.value p emit(update:page, p) emitChange() } function handlePageSizeChange(val: number) { internalPageSize.value val emit(update:pageSize, val) // 改变每页条数后当前页码可能超出新总页数需要回退 if (internalPage.value totalPages.value) { internalPage.value totalPages.value emit(update:page, internalPage.value) } emitChange() } function emitChange() { emit(change, { page: internalPage.value, pageSize: internalPageSize.value }) }这里有几个细节值得聊一下。第一内部状态和外部 prop 的同步使用 watch 而不是直接在模板里用 props.page。好处是组件可以作为一个半受控组件使用父组件可以通过修改 prop 的方式主动调整页码组件本身也可以在用户交互时临时修改内部值。如果直接绑定 props.page组件内部就无法修改当前页了每次点击页码都要求父组件配合更新用起来会非常累。第二点击当前页不重复触发请求。if (p internalPage.value) return这行看着简单但实际能避免大量无意义请求。用户连续点击同一个页码时没有这行代码就会反复拉数据接口浪费流量不说还可能引发后面要讲到的竞态问题。第三切换每页条数后回退页码。这个逻辑很多新人会漏。想象一个场景当前在第 5 页每页 20 条总数据 60 条总共 3 页现在把每页条数改成 50 条总页数变成 2 页但 currentPage 还是 5这时候组件就会渲染出空页面。我这里的处理是把页码强制回退到新的总页数也就是第 2 页保证页面始终落在有效数据范围内。4. 进阶让分页组件更强大4.1 与数据请求逻辑的协同组件本身是哑组件但实际业务必须和请求逻辑紧密结合。我习惯把分页状态管理 数据请求抽成一个可复用的组合式函数比如usePagination这样业务组件只在模板层耦合组件业务逻辑层完全解耦。这是我的标准做法先定义一个数据加载函数由调用页提供具体 API// composables/usePagination.ts import { ref, computed } from vue export function usePagination(fetcher: (params: any) Promiseany) { const page ref(1) const pageSize ref(10) const total ref(0) const list ref([]) const loading ref(false) const totalPages computed(() Math.ceil(total.value / pageSize.value)) async function loadData() { if (loading.value) return loading.value true try { const res await fetcher({ page: page.value, pageSize: pageSize.value }) list.value res.list total.value res.total // 处理删除当前页最后一条数据后自动回退页码 if (list.value.length 0 page.value 1) { page.value - 1 await loadData() } } finally { loading.value false } } function handlePageChange(p: number) { page.value p loadData() } function handleSizeChange(size: number) { pageSize.value size page.value 1 // 每页条数变化时一般回到第一页 loadData() } return { page, pageSize, total, list, loading, totalPages, loadData, handlePageChange, handleSizeChange } }这里有一个隐藏很深但特别实用的场景当列表最后一页只剩一条数据时用户删掉这条数据接口返回的数据 list 为空但 total 还没更新或已经更新为上一页的边界值。如果不去回退页码用户就会卡在空页面上体验极差。我在loadData里加了空数据回退处理list.value.length 0 page.value 1时自动把页码减一再重新拉一次数据。这个边界问题在很多后端接口设计不完善的系统里非常常见强烈建议每个项目都处理好。4.2 多框架适配的思路Vue 3 的代码写完了但工作中可能遇到 React、uni-app 等不同技术栈。封装分页组件时其实核心思维是一致的差异只在语法和状态管理模型上。这里说说为什么封装这件事在这个场景下更多是思路层面的东西而不仅仅是代码层面的。以 React 为例用 Hooks 写分页逻辑会非常顺畅。因为 React 的函数组件本身就是状态容器useState天然对应 Vue 的 refuseMemo对应 computeduseEffect对应 watch。如果把上面的usePagination换成 React 版本核心逻辑差别很小// hooks/usePagination.ts import { useState, useMemo, useCallback } from react export function usePagination(fetcher: (params: any) Promiseany) { const [page, setPage] useState(1) const [pageSize, setPageSize] useState(10) const [total, setTotal] useState(0) const [list, setList] useState([]) const [loading, setLoading] useState(false) const totalPages useMemo(() Math.ceil(total / pageSize), [total, pageSize]) const handlePageChange useCallback((p: number) { setPage(p) fetcher({ page: p, pageSize }).then(res { setList(res.list) setTotal(res.total) }) }, [pageSize]) return { page, pageSize, total, list, loading, totalPages, handlePageChange } }如果要适配 uni-app那就更简单了因为 uni-app 本身基于 Vue 语法模板部分可以直接复用只是把div换成view把button的样式调整成小程序端支持的标签。重点在于封装的组件要能够在多个端上保持一致的交互逻辑所以我才把状态和请求逻辑放到 composable / hooks 里UI 组件只是这层逻辑的皮囊。5. 常见问题与排查技巧实录5.1 页码跳变的坑我遇到过最典型的页码跳变 bug是用户在输入框里输入页码后回车触发请求但请求还没返回用户又快速点了下一页结果请求结果错乱。这个问题发生在输入跳页交互上。我在很多项目中补充了输入防抖 回车确认的逻辑类似这样input v-model.trimjumpPage typenumber min1 :maxtotalPages keyup.enterhandleJump /handleJump里必须做两件事校验输入值在 [1, totalPages] 范围内超出就自动 clamp校验通过后把 internalPage 设置为目标页码并触发 change。如果不校验用户在输入框里输入 99请求发出去了接口返回空列表页面就白屏。还有一个相关的坑typenumber的输入框在部分浏览器中依然可以输入e、、-等符号需要在 handleJump 里用正则或者parseInt后再校验防止拿到一个 NaN。5.2 异步竞态问题分页组件最隐蔽的坑是异步请求竞态。用户翻页速度很快时比如快速从第 1 页点向第 2 页、第 3 页、第 4 页每次点击都会触发一次请求。如果第 2 页的接口响应比较慢响应晚于第 4 页返回那么第 4 页的渲染结果会被第 2 页的数据覆盖页面会展示错误的内容。解决思路有三种。第一种用请求序号AbortController / cancelToken每次请求发出前取消上一次请求第二种用竞态锁只有当最近一次请求返回时才更新数据第三种给每页渲染加一个sequence标识响应回来时对比 sequence 是否是最新。我在 Vue 项目里最常用的是请求序号方案let requestSeq 0 async function loadData() { const seq requestSeq loading.value true try { const res await fetcher({ page: page.value, pageSize: pageSize.value }) if (seq ! requestSeq) return // 已经过期丢弃结果 list.value res.list total.value res.total } finally { if (seq requestSeq) loading.value false } }这样做的好处是逻辑简单不需要引入额外依赖唯一的成本是每个请求函数里多维护一个 seq。对于分页这种高频短请求场景这个方案已经足够稳定而且不会出现 AbortController 在部分老旧浏览器上的兼容问题。5.3 表格分页常见套路pagination 组件怎么和 el-table 配合如果你使用的是 Element Plus 这类组件库它的 el-pagination 已经内置了完整的分页逻辑你只需要管好数据请求。但是这里有个隐藏的陷阱el-pagination 默认不会校验当前页码是否越界。数据被过滤后比如当前在第 8 页但筛选条件下只剩 3 页数据此时 el-pagination 会把当前页码显示成 8但表格里没有数据。我的套路是写一个专门的封装函数处理这种情况function normalizePage(data: { list: any[], total: number }, query: { page: number, pageSize: number }) { if (data.list.length 0 data.total 0 query.page 1) { // 当前页数据为空但总数不为零回退一页 query.page Math.max(1, Math.ceil(data.total / query.pageSize)) return true // 表示需要重新请求 } return false }拿到接口返回后先调 normalizePage返回 true 就说明当前页码无效要重新发请求。这个逻辑放在请求层而不是组件层是为了避免组件耦合接口返回的数据结构。5.4 常见的其他问题与避坑清单我把平时最容易遇到的分页问题整理成一个速查表方便取用问题现象可能原因解决方案点击页码无响应组件内部判断 p 与 internalPage 相等直接 return检查 handleChangePage 的判断逻辑确保只在相同页码时拦截查询条件变化后页码没重置业务方没有在查询时重置 page 到 1在父组件搜索函数里主动 setPage(1)或者在监听搜索条件变化时重置修改 pageSize 后页码越界没有在切换 pageSize 时处理 page 溢出参考 3.3 里的 handlePageSizeChange回退 page翻页后数据还没加载完成就切换条件请求竞态使用 requestSeq 思路过滤过期请求totalPages 显示为 0total 初始值默认为 0Math.ceil(0 / 10) 0将 totalPages 计算改为Math.max(1, Math.ceil(total / pageSize))后端从 0 开始计数页码前后端约定不一致组件层统一转换或请求层转换后再传入组件点击上一页时按钮置灰逻辑错误判断条件写成 0而不是 1确保最小页码是 1置灰条件用currentPage 1这个表格看起来是零散的经验但其实每一行背后都是一个真实项目里的血泪教训尤其是后端从 0 开始计数这条。有的后端返回的页码从 0 开始前端展示的分页从 1 开始如果不做转换用户永远点不到第一页。封装的请求层应该统一负责这类格式转换组件内部只处理从 1 开始的语义。5.5 封装越界的问题最后还想多说一点分页组件的边界也是封装的边界。组件封装不是越厚越好。有的同学习惯把排序、筛选、搜索、导出全部塞进分页组件里最后写出来的组件异常庞大任何一个页面出问题都要去翻公共组件代码这其实违背了封装的初衷。分页组件应该只负责分页包括页码展示、页码切换、每页条数切换、总条数展示。搜索框、表格渲染、操作按钮这些属于页面业务逻辑应该由页面自己管。我见过一个项目分页组件被扩展到了全功能列表组件包含搜索表单定义、表格列定义、删除确认弹窗等等。一开始确实开发快但后来产品要在 A 页面用树形列表、在 B 页面用卡片布局公共组件全部派不上用场还因为过多的 props 和 slots 导致维护成本成倍上升。所以封装分页组件时记得时刻问自己这个功能是每个分页场景都用得到的吗如果不是就应该放到组件外面去。分页组件封装这块我个人在实际操作中还有一个特别的体会别急着写代码先把组件状态是受控还是非受控、请求逻辑放哪层、边界情况怎么处理这三个问题想清楚。任何组件封装设计思考的时间往往比写代码的时间更能决定这个组件能走多远。另外如果你在现有项目里补封装建议先用一个页面做试点跑通之后再推广到其他页面不要在没验证的情况下就全局替换那种大面积重构一旦出问题排查成本会让人非常头疼。最后再分享一个小技巧封装完成后花点时间写一个简单的使用文档哪怕只是十来行的 README把 props、events 和边界行为列清楚对团队后续使用和维护的帮助远超你的想象。

相关推荐

Windows下RAR/ZIP/7z密码破解实战:算法选型与硬件优化指南
Windows下RAR/ZIP/7z密码破解实战:算法选型与硬件优化指南

1. 这不是“黑客教程”,而是一次密码安全认知的实战复盘 你搜“RAR密码移除”“ZIP解压密码清除工具”点进来的,大概率正被一个带密码的压缩包卡住——可能是同事发来的项目资料、下载的开源硬件资料包(比如那个“sw6206原厂方案.rar”&… · 2026/9/24 21:30:08

纺织机械用液压上轴车 电动升降经轴车 适用喷气织机剑杆织机
纺织机械用液压上轴车 电动升降经轴车 适用喷气织机剑杆织机

随着国内无梭织机产业的规模化普及,纺织织造车间的生产自动化、省力化转型需求持续提升。织轴转运、对位上机、落布存放作为织造生产的核心前置工序,传统人工作业模式已经难以适配现代化纺织工厂的降本增效需求,纺织机械专用液压上轴车、电动… · 2026/9/24 21:30:08

国产GPU虚拟化实战:8张卡撑起30个开发环境
国产GPU虚拟化实战:8张卡撑起30个开发环境

8张卡撑起30个开发环境,这个比例第一眼看上去有点像在做资源魔术。我们去年在电科云内部搭AI研发平台时,就因为这个数字被团队内部挑战过好几轮:国产GPU本来就紧张,怎么还敢把一张卡拆给四五个环境用?先说结论&#xf… · 2026/9/24 21:29:48

AI Agent驱动Unity自动化编译与测试:从人肉点点到机器全流程
AI Agent驱动Unity自动化编译与测试:从人肉点点到机器全流程

上班摸鱼的时候刷到一个挺扎心的段子:很多团队嘴上说着“全流程自动化”,实际干活的还是人肉点点点。我一想,这不就是说我之前干的活儿吗?Unity 项目一多,每天光编译、跑测试、看日志就耗掉大半天,纯纯的人… · 2026/9/24 22:02:26

Windows中文输入栏消失?简繁体切换导致任务栏不显示输入指示器的修复方法
Windows中文输入栏消失?简繁体切换导致任务栏不显示输入指示器的修复方法

1. 任务栏上那个"消失"的中文输入栏,到底去哪了如果你正在用 Windows 打中文,突然发现任务栏右下角那个熟悉的"中/英"标识、或者那个悬浮的中文输入状态条不见了,先别急着怀疑系统坏了。这个现象在简繁体切换场景下尤其常… · 2026/9/24 22:02:26

Go 多模块仓库版本发布完全指南:以 cloud.google.com/go 的 RELEASING 流程与源码实现为例
Go 多模块仓库版本发布完全指南:以 cloud.google.com/go 的 RELEASING 流程与源码实现为例

Go 多模块仓库版本发布完全指南:以 cloud.google.com/go 的 RELEASING 流程与源码实现为例 【免费下载链接】substrate Agent Substrate: the core system 项目地址: https://gitcode.com/GitHub_Trending/substrate7/substrate 本指南以当前仓库 vendor 目录… · 2026/9/24 22:02:19

Java Swing 黄金矿工小游戏:抓钩状态机与碰撞检测实战
Java Swing 黄金矿工小游戏:抓钩状态机与碰撞检测实战

简介:这是一份基于Java实现的黄金矿工小游戏完整源码包,面向Java初学者、课程设计学生以及想通过经典小游戏练手的开发者,帮助读者理解Swing图形界面、游戏循环、碰撞检测与资源加载等核心机制。压缩包共30个文件,约141KB&#xf… · 2026/9/24 22:02:05

体育馆场地预约系统开发实战:微信小程序+Django+Flask架构解析
体育馆场地预约系统开发实战:微信小程序+Django+Flask架构解析

体育馆场地预约平台开发手记:从电话排队到小程序一键订场做体育馆场地预约系统,最早是因为一个朋友在高校体育部上班,天天被电话轰炸:羽毛球场地有没有?今晚七点的场子被人占了能不能调?隔壁单位想包场怎么… · 2026/9/24 22:02:05

GPT-Live-1+Agora构建AI会议助手实战指南
GPT-Live-1+Agora构建AI会议助手实战指南

1. 这不是“又一个AI聊天框”,而是一个能真正坐在会议室里干活的数字同事GPT‑Live‑1 Agora 实战教程:做一个能参会、操作看板的 AI 助手——这个标题里藏着三个被多数人忽略的关键动作:“能参会”、“操作看板”、“实战教程”。它不讲大模… · 2026/9/24 22:02:05

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码