仿星巴克微信小程序源码解析:从启动配置到点单流程与避坑指南
简介这是一份微信小程序仿星巴克项目的完整源码主要面向小程序入门与进阶开发者可参考其还原商业级UI界面、页面跳转与底部导航等常见功能。资源共26个文件以js逻辑脚本、wxml页面结构、wxss样式表及json配置文件为主体另含少量png图片与说明文档压缩包仅317KB结构轻量便于快速查看核心代码。目前已有1552人学习下载具备一定参考热度。从内容预览看项目包含pages页面模块、utils工具模块和images资源目录覆盖了门店列表、商品展示等典型场景同时附带渠道统计链接与使用说明txt方便了解小程序统计接入思路。整体可作为仿写企业级小程序界面、梳理前端交互逻辑的入门参考资料。1. 仿星巴克微信小程序源码拿到手先确认它能跑再看它值不值得改很多开发者下载“仿星巴克”这类小程序源码第一反应是赶紧导入开发者工具结果要么白屏、要么报错一堆十有八九是栽在配置和路径上。这套源码的价值不在于“像不像星巴克”而在于它把一个真实点单场景的小程序拆成了可以直接改的业务骨架首页轮播、饮品列表、规格选择、购物车、会员卡、积分记录都在里面。适合两类人一是想快速搭一个有完整交互链的小程序Demo去面试或做课程设计二是想搞清楚小程序页面传参、自定义组件、数据绑定这些基础机制却不想从零写一遍样式的人。先说结论值得下但下载之后第一步不是看代码是按本文第 2 章的方式把项目跑起来再决定从哪里动手改。2. 项目拆解目录结构、启动配置与四个核心模块的边界2.1 目录结构与启动流程先搞懂每个文件夹是干什么的小程序源码拿到手第一件事不是双击app.js而是展开根目录看结构。这套仿星巴克项目的目录是典型的三层拆分全局配置、页面、公共资源。一个合格的微信小程序源码至少要包含app.js、app.json、app.wxss三个全局文件以及pages/目录下按业务划分的页面文件夹。每个页面文件夹里通常放着.js、.json、.wxml、.wxss四个同名的文件这套源码也是这么组织的。常见目录结构大致如下├── app.js ├── app.json ├── app.wxss ├── pages │ ├── index # 首页banner轮播 饮品推荐列表 │ ├── menu # 菜单页左侧分类 右侧商品列表 │ ├── order # 点单页规格选择 购物车 │ ├── member # 会员卡二维码 积分记录 │ └── store # 门店列表地图展示 门店详情 ├── components # 自定义组件商品卡片、数量步进器 ├── utils # 工具函数请求封装、格式化 └── static # 静态资源图片、icon打开app.json时注意两点一是pages数组里的第一个路径就是小程序启动的首页这套源码把pages/index/index放在第一位所以启动后先进首页二是全局window配置里定义了导航栏背景色和标题星巴克风格的深色导航栏主要靠这里撑起来改色时先改这里别一个页面一个页面去调。{ pages: [ pages/index/index, pages/menu/menu, pages/order/order, pages/member/member, pages/store/store ], window: { navigationBarBackgroundColor: #0a0a0a, navigationBarTextStyle: white, navigationBarTitleText: 星巴克, backgroundColor: #f5f5f5 } }这段配置决定了整个小程序的底色和导航行为。如果启动后出现导航栏白底黑字但页面内部是深色主题多半是navigationBarTextStyle只支持white或black两个值想用其他颜色只能自定义导航栏组件这个坑后面第 5 章细说。2.2 四个核心模块的功能边界首页、点单、会员、门店各自管什么这套源码的页面分工很清晰四个模块分别对应一个 tabBar 入口代码层面互不越界首页index负责品牌展示和引流核心是 banner 轮播和推荐饮品列表。数据来源是页面data里的静态数组没有依赖后端接口。菜单与点单menu/order这是整套源码里业务逻辑最重的部分。菜单页用左右两栏布局左侧是咖啡分类右侧对应分类下的饮品列表点单页处理规格选择、数量增减、购物车结算。会员卡member展示用户会员码和积分记录这笔源码里的会员码是用 canvas 绘制插件生成的不是直接用image标签。门店store用地图组件展示门店坐标底部有门店列表和导航按钮。这四个模块的边界感很重要改的时候不会牵一发动全身。比如只想替换首页轮播图就不需要碰order页面里的购物车逻辑。我一般建议拿到源码后先把每个页面的文字和图片标记出来确认哪些是静态写死的哪些是动态渲染的再动手改。3. 把首页做真banner 轮播、饮品列表的渲染细节与数据绑定3.1 swiper 组件的参数含义autoplay、interval、circular 缺一不可首页最上面是 banner 轮播源码里用的是小程序原生swiper组件。很多新手自己写轮播时只写了autoplay和indicator-dots跑起来发现划到第三张就停住了就是因为漏了circular。swiper classbanner autoplaytrue interval4000 duration600 circulartrue block wx:for{{banners}} wx:keyid swiper-item image src{{item.image}} modeaspectFill classbanner-img/image /swiper-item /block /swiperinterval控制轮播间隔单位是毫秒4000 表示 4 秒切换一次duration是切换动画耗时circular为true时才能实现“从最后一张划回第一张”的无缝循环否则划到头就无法继续。modeaspectFill的意思是图片等比缩放并自动裁剪中间部分banner 区域不会被拉伸变形。改轮播图时注意/static/banner/目录下的图片尺寸这套源码的 banner 设计稿是 750 宽建议替换图时保持宽高比在 2.5:1 到 3:1 之间不然上下会露白或者裁掉太多。3.2 饮品列表的数据结构为什么推荐列表用数组嵌套而不是写死节点首页推荐饮品列表在源码里是一个典型的数据驱动结构。data里的recommendList是一个数组每个元素包含图片、名称、描述、价格和 id模板里用wx:for循环渲染。Page({ data: { recommendList: [ { id: 1, name: 拿铁, desc: 浓缩咖啡与牛奶的经典融合, price: 32, image: /static/images/drink_latte.png, tag: 热销 }, { id: 2, name: 冷萃冰咖啡, desc: 冷萃工艺口感顺滑甘甜, price: 36, image: /static/images/drink_coldbrew.png, tag: } ] } })对应模板里一般是这样的结构view classrecommend-item wx:for{{recommendList}} wx:keyid bindtaponItemTap>onItemTap: function (event) { const id event.currentTarget.dataset.id; wx.navigateTo({ url: /pages/detail/detail?id id }); }这里要说一个新手高频错误页面跳转路径必须是/pages/...开头而不是pages/detail/detail?id1。少了开头斜杠在某些基础库版本上直接跳不过去报错信息又不明显很多人卡在这一步折腾半天。4. 点单流程与会员卡渲染页面传参、状态更新和 canvas 生成二维码4.1 规格选择与购物车数据状态提升到页面级点单页是这套源码里最能学到东西的部分。它没有用全局状态管理而是把购物车数据放在页面data里通过方法修改后再setData驱动视图更新。这种写法在单页场景下完全够用也更好理解。页码选择区通常是点击某个饮品后弹出底部弹层弹层里展示规格选项比如“中杯”“大杯”“超大杯”每个规格对应不同价格。源码里用一种比较实用的小技巧规格数组里的对象同时包含name和priceDelta实际价格由基础价加上差价计算而不是每个规格写死一个价格。data: { currentDrink: { basePrice: 32, specs: [{ name: 中杯, priceDelta: 0 }, { name: 大杯, priceDelta: 4 }, { name: 超大杯, priceDelta: 6 }] }, selectedSpecIndex: 0, cartCount: 0 }用户点击某个规格时把selectedSpecIndex更新为对应索引显示出来的价格就是basePrice selectedSpec.priceDelta。加购物车时把这个组合作为一个cartItem推进数组里。addToCart: function () { const drink this.data.currentDrink; const spec drink.specs[this.data.selectedSpecIndex]; const cartItem { name: drink.name, spec: spec.name, price: drink.basePrice spec.priceDelta, count: 1 }; this.setData({ cartList: this.data.cartList.concat(cartItem), cartCount: this.data.cartCount 1 }); }这里值得注意的一点是concat返回新数组而不是直接push修改原数组。这个写法配合setData才能触发视图更新。如果图省事写this.data.cartList.push(cartItem)再setData视图一般也能更新但会破坏小程序的数据监听机制将来要做撤销操作时很麻烦。我自己的习惯是始终用不可变更新方式写购物车这类高频修改的数据。4.2 会员卡二维码canvas 绘制与组件生命周期会员卡页面最容易被忽略的是二维码绘制逻辑。这套源码里的会员码不是一张静态图片而是用 canvas 根据用户 id 实时生成的。改卡号时只要换生成地址的后缀参数即可。const ctx wx.createCanvasContext(memberQrCode); ctx.drawQrcode({ text: MEMBER-2024-USER-10086, width: 200, height: 200, correctLevel: 1 }); ctx.draw();这段代码里correctLevel: 1表示纠错级别 L是最低一档换而言之二维码容错率低但图案更简洁清晰。如果打印或截图后扫码偶尔失败可以把纠错级别调到 2 或 3二维码会变密一些但扫得更稳。另一个高频问题某些基础库版本下drawQrcode并不是全局方法需要先引入扩展库。{ usingComponents: {}, requiredPrivateInfos: [], lazyCodeLoading: requiredComponents }如果控制台报ctx.drawQrcode is not a function去app.json里检查是否配置了 canvas 相关扩展库。源码里已经配好但如果升级了基础库版本扩展字段可能被重置重新补上即可。4.3 页面传参的两种方式navigateTo 带参和全局缓存首页点击饮品跳详情页是navigateTo带参方式参数拼在url查询字符串里但点单页和会员卡之间如果需要共享用户信息用navigateTo传参就会很笨拙。这套源码的做法是把用户信息放在app.globalData里页面通过getApp()读取。// app.js App({ globalData: { userInfo: null, memberId: MEMBER-2024-USER-10086 } })// member.js const app getApp(); Page({ onLoad: function () { this.setData({ memberId: app.globalData.memberId }); } })这两种传参方式的区别在于navigateTo参数会显示在页面栈拼接的 URL 上适合传短字符串如 idglobalData适合传对象或需要跨多个页面共享的数据。如果传参时遇到中文乱码比如用户昵称里有汉字需要先encodeURIComponent编码再拼接。5. 避坑与排查静态数据、图片资源与发布配置的五个经典问题5.1 页面白屏但控制台无报错最常见的是路径大小写不一致现象导入项目后首页白屏开发者工具控制台没有红色报错只有几行黄色告警。原因图片引用路径里的大小写和实际文件名不一致。小程序在 Windows 上开发时对路径大小写不敏感但编译到真机或某些基础库版本时变成大小写敏感导致图片加载失败但不抛致命错误。这套源码的static/images/目录里文件名都是小写开头我碰到过有人把drink_latte.png改成了Drink_latte.png本地跑通预览到手机就白屏。解决用命令行工具全局搜索项目中所有标签的src属性逐一对比静态目录里实际文件名。更省事的做法是把所有图片文件名统一成小写加下划线命名法这是这套源码自带的规范按原规范改就不会出问题。5.2 tabBar 图标不显示不是图标丢了而是尺寸和命名不对现象底部导航栏能切换页面但两个图标位置是空白占位符。原因微信官方文档规定 tabBar 图标尺寸限制是 40kb 以内推荐 81px * 81px格式为 png 或 jpg。源码里自带的图标满足要求但如果替换后用了 svg 格式开发者工具不报错但真机上不渲染。另外tabBar.list里的iconPath和selectedIconPath都要配只配一个的时候另一个状态就显示空白。解决先把图标转成 png 并控制在 81 * 81 像素体积压到 40kb 内然后在app.json里确认每个 tab 都同时有iconPath和selectedIconPath。改完清缓存重新编译这一步经常被人忽略。5.3 模拟器上可以跑真机预览请求失败域名白名单和 HTTPS 问题现象代码在开发者工具里一切正常扫码真机预览后饮品列表加载不出来。原因最常见的是源码里的接口地址写的是开发环境 IP真机访问不到。而如果换成公网地址但没在小程序后台配置 request 合法域名真机一样被拦。这套源码的列表数据默认用的静态数据不需要请求接口所以这个坑出现在有人把它改成动态接口之后。解决开发阶段在开发者工具里勾选“不校验合法域名”真机预览时在项目设置里打开“开发环境不校验请求域名”。线上版本必须在后台配置 HTTPS 白名单且证书要有效。其实更推荐的做法是保持源码的静态数据不动把动态接口封装在utils/request.js里等后端就绪再一次性切换。5.4 下拉刷新和滚动到底加载更多互相打架onPullDownRefresh 与 scroll-view现象首页设为可下拉刷新后列表页用scroll-view做滚动加载在真机上下拉时页面卡住既不刷新也不滚动。原因onPullDownRefresh是页面级别的事件监听的是整个页面的下拉手势而scroll-view是组件级别的滚动容器两者同时启用时手势冲突。解决要么停用页面级下拉刷新改用scroll-view自带refresher-enabled属性要么去掉scroll-view让页面原生滚动配合onReachBottom实现加载更多。这套源码的首页用的是页面原生滚动不需要加scroll-view加了的同学可以去掉逻辑反而更顺。5.5 setData 频繁更新导致页面卡顿不要整页 setData现象购物车页面操作加减号时明显卡顿真机上尤其明显。原因每次点击都把购物车数组整个setData一次数组越长越卡。这是新手用setData最容易犯的错一次只改一个数字也要传一个 10 项的大数组。解决用数据路径方式更新。// 差的写法 this.setData({ cartList: newCartList }); // 好的写法 this.setData({ [cartList[${index}].count]: newCount });字符串模板语法[key]可以精确定位到数组里某一项去更新视图重绘范围大幅缩小。这套源码里购物车数量步进器就是这个实现思路改的时候注意别破坏这个结构。6. 进阶用法把静态数据 Mock 层拆出来一套代码应对前后端联调拿到这套仿星巴克源码并且跑通之后下一步自然是想把静态数据换成真实接口。我的建议是不要直接在各页面里写wx.request而是先做一个 Mock 层让页面代码全部从 Mock 层取数将来后端就绪时只替换 Mock 层内部实现页面几乎不用动。这是这一篇里我觉得最有用的习惯。先建一个mock/db.js文件把首页推荐列表、菜单分类、会员积分这些散落在各页面里的静态数据集中导出// mock/db.js module.exports { banners: [ { id: 1, image: /static/banner/b1.png, link: /pages/activity/activity } ], recommendList: [ { id: 1, name: 拿铁, price: 32, image: /static/images/drink_latte.png } ], memberData: { memberId: MEMBER-2024-USER-10086, points: 1280 } }然后在utils/api.js里做一层请求封装现阶段 Mock 数据直接返回const mock require(../mock/db.js); function fetchBanners() { // 返回 Promise 便于后续替换真实接口 return new Promise((resolve) { setTimeout(() resolve(mock.banners), 100); }); } function fetchRecommendList() { return new Promise((resolve) { setTimeout(() resolve(mock.recommendList), 100); }); } module.exports { fetchBanners, fetchRecommendList };页面里onLoad时这样调用const api require(../../utils/api.js); Page({ onLoad: function () { api.fetchRecommendList().then(list { this.setData({ recommendList: list }); }); } })这样改造之后页面只面向api这个模块写代码。将来后端接口好了只需改fetchRecommendList函数内部把mock替换成wx.request页面逻辑一行都不用动。这里有个细节所有接口都包一层 Promise目的就是让替换过程中页面调用方式保持不变避免接口一换页面就要大面积重写。从那以后我每次下这类带静态数据的源码都强制走一遍拆 Mock 层的流程哪怕只是一个课程设计也用同样的结构。等后端真的递过来接口文档时十几分钟就能接完不用半夜对着页面里的wx.request一个个查。这个习惯帮我省了很多事希望帮到你。本文还有配套的精品资源点击获取

