news 2026/9/8 2:19:47

HarmonyOS ArkTS层叠布局Stack深度解析:对齐、定位与避坑实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HarmonyOS ArkTS层叠布局Stack深度解析:对齐、定位与避坑实战

搞了半天,终于把HarmonyOS那套ArkTS里的层叠布局(Stack)整明白了。前几天有个刚转鸿蒙开发的朋友问我,一个头像右上角的红色角标,怎么用原生组件放上去?我第一反应就是:这玩意不就是给Stack准备的吗?层叠布局在ArkTS的布局体系里,地位有点像PS里的图层面板,能把一个个组件按Z轴方向堆起来,做到你压我、我盖你,还不影响各自的位置计算。这篇就把我从零踩到顺的全过程写下来,从基础语法到懒人式对齐方法,再到各种坑的排查,一次说清楚。

如果你正要开始写HarmonyOS应用,或者已经在用Column、Row排布界面但总觉得差点意思,这篇文章都值得花十分钟看完。内容不搞虚的,全部以可运行的ArkTS代码和真实界面效果为准,尤其会重点讲热搜里常被问到的那个问题:Stack里的子组件,怎么控制自己在底部上方100的位置水平居中。

1. 布局体系里的“叠罗汉”:层叠布局解决什么问题

1.1 先看懂ArkTS的布局家族

正式开始之前,先花两分钟把ArkTS里这些布局容器捋一遍。做过Android的同学应该能看出它们跟传统ViewGroup的对应关系,理解了这个,后面学什么布局都快。

ArkTS声明式UI里常用的容器布局有这么几类:Column(线性纵向排列)、Row(线性横向排列)、Flex(弹性布局,可以换行,类似CSS的flex)、Grid(网格布局,适合九宫格这种规整格子)、RelativeContainer(相对定位容器),以及今天的主角Stack(层叠布局)。

它们的分工很明确:Column和Row解决的是“排队”问题,让元素一个挨一个排;Flex解决“空间分配”问题,一行放不下就换行,剩下的空间按比例瓜分;Grid解决“对齐格子”的问题,列数固定,格子规整。一旦需求变成“两个组件需要重叠在一起”,比如图片上方盖一行半透明文字、角标压在图标右上角,没一个容器能优雅地接住这活,只有Stack能办。

1.2 Stack的核心能力:Z轴上的自由

Stack的核心思路其实特别朴素:它的子组件不横向排、不纵向排,而是全部默认从左上角开始重叠,后加入的子组件会盖在先加入的子组件上面,形成一个Z轴方向的堆叠。

理解这一点的时候,我建议你把它类比成桌面上堆了一摞便签纸。最先放的那张在最底下,后放的往上盖,最上面那张只有你能看到全部内容,下面的全被挡住了一部分。Android里叫FrameLayout,Web里用position: relative加z-index也能实现类似效果,ArkTS里就是Stack。

刚开始用Stack的人容易犯一个糊涂:以为子组件放在Stack里就只能左上角叠在一起,没法控制各自的位置。其实Stack本身提供了两种位置控制手段,一个管全局、一个管个体,稍后第3节会细讲。你只要记住,Stack负责把子组件切换成“可重叠”的模式,至于每个组件具体待在哪,完全可以通过属性单独指定,自由度比线性布局高得多。

2. 环境准备与一个最简层叠案例

2.1 开发环境快速搭建

先确认一下你手上的开发环境。目前主流方案是使用DevEco Studio,版本建议4.0及以上,对应的HarmonyOS SDK版本最好在API 9以上,这样声明式UI的ArkTS支持才完整,写起来也顺手。

新建项目的时候,注意选择一个带UIAbility的Empty Ability模板,ArkTS代码写在entry模块的pages目录下。一个最小的ArkTS页面其实就是一个被@Entry装饰的struct组件,里面由build方法描述UI结构。如果你之前写过Flutter或者SwiftUI,这套写法的上手成本几乎为零;如果只写过Android XML布局,也没关系,多写几次就习惯了。

我强烈建议初学阶段不要开预览器看效果,直接在模拟器或者真机上跑,因为Stack的层级关系在预览器里有时候会有渲染时序问题,看着是错位的,真机上跑反而是正常的,免得被工具误导。

2.2 从零手写第一个Stack页面

