Skip to content

Commit

Permalink
feat: prop and attr modifiers for v-bind
Browse files Browse the repository at this point in the history
  • Loading branch information
ygj6 committed Dec 23, 2023
1 parent 597eae4 commit a344ef4
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 12 deletions.
45 changes: 40 additions & 5 deletions packages/compiler-vapor/__tests__/transforms/vBind.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ describe('compiler v-bind', () => {
})

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', () => {
Expand All @@ -211,7 +211,7 @@ describe('compiler v-bind', () => {

expect(code).matchSnapshot()
expect(code).contains('effect')
expect(code).contains('_setAttr(n1, "fooBar", undefined, _ctx.fooBar)')
expect(code).contains('_setDOMProp(n1, "fooBar", undefined, _ctx.fooBar)')
})

test('.camel modifier w/ dynamic arg', () => {
Expand All @@ -232,17 +232,52 @@ describe('compiler v-bind', () => {
expect(code).matchSnapshot()
expect(code).contains('effect')
expect(code).contains(
`_setAttr(n1, _camelize(_ctx.foo), undefined, _ctx.id)`,
`_setDOMProp(n1, _camelize(_ctx.foo), undefined, _ctx.id)`,
)
})

test.todo('.camel modifier w/ dynamic arg + prefixIdentifiers')

test.todo('.prop modifier')
test('.prop modifier', () => {
const { ir, code } = compileWithVBind(`<div v-bind:fooBar.prop="id"/>`)

expect(ir.effect[0].operations[0]).toMatchObject({
key: {
content: `.fooBar`,
isStatic: true,
},
value: {
content: `id`,
isStatic: false,
},
})

expect(code).matchSnapshot()
expect(code).contains('')
})

test.todo('.prop modifier w/ no expression')
test.todo('.prop modifier w/ dynamic arg')
test.todo('.prop modifier w/ dynamic arg + prefixIdentifiers')
test.todo('.prop modifier (shorthand)')

test('.prop modifier (shorthand)', () => {
const { ir, code } = compileWithVBind(`<div .fooBar="id"/>`)

expect(ir.effect[0].operations[0]).toMatchObject({
key: {
content: `.fooBar`,
isStatic: true,
},
value: {
content: `id`,
isStatic: false,
},
})

expect(code).matchSnapshot()
expect(code).contains('')
})

test.todo('.prop modifier (shortband) w/ no expression')
test.todo('.attr modifier')
test.todo('.attr modifier w/ no expression')
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-vapor/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ function genSetProp(oper: SetPropIRNode, context: CodegenContext) {

newline()
pushFnCall(
vaporHelper('setAttr'),
vaporHelper('setDynamicProp'),
`n${oper.element}`,
// 2. key name
() => {
Expand Down
16 changes: 16 additions & 0 deletions packages/compiler-vapor/src/transforms/vBind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
createCompilerError,
createSimpleExpression,
ErrorCodes,
SimpleExpressionNode,
} from '@vue/compiler-core'
import { camelize } from '@vue/shared'
import { IRNodeTypes } from '../ir'
Expand Down Expand Up @@ -30,6 +31,13 @@ export const transformVBind: DirectiveTransform = (dir, node, context) => {
}
}

if (modifiers.includes('prop')) {
injectPrefix(arg, '.')
}
if (modifiers.includes('attr')) {
injectPrefix(arg, '^')
}

if (!exp.content.trim()) {
context.options.onError(
createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
Expand All @@ -52,3 +60,11 @@ export const transformVBind: DirectiveTransform = (dir, node, context) => {
],
)
}

const injectPrefix = (arg: SimpleExpressionNode, prefix: string) => {
if (arg.isStatic) {
arg.content = prefix + arg.content
} else {
arg.content = `\`${prefix}\${${arg.content}}\``
}
}
30 changes: 24 additions & 6 deletions packages/runtime-vapor/src/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,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') {
setClass(el, void 0, val)
setClass(el, oldVal, newVal)
} else if (key === 'style') {
setStyle(el as HTMLElement, void 0, val)
} else if (key in el) {
;(el as any)[key] = val
setStyle(el as HTMLElement, oldVal, newVal)
} else if (
key[0] === '.'
? ((key = key.slice(1)), true)
: key[0] === '^'
? ((key = key.slice(1)), false)
: key in el
) {
setDOMProp(el, key, oldVal, newVal)
} else {
// TODO special checks
setAttr(el, key, void 0, val)
setAttr(el, key, oldVal, newVal)
}
}

Expand Down

0 comments on commit a344ef4

Please sign in to comment.