feat: support v-bind .prop & .attr modifiers

Also allows render function usage like the following:

```js
h({
  '.prop': 1, // force set as property
  '^attr': 'foo' // force set as attribute
})
```
This commit is contained in:
Evan You
2021-07-13 15:58:18 -04:00
parent 00f0b3c465
commit 1c7d737cc8
9 changed files with 279 additions and 60 deletions

View File

@@ -171,6 +171,20 @@ describe('runtime-dom: props patching', () => {
patchProp(el, 'type', 'text', null)
})
test('force patch as prop', () => {
const el = document.createElement('div') as any
patchProp(el, '.x', null, 1)
expect(el.x).toBe(1)
})
test('force patch as attribute', () => {
const el = document.createElement('div') as any
el.x = 1
patchProp(el, '^x', null, 2)
expect(el.x).toBe(1)
expect(el.getAttribute('x')).toBe('2')
})
test('input with size', () => {
const el = document.createElement('input')
patchProp(el, 'size', null, 100)

View File

@@ -24,43 +24,42 @@ export const patchProp: DOMRendererOptions['patchProp'] = (
parentSuspense,
unmountChildren
) => {
switch (key) {
// special
case 'class':
patchClass(el, nextValue, isSVG)
break
case 'style':
patchStyle(el, prevValue, nextValue)
break
default:
if (isOn(key)) {
// ignore v-model listeners
if (!isModelListener(key)) {
patchEvent(el, key, prevValue, nextValue, parentComponent)
}
} else if (shouldSetAsProp(el, key, nextValue, isSVG)) {
patchDOMProp(
el,
key,
nextValue,
prevChildren,
parentComponent,
parentSuspense,
unmountChildren
)
} else {
// special case for <input v-model type="checkbox"> with
// :true-value & :false-value
// store value as dom properties since non-string values will be
// stringified.
if (key === 'true-value') {
;(el as any)._trueValue = nextValue
} else if (key === 'false-value') {
;(el as any)._falseValue = nextValue
}
patchAttr(el, key, nextValue, isSVG, parentComponent)
}
break
if (key === 'class') {
patchClass(el, nextValue, isSVG)
} else if (key === 'style') {
patchStyle(el, prevValue, nextValue)
} else if (isOn(key)) {
// ignore v-model listeners
if (!isModelListener(key)) {
patchEvent(el, key, prevValue, nextValue, parentComponent)
}
} else if (
key[0] === '.'
? ((key = key.slice(1)), true)
: key[0] === '^'
? ((key = key.slice(1)), false)
: shouldSetAsProp(el, key, nextValue, isSVG)
) {
patchDOMProp(
el,
key,
nextValue,
prevChildren,
parentComponent,
parentSuspense,
unmountChildren
)
} else {
// special case for <input v-model type="checkbox"> with
// :true-value & :false-value
// store value as dom properties since non-string values will be
// stringified.
if (key === 'true-value') {
;(el as any)._trueValue = nextValue
} else if (key === 'false-value') {
;(el as any)._falseValue = nextValue
}
patchAttr(el, key, nextValue, isSVG, parentComponent)
}
}