直接看代码。下面这个例子是Stack最经典的演示:三个不同颜色、不同尺寸的正方形叠在一起,感受一下默认的层级效果。

@Entry @Component struct StackDemo { build() { Stack() { Column() .width(240) .height(240) .backgroundColor('#FF6B6B') Column() .width(160) .height(160) .backgroundColor('#4ECDC4') Column() .width(90) .height(90) .backgroundColor('#FFE66D') } .width('100%') .height('100%') .alignContent(Alignment.Center) } }

代码里我特意把三个Column的宽高设成了240、160、90三档,背景色也不一样。运行一下你就明白Stack的行为模式了:

  • 三个子组件默认重叠对齐,对齐方式由Stack自身的alignContent属性决定,这里我设成了Alignment.Center,所以三者都水平垂直居中;
  • 先写的红色块在底层,最后写的黄色块在最上层,所以黄色块完整可见,绿色块露出四周,红色块只露出一圈边框;
  • 每个子组件的位置互不影响,不存在线性布局那种挤压和占位问题。

这个Demo虽然短,但已经把Stack的核心机制演示透了。接下来的所有复杂效果,本质都是在“多个子组件叠放”的基础上,加上尺寸、位置、事件的精确控制。

3. 控制子组件位置的两种姿势:整体对齐与个体对齐

3.1 容器级对齐:alignContent

先讲那个管全局的参数:alignContent。这个属性挂在Stack根节点上,决定所有子组件的“默认排队位置”。它的取值范围就是Alignment那一组枚举,常见的有:

枚举值实际效果
Alignment.TopStart所有子组件默认对齐到左上角
Alignment.Top所有子组件默认对齐到顶部水平居中
Alignment.TopEnd所有子组件默认对齐到右上角
Alignment.Start所有子组件默认对齐到左侧垂直居中
Alignment.Center所有子组件默认水平垂直居中
Alignment.End所有子组件默认对齐到右侧垂直居中
Alignment.BottomStart所有子组件默认对齐到左下角
Alignment.Bottom所有子组件默认对齐到底部水平居中
Alignment.BottomEnd所有子组件默认对齐到右下角

实操里我的经验是,先把整个Stack的alignContent设为某个基准位置,比如一个全屏的Stack,通常设成Alignment.Center或者Alignment.Bottom,这样大多数子组件不需要单独设置位置,只有少数元素再用alignSelf做微调。

要注意,alignContent只是一个“默认值”逻辑,不是强制锁死。意思就是子组件如果自己带了alignSelf或者margin、position之类的属性,那以它自己的为准。所以别担心设了容器级对齐后,所有儿子就只能挤在一个角落了,后面还有手段解放它们。

3.2 子组件级对齐:alignSelf

再讲那个管个体的属性:alignSelf。这个属性让单个子组件在Stack内部单独调整自己的对齐方式,完全不用管兄弟组件。

用法是在子组件链式调用里加一个.alignSelf():

Stack({ alignContent: Alignment.Center }) { Column() .width(200) .height(200) .backgroundColor('#FF6B6B') Text('右下角标签') .alignSelf(Alignment.BottomEnd) .margin({ right: 16, bottom: 16 }) .fontSize(14) .fontColor(Color.White) .backgroundColor('#33000000') .padding({ left: 8, right: 8, top: 4, bottom: 4 }) .borderRadius(4) } .width('100%') .height(200)

注意这里Stack容器整体alignContent设了Center,但第二个子组件Text通过alignSelf(BottomEnd)把自己定位到了右下角,还加了margin进一步偏移。这就是Stack真正灵活的地方:全局统一,局部自由,互不干扰。

实战里alignSelf最好用的场景就是做角标。比如一个卡片右上角的“HOT”标签,整个卡片放在一个居中Stack里,标签自己alignSelf到TopEnd,再margin调整距离边缘的间距,几行代码搞定,不用嵌套一堆容器。

3.3 热搜实战:底部上方100居中的写法

下面进入很多初学者问了无数遍的实战题:Stack里的一个子组件,要相对整个Stack的水平方向居中,同时垂直方向距离底部100。别小看这个问题,热搜里反复出现“鸿蒙 stack布局子组件怎么控制自己在底部上方100的位置居中”,说明卡在这的人真不少。

先给答案,最简单的写法:

