Axure变量与表达式使用详解:跨页传值、中继器分页筛选避坑

发布时间:2026/10/29 0:48:26
Axure变量与表达式使用详解:跨页传值、中继器分页筛选避坑 简介面向具备一定Axure基础的产品经理、UI/UX设计师与前端原型开发人员这份专题PDF聚焦变量与函数系统在复杂原型交互中的落地方法帮助读者从基础操作过渡到跨页面数据共享、动态列表生成、响应式布局调整与条件分支等进阶实现。资源包仅含1个PDF文件体积约556KB轻量便于随查随用内容按全局变量、中继器数据集、元件、页面、窗口、鼠标指针、数值、字符串、日期处理及布尔逻辑运算符展开并配具体表达式示例说明作用范围。已有218人学习适合作为案头速查与实操练习材料读者可从中掌握中继器分页、用户状态管理、动态内容控制等常见做法同时关注命名规范、作用域管理与数据类型匹配减少命名冲突和逻辑错误提升原型可维护性。1. 变量不是选修课原型一交互就露馅问题多半出在变量上上个月陪某公司产品团队过一版内部系统的交互稿列表页刚演示到筛选业务方顺口问了句筛完翻到第二页条件还在吗。点了一下条件归零页码回到第一页会议室安静了两秒。静态摆位画得再齐整只要没把 Axure 常用变量用起来原型就只是一张会翻页的图片。这份《Axure常用变量及使用方法详解.pdf》把全局变量、中继器数据集、元件/页面/窗口/鼠标指针这四类环境变量以及数值、字符串、日期三类处理函数和布尔逻辑运算符串成了一条线每一类都配了能直接抄进项目的表达式写法。它适合已经能画页面、但一碰到跨页传值、动态列表、滚动触发就卡住的交互设计和原型设计从业者也适合想回头确认自己那套写法有没有摸到边界的老手。2. 全局变量与中继器数据集跨页传值和动态列表的两根主梁这两块是 Axure 变量函数体系里最容易被低估的部分。全局变量看起来只是存个值实际决定了整个原型的用户状态能不能连贯中继器看起来只是循环一个列表实际决定了数据量上来之后原型还能不能演示。把这两个吃透剩下的元件、页面、窗口、鼠标变量都只是取值来源不同而已。下面按先讲清结构、再落到可抄的表达式的顺序推。2.1 全局变量的作用域与命名约定全局变量在项目 全局变量里定义命名后在整个原型的任意页面、任意元件、任意中继器行内都能通过[[变量名]]读到。它没有强类型存文本就是文本存数字就是数字类型完全靠你自己守。这一点是后面大量踩坑的源头同一个变量先存1再存1显示出来一模一样比较起来结果完全不同。命名上我一般按前缀分三类落到表格里更直观前缀承载内容示例备注g_全局登录态、主题、语言g_isLoggedIn全原型唯一改动前先搜引用u_用户输入、表单值u_userName只在写入页和读取页出现f_筛选条件、排序方式、分页大小f_filterCriteria中继器筛选基本都靠它前缀不是形式主义。全局变量在较新版本的 Axure RP 里没有分组视图变量一多就是一条长列表命名不统一的时候找theme能翻出theme、Theme、themeColor三个改一个漏两个这种玄学问题排查起来最费时间。作用域上要守住一条全局变量只放跨页面还需要活着的东西。页面内的临时计算比如当前行是否选中用元件自身的[[This.isSelected]]或者中继器的[[Item.isMarked]]别往全局塞。全局变量一旦被当成草稿纸用数据污染就是必然的尤其在多人协作的原型文件里谁都能改谁都不敢删。提示全局变量改值之后已经渲染在页面上的静态文本不会自动刷新。文本是在页面载入时求值一次的后续变更必须靠设置文本动作再赋一次值。最后一条容易被忽略的自定义全局变量名不要和 Axure 内置的对象名撞车Page、Window、This、Target、Item、Now、Cursor这些词拿来做变量名表达式会解析成内置对象取值直接是空或者一串看不懂的东西而且不报错。这种黑匣子式的失败新手基本无从下手。2.2 中继器数据集的三层结构Item、Repeater、TargetItem中继器的变量分三层理清层级比背函数表有用得多。第一层是数据集本身也就是你在中继器面板里那张表格的行和列列名就是ColumnName。第二层是行上下文Item它只在每项加载时项被点击时这类逐行触发的场景里有效代表当前这一行。第三层是组件对象Repeater代表中继器整体能拿到总条数、总页数、当前页码。Item这一层的常用函数函数含义典型用法[[Item.ColumnName]]当前行指定列的值[[Item.Name]][[Item.index]]当前项索引从 1 开始序号列、隔行变色[[Item.isFirst]]是否第一项返回 true/false首项加圆角、隐藏上分割线[[Item.isLast]]是否最后一项末项隐藏下分割线[[Item.isEven]]/[[Item.isOdd]]索引奇偶斑马纹[[Item.isMarked]]当前行是否被标记多选、批量操作[[Item.isVisible]]当前行是否可见筛选后统计Repeater这一层的常用函数函数含义注意点[[Repeater.dataCount]]数据集总行数筛选后仍是原始总数不受筛选影响[[Repeater.itemCount]]当前加载出来的项数分页时是当前页条数[[Repeater.pageCount]]总页数由每页条数和筛选结果共同决定[[Repeater.pageIndex]]当前页码从 1 开始[[Repeater.visibleItemCount]]当前页可见项数最后一页不满时用它算真实条数[[Repeater.TargetItem]]目标数据行对象配合更新行标记行定位这里有个特别容易混的点dataCount和itemCount在没分页、没筛选的时候数值一样看不出差别一旦开了分页dataCount还是 20itemCount变成 5。做共 X 条 / 当前页 Y 条这种统计文案两个都得用上写错一个数字就露馅。还有TargetItem。它不是当前行是你要操作的那一行。典型场景是列表里每行有个删除按钮点击后要标记这一行这时候用标记行动作目标行选[[Repeater.TargetItem]]而不是[[Item]]。这两者在项被点击时里经常是同一个值但在外部按钮批量操作的场景里完全不同用混了就是点 A 行删 B 行。2.3 动手登录态跨页传递与可翻页列表把上面两块拼成一个能跑的最小案例登录页写入全局变量主页读取并渲染一个带分页、带筛选、带斑马纹的中继器列表。步骤按顺序来每一步的表达式都能直接抄。第一步在项目 全局变量里建两个变量g_userName存文本g_isLoggedIn存true/false。登录页放一个输入框元件命名input_userName一个登录按钮。// 登录按钮 - 单击时 // 动作1设置变量值 // 变量g_userName值元件文字 input_userName // 动作2设置变量值 // 变量g_isLoggedIn值true // 动作3打开链接 主页这段没有任何函数但顺序不能反。先写变量再跳转主页载入时才能读到值反过来写主页拿到的就是空字符串而且不会报错只是页面上欢迎后面光秃秃的。参数说明一下g_isLoggedIn存的是字符串true而不是布尔 true后面比较时必须用true带引号这是 Axure 全局变量的固有行为别指望它做类型转换。第二步主页的页面载入时把值读出来。// 页面载入时 // 设置文本 欢迎语 的值为 欢迎, [[g_userName]]! // 设置文本 登录状态 的值为 [[If(g_isLoggedIn true, 已登录, 未登录)]]If(条件, 真值, 假值)是 Axure 里最常用的条件函数返回的是字符串。逻辑说明第一行是纯插值变量为空就显示欢迎, !第二行做了兜底未登录时显示未登录不会出现空白。失败时看什么如果两个都显示异常先回到全局变量面板确认变量名拼写再确认登录页是否真的执行了设置变量值动作——用预览里的调试不方便我一般会在主页角落放一个临时文本框值设成[[g_userName]]一眼就能看出传没传过来。第三步中继器列表。数据集建三列Name、Description、Category。中继器里放三个文本元件分别命名txt_name、txt_desc、txt_index。// 中继器 - 每项加载时 // 设置文本 txt_name 为[[Item.Name]] // 设置文本 txt_desc 为[[Item.Description]] // 设置文本 txt_index 为[[Item.index]] // 设置填充色作用于整行矩形 row_bg为 [[If(Item.isEven, #F7F8FA, #FFFFFF)]]逻辑说明Item.index是数据集内的绝对序号从 1 开始跨页连续第 2 页第一行的 index 是 6 而不是 1。参数上isEven判定的是 index 的奇偶不是视觉上的第几行所以开了分页之后斑马纹可能出现上一页末行灰色、下一页首行也是灰色想强制每页从白色起始得用页内序号// 页内序号 绝对序号 - (当前页 - 1) * 每页条数 [[Item.index - (Repeater.pageIndex - 1) * 5]]这里的 5 要和分页设置里的每页项目数保持一致改了一处忘了另一处序号就会从 3 开始跳是高频翻车点。第四步分页控制条。// 上一页按钮 - 单击时 // 动作设置当前显示页面 中继器 上一页 // 页码文本 - 页面载入时 每次翻页后 第 [[Repeater.pageIndex]] / [[Repeater.pageCount]] 页共 [[Repeater.dataCount]] 条 // 上一页按钮的启用/禁用状态 [[If(Repeater.pageIndex 1, 启用, 禁用)]]逻辑说明pageIndex到边界时不会变成 0 或超出点击下一页在最后一页是无效的所以按钮状态要单独判断否则用户会以为卡住了。dataCount是筛选前的总数如果要做筛选后共 X 条得换成Repeater.visibleItemCount配合筛选结果累加这一点原料里没展开但实际项目里业务方一定会问。第五步筛选。// 筛选按钮 - 单击时 // 动作1设置变量值 f_filterCriteria 元件文字 drp_category下拉框选中项 // 动作2给中继器添加筛选 // 条件[[Item.Category]] [[f_filterCriteria]] // 动作3设置当前显示页面 中继器 第 1 页第三步的回到第 1 页是必须的。筛选之后结果只剩 2 条但当前页码还停在第 3 页中继器会显示空白用户以为筛选没生效。这个坑我在三个不同项目里都见过属于典型的代码没错、体验翻车。3. 元件、页面、窗口、鼠标四类环境变量的取值边界与触发时机这四类变量的共同点是不用你定义Axure 自己维护共同的问题也在这——它们各自有明确的生效范围超出范围取值就是空或者 0而且不会报错。分清楚谁是触发者、谁是目标、谁是视口、谁只在拖拽里活着比记住函数表更重要。3.1 This 与 Target触发者和目标的区别[[This]]指触发当前事件的元件本身[[Target]]指动作里被指定的目标元件。听起来像同义词实际用起来完全不同。做鼠标悬停放大效果用 This 最省事不用绑定目标// 卡片元件 - 鼠标悬停时 // 设置尺寸 This 宽 [[This.width * 1.05]]高 [[This.height * 1.05]] // 鼠标移出时 // 设置尺寸 This 宽 [[This.width / 1.05]]高 [[This.height / 1.05]]逻辑说明这里读取的是元件的当前尺寸再乘系数所以能反复触发不失真。参数上 1.05 是经验值超过 1.1 在列表里会互相压盖小于 1.02 又看不出来。失败时看什么如果悬停后元件越变越大收不住多半是把鼠标移出的除数写成了乘数/1.05和*1.05写反了在预览里要反复悬停十几次才看得出漂移。Target的典型场景是一个按钮控制一堆元件。比如侧边栏折叠按钮点一下五个图标的透明度同时变// 折叠按钮 - 单击时 // 设置不透明度 Target [[If(This.isSelected, 1, 0.3)]] // 配合切换选中状态动作先把按钮自身设为选中这样写的好处是一个动作能带多个目标不用给每个图标单独挂交互。代价是可读性差交接的时候别人看到Target得先点开动作看目标是谁所以我一般会在元件命名上带前缀icon_menu、icon_search看名字就知道这一组是一起动的。元件变量里还有一组坐标和滚动相关的This.x、This.y、This.scrollX、This.scrollY。x/y是相对父容器的坐标放在动态面板里就是相对面板的不是相对页面的。做拖拽后归位时用它记初始位置比写死坐标稳。3.2 Page 与 Window画布尺寸和视口尺寸别混用这两个最容易写错因为函数名太像了。变量取的是什么什么时候用[[Page.width]]/[[Page.height]]页面画布尺寸你在设计区设定的固定值计算元素居中、按设计稿栅格布局[[Window.width]]/[[Window.height]]浏览器视口尺寸随窗口缩放变化响应式断点、全屏适配[[Page.scrollX]]/[[Page.scrollY]]页面滚动位置页面内锚点定位[[Window.scrollX]]/[[Window.scrollY]]视口滚动位置吸顶导航、回顶按钮[[Page.url]]/[[Page.title]]当前页面地址与标题埋点演示、面包屑[[PageName]]当前页面名称高亮当前导航项响应式判断必须用 Window用 Page 的话无论窗口怎么缩值都不变看起来判断写了但没反应// 页面载入时 窗口尺寸改变时 // 设置文本 layout_flag 为 [[If(Window.width 1200, large, If(Window.width 768, medium, small))]]逻辑说明If可以嵌套从宽到窄依次判断第一个命中的分支返回。参数上 1200 和 768 是常见的断点值实际项目按设计稿栅格调整。要注意 Axure 不会自动监听窗口尺寸变化得靠窗口尺寸改变时这个事件重新求值一次否则用户拉大窗口之后文案还停在 small。吸顶导航用Window.scrollY做阈值判断// 窗口滚动时 // 设置文本 nav_bar 的背景色为 [[If(Window.scrollY 100, #FFFFFF, transparent)]] // 设置阴影可见性为 [[If(Window.scrollY 100, 显示, 隐藏)]]阈值 100 不是随便定的一般取导航栏自身高度滚过导航栏才变色早了会显得页面一直在半悬浮状态。这个数值在预览里滚两下就能校准。3.3 Cursor拖拽判定与长按计时鼠标指针变量是一组有严格生效范围的变量Cursor.x、Cursor.y、Cursor.dragX、Cursor.dragY、Cursor.totalDragX、Cursor.totalDragY、Cursor.downTime这些只在拖拽类交互拖动开始、拖动时、拖动结束里取值有效。挂在单击时上读出来全是 0。dragX/dragY是相对上一次采样点的增量totalDragX/totalDragY是从按下到当前的总位移。做左滑删除判定要用总量// 列表行 - 拖动结束时 // 设置文本 action_hint 为 [[If(Cursor.totalDragX -50, 触发删除, 回弹归位)]]逻辑说明负数代表向左滑50 是触发阈值单位像素。阈值低于 30 时轻微手抖就触发用户会误删高于 80 又要滑很久手感发涩。参数调优只能靠预览里反复拖我在触屏模拟下一般定在 50~60 之间。长按用downTime单位是毫秒// 元件 - 拖动结束时 [[If(Cursor.downTime 800, 长按进入编辑, 普通点击)]]800ms 是常见的长按判定线比 500ms 稳比 1000ms 跟手。要注意downTime计的是按下到当前的总时长拖动过程中它一直在涨所以判定要放在拖动结束或鼠标松开里不能放在拖动时里否则拖到一半就误触发。Cursor.x/Cursor.y适合做跟随效果比如自定义光标提示// 跟随提示元件 - 拖动时 // 移动 This 到 ([[Cursor.x 12]], [[Cursor.y 12]])偏移 12 像素是为了让提示不压住系统光标这个数在预览里调到顺手为止。4. 数值、字符串、日期三类处理函数的组合写法函数单独用都不难难在组合。一个手机号脱敏 金额千分位 日期补零的详情页三行表达式能写对的人不多原因基本集中在两处类型没转、索引没对齐。这一章按数值、字符串、日期的顺序每类给一个能落地的组合写法。4.1 Number精度、取整和类型转换数值函数分两组。一组是格式化toFixed(n)保留 n 位小数并返回字符串toExponential(n)转科学计数法toPrecision(n)保留总位数。另一组是数学运算Math.abs、Math.ceil、Math.floor、Math.round、Math.max、Math.min、Math.random、Math.sqrt。先讲最常见的金额计算。单价乘以数量直接乘会出现19.900000000000002这种尾巴// 局部变量 LVAR1 单价数字型LVAR2 数量数字型 // 设置文本 txt_total 为 ¥[[ Math.round(LVAR1 * LVAR2 * 100) / 100 ]]逻辑说明先乘 100 把两位小数抬成整数Math.round四舍五入到整数再除 100 还原。参数 100 对应保留两位要保留一位就改成 10。为什么不用toFixed(2)因为toFixed返回的是字符串后面还要参与运算的话类型会断掉显示用toFixed、运算用Math.round是我的一般做法。再讲取整的选择。分页算总页数// 每页 5 条共 23 条 [[ Math.ceil(Repeater.dataCount / 5) ]]这里必须是Math.ceil向上取整23 条要算 5 页。用Math.floor会得到 4 页最后一页的 3 条永远显示不出来。反过来做整屏展示几行这种场景就要Math.floor因为不足一行的部分放不下。单页展示条数// 视口高度 800每行 60 [[ Math.floor(800 / 60) ]]Math.random()返回 0 到 1 之间的随机数做随机推荐要取整// 从 10 条数据里随机取一条序号1~10 [[ Math.floor(Math.random() * 10) 1 ]]参数说明Math.random()是左闭右开取不到 1所以乘 10 得 0~9.99floor之后是 0~9加 1 才是 1~10。少加这个 1永远取不到最后一条这种边界问题在演示时几乎不会被发现上线前才被较真的人挑出来。类型转换是这一节最重要的部分。Axure 里从输入框读出来的值永远是字符串12 3得到的是123不是 15。要么用* 1强转要么在局部变量里把它绑成数字// 输入框 input_qty 里用户填了 3单价是 19.9 // 错误写法[[LVAR1 * LVAR2]] 直接乘有时能算有时算出 NaN // 正确写法 [[ Math.round((LVAR2 * 1) * LVAR1 * 100) / 100 ]]* 1是最轻的转换手法比parseInt稳因为它对3.5也有效。用户在输入框里多敲一个空格* 1得到 NaN页面上就是¥NaN这反而是好事一眼能看出输入有问题比默默算出 0 强。4.2 String索引对齐和切片函数的选择字符串函数表很长真正需要记的是三件事索引从 0 开始、slice/substring/substr的差异、replace只换第一个。函数作用索引规则length字符长度无concat(s)拼接无indexOf(s)首次出现位置找不到返回 -1lastIndexOf(s)最后出现位置找不到返回 -1slice(start, end)截取 [start, end)支持负数从头算substring(start, end)截取 [start, end)负数按 0 处理substr(start, len)从 start 取 len 个第二个参数是长度不是终点split(sep)分割成数组无replace(a, b)替换只替换首个匹配toLowerCase()/toUpperCase()大小写无trim()去首尾空白无手机号脱敏用substring// 局部变量 LVAR1 输入框 input_phone 的文字 [[ LVAR1.substring(0, 3) ]]****[[ LVAR1.substring(7, 11) ]]逻辑说明11 位手机号前 3 位保留中间 4 位打码后 4 位保留。substring(7, 11)的终点写 11 不是 10因为区间是左闭右开写 10 会少一位。这个 off-by-one 是字符串处理里最高频的错误预览时数字看着差不多仔细数才发现少了一位。用户名截断显示用slice更安全// 超过 8 个字符就截断加省略号 [[ If(LVAR1.length 8, LVAR1.slice(0, 8) ..., LVAR1) ]]slice和substring在正索引下行为一致区别在负索引slice(-4)取末尾 4 位substring(-4)直接当 0 处理返回整个字符串。做取文件扩展名这种要从后往前数的必须用slice// 从 report.pdf 里取 pdf [[ LVAR1.slice(LVAR1.lastIndexOf(.) 1) ]]lastIndexOf找不到匹配时返回 -1加 1 之后是 0slice(0)返回整个字符串不会报错但结果是错的。加一层保护[[ If(LVAR1.lastIndexOf(.) 0, LVAR1.slice(LVAR1.lastIndexOf(.) 1), 无扩展名) ]]split返回数组单独打印出来是逗号拼接的一串实际用法是配合中继器做标签云// 输入框里填 设计,原型,交互 // 中继器的数据集用更新动作按 split 结果逐项添加 [[ LVAR1.split(,) ]]trim()专门治输入框首尾空格。登录校验里这个几乎是必备[[ If(LVAR1.trim().length 0, 请输入用户名, 校验通过) ]]不加trim用户敲一个空格就能通过必填校验这种问题在真实用户手里百分百会遇到。4.3 Date月份偏移、补零和时区[[Now]]是当前时间对象日期函数都是从它上面取。第一个必须记住的getMonth()返回 0 到 11一月是 0所以显示的时候永远要 1。第二个getDay()返回 0 到 60 是周日。// 日期时间格式化 [[ Now.getFullYear() ]]-[[ Now.getMonth() 1 ]]-[[ Now.getDate() ]] [[ Now.getHours() ]]:[[ Now.getMinutes() ]]这样写出来是2024-6-1 9:5不是2024-06-01 09:05。补零得手动做// 分钟补零 [[ If(Now.getMinutes() 10, 0, ) ]][[ Now.getMinutes() ]] // 完整版 [[ Now.getFullYear() ]]-[[ If(Now.getMonth() 1 10, 0, ) ]][[ Now.getMonth() 1 ]]-[[ If(Now.getDate() 10, 0, ) ]][[ Now.getDate() ]]逻辑说明If返回空串或者0拼在前面。参数上判断条件是 10而不是 1010 本身是两位数不需要补。这串表达式很长实际项目里我会把它做成一个不可见的日期文本元件页面载入时算一次其他地方引用这个元件的文字避免到处复制。倒计时用时间戳相减// 距离目标日期还有几天 [[ Math.floor((Date.parse(2025-01-01) - Now.getTime()) / 86400000) ]]逻辑说明Date.parse把日期字符串解析成毫秒时间戳Now.getTime()也是毫秒相减得到毫秒差除以 86400000一天的毫秒数得到天数。Math.floor保证不足一天按 0 天算不会出现3.7 天这种显示。时区用getTimezoneOffset()返回的是本地时间与 UTC 的分钟差而且符号和直觉相反东八区返回 -480。做跨时区演示时这个值要摆正// 换算成小时东八区显示 8 [[ -Now.getTimezoneOffset() / 60 ]]前面加负号是关键不加的话东八区显示 -8业务方一眼就看出不对。5. 避坑五条变量表达式翻车记录与一套排查顺序变量这块的失败有个共同特点不报错。表达式写错了页面照常渲染只是内容是空的、数字是 0、按钮点不动。没有报错信息可看只能靠一套固定的排查路径把范围缩小。下面五条是我和团队里其他人踩过的每条按现象 → 原因 → 解决记。5.1 五条高频翻车记录第一条全局变量改了页面上文字没变。现象是登录之后跳回主页欢迎XXX里的名字还是空的但重新刷新预览就正常了。原因是静态文本只在页面载入时求值一次后续变量变更不会触发重新渲染。解决办法是在改变量的同一个交互里追加一个设置文本动作重新赋一次[[g_userName]]或者把显示逻辑统一收到页面载入时的设置文本里不用静态插值。我现在的习惯是凡是绑定全局变量的文本一律走设置文本动作不用默认文本里的[[ ]]。第二条中继器筛选后当前页变成空白。现象是列表本来在第 3 页点了筛选结果只剩 2 条但页码还停在第 3 页区域一片空白。原因是筛选只更新了数据集没有重置页码。解决办法是在添加筛选动作之后追加一条设置当前显示页面 第 1 页。这条要养成肌肉记忆就像写 SQL 分页必须带order by一样。第三条Item.index和视觉行号对不上。现象是开了分页之后第二页第一行的序号显示成 6 而不是 1。原因是Item.index是数据集内的绝对索引跨页连续它不关心你分了几页。解决办法是用[[Item.index - (Repeater.pageIndex - 1) * 每页条数]]算页内序号并且把每页条数抽成一个全局变量g_pageSize分页设置和表达式都引用它改一处就够。写死数字的版本改分页大小的时候必然漏改。第四条数字比较结果反直觉。现象是10 9返回 false。原因是从输入框或中继器读出来的值是字符串字符串比较按字符逐位比1小于9所以10排在9前面。解决办法是参与大小比较前统一转数字[[LVAR1 * 1 LVAR2 * 1]]或者在局部变量绑定时就选数字类型。这条坑在价格区间筛选里特别常见100 元以上筛出来的结果里混着 20 元的商品。第五条Cursor相关函数在单击事件里全是 0。现象是给列表行加了单击时读取Cursor.x结果永远是 0。原因是鼠标指针变量只在拖拽类交互里有上下文单击事件里没有拖拽会话。解决办法是把逻辑挪到拖动时或拖动结束里确实需要在单击里拿到位置就用元件的This.x/This.y配合鼠标移入时缓存到局部变量。这条没有捷径只能记住哪些函数属于哪个事件域。5.2 一套可复用的四步排查顺序翻车之后不要从头改表达式按这个顺序走八成问题在前两步就能定位。第一步打印。在页面角落放一个临时文本框把可疑变量直接[[变量名]]打出来。空的话说明没写进去或者作用域不对有值但显示不对说明是格式化问题跳到第四步。这一步的价值在于把变量没值和变量有值但用错了两类问题分开省掉大量瞎猜。第二步查作用域。全局变量看是否在目标页面的页面载入时之前写入中继器的Item系列看是否写在了每项加载时里写到外面就是空Target看动作的目标是不是被复制出来的旧元件——复制粘贴元件之后目标引用有时还指着原来那个预览里点新元件没反应点旧位置反而有反应这种最费时间。第三步查求值时机。同一个表达式放在页面载入时和放在单击时结果可能完全不同因为依赖的变量在中间被改过。判断方法是给两个时机各打一次日志看值在哪一步变的。带条件分支的交互尤其要注意切换选中状态这类动作会改变This.isSelected写在它前面的表达式读到的是旧值。第四步查类型。到这一步基本只剩数字和字符串混用的问题。判据很土但有效如果结果是拼接而不是相加就是字符串如果比较结果和数值直觉不符也是字符串。统一用* 1转一遍再不行就在局部变量里明确绑成数字类型。这四步走完还不对的我会把整段交互删了重画。Axure 里有些状态是删不干净的尤其是反复复制粘贴过的元件重画比修快这是血泪经验。6. 布尔逻辑与表达式收敛把散落的判断收成一行布尔这块的坑不在语法在可维护性。一个列表项要不要显示删除按钮条件可能是已登录 且 是本人 且 未锁定 且 不在回收站四个条件分别写在四个交互里改一个漏三个最后没人敢动。收敛成一行表达式是这类问题的唯一解。先看优先级Axure 的运算符顺序和 JS 一致优先级运算符说明1!逻辑非最高2比较3!相等判断4逻辑与5||逻辑或最低比||优先级高所以a || b c实际是a || (b c)。记不住就全加括号多打两个字符不会有人怪你写错了要查半天。短路特性也要用起来左边为假右边不求值||左边为真右边不求值。这个特性可以用来防错比如先判空再取长度// 先判空再判长度避免对空值调用字符串函数 [[ If(LVAR1 ! LVAR1.length 3, 有效, 无效) ]]如果顺序反过来写成LVAR1.length 3 LVAR1 ! 空值的时候前半段已经在求值了虽然 Axure 大多时候能兜住但换成别的表达式就容易出空指针。这个顺序我一般固定成先判存在再判内容最后判业务。把四个条件收成一行// 局部变量LVAR1 当前用户 IDLVAR2 内容作者 ID // 全局变量g_isLoggedIn、g_isLocked、g_isDeleted [[ If(g_isLoggedIn true LVAR1 LVAR2 g_isLocked ! true g_isDeleted ! true, 显示, 隐藏) ]]逻辑说明四个条件用串起来任一不满足就隐藏。参数上注意g_isLocked ! true而不是 false因为全局变量可能从没被赋过值这时候是空字符串 false判断不出来。用不等于 true来兜底空值也能正确走到显示分支。这个写法看着别扭但它能挡住一类变量忘了初始化的线上问题。If和三元表达式的取舍Axure 里没有真正的三元运算符日常说的三元其实就是If。嵌套超过三层就该拆了// 三层嵌套能读但费劲 [[ If(Window.width 1200, large, If(Window.width 768, medium, If(Window.width 480, small, tiny))) ]] // 拆成全局变量 g_layout在窗口尺寸改变时分四次判断分别赋值拆开之后每个分支单独一行改断点值不用去数括号。验证方法很简单预览时把窗口从宽拖到窄看文案是不是按 1200 / 768 / 480 三个点依次变化卡在某个值不变就说明那一层的条件写反了。最后说个我自己的习惯。每次交付前我会把所有带[[ ]]的文本元件过一遍凡是里面出现三个以上或者两层以上If的一律抽成全局变量在页面载入时算一次元件里只留一个变量名。从那以后我每次改判断条件都强制走一遍这个收敛流程改一处就够不用满页面搜表达式。希望帮到你。这份《Axure常用变量及使用方法详解.pdf》里的函数表和示例可以当手册翻配合上面这套收敛习惯用原型的交互逻辑会稳很多需要的可以从文末入口自取。本文还有配套的精品资源点击获取