news 2026/9/18 3:33:44

Adobe XD堆栈与状态:打造会呼吸的响应式UI设计稿

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Adobe XD堆栈与状态:打造会呼吸的响应式UI设计稿

做设计这些年,我最大的感受是:设计稿一旦交付,就成了一具“尸体”。开发照着标注还原,做着做着总会跑回来问:“这个区域内容多了怎么办?”“鼠标悬停时有没有反馈?”“小屏下这几个按钮怎么排?”以前我的答案往往是再补几块画板、再标注几行说明,直到Adobe XD把“堆栈”和“状态”这两个功能补全之后,我才真正体会到什么叫“活”的响应式UI设计稿——它不是一个结果,而是一套规则,一套像代码一样能自动适应、能响应交互的规则。

这篇文章我想把这套玩法完整拆开讲:堆栈怎么做自动布局,状态怎么让组件“有表情”,两者怎么配合起来做真实可用的响应式界面,以及我在实际项目中踩过的坑。适合正在用XD做UI/UX设计、厌倦了反复手动处理静态组件和重复画板的设计师,也适合想搞懂“设计稿里的Flexbox和交互状态到底怎么表达”的前端同学。

1. 静态组件的死穴:为什么设计稿总像一张图

先别急着学功能,我们得先弄明白痛点到底在哪。做了这么多年设计稿,我发现自己绝大多数时间不是在思考方案,而是在给“不会动的图层”收拾烂摊子。组、符号、智能对象……这些工具本质上都只是把元素打包,并没有让元素之间的关系产生任何“规则”。于是设计稿永远是一张静态图,而不是一个可生长的界面。

1.1 组(Group)的痛点:改一处,崩一片

用过XD的人都知道“组”是什么:选中多个对象,右键Group,它们就被打包了。移动方便、缩放方便,看起来挺省心。但本质问题在于,组内的元素彼此之间没有任何约束关系。你往组里加一行文字,其他元素纹丝不动;你把组宽度拉窄,文字可能直接溢出到外面;你想调整某个元素和另一个的间距,得挨个算坐标,眼睛盯到发花。

用组做卡片是最典型的灾难现场。卡片里有图片、标题、两行描述、一个按钮,看着整整齐齐。但如果标题文字长了一点点、按钮文案换成了“加入购物车并查看详情”,整张卡片的垂直节奏瞬间被打乱,你得手动把后面的元素一个个向下挪,同时还要保证卡片高度一致。这种操作在组件库里动辄几十个卡片的情况下,等于上班两小时、调间距一下午。

组还有一个隐藏问题:它只对“你看得见的那一稿”负责。换句话说,组解决的是“当前状态下这些元素摆在一起不散”,但它不回答“元素数量变了、文字长度变了、容器尺寸变了,它们该怎么办”。而这恰恰是响应式UI的核心问题。

1.2 状态的缺失:原型只能演示“理想状态”

静态组件不只是布局上的僵硬,还有交互表达上的苍白。做原型时,我们最常听到的需求是:“这个按钮悬停要变颜色”“这个菜单点完要展开”“这个表单输错要报错”。以前的做法是什么?复制一份画板,把按钮颜色改深一点,然后在原型连线里从“正常画板”跳到“悬停画板”。如果组件有五种状态,你就得复制五份画板,每个状态之间都要连线维护。画板一多,文件体积暴涨,协作时也容易看着满屏箭头失去方向。

更痛的是状态之间的“逻辑”是割裂的。画板A里的蓝色按钮和画板B里的深蓝按钮,在开发眼里本来应该是同一个按钮的两个状态,但在设计文件里它们是两个完全独立的图层。你改了其中一份,另一份不会自动同步。于是经常出现这样的情况:开发实现时照着深蓝色那个去查标注,发现标注还是正常态的蓝色,又得跑去问设计师“到底以哪个为准”。

1.3 XD的破局思路:定义“规则”而不是“结果”

XD引入堆栈和状态,思路和传统设计工具完全不同:它不再让你输出一个个“结果画面”,而是让你定义一套“规则”,让元素在增删、缩放、交互时自动按照规则重新排列和变脸。

