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

refactor(v3): webview event

上级 555262a2
...@@ -278,6 +278,15 @@ var serviceContext = (function () { ...@@ -278,6 +278,15 @@ var serviceContext = (function () {
function guid () { function guid () {
return Math.floor(4294967296 * (1 + Math.random())).toString(16).slice(1) return Math.floor(4294967296 * (1 + Math.random())).toString(16).slice(1)
}
function debounce (fn, delay) {
let timeout;
return function () {
clearTimeout(timeout);
const timerFn = () => fn.apply(this, arguments);
timeout = setTimeout(timerFn, delay);
}
} }
const decode = decodeURIComponent; const decode = decodeURIComponent;
...@@ -6409,6 +6418,31 @@ var serviceContext = (function () { ...@@ -6409,6 +6418,31 @@ var serviceContext = (function () {
} }
} }
const REGEX_UPX = /(\d+(\.\d+)?)[r|u]px/g;
function transformCSS (css) {
return css.replace(REGEX_UPX, (a, b) => {
return uni.upx2px(parseInt(b) || 0) + 'px'
})
}
function parseStyleUnit (styles) {
let newStyles = {};
const stylesStr = JSON.stringify(styles);
if (~stylesStr.indexOf('upx') || ~stylesStr.indexOf('rpx')) {
try {
newStyles = JSON.parse(transformCSS(stylesStr));
} catch (e) {
newStyles = styles;
console.error(e);
}
} else {
newStyles = JSON.parse(stylesStr);
}
return newStyles
}
const WEBVIEW_STYLE_BLACKLIST = [ const WEBVIEW_STYLE_BLACKLIST = [
'navigationBarBackgroundColor', 'navigationBarBackgroundColor',
'navigationBarTextStyle', 'navigationBarTextStyle',
...@@ -6430,10 +6464,10 @@ var serviceContext = (function () { ...@@ -6430,10 +6464,10 @@ var serviceContext = (function () {
const webviewStyle = Object.create(null); const webviewStyle = Object.create(null);
// 合并 // 合并
routeOptions.window = Object.assign( routeOptions.window = parseStyleUnit(Object.assign(
JSON.parse(JSON.stringify(__uniConfig.window || {})), JSON.parse(JSON.stringify(__uniConfig.window || {})),
routeOptions.window || {} routeOptions.window || {}
); ));
Object.keys(routeOptions.window).forEach(name => { Object.keys(routeOptions.window).forEach(name => {
if (WEBVIEW_STYLE_BLACKLIST.indexOf(name) === -1) { if (WEBVIEW_STYLE_BLACKLIST.indexOf(name) === -1) {
...@@ -6475,6 +6509,171 @@ var serviceContext = (function () { ...@@ -6475,6 +6509,171 @@ var serviceContext = (function () {
return webviewStyle return webviewStyle
} }
function backbuttonListener () {
uni.navigateBack({
from: 'backbutton'
});
}
function initPopupSubNVue (subNVueWebview, style, maskWebview) {
if (!maskWebview.popupSubNVueWebviews) {
maskWebview.popupSubNVueWebviews = {};
}
maskWebview.popupSubNVueWebviews[subNVueWebview.id] = subNVueWebview;
if (process.env.NODE_ENV !== 'production') {
console.log(
`UNIAPP[webview][${maskWebview.id}]:add.popupSubNVueWebview[${subNVueWebview.id}]`
);
}
const hideSubNVue = function () {
maskWebview.setStyle({
mask: 'none'
});
subNVueWebview.hide('auto');
};
maskWebview.addEventListener('maskClick', hideSubNVue);
let isRemoved = false; // 增加个 remove 标记,防止出错
subNVueWebview.addEventListener('show', () => {
if (!isRemoved) {
plus.key.removeEventListener('backbutton', backbuttonListener);
plus.key.addEventListener('backbutton', hideSubNVue);
isRemoved = true;
}
});
subNVueWebview.addEventListener('hide', () => {
if (isRemoved) {
plus.key.removeEventListener('backbutton', hideSubNVue);
plus.key.addEventListener('backbutton', backbuttonListener);
isRemoved = false;
}
});
subNVueWebview.addEventListener('close', () => {
delete maskWebview.popupSubNVueWebviews[subNVueWebview.id];
if (isRemoved) {
plus.key.removeEventListener('backbutton', hideSubNVue);
plus.key.addEventListener('backbutton', backbuttonListener);
isRemoved = false;
}
});
}
function initNormalSubNVue (subNVueWebview, style, webview) {
webview.append(subNVueWebview);
}
function initSubNVue (subNVue, routeOptions, webview) {
if (!subNVue.path) {
return
}
const style = subNVue.style || {};
const isNavigationBar = subNVue.type === 'navigationBar';
const isPopup = subNVue.type === 'popup';
delete style.type;
if (isPopup && !subNVue.id) {
console.warn('subNVue[' + subNVue.path + '] 尚未配置 id');
}
// TODO lazyload
style.uniNView = {
path: subNVue.path.replace('.nvue', '.js'),
defaultFontSize: __uniConfig.defaultFontSize,
viewport: __uniConfig.viewport
};
const extras = {
__uniapp_host: routeOptions.path,
__uniapp_origin: style.uniNView.path.split('?')[0].replace('.js', ''),
__uniapp_origin_id: webview.id,
__uniapp_origin_type: webview.__uniapp_type
};
let maskWebview;
if (isNavigationBar) {
style.position = 'dock';
style.dock = 'top';
style.top = 0;
style.width = '100%';
style.height = TITLEBAR_HEIGHT + plus.navigator.getStatusbarHeight();
delete style.left;
delete style.right;
delete style.bottom;
delete style.margin;
} else if (isPopup) {
style.position = 'absolute';
console.log(isTabBarPage(routeOptions.path));
if (isTabBarPage(routeOptions.path)) {
maskWebview = tabBar$1;
} else {
maskWebview = webview;
}
extras.__uniapp_mask = style.mask || 'rgba(0,0,0,0.5)';
extras.__uniapp_mask_id = maskWebview.id;
}
if (process.env.NODE_ENV !== 'production') {
console.log(
`UNIAPP[webview][${webview.id}]:create[${subNVue.id}]:${JSON.stringify(style)}`
);
}
const subNVueWebview = plus.webview.create('', subNVue.id, style, extras);
if (isPopup) {
initPopupSubNVue(subNVueWebview, style, maskWebview);
} else {
initNormalSubNVue(subNVueWebview, style, webview);
}
}
function initSubNVues (routeOptions, webview) {
const subNVues = routeOptions.window.subNVues;
if (!subNVues || !subNVues.length) {
return
}
subNVues.forEach(subNVue => {
initSubNVue(subNVue, routeOptions, webview);
});
}
function onWebviewClose (webview) {
webview.addEventListener('close', () => {
if (webview.popupSubNVueWebviews) { // 移除所有 popupSubNVueWebview
Object.keys(webview.popupSubNVueWebviews).forEach(id => {
if (process.env.NODE_ENV !== 'production') {
console.log(
`UNIAPP[webview][${webview.id}]:popupSubNVueWebview[${id}].close`
);
}
webview.popupSubNVueWebviews[id].close('none');
});
}
});
}
function onWebviewResize (webview) {
const onResize = function ({
width,
height
}) {
const landscape = Math.abs(plus.navigator.getOrientation()) === 90;
const res = {
deviceOrientation: landscape ? 'landscape' : 'portrait',
size: {
windowWidth: Math.ceil(width),
windowHeight: Math.ceil(height)
}
};
publish('onViewDidResize', res); // API
UniServiceJSBridge.emit('onResize', res, parseInt(webview.id)); // Page lifecycle
};
webview.addEventListener('resize', debounce(onResize, 50));
}
const PAGE_CREATE = 2; const PAGE_CREATE = 2;
const MOUNTED_DATA = 4; const MOUNTED_DATA = 4;
const UPDATED_DATA = 6; const UPDATED_DATA = 6;
...@@ -6489,6 +6688,41 @@ var serviceContext = (function () { ...@@ -6489,6 +6688,41 @@ var serviceContext = (function () {
const INVOKE_API = 'invokeApi'; const INVOKE_API = 'invokeApi';
const WEB_INVOKE_APPSERVICE$1 = 'WEB_INVOKE_APPSERVICE'; const WEB_INVOKE_APPSERVICE$1 = 'WEB_INVOKE_APPSERVICE';
function onWebviewRecovery (webview, routeOptions) {
const {
subscribe,
unsubscribe
} = UniServiceJSBridge;
const id = webview.id;
const onWebviewRecoveryReady = function (data, pageId) {
if (id !== pageId) {
return
}
unsubscribe(WEBVIEW_READY, onWebviewRecoveryReady);
if (process.env.NODE_ENV !== 'production') {
console.log(`UNIAPP[webview][${this.id}]:onWebviewRecoveryReady ready`);
}
// 恢复目标页面
pageId = parseInt(pageId);
const page = getCurrentPages(true).find(page => page.$page.id === pageId);
if (!page) {
return console.error(`Page[${pageId}] not found`)
}
page.$vm._$vd.restore();
};
webview.addEventListener('recovery', e => {
if (process.env.NODE_ENV !== 'production') {
console.log(`UNIAPP[webview][${this.id}].recovery.reload:` + JSON.stringify({
path: routeOptions.path,
webviewId: id
}));
}
subscribe(WEBVIEW_READY, onWebviewRecoveryReady);
});
}
let preloadWebview; let preloadWebview;
let id = 2; let id = 2;
...@@ -6526,59 +6760,6 @@ var serviceContext = (function () { ...@@ -6526,59 +6760,6 @@ var serviceContext = (function () {
return webview return webview
} }
function onWebviewResize (webview) {
webview.addEventListener('resize', ({
width,
height
}) => {
const landscape = Math.abs(plus.navigator.getOrientation()) === 90;
const res = {
deviceOrientation: landscape ? 'landscape' : 'portrait',
size: {
windowWidth: Math.ceil(width),
windowHeight: Math.ceil(height)
}
};
publish('onViewDidResize', res); // API
UniServiceJSBridge.emit('onResize', res, parseInt(webview.id)); // Page lifecycle
});
}
function onWebviewRecovery (webview, routeOptions) {
const {
subscribe,
unsubscribe
} = UniServiceJSBridge;
const id = webview.id;
const onWebviewRecoveryReady = function (data, pageId) {
if (id !== pageId) {
return
}
unsubscribe(WEBVIEW_READY, onWebviewRecoveryReady);
if (process.env.NODE_ENV !== 'production') {
console.log(`UNIAPP[webview][${this.id}]:onWebviewRecoveryReady ready`);
}
// 恢复目标页面
pageId = parseInt(pageId);
const page = getCurrentPages(true).find(page => page.$page.id === pageId);
if (!page) {
return console.error(`Page[${pageId}] not found`)
}
page.$vm._$vd.restore();
};
webview.addEventListener('recovery', e => {
if (process.env.NODE_ENV !== 'production') {
console.log(`UNIAPP[webview][${this.id}].recovery.reload:` + JSON.stringify({
path: routeOptions.path,
webviewId: id
}));
}
subscribe(WEBVIEW_READY, onWebviewRecoveryReady);
});
}
function initWebview (webview, routeOptions) { function initWebview (webview, routeOptions) {
// 首页或非 nvue 页面 // 首页或非 nvue 页面
if (webview.id === '1' || !routeOptions.meta.isNVue) { if (webview.id === '1' || !routeOptions.meta.isNVue) {
...@@ -6599,20 +6780,43 @@ var serviceContext = (function () { ...@@ -6599,20 +6780,43 @@ var serviceContext = (function () {
emit emit
} = UniServiceJSBridge; } = UniServiceJSBridge;
// TODO subNVues initSubNVues(routeOptions, webview);
// TODO 优化相关依赖性
// webview.addEventListener('popGesture', e => {
// if (e.type === 'start') {
// // 开始拖拽,还原状态栏前景色
// this.restoreStatusBarStyle()
// } else if (e.type === 'end' && !e.result) {
// // 拖拽未完成,设置为当前状态栏前景色
// this.setStatusBarStyle()
// } else if (e.type === 'end' && e.result) {
// removeWebview(this.id)
// const lastWebview = getLastWebview()
// if (lastWebview) {
// publish('onAppRoute', {
// path: lastWebview.page.replace('.html', ''),
// query: {},
// openType: 'navigateBack',
// webviewId: lastWebview.id
// })
// }
// }
// })
Object.keys(WEBVIEW_LISTENERS).forEach(name => { Object.keys(WEBVIEW_LISTENERS).forEach(name => {
webview.addEventListener(name, (e) => { webview.addEventListener(name, (e) => {
emit(WEBVIEW_LISTENERS[name], e, parseInt(webview.id)); emit(WEBVIEW_LISTENERS[name], e, parseInt(webview.id));
}); });
}); });
onWebviewClose(webview);
onWebviewResize(webview); onWebviewResize(webview);
if (plus.os.name === 'iOS' && webview.nvue) { if (plus.os.name === 'iOS' && webview.nvue) {
onWebviewRecovery(webview, routeOptions); onWebviewRecovery(webview, routeOptions);
} }
// TODO 应该结束之前未完成的下拉刷新
on(webview.id + '.startPullDownRefresh', () => { on(webview.id + '.startPullDownRefresh', () => {
webview.beginPullToRefresh(); webview.beginPullToRefresh();
}); });
...@@ -9724,12 +9928,11 @@ var serviceContext = (function () { ...@@ -9724,12 +9928,11 @@ var serviceContext = (function () {
} }
function initGlobalListeners () { function initGlobalListeners () {
const emit = UniServiceJSBridge.emit; const emit = UniServiceJSBridge.emit;
plus.key.addEventListener('backbutton', () => { // splashclosed 时开始监听 backbutton
uni.navigateBack({ plus.globalEvent.addEventListener('splashclosed', () => {
from: 'backbutton' plus.key.addEventListener('backbutton', backbuttonListener);
});
}); });
plus.globalEvent.addEventListener('pause', () => { plus.globalEvent.addEventListener('pause', () => {
...@@ -9827,7 +10030,7 @@ var serviceContext = (function () { ...@@ -9827,7 +10030,7 @@ var serviceContext = (function () {
initAppLaunch(appVm); initAppLaunch(appVm);
__uniConfig.ready = true; __uniConfig.ready = true;
process.env.NODE_ENV !== 'production' && perf('registerApp'); process.env.NODE_ENV !== 'production' && perf('registerApp');
} }
......
...@@ -28,7 +28,7 @@ import { ...@@ -28,7 +28,7 @@ import {
import { import {
perf perf
} from './perf' } from './perf'
import { import {
backbuttonListener backbuttonListener
...@@ -41,9 +41,12 @@ export function getApp () { ...@@ -41,9 +41,12 @@ export function getApp () {
} }
function initGlobalListeners () { function initGlobalListeners () {
const emit = UniServiceJSBridge.emit const emit = UniServiceJSBridge.emit
plus.key.addEventListener('backbutton', backbuttonListener) // splashclosed 时开始监听 backbutton
plus.globalEvent.addEventListener('splashclosed', () => {
plus.key.addEventListener('backbutton', backbuttonListener)
})
plus.globalEvent.addEventListener('pause', () => { plus.globalEvent.addEventListener('pause', () => {
emit('onAppEnterBackground') emit('onAppEnterBackground')
...@@ -140,7 +143,7 @@ export function registerApp (appVm) { ...@@ -140,7 +143,7 @@ export function registerApp (appVm) {
initAppLaunch(appVm) initAppLaunch(appVm)
__uniConfig.ready = true __uniConfig.ready = true
process.env.NODE_ENV !== 'production' && perf('registerApp') process.env.NODE_ENV !== 'production' && perf('registerApp')
} }
import { import {
parseWebviewStyle parseWebviewStyle
} from './parser/webview-style-parser' } from './parser/webview-style-parser'
import {
initSubNVues
} from './parser/sub-nvue-parser'
import { import {
publish initSubNVues
} from '../../bridge' } from './parser/sub-nvue-parser'
import { import {
VIEW_WEBVIEW_PATH VIEW_WEBVIEW_PATH
} from '../../constants' } from '../../constants'
import { import {
WEBVIEW_READY onWebviewClose
} from '../../../constants' } from './on-webview-close'
import {
onWebviewResize
} from './on-webview-resize'
import {
onWebviewRecovery
} from './on-webview-recovery'
export let preloadWebview export let preloadWebview
...@@ -55,59 +59,6 @@ export function createWebview (path, routeOptions) { ...@@ -55,59 +59,6 @@ export function createWebview (path, routeOptions) {
return webview return webview
} }
function onWebviewResize (webview) {
webview.addEventListener('resize', ({
width,
height
}) => {
const landscape = Math.abs(plus.navigator.getOrientation()) === 90
const res = {
deviceOrientation: landscape ? 'landscape' : 'portrait',
size: {
windowWidth: Math.ceil(width),
windowHeight: Math.ceil(height)
}
}
publish('onViewDidResize', res) // API
UniServiceJSBridge.emit('onResize', res, parseInt(webview.id)) // Page lifecycle
})
}
function onWebviewRecovery (webview, routeOptions) {
const {
subscribe,
unsubscribe
} = UniServiceJSBridge
const id = webview.id
const onWebviewRecoveryReady = function (data, pageId) {
if (id !== pageId) {
return
}
unsubscribe(WEBVIEW_READY, onWebviewRecoveryReady)
if (process.env.NODE_ENV !== 'production') {
console.log(`UNIAPP[webview][${this.id}]:onWebviewRecoveryReady ready`)
}
// 恢复目标页面
pageId = parseInt(pageId)
const page = getCurrentPages(true).find(page => page.$page.id === pageId)
if (!page) {
return console.error(`Page[${pageId}] not found`)
}
page.$vm._$vd.restore()
}
webview.addEventListener('recovery', e => {
if (process.env.NODE_ENV !== 'production') {
console.log(`UNIAPP[webview][${this.id}].recovery.reload:` + JSON.stringify({
path: routeOptions.path,
webviewId: id
}))
}
subscribe(WEBVIEW_READY, onWebviewRecoveryReady)
})
}
export function initWebview (webview, routeOptions) { export function initWebview (webview, routeOptions) {
// 首页或非 nvue 页面 // 首页或非 nvue 页面
if (webview.id === '1' || !routeOptions.meta.isNVue) { if (webview.id === '1' || !routeOptions.meta.isNVue) {
...@@ -127,43 +78,30 @@ export function initWebview (webview, routeOptions) { ...@@ -127,43 +78,30 @@ export function initWebview (webview, routeOptions) {
on, on,
emit emit
} = UniServiceJSBridge } = UniServiceJSBridge
initSubNVues(routeOptions, webview) initSubNVues(routeOptions, webview)
// TODO 优化相关依赖性 // TODO 优化相关依赖性
// webview.addEventListener('popGesture', e => { // webview.addEventListener('popGesture', e => {
// if (e.type === 'start') { // if (e.type === 'start') {
// // 开始拖拽,还原状态栏前景色 // // 开始拖拽,还原状态栏前景色
// this.restoreStatusBarStyle() // this.restoreStatusBarStyle()
// } else if (e.type === 'end' && !e.result) { // } else if (e.type === 'end' && !e.result) {
// // 拖拽未完成,设置为当前状态栏前景色 // // 拖拽未完成,设置为当前状态栏前景色
// this.setStatusBarStyle() // this.setStatusBarStyle()
// } else if (e.type === 'end' && e.result) { // } else if (e.type === 'end' && e.result) {
// removeWebview(this.id) // removeWebview(this.id)
// const lastWebview = getLastWebview() // const lastWebview = getLastWebview()
// if (lastWebview) { // if (lastWebview) {
// publish('onAppRoute', { // publish('onAppRoute', {
// path: lastWebview.page.replace('.html', ''), // path: lastWebview.page.replace('.html', ''),
// query: {}, // query: {},
// openType: 'navigateBack', // openType: 'navigateBack',
// webviewId: lastWebview.id // webviewId: lastWebview.id
// }) // })
// } // }
// } // }
// }) // })
webview.addEventListener('close', () => {
if (webview.popupSubNVueWebviews) { // 移除所有 popupSubNVueWebview
Object.keys(webview.popupSubNVueWebviews).forEach(id => {
if (process.env.NODE_ENV !== 'production') {
console.log(
`UNIAPP[webview][${webview.id}]:popupSubNVueWebview[${id}].close`
)
}
webview.popupSubNVueWebviews[id].close('none')
})
}
})
Object.keys(WEBVIEW_LISTENERS).forEach(name => { Object.keys(WEBVIEW_LISTENERS).forEach(name => {
webview.addEventListener(name, (e) => { webview.addEventListener(name, (e) => {
...@@ -171,6 +109,7 @@ export function initWebview (webview, routeOptions) { ...@@ -171,6 +109,7 @@ export function initWebview (webview, routeOptions) {
}) })
}) })
onWebviewClose(webview)
onWebviewResize(webview) onWebviewResize(webview)
if (plus.os.name === 'iOS' && webview.nvue) { if (plus.os.name === 'iOS' && webview.nvue) {
......
export function onWebviewClose (webview) {
webview.addEventListener('close', () => {
if (webview.popupSubNVueWebviews) { // 移除所有 popupSubNVueWebview
Object.keys(webview.popupSubNVueWebviews).forEach(id => {
if (process.env.NODE_ENV !== 'production') {
console.log(
`UNIAPP[webview][${webview.id}]:popupSubNVueWebview[${id}].close`
)
}
webview.popupSubNVueWebviews[id].close('none')
})
}
})
}
import {
WEBVIEW_READY
} from '../../../constants'
export function onWebviewRecovery (webview, routeOptions) {
const {
subscribe,
unsubscribe
} = UniServiceJSBridge
const id = webview.id
const onWebviewRecoveryReady = function (data, pageId) {
if (id !== pageId) {
return
}
unsubscribe(WEBVIEW_READY, onWebviewRecoveryReady)
if (process.env.NODE_ENV !== 'production') {
console.log(`UNIAPP[webview][${this.id}]:onWebviewRecoveryReady ready`)
}
// 恢复目标页面
pageId = parseInt(pageId)
const page = getCurrentPages(true).find(page => page.$page.id === pageId)
if (!page) {
return console.error(`Page[${pageId}] not found`)
}
page.$vm._$vd.restore()
}
webview.addEventListener('recovery', e => {
if (process.env.NODE_ENV !== 'production') {
console.log(`UNIAPP[webview][${this.id}].recovery.reload:` + JSON.stringify({
path: routeOptions.path,
webviewId: id
}))
}
subscribe(WEBVIEW_READY, onWebviewRecoveryReady)
})
}
import {
debounce
} from 'uni-shared'
import {
publish
} from '../../bridge'
export function onWebviewResize (webview) {
const onResize = function ({
width,
height
}) {
const landscape = Math.abs(plus.navigator.getOrientation()) === 90
const res = {
deviceOrientation: landscape ? 'landscape' : 'portrait',
size: {
windowWidth: Math.ceil(width),
windowHeight: Math.ceil(height)
}
}
publish('onViewDidResize', res) // API
UniServiceJSBridge.emit('onResize', res, parseInt(webview.id)) // Page lifecycle
}
webview.addEventListener('resize', debounce(onResize, 50))
}
...@@ -78,4 +78,13 @@ export function updateElementStyle (element, styles) { ...@@ -78,4 +78,13 @@ export function updateElementStyle (element, styles) {
export function guid () { export function guid () {
return Math.floor(4294967296 * (1 + Math.random())).toString(16).slice(1) return Math.floor(4294967296 * (1 + Math.random())).toString(16).slice(1)
}
export function debounce (fn, delay) {
let timeout
return function () {
clearTimeout(timeout)
const timerFn = () => fn.apply(this, arguments)
timeout = setTimeout(timerFn, delay)
}
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册