@Entry @Component struct BottomButtonDemo { build() { Stack() { // 背景层,可以是任意内容 Column() .width('100%') .height('100%') .backgroundColor('#F1F3F5') // 这个按钮就是目标:水平居中,距离底部100 Button('我知道了') .width(200) .height(48) .alignSelf(Alignment.Bottom) // 先放到水平居中、底部对齐 .margin({ bottom: 100 }) // 再往上推100 } .width('100%') .height('100%') } }

拆解一下思路:Stack对齐系统里,Alignment.Bottom本身就是“水平居中+底部对齐”,所以直接alignSelf(Bottom)就完成了水平居中这一半。然后想做到“距离底部100”,就在子组件的margin里把bottom设为100,相当于让按钮整体往上抬了100。两步合起来,就是底部上方100且水平居中。

很多人想不明白的点在于是用margin还是position。在Stack里,最简单有效的偏移方式就是margin,它会参与布局计算,真机上对尺寸自适应也更友好。position属性也能用,但它会把元素变成绝对定位,后续父容器尺寸变化时容易出现超出边界的情况,初学阶段建议优先用margin。

如果还想更精细一点,比如按钮要求距离底部100,同时还要距离右侧20,可以连续叠加:先.alignSelf(Alignment.BottomEnd), 再.margin({ right: 20, bottom: 100 })。但注意,一旦alignSelf用了End,水平方向就不再是居中,而是靠右了,二者是不可兼得的“方向组合”。所以要先想清楚自己要的是靠哪边。

4. 层叠布局的高频应用场景

4.1 右上角角标:电商列表的未读红点

Stack在真实项目中最常见的用途就是角标类需求。拿电商应用举例,商品列表每个格子的右上角经常会有一个“满减”标签或者未读红点。这种UI结构天然就是“原内容 + 覆盖物”的关系,用线性布局写会麻烦到怀疑人生,用Stack写就是两三行的事。

@Entry @Component struct BadgeDemo { build() { Stack({ alignContent: Alignment.Center }) { // 商品图底板 Column() .width(120) .height(120) .backgroundColor('#DEE2E6') .borderRadius(12) // 右上角红点 Column() .width(16) .height(16) .backgroundColor('#FA5252') .borderRadius(8) .alignSelf(Alignment.TopEnd) .margin({ top: 6, right: 6 }) } .width('100%') .height('100%') } }

这里我假装商品底图是一个灰色色块,红点通过alignSelf(TopEnd)跑到右上角,再用margin把红点往里收6,避免贴边太紧。你把这个红点换成Text标签,里面塞数字或者“NEW”,就是一个标准的加号角标。

做角标的时候有个细节值得注意:角标内容变化时,比如从9变成99,它的宽度会自动撑开,但因为alignSelf加margin的写法不会影响容器其他兄弟组件,所以整体布局不会晃动,这一点比用线性布局里做fixed宽高的方案稳得多。

4.2 悬浮按钮与底部操作栏

另一个高频场景是做页面的悬浮操作区。比如一个视频播放页面,返回按钮、点赞按钮、评论输入框经常要悬浮在播放器内容上。这种界面用Stack就是天然解:背景放视频层,前景放操作层,互不打扰。

@Entry @Component struct FloatActionDemo { build() { Stack() { // 模拟视频区域 Column() .width('100%') .height('100%') .backgroundColor('#212529') // 顶部返回按钮 Button('返回') .backgroundColor('#66000000') .fontColor(Color.White) .alignSelf(Alignment.TopStart) .margin({ left: 16, top: 16 }) // 底部操作栏 Row() { Text('点赞') Text('评论') Text('分享') } .width('100%') .justifyContent(FlexAlign.SpaceAround) .backgroundColor('#66000000') .fontColor(Color.White) .padding({ top: 10, bottom: 10 }) .alignSelf(Alignment.Bottom) } .width('100%') .height('100%') } }

从上面这段可以看到,Stack不仅能容纳单个组件,里面嵌套一个Row,再放整行操作栏也完全没问题。也就是说Stack的层级能力完全可以搭载一行内部有复杂布局的区块,它只负责“这行整体待在我这个容器底下”,不负责管行内元素的排列。

这种做法比用绝对坐标定位的写法省心在一点:不同屏幕尺寸下,Stack的百分比宽高依然生效,悬浮按钮的位置不会因为机型尺寸变化而跑偏。

4.3 图片文字叠加:封面卡片

图片上盖文字,基本是内容类应用的家常便饭。头条、抖音、购物车里的商品卡,都在玩这个套路:一张封面图,底下盖一层半透明渐变或者一块深色遮罩,再放标题和价格。

实现上仍然是Stack,整个卡片只有一层结构:

@Entry @Component struct CoverCardDemo { build() { Stack() { // 图片占位,实际开发换成Image组件 Column() .width('100%') .height(200) .backgroundColor('#343A40') // 底部信息遮罩层 Column() .width('100%') .height(60) .backgroundColor('#AA000000') .alignSelf(Alignment.Bottom) // 白色文字 Text('这是一条测试标题,长度随意观察换行效果') .fontSize(16) .fontColor(Color.White) .alignSelf(Alignment.BottomStart) .margin({ left: 12, right: 60, bottom: 20 }) } .width('100%') .height(200) .borderRadius(12) .clip(true) } }

这里上方遮罩和文字都在Stack里,遮罩通过alignSelf(Bottom)固定在底部区域,文字通过BottomStart加margin对齐到左下角,right留了60的空间给可能存在的价格标签。最后那个.clip(true)很重要,它让Stack裁剪掉超出圆角范围的子组件,不然盖上的遮罩会把父容器的圆角给“顶掉”,效果非常丑。

4.4 头像与在线状态徽章

最后一个高频场景是社交应用里几乎人人见过的头像加状态点。头像底部对齐,在线状态点压到头像右下角,稍微露出半个身位。

@Entry @Component struct AvatarDemo { build() { Stack() { // 头像外层白圈 Column() .width(72) .height(72) .backgroundColor('#FFFFFF') .borderRadius(36) // 头像内层图 Column() .width(64) .height(64) .backgroundColor('#ADB5BD') .borderRadius(32) // 在线状态点 Column() .width(18) .height(18) .backgroundColor('#40C057') .borderRadius(9) .alignSelf(Alignment.BottomEnd) .margin({ right: 2, bottom: 2 }) } .width('100%') .height('100%') } }

这个例子的重点是那个状态点,它比头像本身小一圈,而且刻意露出棋子边儿,这种效果在线性布局里做会很别扭,你需要算各种偏移量。但在Stack里就是alignSelf到右下角,再margin往外挪一点点即可,和实际设计稿的对齐意图非常匹配。

5. 避坑指南:布局重叠、事件穿透与性能

5.1 布局重叠不是bug,但要注意层级

搜“布局重叠”这个词的人,很多是因为在Stack里发现子组件叠到不想叠的地方,以为出bug了。其实这不是错误,而是Stack的设计目的。真正该做的是明确每个子组件的层级顺序和位置。

Stack的子组件层级规则很简单:先写的在下,后写的在上,而zIndex属性可以显式调整。比如有两个按钮叠在一起,想让红色的永远盖在蓝色上面,在红色按钮上加一个.zIndex(2),蓝色设.zIndex(1),层级关系就锁死了。

实际项目里,层级冲突最容易出现在“同一个Stack里既有背景元素又有交互元素”的场景。我的习惯是:把背景类元素放在最前面,交互元素随后,最后用zIndex控制覆盖关系,避免因为多个元素同时集中在某个区域,导致点击目标被兄弟组件挡住。

5.2 事件命中与穿透控制

比层级更隐蔽的坑是事件穿透。Stack里上层组件如果设置成了透明背景,或者背景色接近全透明,它虽然看不见,但依然会拦截点击事件。也就是说,你放了一个全屏透明层在顶部,下面所有按钮都会点不动,但界面上根本看不到原因。

解决办法是使用hitTestBehavior属性。ArkTS里对它有三种主流的取值:

取值行为
HitTestMode.Default默认模式,组件自身响应事件,并且阻止事件传递给底部兄弟组件
HitTestMode.Block组件自身不响应事件,但依然阻断事件向下传递
HitTestMode.Transparent组件自身尝试响应事件,同时透传给下层组件
HitTestMode.None组件完全不参与事件命中测试,事件直接穿过它命中底层组件

做了一个悬浮评分弹层时,经常需要半透明遮罩后面的内容不可点,那遮罩就设Default;如果是一个纯装饰的引导层,要既能响应点击关闭,又让点击事件穿透到底层,那就用Transparent。这个调起来需要结合具体交互设计去试,但知道有这些选项,排查问题时就快多了。

5.3 尺寸约束、百分比与自适应边界

Stack虽然“自由”,但它对子组件的尺寸仍然有约束。子组件如果没设置宽高,会尽量跟随内容大小;如果设置了百分比宽高,参考的是Stack自身的尺寸;如果子组件的固定尺寸超过了Stack容器,就会发生溢出。

实际开发里我见过不少新手在Stack里放了固定宽度300的组件,但容器只有200宽,真机上部分内容被切掉,或者莫名其妙把别的组件顶出区域。这种时候优先检查的是:子组件是否设置了合理的最大宽度、容器是否设置了.clip(true),以及用的是不是百分比宽高。

自适应场景下,建议优先用百分比和margin/dimension配合,少写死px数值。比如一个卡片要适配不同手机宽度,把卡片宽度设成'90%',角标的位置用alignSelf加margin控制,这样任何屏幕尺寸下都能保持相对位置一致,不会因为某一端过窄导致界面元素跑出屏幕。

5.4 不要滥用Stack:什么时候换Flex

Stack虽然好用,但不是什么场景都适合。如果一个页面里几乎都是依次排列的内容,比如表单页、设置页、纵向列表页,用Column或者List才是正解,硬用Stack去叠,反而会让布局层级变得复杂,维护成本直线上升。

给一个简单的判断标准:如果界面元素之间没有“重叠”需求,并且需要响应式换行或按比例分配空间,那就别用Stack;如果元素之间天然存在压盖关系、需要Z轴层叠、需要某个元素悬浮在其他内容之上,那Stack就是最佳选择。

还有就是性能。Stack本身并不重,但如果一个页面里嵌套了十几层Stack,每层还都带了复杂的子组件,那渲染压力会比同等结构的Column大不少。我的习惯是控制层级深度,能用一层Stack加alignSelf解决的问题,绝不用三层嵌套。这不是Stack的问题,是所有容器布局的通用原则。

6. 进阶:Stack与其他布局的搭配与状态联动

6.1 页面路由栈与Stack布局的区别

讲到这里,顺便厘清一个概念:ArkTS里的页面路由栈(router栈)和Stack布局是两码事。路由栈管的是页面之间的跳转,每个页面是独立的路由实例,从一个页面跳到另一个页面,靠的是router.pushUrl。而Stack布局是在同一个页面内部,管的是组件和组件的叠放。

这两个概念在鸿蒙开发里都带“栈”字,但层级完全不同,千万别混。在页面上看不到“路由栈”这个组件,你是操作不了它的显隐的;反过来,Stack布局也没有能力去控制页面跳转,它只负责组件排版。把它们弄混是不少初学者写了好几天之后才反应过来的事。

如果看到有些人把多个“页面内容”直接塞进同一个Stack里,用状态变量控制显示和隐藏,那一定要小心,这属于“伪页面切换”,页面之间没有独立生命周期,状态管理也容易乱,不如直接用路由栈来得干净。

6.2 配合Flex/Grid实现复杂面板

Stack的另一个高价值用法,是在复杂面板里作为“局部层叠容器”和其他布局嵌套。最常见的就是:一个Grid网格,每个格子内部再用Stack去叠角标;或者一个Flex流式标签区域,每个标签做一个小型Stack来展示删除按钮。

比如做一个九宫格图片上传组件(热搜里也经常有人搜“android 九宫格布局”),每格的右上角放一个删除按钮,就可以在Grid的item构造里,用一个Stack包住图片和删除按钮。这样外层Grid负责网格排布,内层Stack负责“图片+删除键”的层叠关系,职责清晰,不会互相污染。

Grid() { ForEach(this.imageList, (item: string) => { GridItem() { Stack({ alignContent: Alignment.Center }) { // 假图片,实际是Image(item) Column() .width('100%') .height('100%') .backgroundColor('#E9ECEF') // 右上角删除按钮 Text('×') .fontSize(18) .fontColor(Color.White) .backgroundColor('#FA5252') .borderRadius(10) .width(20) .height(20) .textAlign(TextAlign.Center) .alignSelf(Alignment.TopEnd) .margin({ top: 4, right: 4 }) .onClick(() => { this.imageList = this.imageList.filter((v: string) => v !== item) }) } } }, (item: string) => item) } .columnsTemplate('1fr 1fr 1fr') .rowsTemplate('1fr 1fr 1fr') .columnsGap(8) .rowsGap(8) .width('100%') .height(260)

这套组合方式在内容型应用里几乎天天用。它继承了Grid的整齐排布优点,又叠加了Stack的层叠能力,两者配合得当,代码可读性和UI还原度都很好。

6.3 状态管理下的层叠刷新细节

最后提一个和状态管理相关的细节。Stack里的子组件显隐切换,如果依赖的是状态变量,那么状态变化的触发方式会影响层级刷新效果。

比如你在Stack里放了一个loading蒙层,用一个布尔变量控制它是否显示。当网络请求开始时把变量设为true,请求结束时设为false。这时候要注意:Stack并不会因为你改变一个状态变量就“重新分配”所有子组件的位置,它只会更新那些真正依赖该状态的节点的可见性、尺寸、内容等。所以只要你没有改其他子组件的数据,兄弟组件的位置基本不会跳动。

但如果你的状态变量里存的是一个数组,比如列表数据,并且你直接修改了数组某个元素,就可能触发包含该元素的组件的重新测量和绘制。如果组件刚好在Stack里,且尺寸是自适应内容,那布局就会重新计算。这一机制本身没问题,但如果发现某些堆叠组件“莫名抖动”,先排查一下是不是父组件或者兄弟组件的某个状态被无意间更新了。

我建议把“遮罩层”“悬浮层”这类组件的显隐和业务数据状态分开维护,尽量让它们只依赖一两个专门的布尔变量,不要和列表、表单数据混在同一个大对象里。这样状态刷新时影响范围最小,不是所有数据变了都需要重新计算整个Stack的布局。

Stack这个布局在ArkTS里的地位,我用一句话总结就是:它解决的是你无法用线性容器解决的“叠放”需求,但它的灵活性也意味着你需要有更明确的层级意识和尺寸控制能力。上面的内容是我在实际项目中反复试出来的,几乎每个示例都在真机上跑过。尤其是alignSelf加margin这套组合方式,学会之后,鸿蒙界面里能挡住你的布局难题,十之八九都能化解。

如果你在某一步踩了坑,建议先回到这一篇文章,把第3节的两种对齐方式重新吃透,再去看第5节的避坑场景。很多看起来玄乎的布局问题,本质上就是对“整体对齐”和“个体对齐”这两个概念没分清楚。搞定了这两个点,Stack用起来就顺畅多了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 2:19:20

基于OpenCV的舞蹈镜像对比学习工具开发实战

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

作者头像 李华
网站建设 2026/9/8 2:18:23

Word论文页眉页脚设置:分节、页码与常见问题全解析

写毕业论文的时候,很多人都被 Word 页眉页脚折磨过。明明设置了页码,正文前面的摘要目录也带上了编号;明明删掉了页眉里的横线,下一页又冒出来;明明想从某一页开始插入罗马数字页码,结果整个文档全都乱了。…

作者头像 李华
网站建设 2026/9/8 2:17:35

1968道奇Charger改装:千匹马力碳纤维肌肉车技术解析

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

作者头像 李华
网站建设 2026/9/8 2:17:22

轻量级灰度发布平台实践:基于Spring Cloud Gateway与Redis的动态流量控制

1. 先想清楚再动手:这套轻量灰度平台的方案选型 先说一个我自己的线上事故。有一次发一个新版订单服务,自测、测试环境全过了,结果全量上线后不到十分钟,用户开始集中反馈下单页白屏。最后定位到是某个老浏览器不兼容新前端资源的…

作者头像 李华
网站建设 2026/9/8 2:17:12

flutter_displaymode_鸿蒙适配与权限调研

Flutter Display Mode 适配 OpenHarmony:先确认三方应用能否设置显示模式 前言 flutter_displaymode 是一个面向 Android 的 Flutter 插件,用于读取设备支持的显示模式,并设置应用希望使用的分辨率与刷新率。pub.dev 当前页面显示的版本为 …

作者头像 李华
网站建设 2026/9/8 2:15:08

AI视频生成技术解析:从扩散模型到创意短视频实战

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

作者头像 李华