Skip to content

范围限制

a-calc 3.x 引入了范围限制语法 [min, max],可以将计算结果限制在指定范围内,超出范围的值会被截取到边界值。

基本语法

expression | [min, max]
  • min:最小边界值
  • max:最大边界值

当计算结果小于 min 时返回 min,大于 max 时返回 max,否则保持不变。

基本用法

javascript
import { calc } from 'a-calc'

// 超过最大值,截取到最大值
calc('150 | [0, 100]')     // '100'

// 低于最小值,截取到最小值
calc('-50 | [0, 100]')     // '0'

// 在范围内,保持不变
calc('50 | [0, 100]')      // '50'
Ctrl+D 选择词, Ctrl+/ 注释

表达式结合

范围限制可以应用于任意复杂的表达式结果:

javascript
// 表达式结果超出范围
calc('50 + 80 | [0, 100]')              // '100' (130 被截取)
calc('10 - 50 | [0, 100]')              // '0' (-40 被截取)

// 乘除运算
calc('25 * 5 | [0, 100]')               // '100' (125 被截取)
calc('50 / 2 | [0, 100]')               // '25' (在范围内)

// 复杂表达式
calc('(a + b) * c | [0, 100]', {
  a: 10, b: 20, c: 5
})  // '100' (150 被截取)

结合变量

javascript
// 变量值超出范围
calc('x | [0, 100]', { x: 200 })        // '100'
calc('x | [0, 100]', { x: -50 })        // '0'

// 多变量表达式
calc('a + b | [0, 100]', { a: 80, b: 50 })  // '100'
calc('a - b | [0, 100]', { a: 30, b: 50 })  // '0'

使用变量作为边界

使用 @ 前缀可以引用变量值作为范围边界:

javascript
// 使用变量作为边界
calc('150 | [@min, @max]', { min: 0, max: 100 })     // '100'
calc('-50 | [@lower, @upper]', { lower: 0, upper: 100 })  // '0'

// 动态边界
calc('value | [@min, @max]', {
  value: 150,
  min: 10,
  max: 90
})  // '90'

嵌套属性路径

支持使用点号访问嵌套对象属性:

javascript
calc('150 | [@range.min, @range.max]', {
  range: { min: 0, max: 100 }
})  // '100'

calc('value | [@config.limits.min, @config.limits.max]', {
  value: 50,
  config: {
    limits: { min: 0, max: 100 }
  }
})  // '50'

特殊范围

负数范围

javascript
calc('0 | [-100, -10]')                 // '-10' (截取到最大值)
calc('-200 | [-100, -10]')              // '-100' (截取到最小值)
calc('-50 | [-100, -10]')               // '-50' (在范围内)

小数范围

javascript
calc('1.5 | [0, 1]')                    // '1'
calc('-0.5 | [0, 1]')                   // '0'
calc('0.5 | [0, 1]')                    // '0.5'

// 精确小数边界
calc('0.75 | [0.25, 0.5]')              // '0.5'
calc('0.1 | [0.25, 0.5]')               // '0.25'

单边限制

如果只需要限制一边,可以使用极值:

javascript
// 只限制最小值(最大值设为极大)
calc('x | [0, 999999999]', { x: -10 })  // '0'

// 只限制最大值(最小值设为极小)
calc('x | [-999999999, 100]', { x: 200 })  // '100'

结合其他格式化

范围限制可以与其他格式化规则组合使用:

javascript
// 范围限制 + 小数位数
calc('150.567 | [0, 100] =2')           // '100.00'
calc('50.567 | [0, 100] =2')            // '50.57'

// 范围限制 + 千分位
calc('15000 | [0, 10000] ,')            // '10,000'
calc('5000 | [0, 10000] ,')             // '5,000'

// 范围限制 + 百分比
calc('1.5 | [0, 1] %')                  // '100%'
calc('0.5 | [0, 1] %')                  // '50%'

// 范围限制 + 正号
calc('150 | [0, 100] +')                // '+100'
calc('-50 | [0, 100] +')                // '+0'

// 组合多个格式化
calc('15000.567 | [0, 10000] ~5=2,')    // '10,000.00'
Ctrl+D 选择词, Ctrl+/ 注释

与条件表达式对比

范围限制是简化版的边界检查,等价于嵌套的条件表达式:

javascript
// 使用范围限制
calc('x | [0, 100]', { x: 150 })

// 等价的条件表达式
calc('x < 0 ? 0 : (x > 100 ? 100 : x)', { x: 150 })

但范围限制语法更简洁,可读性更好。

使用场景

进度条限制

javascript
// 进度值限制在 0-100%
function getProgress(current, total) {
  return calc('current / total * 100 | [0, 100]', { current, total })
}

getProgress(150, 100)  // '100' (不超过 100%)
getProgress(-10, 100)  // '0' (不低于 0%)

音量/亮度控制

javascript
// 音量限制 0-100
function setVolume(delta, currentVolume) {
  return calc('current + delta | [0, 100]', {
    current: currentVolume,
    delta
  })
}

setVolume(30, 90)   // '100' (最大 100)
setVolume(-50, 30)  // '0' (最小 0)

评分限制

javascript
// 评分限制 1-5 星
calc('rating | [1, 5]', { rating: 0 })   // '1'
calc('rating | [1, 5]', { rating: 6 })   // '5'
calc('rating | [1, 5]', { rating: 3.5 }) // '3.5'

// 或者 0-10 分
calc('score | [0, 10]', { score: 12 })   // '10'

价格保护

javascript
// 价格在最低价和最高价之间
calc('price | [@minPrice, @maxPrice]', {
  price: 50,
  minPrice: 99,
  maxPrice: 999
})  // '99' (提升到最低价)

calc('discountPrice | [@floor, @ceiling]', {
  discountPrice: 1500,
  floor: 100,
  ceiling: 1000
})  // '1000' (限制到最高价)

输入值校验

javascript
// 年龄限制
calc('age | [0, 150]', { age: -5 })      // '0'
calc('age | [0, 150]', { age: 200 })     // '150'

// 数量限制
calc('quantity | [1, @maxStock]', {
  quantity: 100,
  maxStock: 50
})  // '50'

注意事项

  1. 类型转换:边界值和结果都会转换为数字进行比较
  2. 精度保持:在范围内的值会保持原始精度
  3. 顺序重要:必须是 [min, max] 格式,min 应小于 max
  4. 变量前缀:使用变量作为边界时必须加 @ 前缀
javascript
// 正确
calc('x | [@min, @max]', { x: 50, min: 0, max: 100 })

// 错误 - 变量需要 @ 前缀
calc('x | [min, max]', { x: 50, min: 0, max: 100 })  // 会报错

速查表

表达式结果说明
150 | [0, 100]'100'超过最大值
-50 | [0, 100]'0'低于最小值
50 | [0, 100]'50'在范围内
x | [@min, @max]动态使用变量边界
150 | [0, 100] =2'100.00'结合小数格式化
15000 | [0, 10000] ,'10,000'结合千分位

基于 MIT 许可发布