相关新闻

手把手复刻特斯拉Model 3电机:6极54槽IPMSM建模与仿真分析

手把手复刻特斯拉Model 3电机:6极54槽IPMSM建模与仿真分析

电动车圈聊得最凶的是电池和快充,但我这只工科狗更在意的,是那台把电能转成推背感的电机。去年我给自己挖了个大坑:按特斯拉Model 3后驱版永磁电机对外可见的那些技术特征,从定转子冲片、V型磁钢排布到绕组端部,一手搭…

2026/10/13 15:05:35 阅读更多 →
Eclipse代码行数统计插件实战:选型、配置与避坑指南

Eclipse代码行数统计插件实战:选型、配置与避坑指南

简介:面向Eclipse开发者与Java项目团队的代码行数统计插件资源,目标是解决在IDE中快速掌握项目规模、注释密度与空行占比的痛点,适用于项目工作量估算、代码评审与重构决策场景。压缩包共16个文件、约60KB,包含可安装插件jar、插件…

2026/10/13 15:05:35 阅读更多 →
Gin框架接口响应格式规范化:统一封装、错误码设计与实战落地

Gin框架接口响应格式规范化:统一封装、错误码设计与实战落地

上个月接了一个快两年的 Go 老项目,Gin 框架,前后端完全分离,对外接口六十多个。我接手第一天没干别的,先把 controller 层翻了个底朝天。结果呢?有的接口返回 {"code":0,"data":{...}} &#x…

