Skip to content

Commit 9dbff73

Browse files
edison1105yyx990803
authored andcommitted
fix(compiler-ssr): fix ssr compile error for select with non-option children (#9442)
fix #9440
1 parent 6caa2de commit 9dbff73

File tree

2 files changed

+86
-26
lines changed

2 files changed

+86
-26
lines changed

packages/compiler-ssr/__tests__/ssrVModel.spec.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,57 @@ describe('ssr: v-model', () => {
6969
}></option></select></div>\`)
7070
}"
7171
`)
72+
73+
expect(
74+
compileWithWrapper(`<select multiple v-model="model"><slot/></select>`)
75+
.code
76+
).toMatchInlineSnapshot(`
77+
"const { ssrRenderSlot: _ssrRenderSlot, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"vue/server-renderer\\")
78+
79+
return function ssrRender(_ctx, _push, _parent, _attrs) {
80+
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple>\`)
81+
_ssrRenderSlot(_ctx.$slots, \\"default\\", {}, null, _push, _parent)
82+
_push(\`</select></div>\`)
83+
}"
84+
`)
85+
86+
expect(
87+
compileWithWrapper(`
88+
<select multiple v-model="model">
89+
<optgroup label="foo">
90+
<option value="bar">bar</option>
91+
</optgroup>
92+
</select>`).code
93+
).toMatchInlineSnapshot(`
94+
"const { ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"vue/server-renderer\\")
95+
96+
return function ssrRender(_ctx, _push, _parent, _attrs) {
97+
_push(\`<div\${
98+
_ssrRenderAttrs(_attrs)
99+
}><select multiple><optgroup label=\\"foo\\"><option value=\\"bar\\"\${
100+
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
101+
? _ssrLooseContain(_ctx.model, \\"bar\\")
102+
: _ssrLooseEqual(_ctx.model, \\"bar\\"))) ? \\" selected\\" : \\"\\"
103+
}>bar</option></optgroup></select></div>\`)
104+
}"
105+
`)
106+
107+
expect(
108+
compileWithWrapper(`
109+
<select multiple v-model="model">
110+
<optgroup label="foo">
111+
<slot/>
112+
</optgroup>
113+
</select>`).code
114+
).toMatchInlineSnapshot(`
115+
"const { ssrRenderSlot: _ssrRenderSlot, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"vue/server-renderer\\")
116+
117+
return function ssrRender(_ctx, _push, _parent, _attrs) {
118+
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple><optgroup label=\\"foo\\">\`)
119+
_ssrRenderSlot(_ctx.$slots, \\"default\\", {}, null, _push, _parent)
120+
_push(\`</optgroup></select></div>\`)
121+
}"
122+
`)
72123
})
73124

74125
test('<input type="radio">', () => {

packages/compiler-ssr/src/transforms/ssrVModel.ts

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,38 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
3838
}
3939
}
4040

41+
function processOption(plainNode: PlainElementNode) {
42+
if (plainNode.tag === 'option') {
43+
if (plainNode.props.findIndex(p => p.name === 'selected') === -1) {
44+
const value = findValueBinding(plainNode)
45+
plainNode.ssrCodegenNode!.elements.push(
46+
createConditionalExpression(
47+
createCallExpression(context.helper(SSR_INCLUDE_BOOLEAN_ATTR), [
48+
createConditionalExpression(
49+
createCallExpression(`Array.isArray`, [model]),
50+
createCallExpression(context.helper(SSR_LOOSE_CONTAIN), [
51+
model,
52+
value
53+
]),
54+
createCallExpression(context.helper(SSR_LOOSE_EQUAL), [
55+
model,
56+
value
57+
])
58+
)
59+
]),
60+
createSimpleExpression(' selected', true),
61+
createSimpleExpression('', true),
62+
false /* no newline */
63+
)
64+
)
65+
}
66+
} else if (plainNode.tag === 'optgroup') {
67+
plainNode.children.forEach(option =>
68+
processOption(option as PlainElementNode)
69+
)
70+
}
71+
}
72+
4173
if (node.tagType === ElementTypes.ELEMENT) {
4274
const res: DirectiveTransformResult = { props: [] }
4375
const defaultProps = [
@@ -130,32 +162,9 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
130162
checkDuplicatedValue()
131163
node.children = [createInterpolation(model, model.loc)]
132164
} else if (node.tag === 'select') {
133-
node.children.forEach(option => {
134-
if (option.type === NodeTypes.ELEMENT) {
135-
const plainNode = option as PlainElementNode
136-
if (plainNode.props.findIndex(p => p.name === 'selected') === -1) {
137-
const value = findValueBinding(plainNode)
138-
plainNode.ssrCodegenNode!.elements.push(
139-
createConditionalExpression(
140-
createCallExpression(context.helper(SSR_INCLUDE_BOOLEAN_ATTR), [
141-
createConditionalExpression(
142-
createCallExpression(`Array.isArray`, [model]),
143-
createCallExpression(context.helper(SSR_LOOSE_CONTAIN), [
144-
model,
145-
value
146-
]),
147-
createCallExpression(context.helper(SSR_LOOSE_EQUAL), [
148-
model,
149-
value
150-
])
151-
)
152-
]),
153-
createSimpleExpression(' selected', true),
154-
createSimpleExpression('', true),
155-
false /* no newline */
156-
)
157-
)
158-
}
165+
node.children.forEach(child => {
166+
if (child.type === NodeTypes.ELEMENT) {
167+
processOption(child as PlainElementNode)
159168
}
160169
})
161170
} else {

0 commit comments

Comments
 (0)