堆栈对应的其实是前端开发里的Flexbox布局思路:方向、间距、边距、对齐这些约束一旦设定,内部元素发生变化时,布局自动重排,不需要你手动挪。状态对应的则是状态机的思路:同一个组件在默认、悬停、点击、禁用等不同情况下应该长什么样、怎么切换,这些都在组件层面完成,而不是复制出N份松散图层。

我第一次用这两个功能搭出一套带悬停态的自适应卡片时,突然有一种感觉:这不像是在画图,更像是在给界面“编程”。设计稿不再是一张截图,而是一个带规则的模型。这,才是“活”的响应式UI的底层逻辑。

2. 堆栈Stack:让间距和布局拥有“肌肉记忆”

堆栈是XD在布局领域最重要的一次更新。它解决的不是“画得快一点”,而是让整个设计文件里的间距、排列方式变成可维护的规则。我建议所有长期用XD产出界面的同学,把它当成默认工具而不是偶尔用一下的高级功能。

2.1 堆栈的核心逻辑:从“手动安排”到“自动排版”

堆栈的创建很简单:选中多个对象,点击属性面板里的“堆栈”图标(有水平堆栈和垂直堆栈两个选项),它们就自动变成一个有规则的布局容器。在这个容器里,你不需要再记住每个元素之间的间距是多少,只需要在属性面板里设置一个固定的间距值,所有元素都会以这个间距统一排列。

听上去和“对齐工具”差不多?差别非常大。对齐工具是“这一刻把元素摆齐”,而堆栈是“以后无论怎么变,都保持这套对齐和间距规则”。你往堆栈里拖入一个新元素,其他元素会自动让位,间距自动保持一致;你删掉其中一个,剩下的元素会立刻重新排布,不需要后退撤销或者重新对齐。你想调整个间距,只需要改一个数值,整个堆栈里的所有元素全部同步生效。

我用一个生活化的类比来解释:手动排版就像你用手把一摞书一本一本码整齐,哪本书抽出来或塞进去,整摞书都要重新码一遍。堆栈就像给这摞书加了一根固定的书立,间距、整齐度都由书立保证,你只管往里取书、放书就行。这种“肌肉记忆”般的布局约束,就是响应式UI的第一块拼图。

2.2 堆栈实操入坑:从导航栏到卡片列表

先说最简单的导航栏。平时我做导航栏,需要手动调整Logo、菜单项、按钮之间的间距,菜单项数量一变,所有水平间距都要重新弄一遍。用堆栈就干脆多了:把Logo、若干菜单文字、按钮全选,点一下水平堆栈,设置间距为24px,对齐方式为垂直居中对齐,左右再加24px的填充。之后不管是从导航里删除一个菜单项,还是临时加一个“更新日志”的入口,所有内容都会自动保持24px间距并整体水平排列,导航栏的高度也因为有填充的存在而不会变形。

再看内容的垂直堆栈。做一套图文卡片列表时,我会先画好图片、标题、描述、按钮四个元素,全部选中,点垂直堆栈,间距设置12px,内边距设置16px。这样一个卡片就拥有了完整的垂直节奏:图片在上,文字在中间,按钮在底部。当其中一条描述文字在真实场景里可能会变成两行时,我只需要把模型里的文字改长一点,按钮会自动被往下推,卡片高度自动增加,不会出现文字重叠或按钮挤到文字上的情况。

XMind里的嵌套操作也很常见:卡片内部有“头部区域”和“内容区域”,头部又包含头像、昵称、时间,内容又包含正文和操作按钮。我会先把头部做成一个水平堆栈,把内容做成一个垂直堆栈,再把这两个堆栈一起选中,包成一个大的垂直堆栈。嵌套堆栈的好处是每一层都有独立的间距规则。头部间距改了,不会影响正文部分;正文加了内容,也只会在自己的区域内撑开,不会把头部搞乱。

