提交 54e84b3b 编写于 作者: Q qiang

feat(App): subNVue

上级 afd03cf1
......@@ -8704,6 +8704,7 @@ var serviceContext = (function (vue) {
});
const VD_SYNC = 'vdSync';
const APP_SERVICE_ID = '__uniapp__service';
const ON_WEBVIEW_READY = 'onWebviewReady';
const PAGE_SCROLL_TO = 'pageScrollTo';
const LOAD_FONT_FACE = 'loadFontFace';
......@@ -8863,6 +8864,94 @@ var serviceContext = (function (vue) {
resolve();
}, HideTabBarRedDotProtocol, HideTabBarRedDotOptions);
const EVENT_TYPE_NAME = 'UniAppSubNVue';
class SubNvue {
constructor(id, isSub) {
this.callbacks = [];
const webview = (this.webview = plus.webview.getWebviewById(id));
this.isSub = isSub || false;
if (webview.__uniapp_mask_id) {
const maskWebview = (this.maskWebview =
webview.__uniapp_mask_id === '0'
? {
setStyle({ mask }) {
requireNativePlugin('uni-tabview').setMask({
color: mask,
});
},
}
: plus.webview.getWebviewById(webview.__uniapp_mask_id));
const closeMask = function () {
maskWebview.setStyle({
mask: 'none',
});
};
webview.addEventListener('hide', closeMask);
webview.addEventListener('close', closeMask);
}
}
show(...args) {
if (this.maskWebview) {
const maskColor = this.webview.__uniapp_mask;
this.maskWebview.setStyle({
mask: maskColor,
});
}
this.webview.show(...args);
}
hide(...args) {
this.webview.hide(...args);
}
setStyle(style) {
this.webview.setStyle(style);
}
initMessage() {
if (this.messageReady) {
return;
}
this.messageReady = true;
const listener = (event) => {
if (event.data && event.data.type === EVENT_TYPE_NAME) {
const target = event.data.target;
if (target.id === this.webview.id && target.isSub === this.isSub) {
this.callbacks.forEach((callback) => {
callback({
origin: this.webview.__uniapp_host,
data: event.data.data,
});
});
}
}
};
const globalEvent = requireNativePlugin('globalEvent');
globalEvent.addEventListener('plusMessage', listener);
this.webview.addEventListener('close', () => {
// TODO 暂时仅清空回调
this.callbacks.length = 0;
// globalEvent.removeEventListener('plusMessage', listener)
});
}
postMessage(data) {
const webviewExt = plus.webview;
webviewExt.postMessageToUniNView({
type: EVENT_TYPE_NAME,
data,
target: {
id: this.webview.id,
isSub: !this.isSub,
},
}, APP_SERVICE_ID);
}
onMessage(callback) {
this.initMessage();
this.callbacks.push(callback);
}
}
const getSubNVueById = function (id, isSub) {
// TODO 暂时通过 isSub 区分来自 subNVue 页面
return new SubNvue(id, isSub);
};
const providers = {
oauth(callback) {
plus.oauth.getServices((services) => {
......@@ -9971,12 +10060,100 @@ var serviceContext = (function (vue) {
webview.setStyle(webviewStyle);
}
function initSubNVues(webview, path, routeMeta) {
const subNVues = routeMeta.subNVues || [];
subNVues.forEach((subNVue) => {
if (!subNVue.path) {
return;
}
const style = subNVue.style || {};
const isNavigationBar = subNVue.type === 'navigationBar';
const isPopup = subNVue.type === 'popup';
style.uniNView = {
path: subNVue.path.replace('.nvue', '.js'),
defaultFontSize: __uniConfig.defaultFontSize,
viewport: __uniConfig.viewport,
};
const extras = {
__uniapp_host: 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 = String(NAVBAR_HEIGHT + getStatusbarHeight());
delete style.left;
delete style.right;
delete style.bottom;
delete style.margin;
}
else if (isPopup) {
style.position = 'absolute';
if (isTabBarPage$1(path)) {
maskWebview = tabBar$1;
}
else {
maskWebview = webview;
}
extras.__uniapp_mask = style.mask || 'rgba(0,0,0,0.5)';
extras.__uniapp_mask_id = maskWebview.id;
}
delete style.mask;
const subNVueWebview = plus.webview.create('', subNVue.id, style, extras);
if (isPopup) {
if (!maskWebview.popupSubNVueWebviews) {
maskWebview.popupSubNVueWebviews = {};
}
maskWebview.popupSubNVueWebviews[subNVueWebview.id] = subNVueWebview;
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;
}
});
}
else {
webview.append(subNVueWebview);
}
});
}
function initWebview(webview, path, query, routeMeta) {
// 首页或非 nvue 页面
if (webview.id === '1' || !routeMeta.isNVue) {
// path 必须参数为空,因为首页已经在 manifest.json 中设置了 uniNView,不能再次设置,否则会二次加载
initWebviewStyle(webview, '', query, routeMeta);
}
initSubNVues(webview, path, routeMeta);
initWebviewEvent(webview);
}
......@@ -11678,6 +11855,7 @@ var serviceContext = (function (vue) {
showTabBarRedDot: showTabBarRedDot,
removeTabBarBadge: removeTabBarBadge,
hideTabBarRedDot: hideTabBarRedDot,
getSubNVueById: getSubNVueById,
getProvider: getProvider,
login: login,
getUserInfo: getUserInfo,
......
......@@ -5497,6 +5497,7 @@
}
[ON_PAGE_SCROLL, ON_REACH_BOTTOM];
const VD_SYNC = "vdSync";
const APP_SERVICE_ID = "__uniapp__service";
const ON_WEBVIEW_READY = "onWebviewReady";
const PAGE_SCROLL_TO = "pageScrollTo";
const LOAD_FONT_FACE = "loadFontFace";
......@@ -5504,7 +5505,6 @@
const WEBVIEW_INSERTED = "webviewInserted";
const WEBVIEW_REMOVED = "webviewRemoved";
const WEBVIEW_ID_PREFIX = "webviewId";
const APP_SERVICE_ID = "__uniapp__service";
const UniViewJSBridge$1 = /* @__PURE__ */ extend(ViewJSBridge, {
publishHandler
});
......
export const VD_SYNC = 'vdSync'
export const APP_SERVICE_ID = '__uniapp__service'
export const ON_WEBVIEW_READY = 'onWebviewReady'
export const PAGE_SCROLL_TO = 'pageScrollTo'
......
......@@ -52,6 +52,7 @@ export * from './ui/loadFontFace'
export * from './ui/pageScrollTo'
export * from './ui/navigationBar'
export * from './ui/tabBar'
export * from './ui/subNVue'
export * from './plugin/getProvider'
export * from './plugin/oauth'
......
import { APP_SERVICE_ID } from '../.../../../../constants'
import { requireNativePlugin } from '../base/requireNativePlugin'
import { PlusWebviewWebviewObjectWithExtras } from '../../framework/webview/init/subNVues'
const EVENT_TYPE_NAME = 'UniAppSubNVue'
interface OnMessageResult {
origin: string
data: any
}
type AnyFn = (res: OnMessageResult) => void
interface GlobalEventData {
type?: string
data: any
target?: {
id: string
isSub: boolean
}
}
interface WebviewExt extends PlusWebview {
postMessageToUniNView: (message: GlobalEventData, id: string) => void
}
class SubNvue implements ReturnType<typeof uni.getSubNVueById> {
private webview: PlusWebviewWebviewObjectWithExtras
private maskWebview?: PlusWebviewWebviewObject
private callbacks: AnyFn[] = []
private isSub: boolean
private messageReady?: boolean
constructor(id: string, isSub?: boolean) {
const webview = (this.webview = plus.webview.getWebviewById(
id
) as PlusWebviewWebviewObjectWithExtras)
this.isSub = isSub || false
if (webview.__uniapp_mask_id) {
const maskWebview = (this.maskWebview =
webview.__uniapp_mask_id === '0'
? ({
setStyle({ mask }) {
requireNativePlugin('uni-tabview').setMask({
color: mask,
})
},
} as PlusWebviewWebviewObject)
: plus.webview.getWebviewById(webview.__uniapp_mask_id))
const closeMask = function () {
maskWebview.setStyle({
mask: 'none',
})
}
webview.addEventListener('hide', closeMask)
webview.addEventListener('close', closeMask)
}
}
show(...args: any[]) {
if (this.maskWebview) {
const maskColor = this.webview.__uniapp_mask
this.maskWebview.setStyle({
mask: maskColor,
})
}
this.webview.show(...args)
}
hide(...args: any[]) {
this.webview.hide(...args)
}
setStyle(style: PlusWebviewWebviewStyles) {
this.webview.setStyle(style)
}
private initMessage() {
if (this.messageReady) {
return
}
this.messageReady = true
const listener = (event: { data?: GlobalEventData }) => {
if (event.data && event.data.type === EVENT_TYPE_NAME) {
const target = event.data.target!
if (target.id === this.webview.id && target.isSub === this.isSub) {
this.callbacks.forEach((callback) => {
callback({
origin: this.webview.__uniapp_host,
data: event.data!.data,
})
})
}
}
}
const globalEvent = requireNativePlugin('globalEvent')
globalEvent.addEventListener('plusMessage', listener)
this.webview.addEventListener('close', () => {
// TODO 暂时仅清空回调
this.callbacks.length = 0
// globalEvent.removeEventListener('plusMessage', listener)
})
}
postMessage(data: any) {
const webviewExt = plus.webview as WebviewExt
webviewExt.postMessageToUniNView(
{
type: EVENT_TYPE_NAME,
data,
target: {
id: this.webview.id,
isSub: !this.isSub,
},
},
APP_SERVICE_ID
)
}
onMessage(callback: AnyFn) {
this.initMessage()
this.callbacks.push(callback)
}
}
export const getSubNVueById = function (id: string, isSub?: boolean) {
// TODO 暂时通过 isSub 区分来自 subNVue 页面
return new SubNvue(id, isSub)
}
import { NAVBAR_HEIGHT } from '@dcloudio/uni-shared'
import { getStatusbarHeight } from '../../../../helpers/statusBar'
import { isTabBarPage } from '../../../../helpers/plus'
import tabBar from '../../app/tabBar'
import { backbuttonListener } from '../../app/utils'
interface Extras {
__uniapp_host: string
__uniapp_origin: string
__uniapp_origin_id: string
__uniapp_origin_type: string
__uniapp_mask?: string
__uniapp_mask_id?: string
}
export interface PlusWebviewWebviewObjectWithExtras
extends PlusWebviewWebviewObject,
Extras {}
export function initSubNVues(
webview: PlusWebviewWebviewObject,
path: string,
routeMeta: UniApp.PageRouteMeta
) {}
) {
const subNVues = routeMeta.subNVues || []
subNVues.forEach((subNVue) => {
if (!subNVue.path) {
return
}
interface StyleExt extends PlusWebviewWebviewStyles {
uniNView?: {
path: string
defaultFontSize?: number
viewport?: number
}
}
const style: StyleExt = (subNVue.style as StyleExt) || {}
const isNavigationBar = subNVue.type === 'navigationBar'
const isPopup = subNVue.type === 'popup'
style.uniNView = {
path: subNVue.path.replace('.nvue', '.js'),
defaultFontSize: (__uniConfig as any).defaultFontSize,
viewport: (__uniConfig as any).viewport,
}
const extras: Extras = {
__uniapp_host: path,
__uniapp_origin: style.uniNView.path.split('?')[0].replace('.js', ''),
__uniapp_origin_id: webview.id,
__uniapp_origin_type: (webview as any).__uniapp_type,
}
interface MaskWebview extends PlusWebviewWebviewObject {
popupSubNVueWebviews: Record<string, PlusWebviewWebviewObject>
}
let maskWebview: MaskWebview
if (isNavigationBar) {
style.position = 'dock'
style.dock = 'top'
style.top = '0'
style.width = '100%'
style.height = String(NAVBAR_HEIGHT + getStatusbarHeight())
delete style.left
delete style.right
delete style.bottom
delete style.margin
} else if (isPopup) {
style.position = 'absolute'
if (isTabBarPage(path)) {
maskWebview = tabBar as any
} else {
maskWebview = webview as MaskWebview
}
extras.__uniapp_mask = style.mask || 'rgba(0,0,0,0.5)'
extras.__uniapp_mask_id = maskWebview.id
}
delete style.mask
const subNVueWebview = plus.webview.create('', subNVue.id, style, extras)
if (isPopup) {
if (!maskWebview!.popupSubNVueWebviews) {
maskWebview!.popupSubNVueWebviews = {}
}
maskWebview!.popupSubNVueWebviews[subNVueWebview.id] = subNVueWebview
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
}
})
} else {
webview.append(subNVueWebview)
}
})
}
......@@ -2,7 +2,7 @@ import { extend } from '@vue/shared'
import { getCurrentPageId, ViewJSBridge } from '@dcloudio/uni-core'
const APP_SERVICE_ID = '__uniapp__service'
import { APP_SERVICE_ID } from '../../constants'
export const UniViewJSBridge = /*#__PURE__*/ extend(ViewJSBridge, {
publishHandler,
......
export default function getCurrentSubNVue() {
return uni.getSubNVueById(plus.webview.currentWebview().id)
}
return uni.getSubNVueById(plus.webview.currentWebview().id, true)
}
......@@ -922,10 +922,10 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@dcloudio/types@^2.4.4":
version "2.4.4"
resolved "https://registry.yarnpkg.com/@dcloudio/types/-/types-2.4.4.tgz#ae8b09aa0ae51d72d625e1061b4e6948c8ea01d5"
integrity sha512-EzUqM5uDg3ZauhnDj9bJp8OVrO/J1JHRktrO3kkoEtK6sECU/F87GtVVpVActyKAMLOSw65yIfeF17Yl+ctaNA==
"@dcloudio/types@^2.4.5":
version "2.4.5"
resolved "https://registry.yarnpkg.com/@dcloudio/types/-/types-2.4.5.tgz#3ead18599a6da0052afb814b522bc007043d814c"
integrity sha512-6PUP4D4PZgm5Zc7hAegNZZreJN6D9VK8bEp/oHG3tevVJ0w9+C/9PBgcX1kStxIwqYcfR0dv8jTyjG08BF185Q==
"@eslint/eslintrc@^0.4.3":
version "0.4.3"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册