fix(ssr): support client-compiled v-model with dynamic type during ssr (#5787)
fix #5786
This commit is contained in:
parent
847d7f782b
commit
c03459b9b6
@ -269,6 +269,24 @@ export const vModelDynamic: ObjectDirective<
|
||||
}
|
||||
}
|
||||
|
||||
function resolveDynamicModel(tagName: string, type: string | undefined) {
|
||||
switch (tagName) {
|
||||
case 'SELECT':
|
||||
return vModelSelect
|
||||
case 'TEXTAREA':
|
||||
return vModelText
|
||||
default:
|
||||
switch (type) {
|
||||
case 'checkbox':
|
||||
return vModelCheckbox
|
||||
case 'radio':
|
||||
return vModelRadio
|
||||
default:
|
||||
return vModelText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function callModelHook(
|
||||
el: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement,
|
||||
binding: DirectiveBinding,
|
||||
@ -276,26 +294,10 @@ function callModelHook(
|
||||
prevVNode: VNode | null,
|
||||
hook: keyof ObjectDirective
|
||||
) {
|
||||
let modelToUse: ObjectDirective
|
||||
switch (el.tagName) {
|
||||
case 'SELECT':
|
||||
modelToUse = vModelSelect
|
||||
break
|
||||
case 'TEXTAREA':
|
||||
modelToUse = vModelText
|
||||
break
|
||||
default:
|
||||
switch (vnode.props && vnode.props.type) {
|
||||
case 'checkbox':
|
||||
modelToUse = vModelCheckbox
|
||||
break
|
||||
case 'radio':
|
||||
modelToUse = vModelRadio
|
||||
break
|
||||
default:
|
||||
modelToUse = vModelText
|
||||
}
|
||||
}
|
||||
const modelToUse = resolveDynamicModel(
|
||||
el.tagName,
|
||||
vnode.props && vnode.props.type
|
||||
)
|
||||
const fn = modelToUse[hook] as DirectiveHook
|
||||
fn && fn(el, binding, vnode, prevVNode)
|
||||
}
|
||||
@ -324,4 +326,18 @@ export function initVModelForSSR() {
|
||||
return { checked: true }
|
||||
}
|
||||
}
|
||||
|
||||
vModelDynamic.getSSRProps = (binding, vnode) => {
|
||||
if (typeof vnode.type !== 'string') {
|
||||
return
|
||||
}
|
||||
const modelToUse = resolveDynamicModel(
|
||||
// resolveDynamicModel expects an uppercase tag name, but vnode.type is lowercase
|
||||
vnode.type.toUpperCase(),
|
||||
vnode.props && vnode.props.type
|
||||
)
|
||||
if (modelToUse.getSSRProps) {
|
||||
return modelToUse.getSSRProps(binding, vnode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
vModelText,
|
||||
vModelRadio,
|
||||
vModelCheckbox,
|
||||
vModelDynamic,
|
||||
resolveDirective
|
||||
} from 'vue'
|
||||
import { ssrGetDirectiveProps, ssrRenderAttrs } from '../src'
|
||||
@ -376,6 +377,100 @@ describe('ssr: directives', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('vnode v-model dynamic', () => {
|
||||
test('text', async () => {
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
render() {
|
||||
return withDirectives(h('input'), [[vModelDynamic, 'hello']])
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<input value="hello">`)
|
||||
})
|
||||
|
||||
test('radio', async () => {
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
render() {
|
||||
return withDirectives(
|
||||
h('input', { type: 'radio', value: 'hello' }),
|
||||
[[vModelDynamic, 'hello']]
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<input type="radio" value="hello" checked>`)
|
||||
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
render() {
|
||||
return withDirectives(
|
||||
h('input', { type: 'radio', value: 'hello' }),
|
||||
[[vModelDynamic, 'foo']]
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<input type="radio" value="hello">`)
|
||||
})
|
||||
|
||||
test('checkbox', async () => {
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
render() {
|
||||
return withDirectives(h('input', { type: 'checkbox' }), [
|
||||
[vModelDynamic, true]
|
||||
])
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<input type="checkbox" checked>`)
|
||||
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
render() {
|
||||
return withDirectives(h('input', { type: 'checkbox' }), [
|
||||
[vModelDynamic, false]
|
||||
])
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<input type="checkbox">`)
|
||||
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
render() {
|
||||
return withDirectives(
|
||||
h('input', { type: 'checkbox', value: 'foo' }),
|
||||
[[vModelDynamic, ['foo']]]
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<input type="checkbox" value="foo" checked>`)
|
||||
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
render() {
|
||||
return withDirectives(
|
||||
h('input', { type: 'checkbox', value: 'foo' }),
|
||||
[[vModelDynamic, []]]
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<input type="checkbox" value="foo">`)
|
||||
})
|
||||
})
|
||||
|
||||
test('custom directive w/ getSSRProps (vdom)', async () => {
|
||||
expect(
|
||||
await renderToString(
|
||||
|
Loading…
Reference in New Issue
Block a user