2026/10/13 15:05:35 阅读更多 →

最新新闻

AI-Gomoku实战:Minimax+Alpha-Beta打造可部署五子棋AI

AI-Gomoku实战:Minimax+Alpha-Beta打造可部署五子棋AI

简介:AI-Gomoku是一款面向Python初学者与AI算法爱好者的五子棋智能对弈程序,聚焦博弈搜索与轻量级AI实现,适用于算法实践、课程设计及人机对战场景。资源包共11个文件,含4个核心Python源码(如eval.py、referee.py、alg…

2026/10/13 15:57:03 阅读更多 →
多智能体+行业工作台:AI团队协作与业务流程落地的工程实践

多智能体+行业工作台:AI团队协作与业务流程落地的工程实践

最近开源社区里多智能体的项目冒出来一大批,但绝大多数看一眼就能猜到大结局:Demo 跑得飞起,一碰真实业务就散架。要么 Agent 各说各话没人收口,要么任务拆下去结果完全不可控,更别提什么权限隔离、工具管控、知识库绑…

2026/10/13 15:57:03 阅读更多 →
PERT图核心逻辑与PERT Chart EXPERT实战:三点估算、关键路径与避坑指南

PERT图核心逻辑与PERT Chart EXPERT实战:三点估算、关键路径与避坑指南

简介:PERT Chart EXPERT 是一款面向项目经理、计划专员及项目团队的 PERT 图专业绘制软件,基于计划评审技术帮助用户直观梳理任务节点、依赖关系与预期工期,解决项目排期与进度监控难题。压缩包体积约 2.43MB,为 rar 格式&#xf…

2026/10/13 15:57:02 阅读更多 →
C# XML操作全解析:从DOM到LINQ、序列化与流式避坑指南

C# XML操作全解析:从DOM到LINQ、序列化与流式避坑指南

深夜还在跟 XML 较劲的兄弟,我懂你。这种事我干过太多次了,明明就是几个节点的读写,一碰上编码、命名空间、特殊字符,瞬间能把人逼疯。C# 操作 XML 的方式其实有好几条路,DOM、LINQ to XML、序列化、流式读写&#xff…

2026/10/13 15:57:02 阅读更多 →
可再生能源与电动汽车协同调度:Matlab+Python复现全流程

可再生能源与电动汽车协同调度:Matlab+Python复现全流程

我们先把话说清楚:这套课题我在工位上完整复现过一遍,从论文公式到Matlab脚本再到Python绘图,所有流程都走通了。课题全名叫"可再生能源发电与电动汽车的协同调度策略研究",技术栈是Matlab和Python,应用场景…

2026/10/13 15:57:02 阅读更多 →
选择排序与插入排序:手写背后的底层直觉与工程权衡

选择排序与插入排序:手写背后的底层直觉与工程权衡

1. 为什么今天还要手写选择排序和插入排序?——从“能跑通”到“真理解”的分水岭很多人看到“算法-6-选择排序插入排序”这个标题,第一反应是:这都2024年了,Python里一个sorted()、JavaScript里一个.sort()就搞定的事&#xff0c…

2026/10/13 15:56:01 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →