mirror of https://github.com/vuejs/core.git
Merge 74d74d77f4
into 56be3dd4db
This commit is contained in:
commit
7ac8263bdc
|
@ -7,6 +7,8 @@ import {
|
||||||
vModelCheckbox,
|
vModelCheckbox,
|
||||||
withDirectives,
|
withDirectives,
|
||||||
} from '../src'
|
} from '../src'
|
||||||
|
import { defineComponent } from '@vue/runtime-test'
|
||||||
|
import { render as domRender } from 'vue'
|
||||||
|
|
||||||
describe('runtime-dom: props patching', () => {
|
describe('runtime-dom: props patching', () => {
|
||||||
test('basic', () => {
|
test('basic', () => {
|
||||||
|
@ -395,3 +397,114 @@ describe('runtime-dom: props patching', () => {
|
||||||
expect(fn).toBeCalledTimes(0)
|
expect(fn).toBeCalledTimes(0)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #13055
|
||||||
|
test('should lookup camelCase keys in element properties', async () => {
|
||||||
|
class TestElement extends HTMLElement {
|
||||||
|
_complexData = {}
|
||||||
|
|
||||||
|
get primitiveValue(): string | null {
|
||||||
|
return this.getAttribute('primitive-value')
|
||||||
|
}
|
||||||
|
|
||||||
|
set primitiveValue(value: string | undefined) {
|
||||||
|
if (value) {
|
||||||
|
this.setAttribute('primitive-value', value)
|
||||||
|
} else {
|
||||||
|
this.removeAttribute('primitive-value')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get complexData() {
|
||||||
|
return this._complexData
|
||||||
|
}
|
||||||
|
|
||||||
|
set complexData(data) {
|
||||||
|
this._complexData = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define('test-element', TestElement)
|
||||||
|
const el = document.createElement('test-element') as TestElement
|
||||||
|
|
||||||
|
patchProp(el, 'primitive-value', null, 'foo')
|
||||||
|
expect(el.primitiveValue).toBe('foo')
|
||||||
|
|
||||||
|
patchProp(el, 'complex-data', null, { foo: 'bar' })
|
||||||
|
expect(el.hasAttribute('complex-data')).toBe(false)
|
||||||
|
expect(el.getAttribute('complex-data')).not.toBe('[object Object]')
|
||||||
|
expect(el.complexData).toStrictEqual({ foo: 'bar' })
|
||||||
|
})
|
||||||
|
|
||||||
|
// #13055
|
||||||
|
test('should handle kebab-case prop bindings', async () => {
|
||||||
|
class HelloWorld extends HTMLElement {
|
||||||
|
#testProp = ''
|
||||||
|
#output: HTMLDivElement
|
||||||
|
|
||||||
|
get testProp() {
|
||||||
|
return this.#testProp
|
||||||
|
}
|
||||||
|
|
||||||
|
set testProp(value: string) {
|
||||||
|
this.#testProp = value
|
||||||
|
this.#update()
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
|
||||||
|
this.attachShadow({ mode: 'open' })
|
||||||
|
this.shadowRoot!.innerHTML = `<div class="output"></div>`
|
||||||
|
this.#output = this.shadowRoot?.querySelector('.output') as HTMLDivElement
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
console.log('UPDATING!')
|
||||||
|
this.#update()
|
||||||
|
}
|
||||||
|
|
||||||
|
#update() {
|
||||||
|
this.#output.innerHTML = `this.testProp = ${this.#testProp}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define('hello-world', HelloWorld)
|
||||||
|
|
||||||
|
const Comp = defineComponent({
|
||||||
|
setup() {
|
||||||
|
const testProp = ref('Hello, world! from App.vue')
|
||||||
|
return {
|
||||||
|
testProp,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<hello-world .testProp="testProp" />
|
||||||
|
<hello-world .test-prop="testProp" />
|
||||||
|
<hello-world .test-prop.camel="testProp" />
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
|
||||||
|
const root = document.createElement('div')
|
||||||
|
|
||||||
|
// Note this one is using the main Vue render so it can compile template
|
||||||
|
// on the fly
|
||||||
|
domRender(h(Comp), root)
|
||||||
|
|
||||||
|
expect(root.innerHTML).toBe(
|
||||||
|
`<hello-world></hello-world><hello-world></hello-world><hello-world></hello-world>`,
|
||||||
|
)
|
||||||
|
|
||||||
|
const [child1, child2, child3] = Array.from(
|
||||||
|
root.querySelectorAll('hello-world'),
|
||||||
|
)
|
||||||
|
expect(child3.shadowRoot?.innerHTML).toBe(
|
||||||
|
'<div class="output">this.testProp = Hello, world! from App.vue</div>',
|
||||||
|
)
|
||||||
|
expect(child2.shadowRoot?.innerHTML).toBe(
|
||||||
|
'<div class="output">this.testProp = Hello, world! from App.vue</div>',
|
||||||
|
)
|
||||||
|
expect(child1.shadowRoot?.innerHTML).toBe(
|
||||||
|
'<div class="output">this.testProp = Hello, world! from App.vue</div>',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
|
@ -47,7 +47,9 @@ export const patchProp: DOMRendererOptions['patchProp'] = (
|
||||||
? ((key = key.slice(1)), false)
|
? ((key = key.slice(1)), false)
|
||||||
: shouldSetAsProp(el, key, nextValue, isSVG)
|
: shouldSetAsProp(el, key, nextValue, isSVG)
|
||||||
) {
|
) {
|
||||||
patchDOMProp(el, key, nextValue, parentComponent)
|
const camelKey = camelize(key)
|
||||||
|
const propKey = camelKey in el ? camelKey : key
|
||||||
|
patchDOMProp(el, propKey, nextValue, parentComponent, key)
|
||||||
// #6007 also set form state as attributes so they work with
|
// #6007 also set form state as attributes so they work with
|
||||||
// <input type="reset"> or libs / extensions that expect attributes
|
// <input type="reset"> or libs / extensions that expect attributes
|
||||||
// #11163 custom elements may use value as an prop and set it as object
|
// #11163 custom elements may use value as an prop and set it as object
|
||||||
|
@ -145,5 +147,5 @@ function shouldSetAsProp(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return key in el
|
return camelize(key) in el || key in el
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue