feat: prop and attr modifiers for v-bind (#79)

This commit is contained in:
ygj6 2024-01-20 13:31:16 +08:00 committed by GitHub
parent 199b19f076
commit 775491e46d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 323 additions and 49 deletions

View File

@ -121,7 +121,7 @@ export function render(_ctx) {
`; `;
exports[`compile > directives > v-pre > self-closing v-pre 1`] = ` exports[`compile > directives > v-pre > self-closing v-pre 1`] = `
"import { template as _template, children as _children, createTextNode as _createTextNode, append as _append, renderEffect as _renderEffect, setText as _setText, setAttr as _setAttr } from 'vue/vapor'; "import { template as _template, children as _children, createTextNode as _createTextNode, append as _append, renderEffect as _renderEffect, setText as _setText, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) { export function render(_ctx) {
const t0 = _template("<div></div><div><Comp></Comp></div>") const t0 = _template("<div></div><div><Comp></Comp></div>")
@ -133,14 +133,14 @@ export function render(_ctx) {
_setText(n1, undefined, _ctx.bar) _setText(n1, undefined, _ctx.bar)
}) })
_renderEffect(() => { _renderEffect(() => {
_setAttr(n2, "id", undefined, _ctx.foo) _setDynamicProp(n2, "id", undefined, _ctx.foo)
}) })
return n0 return n0
}" }"
`; `;
exports[`compile > directives > v-pre > should not affect siblings after it 1`] = ` exports[`compile > directives > v-pre > should not affect siblings after it 1`] = `
"import { template as _template, children as _children, createTextNode as _createTextNode, append as _append, renderEffect as _renderEffect, setText as _setText, setAttr as _setAttr } from 'vue/vapor'; "import { template as _template, children as _children, createTextNode as _createTextNode, append as _append, renderEffect as _renderEffect, setText as _setText, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) { export function render(_ctx) {
const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div><div><Comp></Comp></div>") const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div><div><Comp></Comp></div>")
@ -152,7 +152,7 @@ export function render(_ctx) {
_setText(n1, undefined, _ctx.bar) _setText(n1, undefined, _ctx.bar)
}) })
_renderEffect(() => { _renderEffect(() => {
_setAttr(n2, "id", undefined, _ctx.foo) _setDynamicProp(n2, "id", undefined, _ctx.foo)
}) })
return n0 return n0
}" }"
@ -179,7 +179,7 @@ export function render(_ctx) {
`; `;
exports[`compile > dynamic root nodes and interpolation 1`] = ` exports[`compile > dynamic root nodes and interpolation 1`] = `
"import { template as _template, children as _children, createTextNode as _createTextNode, prepend as _prepend, insert as _insert, append as _append, on as _on, renderEffect as _renderEffect, setText as _setText, setAttr as _setAttr } from 'vue/vapor'; "import { template as _template, children as _children, createTextNode as _createTextNode, prepend as _prepend, insert as _insert, append as _append, on as _on, renderEffect as _renderEffect, setText as _setText, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) { export function render(_ctx) {
const t0 = _template("<button>foo<!>foo</button>") const t0 = _template("<button>foo<!>foo</button>")
@ -196,7 +196,7 @@ export function render(_ctx) {
_setText(n1, undefined, _ctx.count) _setText(n1, undefined, _ctx.count)
_setText(n2, undefined, _ctx.count) _setText(n2, undefined, _ctx.count)
_setText(n3, undefined, _ctx.count) _setText(n3, undefined, _ctx.count)
_setAttr(n4, "id", undefined, _ctx.count) _setDynamicProp(n4, "id", undefined, _ctx.count)
}) })
return n0 return n0
}" }"
@ -222,7 +222,7 @@ exports[`compile > expression parsing > v-bind 1`] = `
const n0 = t0() const n0 = t0()
const { 0: [n1],} = _children(n0) const { 0: [n1],} = _children(n0)
_renderEffect(() => { _renderEffect(() => {
_setAttr(n1, key.value+1, undefined, _unref(foo)[key.value+1]()) _setDynamicProp(n1, key.value+1, undefined, _unref(foo)[key.value+1]())
}) })
return n0 return n0
})()" })()"

View File

@ -1,14 +1,42 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`compiler v-bind > .camel modifier 1`] = ` exports[`compiler v-bind > .attr modifier 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setAttr as _setAttr } from 'vue/vapor'; "import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) { export function render(_ctx) {
const t0 = _template("<div></div>") const t0 = _template("<div></div>")
const n0 = t0() const n0 = t0()
const { 0: [n1],} = _children(n0) const { 0: [n1],} = _children(n0)
_renderEffect(() => { _renderEffect(() => {
_setAttr(n1, "fooBar", undefined, _ctx.id) _setDynamicProp(n1, "^foo-bar", undefined, _ctx.id)
})
return n0
}"
`;
exports[`compiler v-bind > .attr modifier w/ no expression 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) {
const t0 = _template("<div></div>")
const n0 = t0()
const { 0: [n1],} = _children(n0)
_renderEffect(() => {
_setDynamicProp(n1, "^foo-bar", undefined, _ctx.fooBar)
})
return n0
}"
`;
exports[`compiler v-bind > .camel modifier 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) {
const t0 = _template("<div></div>")
const n0 = t0()
const { 0: [n1],} = _children(n0)
_renderEffect(() => {
_setDynamicProp(n1, "fooBar", undefined, _ctx.id)
}) })
return n0 return n0
}" }"
@ -22,77 +50,147 @@ export function render(_ctx) {
const n0 = t0() const n0 = t0()
const { 0: [n1],} = _children(n0) const { 0: [n1],} = _children(n0)
_renderEffect(() => { _renderEffect(() => {
_setAttr(n1, _camelize(_ctx.foo), undefined, _ctx.id) _setDynamicProp(n1, _camelize(_ctx.foo), undefined, _ctx.id)
}) })
return n0 return n0
}" }"
`; `;
exports[`compiler v-bind > .camel modifier w/ no expression 1`] = ` exports[`compiler v-bind > .camel modifier w/ no expression 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setAttr as _setAttr } from 'vue/vapor'; "import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) { export function render(_ctx) {
const t0 = _template("<div></div>") const t0 = _template("<div></div>")
const n0 = t0() const n0 = t0()
const { 0: [n1],} = _children(n0) const { 0: [n1],} = _children(n0)
_renderEffect(() => { _renderEffect(() => {
_setAttr(n1, "fooBar", undefined, _ctx.fooBar) _setDynamicProp(n1, "fooBar", undefined, _ctx.fooBar)
})
return n0
}"
`;
exports[`compiler v-bind > .prop modifier (shortband) w/ no expression 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) {
const t0 = _template("<div></div>")
const n0 = t0()
const { 0: [n1],} = _children(n0)
_renderEffect(() => {
_setDynamicProp(n1, ".fooBar", undefined, _ctx.fooBar)
})
return n0
}"
`;
exports[`compiler v-bind > .prop modifier (shorthand) 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) {
const t0 = _template("<div></div>")
const n0 = t0()
const { 0: [n1],} = _children(n0)
_renderEffect(() => {
_setDynamicProp(n1, ".fooBar", undefined, _ctx.id)
})
return n0
}"
`;
exports[`compiler v-bind > .prop modifier 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) {
const t0 = _template("<div></div>")
const n0 = t0()
const { 0: [n1],} = _children(n0)
_renderEffect(() => {
_setDynamicProp(n1, ".fooBar", undefined, _ctx.id)
})
return n0
}"
`;
exports[`compiler v-bind > .prop modifier w/ dynamic arg 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) {
const t0 = _template("<div></div>")
const n0 = t0()
const { 0: [n1],} = _children(n0)
_renderEffect(() => {
_setDynamicProp(n1, \`.\${_ctx.fooBar}\`, undefined, _ctx.id)
})
return n0
}"
`;
exports[`compiler v-bind > .prop modifier w/ no expression 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) {
const t0 = _template("<div></div>")
const n0 = t0()
const { 0: [n1],} = _children(n0)
_renderEffect(() => {
_setDynamicProp(n1, ".fooBar", undefined, _ctx.fooBar)
}) })
return n0 return n0
}" }"
`; `;
exports[`compiler v-bind > basic 1`] = ` exports[`compiler v-bind > basic 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setAttr as _setAttr } from 'vue/vapor'; "import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) { export function render(_ctx) {
const t0 = _template("<div></div>") const t0 = _template("<div></div>")
const n0 = t0() const n0 = t0()
const { 0: [n1],} = _children(n0) const { 0: [n1],} = _children(n0)
_renderEffect(() => { _renderEffect(() => {
_setAttr(n1, "id", undefined, _ctx.id) _setDynamicProp(n1, "id", undefined, _ctx.id)
}) })
return n0 return n0
}" }"
`; `;
exports[`compiler v-bind > dynamic arg 1`] = ` exports[`compiler v-bind > dynamic arg 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setAttr as _setAttr } from 'vue/vapor'; "import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) { export function render(_ctx) {
const t0 = _template("<div></div>") const t0 = _template("<div></div>")
const n0 = t0() const n0 = t0()
const { 0: [n1],} = _children(n0) const { 0: [n1],} = _children(n0)
_renderEffect(() => { _renderEffect(() => {
_setAttr(n1, _ctx.id, undefined, _ctx.id) _setDynamicProp(n1, _ctx.id, undefined, _ctx.id)
}) })
return n0 return n0
}" }"
`; `;
exports[`compiler v-bind > no expression (shorthand) 1`] = ` exports[`compiler v-bind > no expression (shorthand) 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setAttr as _setAttr } from 'vue/vapor'; "import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) { export function render(_ctx) {
const t0 = _template("<div></div>") const t0 = _template("<div></div>")
const n0 = t0() const n0 = t0()
const { 0: [n1],} = _children(n0) const { 0: [n1],} = _children(n0)
_renderEffect(() => { _renderEffect(() => {
_setAttr(n1, "camel-case", undefined, _ctx.camelCase) _setDynamicProp(n1, "camel-case", undefined, _ctx.camelCase)
}) })
return n0 return n0
}" }"
`; `;
exports[`compiler v-bind > no expression 1`] = ` exports[`compiler v-bind > no expression 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setAttr as _setAttr } from 'vue/vapor'; "import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) { export function render(_ctx) {
const t0 = _template("<div></div>") const t0 = _template("<div></div>")
const n0 = t0() const n0 = t0()
const { 0: [n1],} = _children(n0) const { 0: [n1],} = _children(n0)
_renderEffect(() => { _renderEffect(() => {
_setAttr(n1, "id", undefined, _ctx.id) _setDynamicProp(n1, "id", undefined, _ctx.id)
}) })
return n0 return n0
}" }"

View File

@ -1,19 +1,19 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`compiler: v-once > as root node 1`] = ` exports[`compiler: v-once > as root node 1`] = `
"import { template as _template, children as _children, setAttr as _setAttr } from 'vue/vapor'; "import { template as _template, children as _children, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) { export function render(_ctx) {
const t0 = _template("<div></div>") const t0 = _template("<div></div>")
const n0 = t0() const n0 = t0()
const { 0: [n1],} = _children(n0) const { 0: [n1],} = _children(n0)
_setAttr(n1, "id", undefined, _ctx.foo) _setDynamicProp(n1, "id", undefined, _ctx.foo)
return n0 return n0
}" }"
`; `;
exports[`compiler: v-once > basic 1`] = ` exports[`compiler: v-once > basic 1`] = `
"import { template as _template, children as _children, createTextNode as _createTextNode, setText as _setText, setAttr as _setAttr, prepend as _prepend } from 'vue/vapor'; "import { template as _template, children as _children, createTextNode as _createTextNode, setText as _setText, setDynamicProp as _setDynamicProp, prepend as _prepend } from 'vue/vapor';
export function render(_ctx) { export function render(_ctx) {
const t0 = _template("<div> <span></span></div>") const t0 = _template("<div> <span></span></div>")
@ -21,7 +21,7 @@ export function render(_ctx) {
const { 0: [n3, { 1: [n2],}],} = _children(n0) const { 0: [n3, { 1: [n2],}],} = _children(n0)
const n1 = _createTextNode(_ctx.msg) const n1 = _createTextNode(_ctx.msg)
_setText(n1, undefined, _ctx.msg) _setText(n1, undefined, _ctx.msg)
_setAttr(n2, "class", undefined, _ctx.clz) _setDynamicProp(n2, "class", undefined, _ctx.clz)
_prepend(n3, n1) _prepend(n3, n1)
return n0 return n0
}" }"
@ -38,13 +38,13 @@ export function render(_ctx) {
`; `;
exports[`compiler: v-once > on nested plain element 1`] = ` exports[`compiler: v-once > on nested plain element 1`] = `
"import { template as _template, children as _children, setAttr as _setAttr } from 'vue/vapor'; "import { template as _template, children as _children, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) { export function render(_ctx) {
const t0 = _template("<div><div></div></div>") const t0 = _template("<div><div></div></div>")
const n0 = t0() const n0 = t0()
const { 0: [, { 0: [n1],}],} = _children(n0) const { 0: [, { 0: [n1],}],} = _children(n0)
_setAttr(n1, "id", undefined, _ctx.foo) _setDynamicProp(n1, "id", undefined, _ctx.foo)
return n0 return n0
}" }"
`; `;

View File

@ -83,7 +83,7 @@ describe('compiler v-bind', () => {
}) })
expect(code).matchSnapshot() expect(code).matchSnapshot()
expect(code).contains('_setAttr(n1, "id", undefined, _ctx.id)') expect(code).contains('_setDynamicProp(n1, "id", undefined, _ctx.id)')
}) })
test('no expression', () => { test('no expression', () => {
@ -110,7 +110,7 @@ describe('compiler v-bind', () => {
}) })
expect(code).matchSnapshot() expect(code).matchSnapshot()
expect(code).contains('_setAttr(n1, "id", undefined, _ctx.id)') expect(code).contains('_setDynamicProp(n1, "id", undefined, _ctx.id)')
}) })
test('no expression (shorthand)', () => { test('no expression (shorthand)', () => {
@ -130,7 +130,7 @@ describe('compiler v-bind', () => {
expect(code).matchSnapshot() expect(code).matchSnapshot()
expect(code).contains( expect(code).contains(
'_setAttr(n1, "camel-case", undefined, _ctx.camelCase)', '_setDynamicProp(n1, "camel-case", undefined, _ctx.camelCase)',
) )
}) })
@ -152,7 +152,7 @@ describe('compiler v-bind', () => {
}) })
expect(code).matchSnapshot() expect(code).matchSnapshot()
expect(code).contains('_setAttr(n1, _ctx.id, undefined, _ctx.id)') expect(code).contains('_setDynamicProp(n1, _ctx.id, undefined, _ctx.id)')
}) })
test('should error if empty expression', () => { test('should error if empty expression', () => {
@ -192,7 +192,7 @@ describe('compiler v-bind', () => {
}) })
expect(code).matchSnapshot() expect(code).matchSnapshot()
expect(code).contains('_setAttr(n1, "fooBar", undefined, _ctx.id)') expect(code).contains('_setDynamicProp(n1, "fooBar", undefined, _ctx.id)')
}) })
test('.camel modifier w/ no expression', () => { test('.camel modifier w/ no expression', () => {
@ -211,7 +211,9 @@ describe('compiler v-bind', () => {
expect(code).matchSnapshot() expect(code).matchSnapshot()
expect(code).contains('renderEffect') expect(code).contains('renderEffect')
expect(code).contains('_setAttr(n1, "fooBar", undefined, _ctx.fooBar)') expect(code).contains(
'_setDynamicProp(n1, "fooBar", undefined, _ctx.fooBar)',
)
}) })
test('.camel modifier w/ dynamic arg', () => { test('.camel modifier w/ dynamic arg', () => {
@ -232,18 +234,152 @@ describe('compiler v-bind', () => {
expect(code).matchSnapshot() expect(code).matchSnapshot()
expect(code).contains('renderEffect') expect(code).contains('renderEffect')
expect(code).contains( expect(code).contains(
`_setAttr(n1, _camelize(_ctx.foo), undefined, _ctx.id)`, `_setDynamicProp(n1, _camelize(_ctx.foo), undefined, _ctx.id)`,
) )
}) })
test.todo('.camel modifier w/ dynamic arg + prefixIdentifiers') test.todo('.camel modifier w/ dynamic arg + prefixIdentifiers')
test.todo('.prop modifier') test('.prop modifier', () => {
test.todo('.prop modifier w/ no expression') const { ir, code } = compileWithVBind(`<div v-bind:fooBar.prop="id"/>`)
test.todo('.prop modifier w/ dynamic arg')
expect(ir.effect[0].operations[0]).toMatchObject({
key: {
content: `.fooBar`,
isStatic: true,
},
value: {
content: `id`,
isStatic: false,
},
})
expect(code).matchSnapshot()
expect(code).contains('renderEffect')
expect(code).contains('_setDynamicProp(n1, ".fooBar", undefined, _ctx.id)')
})
test('.prop modifier w/ no expression', () => {
const { ir, code } = compileWithVBind(`<div v-bind:fooBar.prop />`)
expect(ir.effect[0].operations[0]).toMatchObject({
key: {
content: `.fooBar`,
isStatic: true,
},
value: {
content: `fooBar`,
isStatic: false,
},
})
expect(code).matchSnapshot()
expect(code).contains('renderEffect')
expect(code).contains(
'_setDynamicProp(n1, ".fooBar", undefined, _ctx.fooBar)',
)
})
test('.prop modifier w/ dynamic arg', () => {
const { ir, code } = compileWithVBind(`<div v-bind:[fooBar].prop="id"/>`)
expect(ir.effect[0].operations[0]).toMatchObject({
key: {
content: `fooBar`,
isStatic: false,
},
value: {
content: `id`,
isStatic: false,
},
})
expect(code).matchSnapshot()
expect(code).contains('renderEffect')
expect(code).contains(
'_setDynamicProp(n1, `.${_ctx.fooBar}`, undefined, _ctx.id)',
)
})
test.todo('.prop modifier w/ dynamic arg + prefixIdentifiers') test.todo('.prop modifier w/ dynamic arg + prefixIdentifiers')
test.todo('.prop modifier (shorthand)')
test.todo('.prop modifier (shortband) w/ no expression') test('.prop modifier (shorthand)', () => {
test.todo('.attr modifier') const { ir, code } = compileWithVBind(`<div .fooBar="id"/>`)
test.todo('.attr modifier w/ no expression')
expect(ir.effect[0].operations[0]).toMatchObject({
key: {
content: `.fooBar`,
isStatic: true,
},
value: {
content: `id`,
isStatic: false,
},
})
expect(code).matchSnapshot()
expect(code).contains('renderEffect')
expect(code).contains('_setDynamicProp(n1, ".fooBar", undefined, _ctx.id)')
})
test('.prop modifier (shortband) w/ no expression', () => {
const { ir, code } = compileWithVBind(`<div .fooBar />`)
expect(ir.effect[0].operations[0]).toMatchObject({
key: {
content: `.fooBar`,
isStatic: true,
},
value: {
content: `fooBar`,
isStatic: false,
},
})
expect(code).matchSnapshot()
expect(code).contains('renderEffect')
expect(code).contains(
'_setDynamicProp(n1, ".fooBar", undefined, _ctx.fooBar)',
)
})
test('.attr modifier', () => {
const { ir, code } = compileWithVBind(`<div v-bind:foo-bar.attr="id"/>`)
expect(ir.effect[0].operations[0]).toMatchObject({
key: {
content: `^foo-bar`,
isStatic: true,
},
value: {
content: `id`,
isStatic: false,
},
})
expect(code).matchSnapshot()
expect(code).contains('renderEffect')
expect(code).contains('_setDynamicProp(n1, "^foo-bar", undefined, _ctx.id)')
})
test('.attr modifier w/ no expression', () => {
const { ir, code } = compileWithVBind(`<div v-bind:foo-bar.attr />`)
expect(ir.effect[0].operations[0]).toMatchObject({
key: {
content: `^foo-bar`,
isStatic: true,
},
value: {
content: `fooBar`,
isStatic: false,
},
})
expect(code).matchSnapshot()
expect(code).contains('renderEffect')
expect(code).contains(
'_setDynamicProp(n1, "^foo-bar", undefined, _ctx.fooBar)',
)
})
}) })

View File

@ -403,16 +403,20 @@ function genOperation(oper: OperationNode, context: CodegenContext) {
} }
function genSetProp(oper: SetPropIRNode, context: CodegenContext) { function genSetProp(oper: SetPropIRNode, context: CodegenContext) {
const { pushFnCall, newline, vaporHelper, helper } = context const { pushFnCall, pushMulti, newline, vaporHelper, helper } = context
newline() newline()
pushFnCall( pushFnCall(
vaporHelper('setAttr'), vaporHelper('setDynamicProp'),
`n${oper.element}`, `n${oper.element}`,
// 2. key name // 2. key name
() => { () => {
if (oper.runtimeCamelize) { if (oper.runtimeCamelize) {
pushFnCall(helper('camelize'), () => genExpression(oper.key, context)) pushFnCall(helper('camelize'), () => genExpression(oper.key, context))
} else if (oper.runtimePrefix) {
pushMulti([`\`${oper.runtimePrefix}\${`, `}\``], () =>
genExpression(oper.key, context),
)
} else { } else {
genExpression(oper.key, context) genExpression(oper.key, context)
} }

View File

@ -61,6 +61,7 @@ export interface SetPropIRNode extends BaseIRNode {
key: IRExpression key: IRExpression
value: IRExpression value: IRExpression
runtimeCamelize: boolean runtimeCamelize: boolean
runtimePrefix?: string
} }
export interface SetTextIRNode extends BaseIRNode { export interface SetTextIRNode extends BaseIRNode {

View File

@ -1,5 +1,6 @@
import { import {
ErrorCodes, ErrorCodes,
type SimpleExpressionNode,
createCompilerError, createCompilerError,
createSimpleExpression, createSimpleExpression,
} from '@vue/compiler-core' } from '@vue/compiler-core'
@ -30,6 +31,14 @@ export const transformVBind: DirectiveTransform = (dir, node, context) => {
} }
} }
let prefix: string | undefined
if (modifiers.includes('prop')) {
prefix = injectPrefix(arg, '.')
}
if (modifiers.includes('attr')) {
prefix = injectPrefix(arg, '^')
}
if (!exp.content.trim()) { if (!exp.content.trim()) {
context.options.onError( context.options.onError(
createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc), createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
@ -48,7 +57,15 @@ export const transformVBind: DirectiveTransform = (dir, node, context) => {
key: arg, key: arg,
value: exp, value: exp,
runtimeCamelize: camel, runtimeCamelize: camel,
runtimePrefix: prefix,
}, },
], ],
) )
} }
const injectPrefix = (arg: SimpleExpressionNode, prefix: string) => {
if (!arg.isStatic) {
return prefix
}
arg.content = prefix + arg.content
}

View File

@ -88,16 +88,34 @@ export function setAttr(el: Element, key: string, oldVal: any, newVal: any) {
} }
} }
export function setDynamicProp(el: Element, key: string, val: any) { export function setDOMProp(el: any, key: string, oldVal: any, newVal: any) {
// TODO special checks
if (newVal !== oldVal) {
el[key] = newVal
}
}
export function setDynamicProp(
el: Element,
key: string,
oldVal: any,
newVal: any,
) {
if (key === 'class') { if (key === 'class') {
setClass(el, void 0, val) setClass(el, oldVal, newVal)
} else if (key === 'style') { } else if (key === 'style') {
setStyle(el as HTMLElement, void 0, val) setStyle(el as HTMLElement, oldVal, newVal)
} else if (key in el) { } else if (
;(el as any)[key] = val key[0] === '.'
? ((key = key.slice(1)), true)
: key[0] === '^'
? ((key = key.slice(1)), false)
: key in el
) {
setDOMProp(el, key, oldVal, newVal)
} else { } else {
// TODO special checks // TODO special checks
setAttr(el, key, void 0, val) setAttr(el, key, oldVal, newVal)
} }
} }