ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Axure RP8动态面板实现菜单栏折叠展开实战指南

Axure RP8动态面板实现菜单栏折叠展开实战指南

做原型的人大概都遇到过这样的场面:评审会上有人随手点了一下左侧导航,结果整条菜单纹丝不动,或者"啪"地一下弹开、把下面的内容全盖住了,然后全场安静三秒看着你。折叠展开这个交互看着简单,但在Axure RP8 动态面板里,它是最容易做出"能点但别扭"效果的一个点。这篇文章就围绕Axure RP8 用动态面板实现菜单栏折叠和展开这件事,把我自己反复做过十几遍导航原型的经验整理出来:动态面板为什么是这件事的最优解、状态该怎么切、推动元件的方向为什么老是反、多级菜单怎么做到一次只开一个、以及那些只有真正交付过原型才会遇到的尺寸错位和交互打架问题。不管你是刚开始学 Axure RP8 的新手,还是已经能做页面跳转但一直做不好交互动画的老手,下面这些内容都应该能直接抄到你的文件里用。

1. 折叠展开这件事,为什么第一版几乎都会做歪

1.1 动态面板在原型里的真实角色:一个能装多页内容的卡片盒

先把概念摆正。动态面板(Dynamic Panel)说白了就是一个卡片盒,盒子里可以放很多张卡片,每张卡片叫一个状态(State)。盒子的外框大小是固定的(除非你开了适应内容),你一次只能看到其中一张卡片上的东西。这个比喻很重要,因为很多人做折叠菜单时,脑子里想的是"把菜单变高变矮",而动态面板干的事情其实是"换一张卡片"。

理解了这个差别,你就能明白为什么要做两件事:第一,给面板准备两个状态,一个叫"折叠"、一个叫"展开",两边的菜单条目数量不一样;第二,切换状态的时候,要让下方的联系人、内容区、页脚这些东西跟着上下移动,否则菜单展开后就会盖住下面的内容。前者靠"设置面板状态"实现,后者靠"推动元件"(Push/Pull Widgets)实现。

我见过很多人第一次做这个效果,做法是给菜单项一根一根加"显示/隐藏"交互,做八个菜单项就得写十六行交互,改一个条目要动四行。这不是不行,是没法维护——产品经理说"再加一个二级页面",你就得从头再捋一遍。而用动态面板做,加一个条目只需要进状态里复制一行文字,交互逻辑一行都不用改。这就是我在所有菜单类需求里优先选动态面板的核心原因:把"内容"和"控制"彻底分开。

1.2 三条技术路线的对比与选型依据

做折叠展开,Axure RP8 里其实有三条路可走,各有各的适用场景,选错了后面越做越难受。

实现路线核心动作优点明显短板适合场景
动态面板状态切换设置面板状态 + 推动元件结构清晰,内容与逻辑分离,好维护需要处理状态尺寸一致性菜单、折叠面板、常见问答列表
显示/隐藏元件组逐个设置显示或隐藏,配动画上手最快,不需要建状态条目一多交互就爆炸,无法做统一控制只有两三个条目的简单场景
移动元件移动元件到指定坐标可以做任意的位移动画坐标要手算,内容高度变化就全乱抽屉式侧边栏、从底部升起的面板

我一般这样决策:条目数量固定、每次展开内容一样的,用动态面板;条目数量少、内容不再变的,用显示隐藏;需要整块内容从屏幕外滑进来的,用移动元件。菜单栏这种典型场景,条目会变、层级会加,动态面板是唯一不会让你返工重做的方案。

还有一个经常被忽略的第四种思路:把整块页面内容都包进一个动态面板,开"适应内容"(Fit to Content)。这个做法在 RP8 里其实更稳,因为它让面板高度跟着内容自动变,下方元素天然被"顶"下去,不用依赖推动元件。缺点是设计时要规划好谁在里面谁在外面,临时改动成本高。我在做那种七八个菜单、每个展开高度都不一样的复杂导航时会用它,后面第 4 章会细讲。

1.3 先想清楚"展开"到底要不要盖住内容

