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

feat(app): add recovery

上级 b866985e
import { nextTick } from 'vue'
import { import {
ACTION_TYPE_ADD_EVENT, ACTION_TYPE_ADD_EVENT,
ACTION_TYPE_CREATE, ACTION_TYPE_CREATE,
...@@ -25,6 +26,7 @@ import { ...@@ -25,6 +26,7 @@ import {
setActionMinify, setActionMinify,
} from '../../../src/constants' } from '../../../src/constants'
import { decodeActions } from '../../../src/view/framework/dom/decodeActions' import { decodeActions } from '../../../src/view/framework/dom/decodeActions'
describe('dom', () => { describe('dom', () => {
const pageId = 1 const pageId = 1
const root = createPageNode(pageId, { const root = createPageNode(pageId, {
...@@ -198,6 +200,26 @@ describe('dom', () => { ...@@ -198,6 +200,26 @@ describe('dom', () => {
expect(flag & EventModifierFlags.prevent).toBeTruthy() expect(flag & EventModifierFlags.prevent).toBeTruthy()
expect(flag & EventModifierFlags.self).toBeFalsy() 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) { function expectActions(root: UniPageNode) {
......
...@@ -1858,9 +1858,6 @@ var serviceContext = (function (vue) { ...@@ -1858,9 +1858,6 @@ var serviceContext = (function (vue) {
return rootProxy.$page.id; return rootProxy.$page.id;
} }
} }
function getPageById(id) {
return getCurrentPages().find((page) => page.$page.id === id);
}
function getCurrentPage() { function getCurrentPage() {
const pages = getCurrentPages(); const pages = getCurrentPages();
const len = pages.length; const len = pages.length;
...@@ -9667,11 +9664,85 @@ var serviceContext = (function (vue) { ...@@ -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) { function onNodeEvent(nodeId, evt, pageNode) {
pageNode.fireEvent(nodeId, evt); pageNode.fireEvent(nodeId, evt);
} }
function onVdSync(actions, pageId) { function onVdSync(actions, pageId) {
// 从所有pages中获取
const page = getPageById(parseInt(pageId)); const page = getPageById(parseInt(pageId));
if (!page) { if (!page) {
if ((process.env.NODE_ENV !== 'production')) { if ((process.env.NODE_ENV !== 'production')) {
...@@ -9751,76 +9822,6 @@ var serviceContext = (function (vue) { ...@@ -9751,76 +9822,6 @@ var serviceContext = (function (vue) {
const VIEW_WEBVIEW_PATH = '_www/__uniappview.html'; const VIEW_WEBVIEW_PATH = '_www/__uniappview.html';
const WEBVIEW_ID_PREFIX = 'webviewId'; 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) { function initNVue(webviewStyle, routeMeta, path) {
if (path && routeMeta.isNVue) { if (path && routeMeta.isNVue) {
webviewStyle.uniNView = { webviewStyle.uniNView = {
...@@ -10115,6 +10116,35 @@ var serviceContext = (function (vue) { ...@@ -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) { function onWebviewResize(webview) {
const { emit } = UniServiceJSBridge; const { emit } = UniServiceJSBridge;
const onResize = function ({ width, height, }) { const onResize = function ({ width, height, }) {
...@@ -10152,9 +10182,8 @@ var serviceContext = (function (vue) { ...@@ -10152,9 +10182,8 @@ var serviceContext = (function (vue) {
}); });
onWebviewClose(webview); onWebviewClose(webview);
onWebviewResize(webview); onWebviewResize(webview);
// TODO
if (plus.os.name === 'iOS') { if (plus.os.name === 'iOS') {
// !(webview as any).nvue && onWebviewRecovery(webview, routeOptions) onWebviewRecovery(webview);
onWebviewPopGesture(webview); onWebviewPopGesture(webview);
} }
} }
...@@ -10563,11 +10592,19 @@ var serviceContext = (function (vue) { ...@@ -10563,11 +10592,19 @@ var serviceContext = (function (vue) {
vue.queuePostFlushCb(this._update); vue.queuePostFlushCb(this._update);
} }
restore() { restore() {
this.clear();
this.push(this.createAction); this.push(this.createAction);
if (this.scrollAction) { if (this.scrollAction) {
this.push(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); this.push(this.createdAction);
} }
setup() { setup() {
...@@ -10578,7 +10615,6 @@ var serviceContext = (function (vue) { ...@@ -10578,7 +10615,6 @@ var serviceContext = (function (vue) {
if ((process.env.NODE_ENV !== 'production')) { if ((process.env.NODE_ENV !== 'production')) {
console.log(formatLog('PageNode', 'update', updateActions.length, _createActionMap.size)); console.log(formatLog('PageNode', 'update', updateActions.length, _createActionMap.size));
} }
_createActionMap.clear();
// 首次 // 首次
if (!this._created) { if (!this._created) {
this._created = true; this._created = true;
...@@ -10589,9 +10625,13 @@ var serviceContext = (function (vue) { ...@@ -10589,9 +10625,13 @@ var serviceContext = (function (vue) {
updateActions.unshift([ACTION_TYPE_DICT, dicts]); updateActions.unshift([ACTION_TYPE_DICT, dicts]);
} }
this.send(updateActions); 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) { send(action) {
UniServiceJSBridge.publishHandler(VD_SYNC, action, this.pageId); UniServiceJSBridge.publishHandler(VD_SYNC, action, this.pageId);
......
import { getPageById } from '@dcloudio/uni-core' import { getPageById } from '../../page/getCurrentPages'
export function onWebviewInserted(_: unknown, pageId: string) { export function onWebviewInserted(_: unknown, pageId: string) {
const page = getPageById(parseInt(pageId)) const page = getPageById(parseInt(pageId))
......
...@@ -30,8 +30,6 @@ import { ...@@ -30,8 +30,6 @@ import {
ACTION_TYPE_ADD_WXS_EVENT, ACTION_TYPE_ADD_WXS_EVENT,
} from '@dcloudio/uni-shared' } from '@dcloudio/uni-shared'
import { getPageById } from '@dcloudio/uni-core'
import { import {
ACTION_MINIFY, ACTION_MINIFY,
ACTION_TYPE_DICT, ACTION_TYPE_DICT,
...@@ -40,6 +38,7 @@ import { ...@@ -40,6 +38,7 @@ import {
Value, Value,
VD_SYNC, VD_SYNC,
} from '../../../constants' } from '../../../constants'
import { getPageById } from '../page/getCurrentPages'
export default class UniPageNode extends UniNode implements IUniPageNode { export default class UniPageNode extends UniNode implements IUniPageNode {
pageId: number pageId: number
...@@ -225,11 +224,19 @@ export default class UniPageNode extends UniNode implements IUniPageNode { ...@@ -225,11 +224,19 @@ export default class UniPageNode extends UniNode implements IUniPageNode {
queuePostFlushCb(this._update) queuePostFlushCb(this._update)
} }
restore() { restore() {
this.clear()
this.push(this.createAction) this.push(this.createAction)
if (this.scrollAction) { if (this.scrollAction) {
this.push(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) this.push(this.createdAction)
} }
setup() { setup() {
...@@ -247,7 +254,6 @@ export default class UniPageNode extends UniNode implements IUniPageNode { ...@@ -247,7 +254,6 @@ export default class UniPageNode extends UniNode implements IUniPageNode {
) )
) )
} }
_createActionMap.clear()
// 首次 // 首次
if (!this._created) { if (!this._created) {
this._created = true this._created = true
...@@ -258,9 +264,13 @@ export default class UniPageNode extends UniNode implements IUniPageNode { ...@@ -258,9 +264,13 @@ export default class UniPageNode extends UniNode implements IUniPageNode {
updateActions.unshift([ACTION_TYPE_DICT, dicts]) updateActions.unshift([ACTION_TYPE_DICT, dicts])
} }
this.send(updateActions) 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)[]) { send(action: (PageAction | DictAction)[]) {
UniServiceJSBridge.publishHandler(VD_SYNC, action, this.pageId) UniServiceJSBridge.publishHandler(VD_SYNC, action, this.pageId)
......
import { getPageById } from '@dcloudio/uni-core'
import { ACTION_TYPE_EVENT, formatLog } from '@dcloudio/uni-shared' import { ACTION_TYPE_EVENT, formatLog } from '@dcloudio/uni-shared'
import { getPageById } from '../page/getCurrentPages'
import { EventAction, onNodeEvent } from './onNodeEvent' import { EventAction, onNodeEvent } from './onNodeEvent'
import UniPageNode from './Page' import UniPageNode from './Page'
export function onVdSync(actions: EventAction[], pageId: string) { export function onVdSync(actions: EventAction[], pageId: string) {
// 从所有pages中获取
const page = getPageById(parseInt(pageId)) const page = getPageById(parseInt(pageId))
if (!page) { if (!page) {
if (__DEV__) { if (__DEV__) {
......
...@@ -9,6 +9,10 @@ export function addCurrentPage(page: ComponentPublicInstance) { ...@@ -9,6 +9,10 @@ export function addCurrentPage(page: ComponentPublicInstance) {
pages.push(page) pages.push(page)
} }
export function getPageById(id: number) {
return pages.find((page) => page.$page.id === id)
}
export function getAllPages() { export function getAllPages() {
return pages return pages
} }
......
...@@ -9,6 +9,7 @@ import { ...@@ -9,6 +9,7 @@ import {
import { setPullDownRefreshWebview } from '../../../../utils' import { setPullDownRefreshWebview } from '../../../../utils'
import { onWebviewClose } from './close' import { onWebviewClose } from './close'
import { onWebviewPopGesture } from './popGesture' import { onWebviewPopGesture } from './popGesture'
import { onWebviewRecovery } from './recovery'
import { onWebviewResize } from './resize' import { onWebviewResize } from './resize'
const WEBVIEW_LISTENERS = { const WEBVIEW_LISTENERS = {
...@@ -35,9 +36,8 @@ export function initWebviewEvent(webview: PlusWebviewWebviewObject) { ...@@ -35,9 +36,8 @@ export function initWebviewEvent(webview: PlusWebviewWebviewObject) {
onWebviewClose(webview) onWebviewClose(webview)
onWebviewResize(webview) onWebviewResize(webview)
// TODO
if (plus.os.name === 'iOS') { if (plus.os.name === 'iOS') {
// !(webview as any).nvue && onWebviewRecovery(webview, routeOptions) onWebviewRecovery(webview)
onWebviewPopGesture(webview) onWebviewPopGesture(webview)
} }
} }
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)
})
}
...@@ -21,7 +21,7 @@ export function getPageIdByVm(vm: ComponentPublicInstance) { ...@@ -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) return getCurrentPages().find((page) => page.$page.id === id)
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册