mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-06 22:29:44 +08:00
chore(): resolve merge conflicts
This commit is contained in:
@ -40,16 +40,31 @@ export const IonRouterOutlet = defineComponent({
|
||||
// The base url for this router outlet
|
||||
let parentOutletPath: string;
|
||||
|
||||
watch(matchedRouteRef, (currentValue, previousValue) => {
|
||||
/**
|
||||
* We need to watch the route object
|
||||
* to listen for navigation changes.
|
||||
* Previously we had watched matchedRouteRef,
|
||||
* but if you had a /page/:id route, going from
|
||||
* page/1 to page/2 would not cause this callback
|
||||
* to fire since the matchedRouteRef was the same.
|
||||
*/
|
||||
watch([route, matchedRouteRef], ([currentRoute, currentMatchedRouteRef], [_, previousMatchedRouteRef]) => {
|
||||
/**
|
||||
* We need to make sure that we are not re-rendering
|
||||
* the same view if navigation changes in a sub-outlet.
|
||||
* This is mainly for tabs when outlet 1 renders ion-tabs
|
||||
* and outlet 2 renders the individual tab view. We don't
|
||||
* want outlet 1 creating a new ion-tabs instance every time
|
||||
* we switch tabs.
|
||||
* If the matched route ref has changed,
|
||||
* then we need to set up a new view item.
|
||||
* If the matched route ref has not changed,
|
||||
* it is possible that this is a parameterized URL
|
||||
* change such as /page/1 to /page/2. In that case,
|
||||
* we can assume that the `route` object has changed,
|
||||
* but we should only set up a new view item in this outlet
|
||||
* if that last matched view item matches our current matched
|
||||
* view item otherwise if we had this in a nested outlet the
|
||||
* parent outlet would re-render as well as the child page.
|
||||
*/
|
||||
if (currentValue !== previousValue) {
|
||||
if (
|
||||
currentMatchedRouteRef !== previousMatchedRouteRef ||
|
||||
currentRoute.matched[currentRoute.matched.length - 1] === currentMatchedRouteRef
|
||||
) {
|
||||
setupViewItem(matchedRouteRef);
|
||||
}
|
||||
});
|
||||
|
||||
@ -11,30 +11,53 @@ interface Tab {
|
||||
ref: VNode
|
||||
}
|
||||
|
||||
const isTabButton = (child: any) => child.type?.name === 'IonTabButton';
|
||||
|
||||
const getTabs = (nodes: VNode[]) => {
|
||||
let tabs: VNode[] = [];
|
||||
nodes.forEach((node: VNode) => {
|
||||
if (isTabButton(node)) {
|
||||
tabs.push(node);
|
||||
} else if (Array.isArray(node.children) && node.children.length > 1) {
|
||||
const childTabs = getTabs(node.children as VNode[]);
|
||||
tabs = [...tabs, ...childTabs];
|
||||
}
|
||||
});
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
export const IonTabBar = defineComponent({
|
||||
name: 'IonTabBar',
|
||||
props: {
|
||||
_tabsWillChange: { type: Function, default: () => {} },
|
||||
_tabsDidChange: { type: Function, default: () => {} }
|
||||
},
|
||||
mounted() {
|
||||
const ionRouter: any = inject('navManager');
|
||||
const tabState: TabState = {
|
||||
data() {
|
||||
return {
|
||||
tabState: {
|
||||
activeTab: undefined,
|
||||
tabs: {}
|
||||
};
|
||||
const currentInstance = getCurrentInstance();
|
||||
const isTabButton = (child: any) => child.type?.name === 'IonTabButton';
|
||||
/**
|
||||
* For each tab, we need to keep track of its
|
||||
* base href as well as any child page that
|
||||
* is active in its stack so that when we go back
|
||||
* to a tab from another tab, we can correctly
|
||||
* show any child pages if necessary.
|
||||
*/
|
||||
const children = (currentInstance.subTree.children || []) as VNode[];
|
||||
children.forEach((child: VNode) => {
|
||||
if (isTabButton(child)) {
|
||||
},
|
||||
tabVnodes: []
|
||||
}
|
||||
},
|
||||
updated() {
|
||||
this.setupTabState(inject('navManager'));
|
||||
},
|
||||
methods: {
|
||||
setupTabState(ionRouter: any) {
|
||||
/**
|
||||
* For each tab, we need to keep track of its
|
||||
* base href as well as any child page that
|
||||
* is active in its stack so that when we go back
|
||||
* to a tab from another tab, we can correctly
|
||||
* show any child pages if necessary.
|
||||
*/
|
||||
const tabState: TabState = this.$data.tabState;
|
||||
const currentInstance = getCurrentInstance();
|
||||
const tabs = this.$data.tabVnodes = getTabs((currentInstance.subTree.children || []) as VNode[]);
|
||||
tabs.forEach(child => {
|
||||
tabState.tabs[child.props.tab] = {
|
||||
originalHref: child.props.href,
|
||||
currentHref: child.props.href,
|
||||
@ -47,12 +70,15 @@ export const IonTabBar = defineComponent({
|
||||
* ion-tab-bar is managing for it.
|
||||
*/
|
||||
child.component.props._getTabState = () => tabState;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const checkActiveTab = (currentRoute: any) => {
|
||||
const childNodes = (currentInstance.subTree.children || []) as VNode[];
|
||||
const { tabs, activeTab: prevActiveTab } = tabState;
|
||||
this.checkActiveTab(ionRouter);
|
||||
},
|
||||
checkActiveTab(ionRouter: any) {
|
||||
const currentRoute = ionRouter.getCurrentRouteInfo();
|
||||
const childNodes = this.$data.tabVnodes;
|
||||
const { tabs, activeTab: prevActiveTab } = this.$data.tabState;
|
||||
const tabState = this.$data.tabState;
|
||||
const tabKeys = Object.keys(tabs);
|
||||
const activeTab = tabKeys
|
||||
.find(key => {
|
||||
@ -66,21 +92,19 @@ export const IonTabBar = defineComponent({
|
||||
* it in the tabs state.
|
||||
*/
|
||||
childNodes.forEach((child: VNode) => {
|
||||
if (isTabButton(child)) {
|
||||
const tab = tabs[child.props.tab];
|
||||
if (!tab || (tab.originalHref !== child.props.href)) {
|
||||
const tab = tabs[child.props.tab];
|
||||
if (!tab || (tab.originalHref !== child.props.href)) {
|
||||
|
||||
tabs[child.props.tab] = {
|
||||
originalHref: child.props.href,
|
||||
currentHref: child.props.href,
|
||||
ref: child
|
||||
}
|
||||
tabs[child.props.tab] = {
|
||||
originalHref: child.props.href,
|
||||
currentHref: child.props.href,
|
||||
ref: child
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (activeTab && prevActiveTab) {
|
||||
const prevHref = tabState.tabs[prevActiveTab].currentHref;
|
||||
const prevHref = this.$data.tabState.tabs[prevActiveTab].currentHref;
|
||||
/**
|
||||
* If the tabs change or the url changes,
|
||||
* update the currentHref for the active tab.
|
||||
@ -128,10 +152,14 @@ export const IonTabBar = defineComponent({
|
||||
tabBar.selectedTab = tabState.activeTab = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const ionRouter: any = inject('navManager');
|
||||
|
||||
ionRouter.registerHistoryChangeListener(checkActiveTab.bind(this));
|
||||
checkActiveTab(ionRouter.getCurrentRouteInfo());
|
||||
this.setupTabState(ionRouter);
|
||||
|
||||
ionRouter.registerHistoryChangeListener(() => this.checkActiveTab(ionRouter));
|
||||
},
|
||||
setup(_, { slots }) {
|
||||
return () => {
|
||||
|
||||
@ -1,37 +1,72 @@
|
||||
import { defineComponent, h, ref, VNode, getCurrentInstance } from 'vue';
|
||||
import { defineComponent, h, ref, VNode, getCurrentInstance, ComponentInternalInstance } from 'vue';
|
||||
import { needsKebabCase } from '../utils';
|
||||
|
||||
export interface OverlayProps {
|
||||
isOpen?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure we only
|
||||
* warn user about each
|
||||
* event at most once.
|
||||
*/
|
||||
let willPresentWarn = false;
|
||||
let didPresentWarn = false;
|
||||
let willDismissWarn = false;
|
||||
let didDismissWarn = false;
|
||||
|
||||
const checkForDeprecatedListeners = (instance: ComponentInternalInstance) => {
|
||||
const props = instance.vnode.props;
|
||||
if (!willPresentWarn && props.onOnWillPresent !== undefined) {
|
||||
console.warn('[@ionic/vue Deprecation]: @onWillPresent has been deprecated in favor of @willPresent and will be removed in Ionic Vue v6.0.');
|
||||
willPresentWarn = true;
|
||||
}
|
||||
|
||||
if (!didPresentWarn && props.onOnDidPresent !== undefined) {
|
||||
console.warn('[@ionic/vue Deprecation]: @onDidPresent has been deprecated in favor of @didPresent and will be removed in Ionic Vue v6.0.');
|
||||
didPresentWarn = true;
|
||||
}
|
||||
|
||||
if (!willDismissWarn && props.onOnWillDismiss !== undefined) {
|
||||
console.warn('[@ionic/vue Deprecation]: @onWillDismiss has been deprecated in favor of @willDismiss and will be removed in Ionic Vue v6.0.');
|
||||
willDismissWarn = true;
|
||||
}
|
||||
|
||||
if (!didDismissWarn && props.onOnDidDismiss !== undefined) {
|
||||
console.warn('[@ionic/vue Deprecation]: @onDidDismiss has been deprecated in favor of @didDismiss and will be removed in Ionic Vue v6.0.');
|
||||
didDismissWarn = true;
|
||||
}
|
||||
}
|
||||
|
||||
export const defineOverlayContainer = <Props extends object>(name: string, componentProps: string[] = [], controller: any) => {
|
||||
/**
|
||||
* Vue 3.0.6 fixed a bug where events on custom elements
|
||||
* were always converted to lower case, so "ionRefresh"
|
||||
* became "ionRefresh". We need to account for the old
|
||||
* became "ionrefresh". We need to account for the old
|
||||
* issue as well as the new behavior where "ionRefresh"
|
||||
* is converted to "ion-refresh".
|
||||
* See https://github.com/vuejs/vue-next/pull/2847
|
||||
*/
|
||||
const eventPrefix = name.toLowerCase().split('-').join('');
|
||||
const lowerCaseListeners = [
|
||||
{ componentEv: `${eventPrefix}willpresent`, frameworkEv: 'onWillPresent' },
|
||||
{ componentEv: `${eventPrefix}didpresent`, frameworkEv: 'onDidPresent' },
|
||||
{ componentEv: `${eventPrefix}willdismiss`, frameworkEv: 'onWillDismiss' },
|
||||
{ componentEv: `${eventPrefix}diddismiss`, frameworkEv: 'onDidDismiss' },
|
||||
{ componentEv: `${eventPrefix}willpresent`, frameworkEv: 'willPresent', deprecatedEv: 'onWillPresent' },
|
||||
{ componentEv: `${eventPrefix}didpresent`, frameworkEv: 'didPresent', deprecatedEv: 'onDidPresent' },
|
||||
{ componentEv: `${eventPrefix}willdismiss`, frameworkEv: 'willDismiss', deprecatedEv: 'onWillDismiss' },
|
||||
{ componentEv: `${eventPrefix}diddismiss`, frameworkEv: 'didDismiss', deprecatedEv: 'onDidDismiss' },
|
||||
];
|
||||
const kebabCaseListeners = [
|
||||
{ componentEv: `${name}-will-present`, frameworkEv: 'onWillPresent' },
|
||||
{ componentEv: `${name}-did-present`, frameworkEv: 'onDidPresent' },
|
||||
{ componentEv: `${name}-will-dismiss`, frameworkEv: 'onWillDismiss' },
|
||||
{ componentEv: `${name}-did-dismiss`, frameworkEv: 'onDidDismiss' },
|
||||
{ componentEv: `${name}-will-present`, frameworkEv: 'willPresent', deprecatedEv: 'onWillPresent' },
|
||||
{ componentEv: `${name}-did-present`, frameworkEv: 'didPresent', deprecatedEv: 'onDidPresent' },
|
||||
{ componentEv: `${name}-will-dismiss`, frameworkEv: 'willDismiss', deprecatedEv: 'onWillDismiss' },
|
||||
{ componentEv: `${name}-did-dismiss`, frameworkEv: 'didDismiss', deprecatedEv: 'onDidDismiss' },
|
||||
];
|
||||
|
||||
const Container = defineComponent<Props & OverlayProps>((props, { slots, emit }) => {
|
||||
const instance = getCurrentInstance();
|
||||
const adjustedEventListeners = needsKebabCase(instance.appContext.app.version) ? kebabCaseListeners : lowerCaseListeners;
|
||||
|
||||
checkForDeprecatedListeners(instance);
|
||||
|
||||
const overlay = ref();
|
||||
const onVnodeMounted = async () => {
|
||||
const isOpen = props.isOpen;
|
||||
@ -85,9 +120,21 @@ export const defineOverlayContainer = <Props extends object>(name: string, compo
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* When supporting both the "on" prefixed and non-"on" prefixed
|
||||
* events, there seems to be an issue where the handlers are
|
||||
* getting passed as props. This should be resolved when we drop
|
||||
* support for the "on" prefixed listeners.
|
||||
*/
|
||||
const restOfProps = { ...(props as any) };
|
||||
delete restOfProps.onWillPresent;
|
||||
delete restOfProps.onDidPresent;
|
||||
delete restOfProps.onWillDismiss;
|
||||
delete restOfProps.onDidDismiss;
|
||||
|
||||
const component = slots.default && slots.default()[0];
|
||||
overlay.value = controller.create({
|
||||
...props,
|
||||
...restOfProps,
|
||||
component
|
||||
});
|
||||
|
||||
@ -96,6 +143,7 @@ export const defineOverlayContainer = <Props extends object>(name: string, compo
|
||||
adjustedEventListeners.forEach(eventListener => {
|
||||
overlay.value.addEventListener(eventListener.componentEv, () => {
|
||||
emit(eventListener.frameworkEv);
|
||||
emit(eventListener.deprecatedEv);
|
||||
});
|
||||
})
|
||||
|
||||
@ -118,7 +166,10 @@ export const defineOverlayContainer = <Props extends object>(name: string, compo
|
||||
|
||||
Container.displayName = name;
|
||||
Container.props = [...componentProps, 'isOpen'];
|
||||
Container.emits = [...lowerCaseListeners.map(ev => ev.frameworkEv), ...kebabCaseListeners.map(ev => ev.frameworkEv)];
|
||||
Container.emits = [
|
||||
'willPresent', 'didPresent', 'willDismiss', 'didDismiss',
|
||||
'onWillPresent', 'onDidPresent', 'onWillDismiss', 'onDidDismiss'
|
||||
];
|
||||
|
||||
return Container;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user