diff --git a/packages/uni-app-plus/__tests__/service/dom/dom.spec.ts b/packages/uni-app-plus/__tests__/service/dom/dom.spec.ts index 3111b2c6988b6b5376088f91dd4e12c1f2aa5276..0752a482937aa7e0fd9a3bda04eb493fea31c39d 100644 --- a/packages/uni-app-plus/__tests__/service/dom/dom.spec.ts +++ b/packages/uni-app-plus/__tests__/service/dom/dom.spec.ts @@ -1,3 +1,4 @@ +import { nextTick } from 'vue' import { ACTION_TYPE_ADD_EVENT, ACTION_TYPE_CREATE, @@ -25,6 +26,7 @@ import { setActionMinify, } from '../../../src/constants' import { decodeActions } from '../../../src/view/framework/dom/decodeActions' + describe('dom', () => { const pageId = 1 const root = createPageNode(pageId, { @@ -198,6 +200,26 @@ describe('dom', () => { expect(flag & EventModifierFlags.prevent).toBeTruthy() expect(flag & EventModifierFlags.self).toBeFalsy() }) + test('restore', (done) => { + root.childNodes = [] + root.clear() + const viewElem = createElement('view', { pageNode: root }) + viewElem.setAttribute('id', 'view') + root.appendChild(viewElem) + viewElem.setAttribute('hidden', true) + + const textNode = createTextNode('hello', { pageNode: root }) + root.appendChild(textNode) + const clickFn1 = withModifiers(() => {}, [ + 'stop', + 'prevent', + ]) as unknown as UniEventListener + textNode.addEventListener('click', clickFn1, { capture: true }) + nextTick(() => { + root.restore() + nextTick(done) + }) + }) }) function expectActions(root: UniPageNode) { diff --git a/packages/uni-app-plus/dist/uni-app-service.es.js b/packages/uni-app-plus/dist/uni-app-service.es.js index 8a9ff7936dab27b606479c61ab9c914237a2c058..ee79352487be1a603d6b47264773a23aa4cc7315 100644 --- a/packages/uni-app-plus/dist/uni-app-service.es.js +++ b/packages/uni-app-plus/dist/uni-app-service.es.js @@ -1858,9 +1858,6 @@ var serviceContext = (function (vue) { return rootProxy.$page.id; } } - function getPageById(id) { - return getCurrentPages().find((page) => page.$page.id === id); - } function getCurrentPage() { const pages = getCurrentPages(); const len = pages.length; @@ -9667,11 +9664,85 @@ var serviceContext = (function (vue) { }); } + let vueApp; + function getVueApp() { + return vueApp; + } + function initVueApp(appVm) { + const appContext = appVm.$.appContext; + vueApp = extend(appContext.app, { + mountPage(pageComponent, pageProps, pageContainer) { + const vnode = vue.createVNode(pageComponent, pageProps); + // store app context on the root VNode. + // this will be set on the root instance on initial mount. + vnode.appContext = appContext; + vnode.__page_container__ = pageContainer; + vue.render(vnode, pageContainer); + const publicThis = vnode.component.proxy; + publicThis.__page_container__ = pageContainer; + return publicThis; + }, + unmountPage: (pageInstance) => { + const { __page_container__ } = pageInstance; + if (__page_container__) { + __page_container__.isUnmounted = true; + vue.render(null, __page_container__); + } + }, + }); + } + + const pages = []; + function addCurrentPage(page) { + pages.push(page); + } + function getPageById(id) { + return pages.find((page) => page.$page.id === id); + } + function getAllPages() { + return pages; + } + function getCurrentPages$1() { + const curPages = []; + pages.forEach((page) => { + if (page.__isTabBar) { + if (page.$.__isActive) { + curPages.push(page); + } + } + else { + curPages.push(page); + } + }); + return curPages; + } + function removeCurrentPage() { + const page = getCurrentPage(); + if (!page) { + return; + } + removePage(page); + } + function removePage(curPage) { + const index = pages.findIndex((page) => page === curPage); + if (index === -1) { + return; + } + if (!curPage.$page.meta.isNVue) { + getVueApp().unmountPage(curPage); + } + pages.splice(index, 1); + if ((process.env.NODE_ENV !== 'production')) { + console.log(formatLog('removePage', curPage.$page)); + } + } + function onNodeEvent(nodeId, evt, pageNode) { pageNode.fireEvent(nodeId, evt); } function onVdSync(actions, pageId) { + // 从所有pages中获取 const page = getPageById(parseInt(pageId)); if (!page) { if ((process.env.NODE_ENV !== 'production')) { @@ -9751,76 +9822,6 @@ var serviceContext = (function (vue) { const VIEW_WEBVIEW_PATH = '_www/__uniappview.html'; const WEBVIEW_ID_PREFIX = 'webviewId'; - let vueApp; - function getVueApp() { - return vueApp; - } - function initVueApp(appVm) { - const appContext = appVm.$.appContext; - vueApp = extend(appContext.app, { - mountPage(pageComponent, pageProps, pageContainer) { - const vnode = vue.createVNode(pageComponent, pageProps); - // store app context on the root VNode. - // this will be set on the root instance on initial mount. - vnode.appContext = appContext; - vnode.__page_container__ = pageContainer; - vue.render(vnode, pageContainer); - const publicThis = vnode.component.proxy; - publicThis.__page_container__ = pageContainer; - return publicThis; - }, - unmountPage: (pageInstance) => { - const { __page_container__ } = pageInstance; - if (__page_container__) { - __page_container__.isUnmounted = true; - vue.render(null, __page_container__); - } - }, - }); - } - - const pages = []; - function addCurrentPage(page) { - pages.push(page); - } - function getAllPages() { - return pages; - } - function getCurrentPages$1() { - const curPages = []; - pages.forEach((page) => { - if (page.__isTabBar) { - if (page.$.__isActive) { - curPages.push(page); - } - } - else { - curPages.push(page); - } - }); - return curPages; - } - function removeCurrentPage() { - const page = getCurrentPage(); - if (!page) { - return; - } - removePage(page); - } - function removePage(curPage) { - const index = pages.findIndex((page) => page === curPage); - if (index === -1) { - return; - } - if (!curPage.$page.meta.isNVue) { - getVueApp().unmountPage(curPage); - } - pages.splice(index, 1); - if ((process.env.NODE_ENV !== 'production')) { - console.log(formatLog('removePage', curPage.$page)); - } - } - function initNVue(webviewStyle, routeMeta, path) { if (path && routeMeta.isNVue) { webviewStyle.uniNView = { @@ -10115,6 +10116,35 @@ var serviceContext = (function (vue) { }); } + function onWebviewRecovery(webview) { + if (webview.nvue) { + return; + } + const webviewId = webview.id; + const { subscribe, unsubscribe } = UniServiceJSBridge; + const onWebviewRecoveryReady = (_, pageId) => { + if (webviewId !== pageId) { + return; + } + unsubscribe(ON_WEBVIEW_READY, onWebviewRecoveryReady); + if ((process.env.NODE_ENV !== 'production')) { + console.log(formatLog(`Recovery`, webviewId, 'ready')); + } + const page = getPageById(parseInt(pageId)); + if (page) { + const pageNode = page.__page_container__; + pageNode.restore(); + } + }; + // @ts-expect-error + webview.addEventListener('recovery', () => { + if ((process.env.NODE_ENV !== 'production')) { + console.log(formatLog('Recovery', webview.id)); + } + subscribe(ON_WEBVIEW_READY, onWebviewRecoveryReady); + }); + } + function onWebviewResize(webview) { const { emit } = UniServiceJSBridge; const onResize = function ({ width, height, }) { @@ -10152,9 +10182,8 @@ var serviceContext = (function (vue) { }); onWebviewClose(webview); onWebviewResize(webview); - // TODO if (plus.os.name === 'iOS') { - // !(webview as any).nvue && onWebviewRecovery(webview, routeOptions) + onWebviewRecovery(webview); onWebviewPopGesture(webview); } } @@ -10563,11 +10592,19 @@ var serviceContext = (function (vue) { vue.queuePostFlushCb(this._update); } restore() { + this.clear(); this.push(this.createAction); if (this.scrollAction) { this.push(this.scrollAction); } - // TODO restore children + const restoreNode = (node) => { + this.onCreate(node, node.nodeName); + this.onInsertBefore(node.parentNode, node, null); + node.childNodes.forEach((childNode) => { + restoreNode(childNode); + }); + }; + this.childNodes.forEach((childNode) => restoreNode(childNode)); this.push(this.createdAction); } setup() { @@ -10578,7 +10615,6 @@ var serviceContext = (function (vue) { if ((process.env.NODE_ENV !== 'production')) { console.log(formatLog('PageNode', 'update', updateActions.length, _createActionMap.size)); } - _createActionMap.clear(); // 首次 if (!this._created) { this._created = true; @@ -10589,9 +10625,13 @@ var serviceContext = (function (vue) { updateActions.unshift([ACTION_TYPE_DICT, dicts]); } this.send(updateActions); - dicts.length = 0; - updateActions.length = 0; } + this.clear(); + } + clear() { + this.dicts.length = 0; + this.updateActions.length = 0; + this._createActionMap.clear(); } send(action) { UniServiceJSBridge.publishHandler(VD_SYNC, action, this.pageId); diff --git a/packages/uni-app-plus/src/service/framework/app/subscriber/webviewLifecycle.ts b/packages/uni-app-plus/src/service/framework/app/subscriber/webviewLifecycle.ts index a83ded3ac6958fe82dd184fea6d9f156ff54a1a6..6dcd86f3fe07f52de779186fd178c6d804fd87e2 100644 --- a/packages/uni-app-plus/src/service/framework/app/subscriber/webviewLifecycle.ts +++ b/packages/uni-app-plus/src/service/framework/app/subscriber/webviewLifecycle.ts @@ -1,4 +1,4 @@ -import { getPageById } from '@dcloudio/uni-core' +import { getPageById } from '../../page/getCurrentPages' export function onWebviewInserted(_: unknown, pageId: string) { const page = getPageById(parseInt(pageId)) diff --git a/packages/uni-app-plus/src/service/framework/dom/Page.ts b/packages/uni-app-plus/src/service/framework/dom/Page.ts index fc33ddb059c03524315915ceb5898a664d8a1bb8..c13e29f60b779340f3be9e623ba42ea84ae0944d 100644 --- a/packages/uni-app-plus/src/service/framework/dom/Page.ts +++ b/packages/uni-app-plus/src/service/framework/dom/Page.ts @@ -30,8 +30,6 @@ import { ACTION_TYPE_ADD_WXS_EVENT, } from '@dcloudio/uni-shared' -import { getPageById } from '@dcloudio/uni-core' - import { ACTION_MINIFY, ACTION_TYPE_DICT, @@ -40,6 +38,7 @@ import { Value, VD_SYNC, } from '../../../constants' +import { getPageById } from '../page/getCurrentPages' export default class UniPageNode extends UniNode implements IUniPageNode { pageId: number @@ -225,11 +224,19 @@ export default class UniPageNode extends UniNode implements IUniPageNode { queuePostFlushCb(this._update) } restore() { + this.clear() this.push(this.createAction) if (this.scrollAction) { this.push(this.scrollAction) } - // TODO restore children + const restoreNode = (node: UniNode) => { + this.onCreate(node, node.nodeName) + this.onInsertBefore(node.parentNode!, node, null) + node.childNodes.forEach((childNode) => { + restoreNode(childNode) + }) + } + this.childNodes.forEach((childNode) => restoreNode(childNode)) this.push(this.createdAction) } setup() { @@ -247,7 +254,6 @@ export default class UniPageNode extends UniNode implements IUniPageNode { ) ) } - _createActionMap.clear() // 首次 if (!this._created) { this._created = true @@ -258,9 +264,13 @@ export default class UniPageNode extends UniNode implements IUniPageNode { updateActions.unshift([ACTION_TYPE_DICT, dicts]) } this.send(updateActions) - dicts.length = 0 - updateActions.length = 0 } + this.clear() + } + clear() { + this.dicts.length = 0 + this.updateActions.length = 0 + this._createActionMap.clear() } send(action: (PageAction | DictAction)[]) { UniServiceJSBridge.publishHandler(VD_SYNC, action, this.pageId) diff --git a/packages/uni-app-plus/src/service/framework/dom/index.ts b/packages/uni-app-plus/src/service/framework/dom/index.ts index 12f77155633f0b43e872a98582dffb29e5d165aa..3022da7b6f1d730e205c1da134e76066c7cd7597 100644 --- a/packages/uni-app-plus/src/service/framework/dom/index.ts +++ b/packages/uni-app-plus/src/service/framework/dom/index.ts @@ -1,9 +1,10 @@ -import { getPageById } from '@dcloudio/uni-core' import { ACTION_TYPE_EVENT, formatLog } from '@dcloudio/uni-shared' +import { getPageById } from '../page/getCurrentPages' import { EventAction, onNodeEvent } from './onNodeEvent' import UniPageNode from './Page' export function onVdSync(actions: EventAction[], pageId: string) { + // 从所有pages中获取 const page = getPageById(parseInt(pageId)) if (!page) { if (__DEV__) { diff --git a/packages/uni-app-plus/src/service/framework/page/getCurrentPages.ts b/packages/uni-app-plus/src/service/framework/page/getCurrentPages.ts index 947da9357a5a338c307844a23f5f933c4274dffd..0b5b4e7990fac196a5b3450aea497367bc901119 100644 --- a/packages/uni-app-plus/src/service/framework/page/getCurrentPages.ts +++ b/packages/uni-app-plus/src/service/framework/page/getCurrentPages.ts @@ -9,6 +9,10 @@ export function addCurrentPage(page: ComponentPublicInstance) { pages.push(page) } +export function getPageById(id: number) { + return pages.find((page) => page.$page.id === id) +} + export function getAllPages() { return pages } diff --git a/packages/uni-app-plus/src/service/framework/webview/init/event/index.ts b/packages/uni-app-plus/src/service/framework/webview/init/event/index.ts index c44af8d57f662f76669ea6e55944e1fffb20b86e..953ab3997230eb647e794eb95b6222f6c74fcb59 100644 --- a/packages/uni-app-plus/src/service/framework/webview/init/event/index.ts +++ b/packages/uni-app-plus/src/service/framework/webview/init/event/index.ts @@ -9,6 +9,7 @@ import { import { setPullDownRefreshWebview } from '../../../../utils' import { onWebviewClose } from './close' import { onWebviewPopGesture } from './popGesture' +import { onWebviewRecovery } from './recovery' import { onWebviewResize } from './resize' const WEBVIEW_LISTENERS = { @@ -35,9 +36,8 @@ export function initWebviewEvent(webview: PlusWebviewWebviewObject) { onWebviewClose(webview) onWebviewResize(webview) - // TODO if (plus.os.name === 'iOS') { - // !(webview as any).nvue && onWebviewRecovery(webview, routeOptions) + onWebviewRecovery(webview) onWebviewPopGesture(webview) } } diff --git a/packages/uni-app-plus/src/service/framework/webview/init/event/recovery.ts b/packages/uni-app-plus/src/service/framework/webview/init/event/recovery.ts new file mode 100644 index 0000000000000000000000000000000000000000..6628942a4f29ffb743f073580dff7421cf267d34 --- /dev/null +++ b/packages/uni-app-plus/src/service/framework/webview/init/event/recovery.ts @@ -0,0 +1,34 @@ +import { formatLog } from '@dcloudio/uni-shared' +import { ON_WEBVIEW_READY } from '../../../../../constants' +import UniPageNode from '../../../dom/Page' +import { getPageById } from '../../../page/getCurrentPages' + +export function onWebviewRecovery(webview: PlusWebviewWebviewObject) { + if ((webview as any).nvue) { + return + } + const webviewId = webview.id + const { subscribe, unsubscribe } = UniServiceJSBridge + const onWebviewRecoveryReady = (_: unknown, pageId: string) => { + if (webviewId !== pageId) { + return + } + unsubscribe(ON_WEBVIEW_READY, onWebviewRecoveryReady) + if (__DEV__) { + console.log(formatLog(`Recovery`, webviewId, 'ready')) + } + const page = getPageById(parseInt(pageId)) + if (page) { + const pageNode = (page as any).__page_container__ as UniPageNode + pageNode.restore() + } + } + + // @ts-expect-error + webview.addEventListener('recovery', () => { + if (__DEV__) { + console.log(formatLog('Recovery', webview.id)) + } + subscribe(ON_WEBVIEW_READY, onWebviewRecoveryReady) + }) +} diff --git a/packages/uni-core/src/helpers/page.ts b/packages/uni-core/src/helpers/page.ts index 60afa2072cec043f4c627acc1b3d406ac6124ca2..0765741f64f3d71e898bad99492266857c968e12 100644 --- a/packages/uni-core/src/helpers/page.ts +++ b/packages/uni-core/src/helpers/page.ts @@ -21,7 +21,7 @@ export function getPageIdByVm(vm: ComponentPublicInstance) { } } -export function getPageById(id: number) { +function getPageById(id: number) { return getCurrentPages().find((page) => page.$page.id === id) }