这是个产品层面的问题,但会直接决定你的技术方案。折叠菜单有两种截然不同的行为:

  • 推挤型:菜单展开时把下方内容往下顶,页面整体变长。这是移动端 App 导航的常见做法,也是绝大多数后台系统侧边栏的做法。
  • 覆盖型:菜单展开时浮在上层,下方内容不动,靠 z 轴分层。桌面软件的右键菜单、顶栏下拉菜单是这种。

选择哪一种,要看你的原型演示场景。如果是给客户演示信息层级,推挤型更符合真实浏览习惯;如果是演示弹层类交互,覆盖型更贴切。技术上的差别在于:推挤型必须配推动元件,覆盖型只需要把面板层级调到顶层(顶层容器 / Bring to Front)且不勾推动。

我踩过的第一个坑就在这里:早期做一个顶部导航下拉,我勾了推动,结果整页内容被顶下去,评审时被问"为什么这个菜单一出来页面就跳",很尴尬。从那以后我给自己定了个规矩——横向下拉、浮层类一律不推动;纵向列表、可折叠面板一律推动。这条规律适用面很广,基本不会错。

2. 动手之前,先把结构和尺寸算清楚

2.1 把菜单拆成三个角色:容器、扳机、内容

我建议在落笔之前先在纸上(或者草稿区)把菜单拆成三个角色,这三者理清了,交互逻辑自然就出来了:

  1. 容器(Panel):动态面板本体,负责承载状态、控制高度。
  2. 扳机(Trigger):用户点的那个东西,通常是一行标题或一个图标,比如"产品管理"加上右边一个小三角。
  3. 内容(Content):展开后露出来的那些条目,放在面板的"展开"状态里。

绝大多数人做歪,是因为把扳机放在了容器外面,或者把扳机做进了两个状态里各一份。前者会导致折叠时点击区域和面板脱节,后者会出现"点击同一位置但实际是两个不同元件"的诡异 bug——尤其是你做悬停效果的时候,鼠标移过去图标闪一下,因为状态切换把元件换掉了。

我的做法固定下来是这样的:扳机放在容器内部、放在两个状态里的相同位置、并且用同一个元件(通过复制粘贴状态内容来保证一致)。这样无论展开还是折叠,用户点到的永远是同一个坐标、同一块区域,交互也只需要绑定一次。RP8 的状态切换不会销毁元件实例,所以绑在扳机上的交互在两个状态下都生效,不用重复写。

2.2 尺寸与间距的预先计算,附一张够用的参数表

原型做多了会发现,视觉上"别扭"十有八九是尺寸不齐。折叠菜单尤其敏感,因为它在展开和折叠之间切换,任何一像素的错位都会被动画放大。

我常用的参数起点是这样的(按 1440 宽桌面端设计稿,移动端按 375 宽等比缩):

参数项建议值说明
一级菜单行高44 px低于 40 点击区域偏小,高于 48 显得松散
二级菜单行高36 px比一级矮一档,形成层级感
二级菜单左缩进24 px缩进太小层级看不出来,太大文字挤
图标尺寸16 × 16 px三角、箭头、加号都用这个尺寸
图标与文字间距8 px再小就贴住了
容器宽度240 px侧边栏常用值;顶栏下拉按内容撑开
展开动画时长300 ms400 ms 偏拖沓,200 ms 又太急
折叠动画时长250 ms收起比展开略快,体感更利落

这里有两个经验值值得单独说。第一,收缩动画比展开动画快一点。这是很多交互设计师的共识,因为用户"关闭"的心理预期是立即消失,而"打开"需要一点时间建立空间关系。我一般设展开 300ms、折叠 250ms,实测下来节奏很舒服。第二,缓动(Easing)别用默认的线性。线性动画看起来机械,改用 Ease Out(先快后慢)会自然很多,尤其是向下展开的时候,末尾那一点减速让人感觉面板"落"下来了。

还有一个隐蔽的尺寸问题:折叠状态和展开状态的容器宽度必须完全一致。如果展开状态里因为加了缩进文字,面板被撑宽了 2px,切换的时候整体布局会左右抖一下。我的做法是先把两个状态都建好,然后手动把两个状态的尺寸输成同一个数值,不依赖拖拽。

3. 从零做出一个能用的折叠菜单

3.1 建面板、加状态、铺内容

