mirror of https://github.com/vuejs/core.git
fix(custom-element): handle keys set on custom elements (#11655)
close #11641
This commit is contained in:
parent
1d988b5b99
commit
f1d1831f07
|
@ -487,6 +487,10 @@ export class VueElement
|
||||||
delete this._props[key]
|
delete this._props[key]
|
||||||
} else {
|
} else {
|
||||||
this._props[key] = val
|
this._props[key] = val
|
||||||
|
// support set key on ceVNode
|
||||||
|
if (key === 'key' && this._app) {
|
||||||
|
this._app._ceVNode!.key = val
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (shouldUpdate && this._instance) {
|
if (shouldUpdate && this._instance) {
|
||||||
this._update()
|
this._update()
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
<script src="../../dist/vue.global.js"></script>
|
|
||||||
|
|
||||||
<my-element
|
|
||||||
><template shadowrootmode="open"><button>1</button></template></my-element
|
|
||||||
>
|
|
||||||
<my-element-async
|
|
||||||
><template shadowrootmode="open"
|
|
||||||
><button>1</button></template
|
|
||||||
></my-element-async
|
|
||||||
>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
const {
|
|
||||||
h,
|
|
||||||
ref,
|
|
||||||
defineSSRCustomElement,
|
|
||||||
defineAsyncComponent,
|
|
||||||
onMounted,
|
|
||||||
useHost,
|
|
||||||
} = Vue
|
|
||||||
|
|
||||||
const def = {
|
|
||||||
setup() {
|
|
||||||
const count = ref(1)
|
|
||||||
const el = useHost()
|
|
||||||
onMounted(() => (el.style.border = '1px solid red'))
|
|
||||||
|
|
||||||
return () => h('button', { onClick: () => count.value++ }, count.value)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define('my-element', defineSSRCustomElement(def))
|
|
||||||
customElements.define(
|
|
||||||
'my-element-async',
|
|
||||||
defineSSRCustomElement(
|
|
||||||
defineAsyncComponent(
|
|
||||||
() =>
|
|
||||||
new Promise(r => {
|
|
||||||
window.resolve = () => r(def)
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
</script>
|
|
|
@ -3,13 +3,57 @@ import { setupPuppeteer } from './e2eUtils'
|
||||||
|
|
||||||
const { page, click, text } = setupPuppeteer()
|
const { page, click, text } = setupPuppeteer()
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await page().addScriptTag({
|
||||||
|
path: path.resolve(__dirname, '../../dist/vue.global.js'),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
async function setContent(html: string) {
|
||||||
|
await page().setContent(`<div id="app">${html}</div>`)
|
||||||
|
}
|
||||||
|
|
||||||
// this must be tested in actual Chrome because jsdom does not support
|
// this must be tested in actual Chrome because jsdom does not support
|
||||||
// declarative shadow DOM
|
// declarative shadow DOM
|
||||||
test('ssr custom element hydration', async () => {
|
test('ssr custom element hydration', async () => {
|
||||||
await page().goto(
|
await setContent(
|
||||||
`file://${path.resolve(__dirname, './ssr-custom-element.html')}`,
|
`<my-element><template shadowrootmode="open"><button>1</button></template></my-element><my-element-async><template shadowrootmode="open"><button>1</button></template></my-element-async>`,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
await page().evaluate(() => {
|
||||||
|
const {
|
||||||
|
h,
|
||||||
|
ref,
|
||||||
|
defineSSRCustomElement,
|
||||||
|
defineAsyncComponent,
|
||||||
|
onMounted,
|
||||||
|
useHost,
|
||||||
|
} = (window as any).Vue
|
||||||
|
|
||||||
|
const def = {
|
||||||
|
setup() {
|
||||||
|
const count = ref(1)
|
||||||
|
const el = useHost()
|
||||||
|
onMounted(() => (el.style.border = '1px solid red'))
|
||||||
|
|
||||||
|
return () => h('button', { onClick: () => count.value++ }, count.value)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('my-element', defineSSRCustomElement(def))
|
||||||
|
customElements.define(
|
||||||
|
'my-element-async',
|
||||||
|
defineSSRCustomElement(
|
||||||
|
defineAsyncComponent(
|
||||||
|
() =>
|
||||||
|
new Promise(r => {
|
||||||
|
;(window as any).resolve = () => r(def)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
function getColor() {
|
function getColor() {
|
||||||
return page().evaluate(() => {
|
return page().evaluate(() => {
|
||||||
return [
|
return [
|
||||||
|
@ -33,3 +77,55 @@ test('ssr custom element hydration', async () => {
|
||||||
await assertInteraction('my-element')
|
await assertInteraction('my-element')
|
||||||
await assertInteraction('my-element-async')
|
await assertInteraction('my-element-async')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #11641
|
||||||
|
test('pass key to custom element', async () => {
|
||||||
|
const messages: string[] = []
|
||||||
|
page().on('console', e => messages.push(e.text()))
|
||||||
|
|
||||||
|
await setContent(
|
||||||
|
`<!--[--><my-element str="1"><template shadowrootmode="open"><div>1</div></template></my-element><!--]-->`,
|
||||||
|
)
|
||||||
|
await page().evaluate(() => {
|
||||||
|
const {
|
||||||
|
h,
|
||||||
|
ref,
|
||||||
|
defineSSRCustomElement,
|
||||||
|
onBeforeUnmount,
|
||||||
|
onMounted,
|
||||||
|
createSSRApp,
|
||||||
|
renderList,
|
||||||
|
} = (window as any).Vue
|
||||||
|
|
||||||
|
const MyElement = defineSSRCustomElement({
|
||||||
|
props: {
|
||||||
|
str: String,
|
||||||
|
},
|
||||||
|
setup(props: any) {
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('child mounted')
|
||||||
|
})
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
console.log('child unmount')
|
||||||
|
})
|
||||||
|
return () => h('div', props.str)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
customElements.define('my-element', MyElement)
|
||||||
|
|
||||||
|
createSSRApp({
|
||||||
|
setup() {
|
||||||
|
const arr = ref(['1'])
|
||||||
|
// pass key to custom element
|
||||||
|
return () =>
|
||||||
|
renderList(arr.value, (i: string) =>
|
||||||
|
h('my-element', { key: i, str: i }, null),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}).mount('#app')
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(messages.includes('child mounted')).toBe(true)
|
||||||
|
expect(messages.includes('child unmount')).toBe(false)
|
||||||
|
expect(await text('my-element >>> div')).toBe('1')
|
||||||
|
})
|
||||||
|
|
Loading…
Reference in New Issue