diff --git "a/NutUI-React_\347\273\204\344\273\266\346\240\207\345\207\206\347\231\275\347\232\256\344\271\246.md" "b/NutUI-React_\347\273\204\344\273\266\346\240\207\345\207\206\347\231\275\347\232\256\344\271\246.md" index 0bdb4aedce..7a53a59c4a 100644 --- "a/NutUI-React_\347\273\204\344\273\266\346\240\207\345\207\206\347\231\275\347\232\256\344\271\246.md" +++ "b/NutUI-React_\347\273\204\344\273\266\346\240\207\345\207\206\347\231\275\347\232\256\344\271\246.md" @@ -114,7 +114,6 @@ NutUI 的演进伴随着移动端技术的演进,从移动端到跨端,从 V 定义组件 Props 前,**必须(MUST)**继承全局抽象类型 `BasicComponent`(或 `MiniProgramBasicProps` 等多端公共类型),确保组件基础能力的统一。 2. **强类型声明与规范**: - - **禁止 `any`**:Props 参数需使用显式联合类型,严禁使用 `any` 逃避类型检查。 - **事件命名**:对外事件统一以 `onXXX`(小驼峰)命名。 - **精简通信**:事件通信仅传递必要数据,避免携带冗余的组件实例或私有变量。 @@ -150,7 +149,6 @@ export const Button = React.forwardRef>( ### 5.4 组件防御与容灾红线 1. **防阻断式崩溃**: - - 针对入参异常、异步失败、逻辑边界等风险点,必须内置 `try-catch` 或提供兜底 UI。 - 组件内部错误不得外溢导致整个前端应用白屏死机。 diff --git a/src/packages/price/doc.en-US.md b/src/packages/price/doc.en-US.md index 62981b1732..9cf606d2cd 100644 --- a/src/packages/price/doc.en-US.md +++ b/src/packages/price/doc.en-US.md @@ -112,6 +112,7 @@ import { Price } from '@nutui/nutui-react' | position | The symbol appear before or after the price,`before`、`after` | `string` | `before` | | size | Size,`xlarge` \| `large` \| `normal` \| `small` | `string` | `normal` | | line | Line-through price | `boolean` | `false` | +| raw | When enabled, if price contains invalid characters, it is displayed as-is without formatting | `boolean` | `false` | ## Theming diff --git a/src/packages/price/doc.md b/src/packages/price/doc.md index 56daa10866..c19d3e0cf7 100644 --- a/src/packages/price/doc.md +++ b/src/packages/price/doc.md @@ -112,6 +112,7 @@ import { Price } from '@nutui/nutui-react' | position | 符号显示在价格前或者后,`before`、`after` | `string` | `before` | | size | 价格尺寸,`xlarge` \| `large` \| `normal` \| `small` | `string` | `normal` | | line | 是否划线价 | `boolean` | `false` | +| raw | 开启后,当 price 包含非法字符时,原样展示,不做格式化处理 | `boolean` | `false` | ## 主题定制 diff --git a/src/packages/price/doc.taro.md b/src/packages/price/doc.taro.md index a61fea1bbd..e2927667c0 100644 --- a/src/packages/price/doc.taro.md +++ b/src/packages/price/doc.taro.md @@ -112,6 +112,7 @@ import { Price } from '@nutui/nutui-react-taro' | position | 符号显示在价格前或者后,`before`、`after` | `string` | `before` | | size | 价格尺寸,`xlarge` \| `large` \| `normal` \| `small` | `string` | `normal` | | line | 是否划线价 | `boolean` | `false` | +| raw | 开启后,当 price 包含非法字符时,原样展示,不做格式化处理 | `boolean` | `false` | ## 主题定制 diff --git a/src/packages/price/doc.zh-TW.md b/src/packages/price/doc.zh-TW.md index 3b48215736..58da31f8ff 100644 --- a/src/packages/price/doc.zh-TW.md +++ b/src/packages/price/doc.zh-TW.md @@ -112,6 +112,7 @@ import { Price } from '@nutui/nutui-react' | position | 符號顯示在價格前或者後,`before`、`after` | `string` | `before` | | size | 價格尺寸,`xlarge` \| `large` \| `normal` \| `small` | `string` | `normal` | | line | 是否劃線價 | `boolean` | `false` | +| raw | 開啟後,當 price 包含非法字符時,原樣展示,不做格式化處理 | `boolean` | `false` | ## 主題定製 diff --git a/src/packages/price/price.tsx b/src/packages/price/price.tsx index 44f3c2474d..38d9ceb54f 100644 --- a/src/packages/price/price.tsx +++ b/src/packages/price/price.tsx @@ -3,7 +3,10 @@ import classNames from 'classnames' import { ComponentDefaults } from '@/utils/typings' import { useRtl } from '@/packages/configprovider/index' import { WebPriceProps, PriceColorEnum } from '@/types' -import { shouldRenderPriceAsRaw } from '@/utils/should-render-price-raw' +import { + shouldRenderPriceAsRaw, + hasNonPriceChars, +} from '@/utils/should-render-price-raw' const defaultProps = { ...ComponentDefaults, @@ -15,6 +18,7 @@ const defaultProps = { position: 'before', size: 'normal', line: false, + raw: false, } as WebPriceProps export const Price: FunctionComponent> = (props) => { const { @@ -26,6 +30,7 @@ export const Price: FunctionComponent> = (props) => { position, size, line, + raw, className, style, ...rest @@ -39,9 +44,12 @@ export const Price: FunctionComponent> = (props) => { const rtl = useRtl() const isRenderPriceRaw = useMemo( () => - typeof originalPrice === 'string' && - shouldRenderPriceAsRaw(originalPrice), - [originalPrice] + (typeof originalPrice === 'string' && + shouldRenderPriceAsRaw(originalPrice)) || + (raw && + typeof originalPrice === 'string' && + hasNonPriceChars(originalPrice)), + [originalPrice, raw] ) const price = useMemo(() => { @@ -82,7 +90,7 @@ export const Price: FunctionComponent> = (props) => { } const formatDecimal = (decimalNum: any) => { - if (Number(decimalNum) === 0) { + if (Number(decimalNum) === 0 && !checkPoint(decimalNum)) { decimalNum = 0 } diff --git a/src/utils/should-render-price-raw.ts b/src/utils/should-render-price-raw.ts index 35fa961a80..d07c4f4728 100644 --- a/src/utils/should-render-price-raw.ts +++ b/src/utils/should-render-price-raw.ts @@ -3,6 +3,7 @@ const RE_NUM = /\d+(?:\.\d+)?/g // 价格合法字符:数字、小数点、负号、大写货币代码(HK USD EUR 等)、常见货币符号 Unicode 区块(含全角 ¥) const PRICE_CHARS = /^[\d.\-A-Z¥¥$€£₩₹₽₺₴₪฿\u20A0-\u20CF\uFE69\uFF04\uFFE5]*$/ +// 无法提取出有效价格时直接按原文展示,避免把纯文案误格式化成 0 或空串 function hasNoExtractablePrice(s: string) { const t = s.trim() if (!t) return true @@ -11,6 +12,7 @@ function hasNoExtractablePrice(s: string) { return false } +// 只有两段数字之间出现非法字符时,才认为该字符串应走原样渲染 export function shouldRenderPriceAsRaw(s: string) { if (hasNoExtractablePrice(s)) { return true @@ -26,6 +28,7 @@ export function shouldRenderPriceAsRaw(s: string) { return !PRICE_CHARS.test(between) } +// 提供给 Price.raw 开关:调用方可用它判断整串是否包含非法字符 export function hasNonPriceChars(s: string): boolean { return !PRICE_CHARS.test(s) }