具体操作我按顺序走一遍。先在画布上把折叠状态下要显示的那一行做出来——一行文字加一个三角图标,选中它们,右键选"转换为动态面板"(或者从顶部菜单插入动态面板再把元件拖进去)。给它起个名字,比如menu-product,名字一定要起,等到页面里有五六个面板的时候,Dynamic Panel 7这种默认名会让你找疯。

双击面板进入编辑状态,顶部会出现状态标签栏,默认只有State1。点标签栏上的加号新增一个状态,把State1重命名为"折叠"、新的那个叫"展开"。命名这件事同样别偷懒,后面写交互的时候,下拉列表里会并列出现"折叠""展开"和"State 1""State 2",前者一眼就懂,后者要点开试。

然后切换到"展开"状态,把二级菜单条目一条条铺进去。这里有个效率技巧:先在"展开"状态里把内容做好,再复制整块内容回"折叠"状态,然后删掉多余的条目。这样两个状态的扳机行位置、字体、间距天然一致,不会出现切换时文字跳一格的情况。

内容铺完,把面板的尺寸调成"折叠"状态的高度(此时内容会被裁掉,这是正常的,RP8 只显示当前状态那一屏)。如果内容被裁得看不见了,可以在面板属性里把"适应内容"(Fit to Content)打开——这个选项我在后面讲复杂菜单时会重点用。

3.2 绑定切换交互:动画、时长与推动元件的选择

选中面板(注意是选面板,不是选里面的元件),在右侧交互面板里新建交互,触发方式选"单击时"(OnClick),动作选"设置面板状态"(Set Panel State)。

配置有四块,一块都别漏:

  • 目标面板:选你自己,也就是menu-product。这里有个细节——在面板内部选中面板本身有时会选到父级,稳妥的做法是在画布上点面板的外边框,或者从左侧大纲(Outline)面板里点。
  • 状态:选"展开"。
  • 动画:选"向下滑动"(Slide Down)。如果是从下面往上开的,选"向上滑动"。
  • 时长与缓动:300 ms + Ease Out。
  • 推动元件:勾上"推动/拉动元件"(Push/Pull Widgets),方向选"向下"。

这里解释一下为什么要用"滑动"而不是"淡入"。淡入是透明度变化,面板高度瞬间变成展开状态的高度,下方内容会先被顶开再慢慢显影,视觉上"跳"一下。滑动则是高度渐变,配合推动元件,下方内容是被平滑推下去的,这才是真实产品的手感。

然后在"展开"状态里,给同一个扳机再绑一个反向交互:设置面板状态为"折叠",动画选"向上滑动",同样勾推动、方向选"向上"。这两条交互一正一反,就构成了完整的开合循环。

注意:RP8 里"推动/拉动元件"只在你切换状态或显示隐藏时可用,纯移动元件是推不动的。这是很多人找不到推动选项的原因。

3.3 推动元件容易翻车的三个方向问题

推动元件看着只是勾一下加选个方向,但它是我见过翻车率最高的地方,具体有三种表现:

第一种:折叠回去的时候,下方内容没回来。原因通常是折叠那条交互的方向选成了"向下"。记住一个口诀——展开往哪推,折叠就往反方向拉。展开是把内容往下顶,方向选向下;折叠是把内容往回收,方向选向上。方向反了,RP8 会认为你要把下方元件再往下推一段,于是页面上凭空多出一块空白。

第二种:连点两下就乱了。用户手快点两下,面板在展开和折叠之间来回切,下面内容被推了两次,位置就永久错位了。RP8 没有内置的防抖,解决办法有两个:一是把交互改成"切换"逻辑,用"设置面板状态 → 下一个状态"(Next)代替写死"展开/折叠",这样无论点多少下状态都在两个之间轮转,不会出现"设成展开"但它本来就是展开的无效操作;二是把动画时长缩短到 200ms 以内,让用户来不及连点。

第三种:推动的时候把不该推的东西也推了。推动元件是"把面板下方的、与面板有横向重叠的元件往下推",如果你的画布上左边是菜单、右边是内容区,而内容区恰好有一块元件的横向范围跟面板重叠了,它也会被推下去,出现"左边点菜单右边内容跟着跳"的诡异效果。解决办法是给页面分区:把菜单区和内容区各自包进一个容器(RP8 里可以用一个透明矩形或者再套一层动态面板),推动就只影响容器内的元件。

