diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index 042ac68a7af..e56482c6174 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -9,6 +9,7 @@ import { renderSlot, VueElement } from '../src' +import { parseNumber } from '../src/apiCustomElement' describe('defineCustomElement', () => { const container = document.createElement('div') @@ -394,3 +395,36 @@ describe('defineCustomElement', () => { }) }) }) + +describe('parseNumber', () => { + it('handles strings', () => { + expect(parseNumber('')).toBe('') + expect(parseNumber(null)).toBe('') + expect(parseNumber('Something else')).toBe('Something else') + }) + + it('numbers', () => { + expect(parseNumber('0')).toBe(0) + expect(parseNumber('1')).toBe(1) + expect(parseNumber('1.1')).toBe(1.1) + expect(parseNumber('123e-1')).toBe(12.3) + expect(parseNumber('Infinity')).toBe(Infinity) + }) + + it('NaN', () => { + expect(parseNumber('NaN')).toBeNaN() + expect(parseNumber('nan')).not.toBeNaN() + }) + + // all of these are handled by Number + it('string non decimal bases', () => { + expect(parseNumber('0b0')).toBe(0) + expect(parseNumber('0b1')).toBe(1) + + expect(parseNumber('0o3')).toBe(3) + expect(parseNumber('0o0')).toBe(0) + + expect(parseNumber('0x0')).toBe(0) + expect(parseNumber('0xf')).toBe(15) + }) +}) diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index ca29a436c72..f43d75deea8 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -21,7 +21,7 @@ import { ConcreteComponent, ComponentOptions } from '@vue/runtime-core' -import { camelize, extend, hyphenate, isArray, toNumber } from '@vue/shared' +import { camelize, extend, hyphenate, isArray } from '@vue/shared' import { hydrate, render } from '.' export type VueElementConstructor

= { @@ -246,7 +246,7 @@ export class VueElement extends BaseClass { } protected _setAttr(key: string) { - this._setProp(camelize(key), toNumber(this.getAttribute(key)), false) + this._setProp(camelize(key), parseNumber(this.getAttribute(key)), false) } /** @@ -342,3 +342,10 @@ export class VueElement extends BaseClass { } } } + +export function parseNumber(value: string | null): number | string { + // for Number('') and Number(null) as they both become 0 + if (!value) return '' + const casted = Number(value) + return value === 'NaN' || !Number.isNaN(casted) ? casted : value +}