提交 b182de45 编写于 作者: fxy060608's avatar fxy060608

feat(app): add switchTab

上级 50dc7df0
......@@ -2,6 +2,7 @@ import { UniLifecycleHooks } from '@dcloudio/uni-vue/src/apiLifecycle'
import { ComponentCustomProperties, ComponentInternalInstance } from 'vue'
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
route: string
$scope: {
$getAppWebview?: () => PlusWebviewWebviewObject
}
......
......@@ -131,11 +131,14 @@ function wrapperOffApi<T extends ApiLike>(
}
function normalizeErrMsg(errMsg: string | Error) {
if (errMsg instanceof Error) {
console.error(errMsg)
if (isString(errMsg)) {
return errMsg
}
if (errMsg.stack) {
console.error(errMsg.message + '\n' + errMsg.stack)
return errMsg.message
}
return errMsg
return errMsg as unknown as string
}
function wrapperTaskApi<T extends ApiLike>(
......
......@@ -525,8 +525,11 @@ var serviceContext = (function (vue) {
};
}
function normalizeErrMsg(errMsg) {
if (errMsg instanceof Error) {
console.error(errMsg);
if (isString(errMsg)) {
return errMsg;
}
if (errMsg.stack) {
console.error(errMsg.message + '\n' + errMsg.stack);
return errMsg.message;
}
return errMsg;
......@@ -1801,6 +1804,7 @@ var serviceContext = (function (vue) {
appVm.$mpType = 'app';
}
function initPageVm(pageVm, page) {
pageVm.route = page.route;
pageVm.$vm = pageVm;
pageVm.$page = page;
pageVm.$mpType = 'page';
......@@ -4420,12 +4424,15 @@ var serviceContext = (function (vue) {
}, createAnimationProtocol(ANIMATION_OUT));
const RedirectToProtocol = BaseRouteProtocol;
const ReLaunchProtocol = BaseRouteProtocol;
const SwitchTabProtocol = BaseRouteProtocol;
const NavigateToOptions =
/*#__PURE__*/ createRouteOptions(API_NAVIGATE_TO);
const RedirectToOptions =
/*#__PURE__*/ createRouteOptions(API_REDIRECT_TO);
const ReLaunchOptions =
/*#__PURE__*/ createRouteOptions(API_RE_LAUNCH);
const SwitchTabOptions =
/*#__PURE__*/ createRouteOptions(API_SWITCH_TAB);
const NavigateBackOptions = {
formatArgs: {
delta(value, params) {
......@@ -9068,6 +9075,10 @@ var serviceContext = (function (vue) {
console.log(formatLog('setPendingNavigator', path, msg));
}
}
function closePage(page, animationType, animationDuration) {
removePage(page);
closeWebview(page.$getAppWebview(), animationType, animationDuration);
}
function navigate(path, callback, isAppLaunch = false) {
if (!isAppLaunch && pendingNavigator) {
return console.error(`Waiting to navigate to: ${pendingNavigator.path}, do not operate continuously: ${path}.`);
......@@ -9757,16 +9768,111 @@ var serviceContext = (function (vue) {
query,
openType: 'reLaunch',
}), 'none', 0, () => {
pages.forEach((page) => {
removePage(page);
closeWebview(page.$getAppWebview(), 'none');
});
pages.forEach((page) => closePage(page, 'none'));
resolve(undefined);
});
setStatusBarStyle();
});
}
const switchTab = defineAsyncApi(API_SWITCH_TAB, (args, { resolve, reject }) => {
const { url } = args;
const { path, query } = parseUrl(url);
navigate(path, () => {
_switchTab({
url,
path,
query,
})
.then(resolve)
.catch(reject);
}, args.openType === 'appLaunch');
}, SwitchTabProtocol, SwitchTabOptions);
function _switchTab({ url, path, query, }) {
tabBar$1.switchTab(path.slice(1));
const pages = getCurrentPages();
const len = pages.length;
let callOnHide = false;
let callOnShow = false;
let currentPage;
if (len >= 1) {
// 前一个页面是非 tabBar 页面
currentPage = pages[len - 1];
if (currentPage && !currentPage.__isTabBar) {
// 前一个页面为非 tabBar 页面时,目标tabBar需要强制触发onShow
// 该情况下目标页tabBarPage的visible是不对的
// 除非每次路由跳转都处理一遍tabBarPage的visible,目前仅switchTab会处理
// 简单起见,暂时直接判断该情况,执行onShow
callOnShow = true;
pages.reverse().forEach((page) => {
if (!page.__isTabBar && page !== currentPage) {
closePage(page, 'none');
}
});
removePage(currentPage);
// 延迟执行避免iOS应用退出
setTimeout(() => {
if (currentPage.$page.openType === 'redirectTo') {
closeWebview(currentPage.$getAppWebview(), ANI_CLOSE, ANI_DURATION);
}
else {
closeWebview(currentPage.$getAppWebview(), 'auto');
}
}, 100);
}
else {
callOnHide = true;
}
}
let tabBarPage;
// 查找当前 tabBarPage,且设置 visible
getAllPages().forEach((page) => {
if ('/' + page.route === path) {
if (!page.$.__isActive) {
// 之前未显示
callOnShow = true;
}
page.$.__isActive = true;
tabBarPage = page;
}
else {
if (page.__isTabBar) {
page.$.__isActive = false;
}
}
});
// 相同tabBar页面
if (currentPage === tabBarPage) {
callOnHide = false;
}
if (currentPage && callOnHide) {
invokeHook(currentPage, 'onHide');
}
return new Promise((resolve) => {
if (tabBarPage) {
const webview = tabBarPage.$getAppWebview();
webview.show('none');
// 等visible状态都切换完之后,再触发onShow,否则开发者在onShow里边 getCurrentPages 会不准确
if (callOnShow && !webview.__preload__) {
invokeHook(tabBarPage, 'onShow');
}
resolve(undefined);
}
else {
showWebview(registerPage({
url,
path,
query,
openType: 'switchTab',
}), 'none', 0, () => {
setStatusBarStyle();
resolve(undefined);
}, 70);
}
setStatusBarStyle();
});
}
var uni$1 = /*#__PURE__*/Object.freeze({
__proto__: null,
upx2px: upx2px,
......@@ -9897,7 +10003,8 @@ var serviceContext = (function (vue) {
navigateBack: navigateBack,
navigateTo: navigateTo,
redirectTo: redirectTo,
reLaunch: reLaunch
reLaunch: reLaunch,
switchTab: switchTab
});
let invokeViewMethodId = 0;
......
......@@ -56,6 +56,7 @@ export * from './route/navigateBack'
export * from './route/navigateTo'
export * from './route/redirectTo'
export * from './route/reLaunch'
export * from './route/switchTab'
export {
upx2px,
......
......@@ -6,13 +6,12 @@ import {
ReLaunchProtocol,
} from '@dcloudio/uni-api'
import { parseUrl } from '@dcloudio/uni-shared'
import { ComponentPublicInstance } from 'vue'
import tabBar from '../../framework/app/tabBar'
import { registerPage } from '../../framework/page'
import { getAllPages, removePage } from '../../framework/page/getCurrentPages'
import { getAllPages } from '../../framework/page/getCurrentPages'
import { setStatusBarStyle } from '../../statusBar'
import { navigate, RouteOptions } from './utils'
import { closeWebview, showWebview } from './webview'
import { closePage, navigate, RouteOptions } from './utils'
import { showWebview } from './webview'
export const reLaunch = defineAsyncApi<API_TYPE_RE_LAUNCH>(
API_RE_LAUNCH,
......@@ -53,13 +52,7 @@ function _reLaunch({ url, path, query }: ReLaunchOptions): Promise<undefined> {
'none',
0,
() => {
pages.forEach((page) => {
removePage(page)
closeWebview(
(page as ComponentPublicInstance).$getAppWebview!(),
'none'
)
})
pages.forEach((page) => closePage(page, 'none'))
resolve(undefined)
}
)
......
import {
API_SWITCH_TAB,
API_TYPE_SWITCH_TAB,
defineAsyncApi,
SwitchTabOptions,
SwitchTabProtocol,
} from '@dcloudio/uni-api'
import { invokeHook } from '@dcloudio/uni-core'
import { parseUrl } from '@dcloudio/uni-shared'
import { ComponentPublicInstance } from 'vue'
import { ANI_CLOSE, ANI_DURATION } from '../../constants'
import tabBar from '../../framework/app/tabBar'
import { registerPage } from '../../framework/page'
import { getAllPages, removePage } from '../../framework/page/getCurrentPages'
import { setStatusBarStyle } from '../../statusBar'
import { closePage, navigate, RouteOptions } from './utils'
import { closeWebview, showWebview } from './webview'
export const switchTab = defineAsyncApi<API_TYPE_SWITCH_TAB>(
API_SWITCH_TAB,
(args, { resolve, reject }) => {
const { url } = args
const { path, query } = parseUrl(url)
navigate(
path,
() => {
_switchTab({
url,
path,
query,
})
.then(resolve)
.catch(reject)
},
(args as any).openType === 'appLaunch'
)
},
SwitchTabProtocol,
SwitchTabOptions
)
interface SwitchTabOptions extends RouteOptions {}
function _switchTab({
url,
path,
query,
}: SwitchTabOptions): Promise<undefined> {
tabBar.switchTab(path.slice(1))
const pages = getCurrentPages() as ComponentPublicInstance[]
const len = pages.length
let callOnHide = false
let callOnShow = false
let currentPage: ComponentPublicInstance | undefined
if (len >= 1) {
// 前一个页面是非 tabBar 页面
currentPage = pages[len - 1]! as ComponentPublicInstance
if (currentPage && !currentPage.__isTabBar) {
// 前一个页面为非 tabBar 页面时,目标tabBar需要强制触发onShow
// 该情况下目标页tabBarPage的visible是不对的
// 除非每次路由跳转都处理一遍tabBarPage的visible,目前仅switchTab会处理
// 简单起见,暂时直接判断该情况,执行onShow
callOnShow = true
pages.reverse().forEach((page) => {
if (!page.__isTabBar && page !== currentPage) {
closePage(page, 'none')
}
})
removePage(currentPage)
// 延迟执行避免iOS应用退出
setTimeout(() => {
if (currentPage!.$page.openType === 'redirectTo') {
closeWebview(currentPage!.$getAppWebview!(), ANI_CLOSE, ANI_DURATION)
} else {
closeWebview(currentPage!.$getAppWebview!(), 'auto')
}
}, 100)
} else {
callOnHide = true
}
}
let tabBarPage: ComponentPublicInstance | undefined
// 查找当前 tabBarPage,且设置 visible
getAllPages().forEach((page) => {
if ('/' + page.route === path) {
if (!page.$.__isActive) {
// 之前未显示
callOnShow = true
}
page.$.__isActive = true
tabBarPage = page
} else {
if (page.__isTabBar) {
page.$.__isActive = false
}
}
})
// 相同tabBar页面
if (currentPage === tabBarPage) {
callOnHide = false
}
if (currentPage && callOnHide) {
invokeHook(currentPage, 'onHide')
}
return new Promise((resolve) => {
if (tabBarPage) {
const webview = tabBarPage!.$getAppWebview!()
webview.show('none')
// 等visible状态都切换完之后,再触发onShow,否则开发者在onShow里边 getCurrentPages 会不准确
if (callOnShow && !(webview as any).__preload__) {
invokeHook(tabBarPage, 'onShow')
}
resolve(undefined)
} else {
showWebview(
registerPage({
url,
path,
query,
openType: 'switchTab',
}),
'none',
0,
() => {
setStatusBarStyle()
resolve(undefined)
},
70
)
}
setStatusBarStyle()
})
}
import { getRouteMeta } from '@dcloudio/uni-core'
import { formatLog } from '@dcloudio/uni-shared'
import { ComponentPublicInstance } from 'vue'
import { removePage } from '../../framework/page/getCurrentPages'
import {
createPreloadWebview,
onWebviewReady,
preloadWebview,
} from '../../framework/webview'
import { closeWebview } from './webview'
export interface RouteOptions {
url: string
......@@ -30,6 +33,15 @@ function setPendingNavigator(path: string, callback: Function, msg: string) {
}
}
export function closePage(
page: ComponentPublicInstance,
animationType: string,
animationDuration?: number
) {
removePage(page)
closeWebview(page.$getAppWebview!(), animationType, animationDuration)
}
export function navigate(
path: string,
callback: Function,
......
......@@ -27,6 +27,7 @@ interface AppUniConfig {
uploadFile: number
downloadFile: number
}
tabBar?: UniApp.UniConfig['tabBar']
}
export function normalizeAppUniConfig(
......@@ -54,6 +55,7 @@ export function normalizeAppUniConfig(
compilerVersion: process.env.UNI_COMPILER_VERSION,
entryPagePath: pagesJson.pages[0].path,
networkTimeout: normalizeNetworkTimeout(manifestJson.networkTimeout),
tabBar: pagesJson.tabBar,
}
// TODO 待支持分包
return JSON.stringify(config)
......
......@@ -19,6 +19,7 @@ export function initPageVm(
pageVm: ComponentPublicInstance,
page: Page.PageInstance['$page']
) {
pageVm.route = page.route
pageVm.$vm = pageVm
pageVm.$page = page
pageVm.$mpType = 'page'
......
......@@ -608,6 +608,7 @@ function initAppVm(appVm2) {
appVm2.$mpType = "app";
}
function initPageVm(pageVm, page) {
pageVm.route = page.route;
pageVm.$vm = pageVm;
pageVm.$page = page;
pageVm.$mpType = "page";
......
......@@ -1378,6 +1378,7 @@ function initAppVm(appVm2) {
appVm2.$mpType = "app";
}
function initPageVm(pageVm, page) {
pageVm.route = page.route;
pageVm.$vm = pageVm;
pageVm.$page = page;
pageVm.$mpType = "page";
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册