提示:如果你的菜单右边紧贴着内容区,宁可手动给内容区加一条"移动元件"交互,用坐标控制,也别指望推动元件能精准只推你想推的那部分。

3.4 给箭头加上旋转反馈

菜单能开合了,但用户看不出当前是开着的还是关着的,除非去数下面有几个条目。所以要做图标反馈。RP8 里有三种做法,我按推荐度排:

旋转(Rotate):给三角图标加交互,展开时旋转 180 度、时长 200ms。这是最省事也最专业的做法,视觉上箭头从"朝下"变成"朝上",语义清晰。要注意旋转中心点,默认是元件中心,三角图标的中心旋转没问题;如果是长条形的箭头图标,得先把元件边界调成正方形再转,否则会甩出一段奇怪的弧线。

切换图标(Set Image):准备好朝下和朝上两个图标,展开时设置图片为朝上那个。这个做法的好处是可以换成完全不同的图形(比如加号变减号),坏处是多管理一份素材。

动态面板做图标:把图标本身做成一个小动态面板,两个状态各放一个图标。这种做法最啰嗦,但如果你要做"加号旋转 45 度变成叉号"这种效果,它是最可控的。

我实际用的是旋转 + 时长 200ms + Ease In Out。这个动画和面板的 300ms 滑动画同时在跑,箭头先转完、面板再停稳,节奏感很舒服。

4. 把单条菜单升级成完整导航

4.1 手风琴效果:一次只允许展开一个

单条能开合只是起步,真实导航一定是好几组菜单,而且用户期望"展开这一组时,其它组自动收起",这就是手风琴(Accordion)。RP8 没有现成的"手风琴组",得手动实现。

核心思路是:每次点击时,先把所有面板都设成折叠状态,再把当前这个设成展开状态。具体操作是在面板上新建第二条交互,动作还是"设置面板状态",目标不要选具体某一个面板,改选"全部面板"(All Panels),状态选"折叠",动画"向上滑动",勾推动、方向向上。这条交互要排在"展开自己"的前面执行——RP8 里交互是有执行顺序的,从上往下走,顺序反了就会出现"先展开自己再被自己折叠掉"的无效结果。

这里有个坑必须提:"全部面板"会把你页面上所有的动态面板都收起来,包括那个用来做轮播图的、做标签页切换的。如果你的原型里还有别的动态面板,千万别用 All Panels,老老实实一个一个点名。我第一次做这个效果的时候就中招了,页面上一个轮播突然停止工作,查了半天才发现是被"全部折叠"给误伤了。

另一种更稳妥的做法是用元件组合 + 一个隐藏的控制面板,但实现成本比上面这个高不少,单页面原型的场景下没必要。

4.2 三级嵌套菜单的做法

二级菜单再往下展开,就变成嵌套动态面板:一级面板的"展开"状态里,装着一个二级面板,二级面板里又有自己的折叠/展开状态。结构上是嵌套的,但交互逻辑其实是平的——每个面板管好自己的两个状态,互不干扰。

嵌套时真正麻烦的是高度计算。你在二级面板里点展开,一级面板并不知道自己应该变高,于是新露出来的三级条目会被一级面板裁掉。解决办法是把一级面板开"适应内容",让它跟着子面板的高度走。开了适应内容之后,一级面板的高度等于它当前状态内所有内容的下边界,子面板变高它就跟着变高,理论上可以一直往外顶。

但适应内容不是万能的,它只对直接子级生效,且对"推动元件"的配合不太友好——有时会出现面板变高了但下方内容没跟着下移的情况。我在做三级菜单时的实战做法是:三级以内用嵌套 + 适应内容,超过三级就在原型里放弃展开,改成点击后跳转到一个独立的详情页。因为原型不是真产品,四级菜单就算做出来,评审的时候也没人愿意一层层点下去。这条经验帮我省了很多时间。

4.3 悬停展开、点击展开与"看起来像真的"之间的距离

技术上,把触发方式从"单击时"改成"鼠标移入时"(OnMouseEnter)就完事了,但实际做起来有两个额外问题要处理。