堆栈还有一个容易被忽略的属性——填充(Padding)。它控制的是堆栈边框和内部元素之间的距离。比如按钮组件,我会在文字外面再包一个堆栈,左右填充16px、垂直填充8px。这样按钮的尺寸就是由内容自动撑开的:文字变长了,按钮自动变宽,完全不需要手动拉伸。这一点和开发里的内边距概念完全一致,交付时开发也特别容易理解。

2.3 间距单位、对齐方式和约束的工程化习惯

说实话,堆栈用久了,最大的收获不只是效率,而是你会被迫去想“设计系统”这件事。因为堆栈里的间距是要填数字的,你不可能高兴填多少就填多少,否则整个项目会变成一堆杂乱的数字。我的建议是:用4px或8px作为基础间距单位,堆栈间距尽量选8px、16px、24px、32px这样的整数倍。这样做出来的页面,节奏感会更强,开发还原时也更方便。

对齐方式上,水平堆栈推荐用“垂直居中对齐”,垂直堆栈则多用“左对齐”。这种默认组合在多数字实际界面里最自然。如果某个元素在堆栈里需要独立对齐,比如垂直堆栈里有一行想右对齐,可以选中这个元素,在右侧属性面板单独改它的“对齐”属性,覆盖堆栈的默认对齐方式。这个“局部覆盖”不会破坏整个堆栈的规则,相当实用。

还有一个容易忽略的选项是“响应式调整大小”。开启之后,你可以设置元素相对于堆栈容器的约束方式,比如固定到左、右、顶部或底部。这在容器宽度变化时非常有用。举个例子,一个卡片堆栈,图片区设置为“固定到左右两端并适应宽度”,文字区设置为“固定到左侧”,按钮区设置为“固定到右侧”。当卡片容器变宽时,图片会被拉伸,按钮停在右侧,文字保持在左侧,整个布局依然成立,不需要你手动一个个调位置。约束、堆栈、响应式调整大小这三者一起用,才算真正把XD的响应式能力用到位。

3. 状态States:让组件在不同交互下切换面孔

布局会自动重排了,但界面交互还差一步:组件怎么根据用户的操作“变脸”。传统做法是一组画板之间跳转,既笨重又容易脱节。XD的“状态”功能就是拿来解决这个问题的,它给同一个组件加上了多个“形态”,并通过原型连线定义互相切换的条件。

3.1 状态的本质:同一个组件,多种姿态

在XD里,先把一个对象变成组件(Component),然后在原型模式下选中它,右侧栏会出现“状态”面板。默认状态叫“Default State”,点面板里的“+”号,就可以添加新的状态,比如“Hover”“Pressed”“Disabled”或者自定义名称如“展开”“收起”。每个状态下,你可以独立修改组件的外观:颜色、圆角、阴影、文字内容、内部布局都可以不同。

关键在于,这些状态是挂在同一个组件上的。你在默认状态里改了按钮文字,其他状态不会自动跟着改(因为状态之间可以有差异),你可以理解为这是一种“并行版本”:同一个组件,根据不同的外部条件,展示不同的变体。不需要复制图层,不需要新建画板,组件库也不会膨胀,所有状态整整齐齐收在同一个组件下面。

我在实际项目中最常用的是给按钮做三件套:默认状态、悬停状态、禁用状态。默认状态是蓝色填充、白色文字,悬停状态把填充色加深一档并加一个轻微阴影,禁用状态把填充改为灰色、文字透明度降低。一套按钮组件拥有了三个“面孔”,但在组件列表里仍然只有一个组件。

3.2 状态切换的五种触发方式与动画设置

状态之间不是自动切换的,需要你明确建立“交互规则”。在原型模式下,选中组件的默认状态,拖动右上角的连线手柄到另一个状态画布上,松开后会弹出交互设置面板。在这里可以设置触发器、动作和过渡动画。

触发器有以下几种常用类型:点击(适用于按钮、菜单项)、悬停(适用于桌面端hover反馈)、键盘按键(比如按“空格”播放、Esc关闭弹窗)、时间延迟(比如3秒后自动跳转到下一个状态)、语音(主要用于语音交互原型),以及拖拽。选择哪种触发方式,取决于你要模拟的现实场景。桌面端悬停是刚需,移动端往往用点击代替。

