parent
fded1e8dfa
commit
34d4991dd5
@ -10,9 +10,13 @@ import {
|
|||||||
onMounted,
|
onMounted,
|
||||||
defineAsyncComponent,
|
defineAsyncComponent,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
createTextVNode
|
createTextVNode,
|
||||||
|
createVNode,
|
||||||
|
withDirectives,
|
||||||
|
vModelCheckbox
|
||||||
} from '@vue/runtime-dom'
|
} from '@vue/runtime-dom'
|
||||||
import { renderToString, SSRContext } from '@vue/server-renderer'
|
import { renderToString, SSRContext } from '@vue/server-renderer'
|
||||||
|
import { PatchFlags } from '../../shared/src'
|
||||||
|
|
||||||
function mountWithHydration(html: string, render: () => any) {
|
function mountWithHydration(html: string, render: () => any) {
|
||||||
const container = document.createElement('div')
|
const container = document.createElement('div')
|
||||||
@ -761,6 +765,36 @@ describe('SSR hydration', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('force hydrate input v-model with non-string value bindings', () => {
|
||||||
|
const { container } = mountWithHydration(
|
||||||
|
'<input type="checkbox" value="true">',
|
||||||
|
() =>
|
||||||
|
withDirectives(
|
||||||
|
createVNode(
|
||||||
|
'input',
|
||||||
|
{ type: 'checkbox', 'true-value': true },
|
||||||
|
null,
|
||||||
|
PatchFlags.PROPS,
|
||||||
|
['true-value']
|
||||||
|
),
|
||||||
|
[[vModelCheckbox, true]]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
expect((container.firstChild as any)._trueValue).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('force hydrate select option with non-string value bindings', () => {
|
||||||
|
const { container } = mountWithHydration(
|
||||||
|
'<select><option :value="true">ok</option></select>',
|
||||||
|
() =>
|
||||||
|
h('select', [
|
||||||
|
// hoisted because bound value is a constant...
|
||||||
|
createVNode('option', { value: true }, null, -1 /* HOISTED */)
|
||||||
|
])
|
||||||
|
)
|
||||||
|
expect((container.firstChild!.firstChild as any)._value).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
describe('mismatch handling', () => {
|
describe('mismatch handling', () => {
|
||||||
test('text node', () => {
|
test('text node', () => {
|
||||||
const { container } = mountWithHydration(`foo`, () => 'bar')
|
const { container } = mountWithHydration(`foo`, () => 'bar')
|
||||||
|
@ -264,21 +264,28 @@ export function createHydrationFunctions(
|
|||||||
optimized: boolean
|
optimized: boolean
|
||||||
) => {
|
) => {
|
||||||
optimized = optimized || !!vnode.dynamicChildren
|
optimized = optimized || !!vnode.dynamicChildren
|
||||||
const { props, patchFlag, shapeFlag, dirs } = vnode
|
const { type, props, patchFlag, shapeFlag, dirs } = vnode
|
||||||
|
// #4006 for form elements with non-string v-model value bindings
|
||||||
|
// e.g. <option :value="obj">, <input type="checkbox" :true-value="1">
|
||||||
|
const forcePatchValue = (type === 'input' && dirs) || type === 'option'
|
||||||
// skip props & children if this is hoisted static nodes
|
// skip props & children if this is hoisted static nodes
|
||||||
if (patchFlag !== PatchFlags.HOISTED) {
|
if (forcePatchValue || patchFlag !== PatchFlags.HOISTED) {
|
||||||
if (dirs) {
|
if (dirs) {
|
||||||
invokeDirectiveHook(vnode, null, parentComponent, 'created')
|
invokeDirectiveHook(vnode, null, parentComponent, 'created')
|
||||||
}
|
}
|
||||||
// props
|
// props
|
||||||
if (props) {
|
if (props) {
|
||||||
if (
|
if (
|
||||||
|
forcePatchValue ||
|
||||||
!optimized ||
|
!optimized ||
|
||||||
(patchFlag & PatchFlags.FULL_PROPS ||
|
(patchFlag & PatchFlags.FULL_PROPS ||
|
||||||
patchFlag & PatchFlags.HYDRATE_EVENTS)
|
patchFlag & PatchFlags.HYDRATE_EVENTS)
|
||||||
) {
|
) {
|
||||||
for (const key in props) {
|
for (const key in props) {
|
||||||
if (!isReservedProp(key) && isOn(key)) {
|
if (
|
||||||
|
(forcePatchValue && key.endsWith('value')) ||
|
||||||
|
(isOn(key) && !isReservedProp(key))
|
||||||
|
) {
|
||||||
patchProp(el, key, null, props[key])
|
patchProp(el, key, null, props[key])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user