问题一:移出后要不要自动收起?如果自动收,用户想点二级菜单里的某一项,鼠标从扳机移到下面条目的过程中,如果走得快一点,可能会短暂离开面板区域,面板就收了,点了个空。工程上的解法是给面板设一个"鼠标移出时"延迟收起,RP8 里可以用"等待 300ms"再接"设置状态折叠"来模拟,但这个延迟是写死的,鼠标如果停在间隙上依然会闪。所以我的建议是——悬停只用于横向下拉菜单(下拉方向朝下,鼠标路径是连续的),纵向侧边栏一律用点击。这不是妥协,主流后台系统的侧边栏也都是点击展开的。

问题二:徽标数字和文字位置。折叠状态下如果每个菜单右侧都有个角标数字,展开之后这些角标要不要跟着移动?我一般把角标放在扳机行的右侧、固定位置,不跟着二级菜单走,因为这个数字代表的是"这个模块下有多少条待办",属于一级信息。

另外,如果你想让原型更接近真机手感,可以给面板加"移动时"的过渡补偿,但说实话 RP8 在这块的性能撑不太住,元件一多动画就掉帧。我自己的标准是:能流畅跑 300ms 滑动就够了,别在上面加多余的视差效果。

5. 常见故障排查与交付前自检

5.1 高频问题速查表

下面这张表是我这些年被问得最多、自己也踩过的问题,按出现频率排:

现象最可能的原因处理办法
点了面板没反应交互绑在了内部元件上,点击区域和面板不重合从大纲面板选中面板本体,重新绑交互
展开后内容被挡住没勾推动元件,或方向选反勾选推动,展开向下、折叠向上
折叠后页面上多一块空白折叠时指向了错误状态,或状态尺寸不一致检查两个状态宽高数值完全一致
连点两下布局错位交互写死了固定状态,重复触发改用"下一个状态"(Next)逻辑
箭头不动旋转交互绑在了错误的元件实例上两个状态里的图标要保证是同一份复制
二级菜单被裁掉父面板高度固定,未开适应内容父面板开 Fit to Content
其它面板被误伤收起用了"全部面板"作为目标改成逐个点名指定面板
动画卡顿面板内元件过多,或嵌套层数太深合并重复元件,控制在三级以内

5.2 我踩过的坑和几条交付经验

第一个坑:状态里放了不可见的占位元件。有次为了让折叠状态和展开状态的行高对齐,我在折叠状态里塞了一个透明的空矩形做占位。结果导出后发现折叠状态的高度被这个矩形撑大了,导致收起时下面永远多 8px 的缝。教训是——占位这种权宜之计不要往状态里塞,宁可手动调数值。后来我统一改成:两个状态都用绝对坐标定位,不依赖任何隐形的辅助元件。

第二个坑:复制页面导致的面板引用错乱。做一个多页面原型,我把首页连同菜单一起复制成第二个页面,改第二个页面的内容时发现点菜单居然把首页的面板状态改了。原因是复制时面板被重命名了,但交互里引用的还是原来的名字。RP8 在跨页复制这块有时候会保留引用关系,所以复制完一定要在每个交互里点一遍"目标"确认是当前页的面板。

第三个坑:忘了做"初始状态"。原型里所有菜单默认都是收起的,但演示的时候如果想展示某个模块,得先点一下才能看到,很别扭。我现在的做法是在页面加载时(OnPageLoad)给最重要的那一组加一条"设置状态为展开"的交互,演示时一打开就是完整的展开态,评审的第一眼就能看到信息层级。

最后说一个交付层面的建议。原型交付给开发或者客户之前,自己当"第一次用的人"点三遍:一遍正常点、一遍快速连点、一遍从最下面的菜单往上点。这三个动作能覆盖 90% 以上的交互 bug。我做过一个统计,原型评审被打回的交互问题里,连点导致的状态错乱占了将近一半,都是自己没测出来的。另外,菜单面板的命名一律用menu-模块名这种前缀格式,交付时在大纲面板里一眼就能看清楚结构,对方接手改起来也快——这一点在被要求返工时特别值钱。

还有个小细节值得花两分钟处理:给面板加一个"选中"状态样式。在 RP8 里选中状态的写法是新建一个叫"选中"的交互样式,展开时把扳机行设成选中、折叠时取消。这样用户一眼能看出哪一组是当前展开的,比单靠箭头方向要明显得多,尤其是在深色背景的侧边栏上。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进