fix(ssr): handle initial selected state for select with v-model + v-for/v-if option (#13487)
close #13486
This commit is contained in:
parent
f3479aac96
commit
15520954f9
|
@ -166,6 +166,132 @@ describe('ssr: v-model', () => {
|
|||
_push(\`</optgroup></select></div>\`)
|
||||
}"
|
||||
`)
|
||||
|
||||
expect(
|
||||
compileWithWrapper(`
|
||||
<select multiple v-model="model">
|
||||
<optgroup>
|
||||
<option v-for="item in items" :value="item">{{item}}</option>
|
||||
</optgroup>
|
||||
</select>`).code,
|
||||
).toMatchInlineSnapshot(`
|
||||
"const { ssrRenderAttr: _ssrRenderAttr, ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require("vue/server-renderer")
|
||||
|
||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple><optgroup><!--[-->\`)
|
||||
_ssrRenderList(_ctx.items, (item) => {
|
||||
_push(\`<option\${
|
||||
_ssrRenderAttr("value", item)
|
||||
}\${
|
||||
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
|
||||
? _ssrLooseContain(_ctx.model, item)
|
||||
: _ssrLooseEqual(_ctx.model, item))) ? " selected" : ""
|
||||
}>\${
|
||||
_ssrInterpolate(item)
|
||||
}</option>\`)
|
||||
})
|
||||
_push(\`<!--]--></optgroup></select></div>\`)
|
||||
}"
|
||||
`)
|
||||
|
||||
expect(
|
||||
compileWithWrapper(`
|
||||
<select multiple v-model="model">
|
||||
<optgroup>
|
||||
<option v-if="true" :value="item">{{item}}</option>
|
||||
</optgroup>
|
||||
</select>`).code,
|
||||
).toMatchInlineSnapshot(`
|
||||
"const { ssrRenderAttr: _ssrRenderAttr, ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate } = require("vue/server-renderer")
|
||||
|
||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple><optgroup>\`)
|
||||
if (true) {
|
||||
_push(\`<option\${
|
||||
_ssrRenderAttr("value", _ctx.item)
|
||||
}\${
|
||||
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
|
||||
? _ssrLooseContain(_ctx.model, _ctx.item)
|
||||
: _ssrLooseEqual(_ctx.model, _ctx.item))) ? " selected" : ""
|
||||
}>\${
|
||||
_ssrInterpolate(_ctx.item)
|
||||
}</option>\`)
|
||||
} else {
|
||||
_push(\`<!---->\`)
|
||||
}
|
||||
_push(\`</optgroup></select></div>\`)
|
||||
}"
|
||||
`)
|
||||
|
||||
expect(
|
||||
compileWithWrapper(`
|
||||
<select multiple v-model="model">
|
||||
<optgroup>
|
||||
<template v-if="ok">
|
||||
<option v-for="item in items" :value="item">{{item}}</option>
|
||||
</template>
|
||||
</optgroup>
|
||||
</select>`).code,
|
||||
).toMatchInlineSnapshot(`
|
||||
"const { ssrRenderAttr: _ssrRenderAttr, ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require("vue/server-renderer")
|
||||
|
||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple><optgroup>\`)
|
||||
if (_ctx.ok) {
|
||||
_push(\`<!--[-->\`)
|
||||
_ssrRenderList(_ctx.items, (item) => {
|
||||
_push(\`<option\${
|
||||
_ssrRenderAttr("value", item)
|
||||
}\${
|
||||
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
|
||||
? _ssrLooseContain(_ctx.model, item)
|
||||
: _ssrLooseEqual(_ctx.model, item))) ? " selected" : ""
|
||||
}>\${
|
||||
_ssrInterpolate(item)
|
||||
}</option>\`)
|
||||
})
|
||||
_push(\`<!--]-->\`)
|
||||
} else {
|
||||
_push(\`<!---->\`)
|
||||
}
|
||||
_push(\`</optgroup></select></div>\`)
|
||||
}"
|
||||
`)
|
||||
|
||||
expect(
|
||||
compileWithWrapper(`
|
||||
<select multiple v-model="model">
|
||||
<optgroup>
|
||||
<template v-for="item in items" :value="item">
|
||||
<option v-if="item===1" :value="item">{{item}}</option>
|
||||
</template>
|
||||
</optgroup>
|
||||
</select>`).code,
|
||||
).toMatchInlineSnapshot(`
|
||||
"const { ssrRenderAttr: _ssrRenderAttr, ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require("vue/server-renderer")
|
||||
|
||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple><optgroup><!--[-->\`)
|
||||
_ssrRenderList(_ctx.items, (item) => {
|
||||
_push(\`<!--[-->\`)
|
||||
if (item===1) {
|
||||
_push(\`<option\${
|
||||
_ssrRenderAttr("value", item)
|
||||
}\${
|
||||
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
|
||||
? _ssrLooseContain(_ctx.model, item)
|
||||
: _ssrLooseEqual(_ctx.model, item))) ? " selected" : ""
|
||||
}>\${
|
||||
_ssrInterpolate(item)
|
||||
}</option>\`)
|
||||
} else {
|
||||
_push(\`<!---->\`)
|
||||
}
|
||||
_push(\`<!--]-->\`)
|
||||
})
|
||||
_push(\`<!--]--></optgroup></select></div>\`)
|
||||
}"
|
||||
`)
|
||||
})
|
||||
|
||||
test('<input type="radio">', () => {
|
||||
|
|
|
@ -39,6 +39,18 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
|
|||
}
|
||||
}
|
||||
|
||||
const processSelectChildren = (children: TemplateChildNode[]) => {
|
||||
children.forEach(child => {
|
||||
if (child.type === NodeTypes.ELEMENT) {
|
||||
processOption(child as PlainElementNode)
|
||||
} else if (child.type === NodeTypes.FOR) {
|
||||
processSelectChildren(child.children)
|
||||
} else if (child.type === NodeTypes.IF) {
|
||||
child.branches.forEach(b => processSelectChildren(b.children))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function processOption(plainNode: PlainElementNode) {
|
||||
if (plainNode.tag === 'option') {
|
||||
if (plainNode.props.findIndex(p => p.name === 'selected') === -1) {
|
||||
|
@ -65,9 +77,7 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
|
|||
)
|
||||
}
|
||||
} else if (plainNode.tag === 'optgroup') {
|
||||
plainNode.children.forEach(option =>
|
||||
processOption(option as PlainElementNode),
|
||||
)
|
||||
processSelectChildren(plainNode.children)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,18 +173,7 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
|
|||
checkDuplicatedValue()
|
||||
node.children = [createInterpolation(model, model.loc)]
|
||||
} else if (node.tag === 'select') {
|
||||
const processChildren = (children: TemplateChildNode[]) => {
|
||||
children.forEach(child => {
|
||||
if (child.type === NodeTypes.ELEMENT) {
|
||||
processOption(child as PlainElementNode)
|
||||
} else if (child.type === NodeTypes.FOR) {
|
||||
processChildren(child.children)
|
||||
} else if (child.type === NodeTypes.IF) {
|
||||
child.branches.forEach(b => processChildren(b.children))
|
||||
}
|
||||
})
|
||||
}
|
||||
processChildren(node.children)
|
||||
processSelectChildren(node.children)
|
||||
} else {
|
||||
context.onError(
|
||||
createDOMCompilerError(
|
||||
|
|
Loading…
Reference in New Issue