mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 10:01:59 +08:00
fix(vue): ionChange events now propagate correctly (#22872)
resolves #22870
This commit is contained in:
14
core/package-lock.json
generated
14
core/package-lock.json
generated
@ -17,7 +17,7 @@
|
||||
"@rollup/plugin-virtual": "^2.0.3",
|
||||
"@stencil/core": "2.1.2",
|
||||
"@stencil/sass": "1.3.2",
|
||||
"@stencil/vue-output-target": "0.2.5",
|
||||
"@stencil/vue-output-target": "0.3.0",
|
||||
"@types/jest": "^26.0.10",
|
||||
"@types/node": "^14.6.0",
|
||||
"@types/puppeteer": "3.0.1",
|
||||
@ -1657,9 +1657,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@stencil/vue-output-target": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.2.5.tgz",
|
||||
"integrity": "sha512-EnCZbJDD7y2nTnaFXo4PJrEgP9CNvJARZQrnvz93rMDKCzm+19C9goU4D6A1ysblLVvZSTm3wELKSM1auRUm0Q==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.3.0.tgz",
|
||||
"integrity": "sha512-uiBe+o7M+NU0gMRgJfrlepxLPBXK0lX4TL2jIPwhBfxYw++pbtg7BLRO2HxE69GR0nxw+7Uf3uJzOGbMsl+ZUQ==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"@stencil/core": ">=1.8.0"
|
||||
@ -16390,9 +16390,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@stencil/vue-output-target": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.2.5.tgz",
|
||||
"integrity": "sha512-EnCZbJDD7y2nTnaFXo4PJrEgP9CNvJARZQrnvz93rMDKCzm+19C9goU4D6A1ysblLVvZSTm3wELKSM1auRUm0Q==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.3.0.tgz",
|
||||
"integrity": "sha512-uiBe+o7M+NU0gMRgJfrlepxLPBXK0lX4TL2jIPwhBfxYw++pbtg7BLRO2HxE69GR0nxw+7Uf3uJzOGbMsl+ZUQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@stylelint/postcss-css-in-js": {
|
||||
|
@ -38,7 +38,7 @@
|
||||
"@rollup/plugin-virtual": "^2.0.3",
|
||||
"@stencil/core": "2.1.2",
|
||||
"@stencil/sass": "1.3.2",
|
||||
"@stencil/vue-output-target": "0.2.5",
|
||||
"@stencil/vue-output-target": "0.3.0",
|
||||
"@types/jest": "^26.0.10",
|
||||
"@types/node": "^14.6.0",
|
||||
"@types/puppeteer": "3.0.1",
|
||||
|
@ -91,12 +91,14 @@ export const config: Config = {
|
||||
{
|
||||
elements: ['ion-checkbox', 'ion-toggle'],
|
||||
targetAttr: 'checked',
|
||||
event: 'ionChange'
|
||||
event: 'v-ionChange',
|
||||
externalEvent: 'ionChange'
|
||||
},
|
||||
{
|
||||
elements: ['ion-datetime', 'ion-input', 'ion-radio-group', 'ion-radio', 'ion-range', 'ion-searchbar', 'ion-segment', 'ion-segment-button', 'ion-select', 'ion-textarea'],
|
||||
targetAttr: 'value',
|
||||
event: 'ionChange'
|
||||
event: 'v-ionChange',
|
||||
externalEvent: 'ionChange'
|
||||
}
|
||||
],
|
||||
}),
|
||||
|
@ -2,8 +2,17 @@ import { App, Plugin } from 'vue';
|
||||
import { IonicConfig, setupConfig } from '@ionic/core';
|
||||
import { applyPolyfills, defineCustomElements } from '@ionic/core/loader';
|
||||
|
||||
const ael = (el: any, eventName: string, cb: any, opts: any) => el.addEventListener(eventName.toLowerCase(), cb, opts);
|
||||
const rel = (el: any, eventName: string, cb: any, opts: any) => el.removeEventListener(eventName.toLowerCase(), cb, opts);
|
||||
/**
|
||||
* We need to make sure that the web component fires an event
|
||||
* that will not conflict with the user's @ionChange binding,
|
||||
* otherwise the binding's callback will fire before any
|
||||
* v-model values have been updated.
|
||||
*/
|
||||
const transformEventName = (eventName: string) => {
|
||||
return eventName === 'ionChange' ? 'v-ionchange' : eventName.toLowerCase();
|
||||
}
|
||||
const ael = (el: any, eventName: string, cb: any, opts: any) => el.addEventListener(transformEventName(eventName), cb, opts);
|
||||
const rel = (el: any, eventName: string, cb: any, opts: any) => el.removeEventListener(transformEventName(eventName), cb, opts);
|
||||
|
||||
export const IonicVue: Plugin = {
|
||||
|
||||
@ -17,7 +26,7 @@ export const IonicVue: Plugin = {
|
||||
await applyPolyfills();
|
||||
await defineCustomElements(window, {
|
||||
exclude: ['ion-tabs'],
|
||||
ce: (eventName: string, opts: any) => new CustomEvent(eventName.toLowerCase(), opts),
|
||||
ce: (eventName: string, opts: any) => new CustomEvent(transformEventName(eventName), opts),
|
||||
ael,
|
||||
rel
|
||||
} as any);
|
||||
|
@ -97,7 +97,8 @@ export const IonCheckbox = /*@__PURE__*/ defineContainer<JSX.IonCheckbox>('ion-c
|
||||
],
|
||||
{
|
||||
"modelProp": "checked",
|
||||
"modelUpdateEvent": "ionChange"
|
||||
"modelUpdateEvent": "v-ionChange",
|
||||
"externalModelUpdateEvent": "ionChange"
|
||||
});
|
||||
|
||||
|
||||
@ -180,7 +181,8 @@ export const IonDatetime = /*@__PURE__*/ defineContainer<JSX.IonDatetime>('ion-d
|
||||
],
|
||||
{
|
||||
"modelProp": "value",
|
||||
"modelUpdateEvent": "ionChange"
|
||||
"modelUpdateEvent": "v-ionChange",
|
||||
"externalModelUpdateEvent": "ionChange"
|
||||
});
|
||||
|
||||
|
||||
@ -294,7 +296,8 @@ export const IonInput = /*@__PURE__*/ defineContainer<JSX.IonInput>('ion-input',
|
||||
],
|
||||
{
|
||||
"modelProp": "value",
|
||||
"modelUpdateEvent": "ionChange"
|
||||
"modelUpdateEvent": "v-ionChange",
|
||||
"externalModelUpdateEvent": "ionChange"
|
||||
});
|
||||
|
||||
|
||||
@ -445,7 +448,8 @@ export const IonRadio = /*@__PURE__*/ defineContainer<JSX.IonRadio>('ion-radio',
|
||||
],
|
||||
{
|
||||
"modelProp": "value",
|
||||
"modelUpdateEvent": "ionChange"
|
||||
"modelUpdateEvent": "v-ionChange",
|
||||
"externalModelUpdateEvent": "ionChange"
|
||||
});
|
||||
|
||||
|
||||
@ -457,7 +461,8 @@ export const IonRadioGroup = /*@__PURE__*/ defineContainer<JSX.IonRadioGroup>('i
|
||||
],
|
||||
{
|
||||
"modelProp": "value",
|
||||
"modelUpdateEvent": "ionChange"
|
||||
"modelUpdateEvent": "v-ionChange",
|
||||
"externalModelUpdateEvent": "ionChange"
|
||||
});
|
||||
|
||||
|
||||
@ -481,7 +486,8 @@ export const IonRange = /*@__PURE__*/ defineContainer<JSX.IonRange>('ion-range',
|
||||
],
|
||||
{
|
||||
"modelProp": "value",
|
||||
"modelUpdateEvent": "ionChange"
|
||||
"modelUpdateEvent": "v-ionChange",
|
||||
"externalModelUpdateEvent": "ionChange"
|
||||
});
|
||||
|
||||
|
||||
@ -551,7 +557,8 @@ export const IonSearchbar = /*@__PURE__*/ defineContainer<JSX.IonSearchbar>('ion
|
||||
],
|
||||
{
|
||||
"modelProp": "value",
|
||||
"modelUpdateEvent": "ionChange"
|
||||
"modelUpdateEvent": "v-ionChange",
|
||||
"externalModelUpdateEvent": "ionChange"
|
||||
});
|
||||
|
||||
|
||||
@ -567,7 +574,8 @@ export const IonSegment = /*@__PURE__*/ defineContainer<JSX.IonSegment>('ion-seg
|
||||
],
|
||||
{
|
||||
"modelProp": "value",
|
||||
"modelUpdateEvent": "ionChange"
|
||||
"modelUpdateEvent": "v-ionChange",
|
||||
"externalModelUpdateEvent": "ionChange"
|
||||
});
|
||||
|
||||
|
||||
@ -579,7 +587,8 @@ export const IonSegmentButton = /*@__PURE__*/ defineContainer<JSX.IonSegmentButt
|
||||
],
|
||||
{
|
||||
"modelProp": "value",
|
||||
"modelUpdateEvent": "ionChange"
|
||||
"modelUpdateEvent": "v-ionChange",
|
||||
"externalModelUpdateEvent": "ionChange"
|
||||
});
|
||||
|
||||
|
||||
@ -603,7 +612,8 @@ export const IonSelect = /*@__PURE__*/ defineContainer<JSX.IonSelect>('ion-selec
|
||||
],
|
||||
{
|
||||
"modelProp": "value",
|
||||
"modelUpdateEvent": "ionChange"
|
||||
"modelUpdateEvent": "v-ionChange",
|
||||
"externalModelUpdateEvent": "ionChange"
|
||||
});
|
||||
|
||||
|
||||
@ -695,7 +705,8 @@ export const IonTextarea = /*@__PURE__*/ defineContainer<JSX.IonTextarea>('ion-t
|
||||
],
|
||||
{
|
||||
"modelProp": "value",
|
||||
"modelUpdateEvent": "ionChange"
|
||||
"modelUpdateEvent": "v-ionChange",
|
||||
"externalModelUpdateEvent": "ionChange"
|
||||
});
|
||||
|
||||
|
||||
@ -722,7 +733,8 @@ export const IonToggle = /*@__PURE__*/ defineContainer<JSX.IonToggle>('ion-toggl
|
||||
],
|
||||
{
|
||||
"modelProp": "checked",
|
||||
"modelUpdateEvent": "ionChange"
|
||||
"modelUpdateEvent": "v-ionChange",
|
||||
"externalModelUpdateEvent": "ionChange"
|
||||
});
|
||||
|
||||
|
||||
|
@ -17,6 +17,7 @@ interface NavManager<T = any> {
|
||||
interface ComponentOptions {
|
||||
modelProp?: string;
|
||||
modelUpdateEvent?: string;
|
||||
externalModelUpdateEvent?: string;
|
||||
}
|
||||
|
||||
const getComponentClasses = (classes: unknown) => {
|
||||
@ -40,7 +41,7 @@ const getElementClasses = (ref: Ref<HTMLElement | undefined>, componentClasses:
|
||||
* integrations.
|
||||
*/
|
||||
export const defineContainer = <Props>(name: string, componentProps: string[] = [], componentOptions: ComponentOptions = {}) => {
|
||||
const { modelProp, modelUpdateEvent } = componentOptions;
|
||||
const { modelProp, modelUpdateEvent, externalModelUpdateEvent } = componentOptions;
|
||||
|
||||
/**
|
||||
* Create a Vue component wrapper around a Web Component.
|
||||
@ -66,8 +67,7 @@ export const defineContainer = <Props>(name: string, componentProps: string[] =
|
||||
* native web component, but the v-model will
|
||||
* not have been updated yet.
|
||||
*/
|
||||
emit(modelUpdateEvent, e);
|
||||
e.stopImmediatePropagation();
|
||||
emit(externalModelUpdateEvent, e);
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -112,7 +112,7 @@ export const defineContainer = <Props>(name: string, componentProps: string[] =
|
||||
ref: containerRef,
|
||||
class: getElementClasses(containerRef, classes),
|
||||
onClick: handleClick,
|
||||
onVnodeBeforeMount: (modelUpdateEvent) ? onVnodeBeforeMount : undefined
|
||||
onVnodeBeforeMount: (modelUpdateEvent && externalModelUpdateEvent) ? onVnodeBeforeMount : undefined
|
||||
};
|
||||
|
||||
if (modelProp) {
|
||||
@ -130,7 +130,7 @@ export const defineContainer = <Props>(name: string, componentProps: string[] =
|
||||
Container.props = [...componentProps, ROUTER_LINK_VALUE];
|
||||
if (modelProp) {
|
||||
Container.props.push(MODEL_VALUE);
|
||||
Container.emits = [UPDATE_VALUE_EVENT, modelUpdateEvent];
|
||||
Container.emits = [UPDATE_VALUE_EVENT, externalModelUpdateEvent];
|
||||
}
|
||||
|
||||
return Container;
|
||||
|
Reference in New Issue
Block a user