过渡动画的意思是,从一个状态切到另一个状态时,画面怎么变化。XD提供了“无”、“溶解”、“滑动”和“自动制作动画”这几种选项。我强烈推荐“自动制作动画”:它会自动识别两个状态之间相同属性和坐标的对象,然后生成平滑的过渡效果。比如默认状态下按钮的背景色是蓝色,悬停状态是深蓝色,用自动制作动画后,预览时鼠标移上去,背景色会平滑渐变而不是瞬间跳变,观感接近真实网页交互。

为了实际体验,拿我刚说过的三态按钮举例。在默认状态拖连线到Hover状态,触发器选“悬停”,动作选“过渡”,过渡方式选“自动制作动画”;再从Hover状态拉一条线回到Default状态,触发器也选“悬停”,但切换条件可以理解为“离开悬停区域返回默认”。如果还需要“点击”的按压反馈,就再创建Pressed状态,从Default拖线到Pressed,触发器选“点击”。这样一套简单的状态机就搭好了,预览时按钮已经有了完整的交互反馈。

3.3 状态与变体(Variants)到底怎么选?

用XD的人经常会在“状态”和“变体”之间迷惑。我在项目里也纠结过很久。先给结论:两者可以共存,但适用场景不同。

变体(Variants)偏向设计系统管理,你可以把一个组件的多个视觉样式集中放在一个组件里,用属性切换。比如一个按钮有“主要按钮”“次要按钮”“文字按钮”三种变体,它们像同一个组件的多个“版本”,主要用于统一维护设计规范、批量替换样式。状态(States)则更偏向原型交互验证,它强调的是“同一个视觉版本在不同交互阶段的样子”,比如默认、悬停、点击、禁用。变体回答“这个组件有哪几种兄弟样式”,状态回答“这个组件在一个交互流程里有哪些阶段”。

对比项状态(States)变体(Variants)
核心目的表达同一组件的交互阶段管理设计系统中的多套样式
交互能力直接连线触发,支持动画过渡多用于设计面板和组件库管理
典型应用按钮hover、菜单展开、表单焦点按钮主次样式、主题色、尺寸规格

我的经验是:组件库建设阶段多用变体,把一个组件在视觉层面会出现的各种情况定义清楚;交互原型阶段多用状态,把某个场景下用户操作引发的反馈验证清楚。一个商业级组件往往两者都要做:变体定义外观,状态定义交互。

4. 堆栈+状态组合实战:搭一个会呼吸的卡片组件

单独讲完堆栈和状态,很多人还是会觉得这是两个孤立功能。真正产生质变的是把两者组合起来。举个我在实际项目中常做的例子:电商商品卡片。它既有堆栈支撑的自动布局,又有状态支撑的交互反馈,可以说是一个微型“活组件”。

4.1 组合实例如下:一个带悬停展示加购按钮的商品卡片

我先按堆栈的思路把卡片基础结构搭出来:

  1. 顶部放一张商品图片矩形,作为卡片的第一行;
  2. 图片下面依次放商品标题、价格文字;
  3. 再下面放一个“查看详情”按钮;
  4. 将这四部分从上到下选中,点击垂直堆栈,间距设为12px,填充设为16px;
  5. 商品标题和价格都放在一个水平堆栈里,让它们拥有同样的左对齐规则。

现在这个卡片还是一个“静态布局”状态。接下来给它加交互:我在原型模式中,选中这个卡片组件,在状态面板点“+”新建一个“Hover”状态。在Hover状态里,我在“查看详情”按钮下方,再增加一个浅色描边按钮,命名为“加入购物车”。因为我之前把卡片内容做成了一个垂直堆栈,此时“加入购物车”按钮会自动被排进堆栈里,不会出现重叠或者错位。

接下来,从默认状态拖一根连线到Hover状态,触发器选择“悬停”,过渡方式选择“自动制作动画”。再拖一根回到默认状态,同样用“悬停”触发,让鼠标离开时恢复原状。预览时,鼠标移入卡片,“加入购物车”按钮就像被推出来一样平滑出现,原本的按钮和文字自动向上收缩一小段距离,整体高度被撑开;鼠标移出,一切恢复。整个过程中,我几乎没有手动调整过任何坐标或间距,全靠堆栈在状态切换时自动重排。

这个案例完美演示了堆栈和状态的分工:堆栈负责“结构跟着内容走”,状态负责“结构跟着交互走”。没有堆栈,我必须在两个状态里手调所有元素的位置,状态多了必定对不齐;没有状态,我只能把“加入购物车”按钮画死在卡片底部,无法做出悬停展开的效果。

4.2 响应式容器:一个组件适配多种屏宽

响应式UI不能只适配“内容变化”,还要适配“容器宽度变化”。XD里,堆栈容器本身可以手动拉伸,或者通过“响应式调整大小”功能设置约束。我常做的一件事是:把同一个卡片组件复制到移动端、平板端、桌面端三块画板里,然后分别调整容器的宽度,观察堆栈内部元素如何重排。

对于这个商品卡片,在小屏宽下,标题和价格在同一个水平堆栈里会显得拥挤,我可以利用堆栈的“自动换行”特性(XD的堆栈可以通过手动拖动宽度让内部元素自动换行,类似flex-wrap),或者干脆针对小屏调整水平堆栈的方向为垂直堆栈,让标题和价格上下排。之后用状态或组件变体来管理这几套不同屏宽的布局形态。

实际测试中我会重点检查三件事:图片是否会因为容器变宽而变形、按钮是不是始终保持在卡片底部、间距在不同宽度下是否还能保持统一节奏。配合约束功能,把图片设置为“固定到左右两端”,按钮设置为“固定到左端”,这样即使容器变宽了,图片会被拉宽,按钮不会跟着跑到奇怪的位置。对比多个断点画板时,如果发现布局错位,问题通常出在个别元素没有做好约束,而不是整个堆栈失效。

4.3 从原型到交付:把“活”规则交接给开发

很多设计师担心:“如果我用了堆栈和状态,开发能看得懂吗?”我的经验是:只要你在交付时做一点额外工作,开发不仅看得懂,而且会感谢你。XD的开发者模式可以直接查看选中元素的属性、间距、尺寸和代码片段。当你选中一个堆栈容器时,开发者面板会以弹性布局(Flex)的方式展示容器的方向、间隙、内边距和对齐方式——这正好对应前端常用的Flexbox。开发照着堆栈结构来写div和className,几乎可以做到“像素级”还原。

状态这一块,我会在交付说明里额外附一段文字,把每个状态对应的交互条件写清楚。比如“Hover:鼠标悬停时显示加入购物车按钮,过渡动画时长150ms,缓动ease-out”“Disabled:按钮置灰,不可点击”。开发拿到这些信息,能够直接对应到CSS的:hover、:disabled、:active等伪类,甚至能用状态机库来实现复杂交互。堆栈给了我一个可以交给开发的“布局模型”,状态给了我一份“交互状态表”,设计稿终于从静态标注升级成了可执行的行为规格。

5. 翻车复盘:堆栈过深、状态错位与协作难题

功能再好用,落到真实项目里也不会一帆风顺。我用了段时间后发现,堆栈和状态在带来效率提升的同时,也带来了一些新的麻烦。这些问题我在网上不一定搜得到答案,基本是靠自己一点点踩出来的,分享出来给大家排雷。

5.1 堆栈嵌套太深之后,文件开始“犯困”

堆栈可以嵌套,嵌套的层数越多,布局的灵活性越强,但文件性能会明显下降。我第一次做一个复杂后台表单时,把表单容器、区块、行、列全部做成堆栈,一路嵌套了七八层。后果是:编辑某个文本框时,整个画板有明显的延迟,拖动元素像在拖果冻;有时候修改一个间距,要等一两秒才能看到效果。

后来我总结出两个对策。第一,控制堆栈层级,尽量限制在四层以内。如果一个堆栈的内部只是一个静态图标或者固定素材,完全可以把这部分先转成“组”再放进堆栈,没必要所有元素都堆栈化。第二,合理使用“打卡”式的顶层分组。当堆栈结构非常复杂时,我会把已经稳定的部分封装成组件,因为组件在编辑时比原始堆栈结构要轻量一些,整个文件的响应速度也能得到改善。

5.2 状态切换时的自动布局错位

状态切换和堆栈重排的配合,在“悬停新增元素”这个场景下很顺畅,但一旦在状态里改了堆栈的间距或某个元素的大小,就会出现跳变和错位。有一回我做下拉菜单的状态:默认状态只显示一个输入框,展开状态在下方多出一组选项。为了拉开间距,我在展开状态里把垂直堆栈的间距从4px改成了8px,结果预览时点击展开,选项列表出现的同时,整个输入框的位置也跟着抖了一下,观感非常廉价。

排查后发现,问题出在“状态之间的堆栈规则不一致”:两个状态的布局参数没有保持统一,自动制作动画时,XD会尝试在两个状态之间插值过渡,但间距和位置同时变化,过渡就会产生跳跃感。解决方案是:尽量保持状态之间堆栈的间距、填充、对齐方式一致;如果必须调整间距,请给这个变化单独做一个过渡动画,并且把过渡时长放大到300ms以上,让用户的视线能跟上变化,而不是被闪到。另一个更稳妥的方案是:把展开前后的状态设计成“同一套堆栈规则,只是内部元素增删”,这样自动制作动画只会有元素出现/消失的位移,不会触发间距变化导致全局跳动。

5.3 和小白团队协作:接手的人不会用,全废了

这是最让我头疼的一个问题。当我把一个用堆栈和状态做得行云流水的组件文件交给同事,发现对方完全把它当成普通组来用,随手拖拽、随意删掉堆栈中的元素,甚至把状态面板里默认状态下新增了一堆东,没过两天整个组件就变得面目全非。

我后来在公司内部定了几条协作约定:第一,所有用堆栈做布局的组件,必须在图层命名里标注“Stack开头”,并在说明文里写清楚“请不要手动拖动内部元素”;第二,状态相关的内容只在原型模式下编辑,并且给每个状态起语义化名称,而不是默认的“状态1”“状态2”;第三,交付开发前,我会打开原型模式录制一段2分钟的操作演示视频,把哪些地方是悬停、哪些地方是点击触发、哪些布局会自动重排演示一遍,让接手的同事“先看演示再用文件”。

我甚至建议团队里的设计师朋友:把XD文件当作一份“设计系统的源代码”,而不是一张“出图图纸”。维护这份代码需要规范,也需要文档。每次新增或修改组件,备注好改动点和原因,比花时间画一堆静态标注更值得。

实际用下来的感受是:堆栈和状态这两个功能,让XD从“绘图工具”进化成了“设计规则引擎”。它不再逼你用结果去反推过程,而是让你定义过程本身,让界面按照你的规则自己生长、自己变化。如果你现在手头正好有一个待搭建的按钮或者卡片组件,我建议你花十分钟,用堆栈把布局搭出来,再开一个状态做悬停反馈。试完你就会明白,那种“设计稿不再是死的”的感觉,和以前完全不一样。

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

研究情报库检索 RSI,TaoToken 放在向量化脚本

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

作者头像 李华
网站建设 2026/9/18 3:33:39

3ds Max 2027工业级建模工作流实战指南

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

作者头像 李华
网站建设 2026/9/18 3:31:53

闲置盒子变服务器:RK3568 刷 Armbian 的 4 步改造攻略

闲置盒子变服务器:RK3568 刷 Armbian 的 4 步改造攻略 【免费下载链接】amlogic-s9xxx-armbian Supports running Armbian on Amlogic, Allwinner, and Rockchip devices. Support a311d, s922x, s905x3, s905x2, s912, s905d, s905x, s905w, s905, s905l, rk3588, …

作者头像 李华
网站建设 2026/9/18 3:29:52

FDM打印的因果互锁盖板设计:机械互锁成败的关键

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

作者头像 李华