UNPKG

@dcloudio/uni-app-plus-nvue

Version:
1,891 lines (1,677 loc) 237 kB
export function createServiceContext(Vue, weex, plus, __uniConfig, __uniRoutes, UniServiceJSBridge,instanceContext){ var localStorage = plus.storage var setTimeout = instanceContext.setTimeout var clearTimeout = instanceContext.clearTimeout var setInterval = instanceContext.setInterval var clearInterval = instanceContext.clearInterval var serviceContext = (function () { 'use strict'; function callHook (vm, hook, params) { return (vm.$vm || vm).__call_hook(hook, params) } function callAppHook (vm, hook, params) { if (hook !== 'onError') { console.debug(`App:${hook} have been invoked` + (params ? ` ${JSON.stringify(params)}` : '')); } return (vm.$vm || vm).__call_hook(hook, params) } function callPageHook (vm, hook, params) { if (hook !== 'onPageScroll') { console.debug(`${vm.$page.route}[${vm.$page.id}]:${hook} have been invoked`); } return callHook(vm, hook, params) } function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var base64Arraybuffer = createCommonjsModule(function (module, exports) { /* * base64-arraybuffer * https://github.com/niklasvh/base64-arraybuffer * * Copyright (c) 2012 Niklas von Hertzen * Licensed under the MIT license. */ (function(){ var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; // Use a lookup table to find the index. var lookup = new Uint8Array(256); for (var i = 0; i < chars.length; i++) { lookup[chars.charCodeAt(i)] = i; } exports.encode = function(arraybuffer) { var bytes = new Uint8Array(arraybuffer), i, len = bytes.length, base64 = ""; for (i = 0; i < len; i+=3) { base64 += chars[bytes[i] >> 2]; base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; base64 += chars[bytes[i + 2] & 63]; } if ((len % 3) === 2) { base64 = base64.substring(0, base64.length - 1) + "="; } else if (len % 3 === 1) { base64 = base64.substring(0, base64.length - 2) + "=="; } return base64; }; exports.decode = function(base64) { var bufferLength = base64.length * 0.75, len = base64.length, i, p = 0, encoded1, encoded2, encoded3, encoded4; if (base64[base64.length - 1] === "=") { bufferLength--; if (base64[base64.length - 2] === "=") { bufferLength--; } } var arraybuffer = new ArrayBuffer(bufferLength), bytes = new Uint8Array(arraybuffer); for (i = 0; i < len; i+=4) { encoded1 = lookup[base64.charCodeAt(i)]; encoded2 = lookup[base64.charCodeAt(i+1)]; encoded3 = lookup[base64.charCodeAt(i+2)]; encoded4 = lookup[base64.charCodeAt(i+3)]; bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); } return arraybuffer; }; })(); }); var base64Arraybuffer_1 = base64Arraybuffer.encode; var base64Arraybuffer_2 = base64Arraybuffer.decode; function unpack (args) { return args } function invoke (...args) { return UniServiceJSBridge.invokeCallbackHandler(...args) } function requireNativePlugin (name) { return uni.requireNativePlugin(name) } /** * 触发 service 层,与 onMethod 对应 */ function publish (name, res) { return UniServiceJSBridge.emit('api.' + name, res) } let lastStatusBarStyle; function setStatusBarStyle (statusBarStyle) { if (!statusBarStyle) { const pages = getCurrentPages(); if (!pages.length) { return } statusBarStyle = pages[pages.length - 1].$page.meta.statusBarStyle; if (!statusBarStyle || statusBarStyle === lastStatusBarStyle) { return } } if (process.env.NODE_ENV !== 'production') { console.log(`[uni-app] setStatusBarStyle`, statusBarStyle); } lastStatusBarStyle = statusBarStyle; plus.navigator.setStatusBarStyle(statusBarStyle); } function isTabBarPage (path = '') { if (!(__uniConfig.tabBar && Array.isArray(__uniConfig.tabBar.list))) { return false } try { if (!path) { const pages = getCurrentPages(); if (!pages.length) { return false } const page = pages[pages.length - 1]; if (!page) { return false } return page.$page.meta.isTabBar } const route = __uniRoutes.find(route => route.path.slice(1) === path); return route && route.meta.isTabBar } catch (e) { if (process.env.NODE_ENV !== 'production') { console.log('getCurrentPages is not ready'); } } return false } function base64ToArrayBuffer (data) { return base64Arraybuffer_2(data) } function arrayBufferToBase64 (data) { return base64Arraybuffer_1(data) } function callApiSync (api, args, name, alias) { const ret = api(args); if (ret && ret.errMsg) { ret.errMsg = ret.errMsg.replace(name, alias); } return ret } function getLastWebview () { try { const pages = getCurrentPages(); if (pages.length) { return pages[pages.length - 1].$getAppWebview() } } catch (e) { if (process.env.NODE_ENV !== 'production') { console.log('getCurrentPages is not ready'); } } } const getRealRoute = (e, t) => { if (t.indexOf('./') === 0) return getRealRoute(e, t.substr(2)) let n; let i; let o = t.split('/'); for (n = 0, i = o.length; n < i && o[n] === '..'; n++); o.splice(0, n); t = o.join('/'); let r = e.length > 0 ? e.split('/') : []; r.splice(r.length - n - 1, n + 1); return r.concat(o).join('/') }; // 处理 Android 平台解压与非解压模式下获取的路径不一致的情况 const _handleLocalPath = filePath => { let localUrl = plus.io.convertLocalFileSystemURL(filePath); return localUrl.replace(/^\/?apps\//, '/android_asset/apps/').replace(/\/$/, '') }; function getRealPath (filePath) { const SCHEME_RE = /^([a-z-]+:)?\/\//i; const DATA_RE = /^data:.*,.*/; // 无协议的情况补全 https if (filePath.indexOf('//') === 0) { filePath = 'https:' + filePath; } // 网络资源或base64 if (SCHEME_RE.test(filePath) || DATA_RE.test(filePath)) { return filePath } if (filePath.indexOf('_www') === 0 || filePath.indexOf('_doc') === 0 || filePath.indexOf('_documents') === 0 || filePath.indexOf('_downloads') === 0) { return 'file://' + _handleLocalPath(filePath) } const wwwPath = 'file://' + _handleLocalPath('_www'); // 绝对路径转换为本地文件系统路径 if (filePath.indexOf('/') === 0) { return wwwPath + filePath } // 相对资源 if (filePath.indexOf('../') === 0 || filePath.indexOf('./') === 0) { if (typeof __id__ === 'string') { return wwwPath + getRealRoute('/' + __id__, filePath) } else { const pages = getCurrentPages(); if (pages.length) { return wwwPath + getRealRoute('/' + pages[pages.length - 1].route, filePath) } } } return filePath } function getStatusBarStyle () { let style = plus.navigator.getStatusBarStyle(); if (style === 'UIStatusBarStyleBlackTranslucent' || style === 'UIStatusBarStyleBlackOpaque' || style === 'null') { style = 'light'; } else if (style === 'UIStatusBarStyleDefault') { style = 'dark'; } return style } const PI = 3.1415926535897932384626; const a = 6378245.0; const ee = 0.00669342162296594323; function wgs84togcj02 (lng, lat) { lat = +lat; lng = +lng; if (outOfChina(lng, lat)) { return [lng, lat] } let dlat = _transformlat(lng - 105.0, lat - 35.0); let dlng = _transformlng(lng - 105.0, lat - 35.0); const radlat = lat / 180.0 * PI; let magic = Math.sin(radlat); magic = 1 - ee * magic * magic; const sqrtmagic = Math.sqrt(magic); dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI); dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI); const mglat = lat + dlat; const mglng = lng + dlng; return [mglng, mglat] } function gcj02towgs84 (lng, lat) { lat = +lat; lng = +lng; if (outOfChina(lng, lat)) { return [lng, lat] } let dlat = _transformlat(lng - 105.0, lat - 35.0); let dlng = _transformlng(lng - 105.0, lat - 35.0); const radlat = lat / 180.0 * PI; let magic = Math.sin(radlat); magic = 1 - ee * magic * magic; const sqrtmagic = Math.sqrt(magic); dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI); dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI); const mglat = lat + dlat; const mglng = lng + dlng; return [lng * 2 - mglng, lat * 2 - mglat] } const _transformlat = function (lng, lat) { let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng)); ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0; ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0; ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0; return ret }; const _transformlng = function (lng, lat) { let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng)); ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0; ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0; ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0; return ret }; const outOfChina = function (lng, lat) { return (lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false) }; let webview; function setPullDownRefreshPageId (pullDownRefreshWebview) { if (typeof pullDownRefreshWebview === 'number') { webview = plus.webview.getWebviewById(String(pullDownRefreshWebview)); } else { webview = pullDownRefreshWebview; } } function startPullDownRefresh () { if (webview) { webview.endPullToRefresh(); } webview = getLastWebview(); if (webview) { webview.beginPullToRefresh(); return { errMsg: 'startPullDownRefresh:ok' } } return { errMsg: 'startPullDownRefresh:fail' } } function stopPullDownRefresh () { if (!webview) { webview = getLastWebview(); } if (webview) { webview.endPullToRefresh(); webview = null; return { errMsg: 'stopPullDownRefresh:ok' } } return { errMsg: 'stopPullDownRefresh:fail' } } function initOn (on, { getApp, getCurrentPages }) { function onError (err) { callAppHook(getApp(), 'onError', err); } function onPageNotFound (page) { callAppHook(getApp(), 'onPageNotFound', page); } function onPullDownRefresh (args, pageId) { const page = getCurrentPages().find(page => page.$page.id === pageId); if (page) { setPullDownRefreshPageId(pageId); callPageHook(page, 'onPullDownRefresh'); } } function callCurrentPageHook (hook, args) { const pages = getCurrentPages(); if (pages.length) { callPageHook(pages[pages.length - 1], hook, args); } } function createCallCurrentPageHook (hook) { return function (args) { callCurrentPageHook(hook, args); } } function onAppEnterBackground () { callAppHook(getApp(), 'onHide'); callCurrentPageHook('onHide'); } function onAppEnterForeground () { callAppHook(getApp(), 'onShow'); callCurrentPageHook('onShow'); } function onWebInvokeAppService ({ name, arg }, pageId) { if (name === 'postMessage') ; else { uni[name](arg); } } const routeHooks = { navigateTo () { callCurrentPageHook('onHide'); }, navigateBack () { callCurrentPageHook('onShow'); } }; function onAppRoute ({ type }) { const routeHook = routeHooks[type]; routeHook && routeHook(); } on('onError', onError); on('onPageNotFound', onPageNotFound); { // 后续有时间,h5 平台也要迁移到 onAppRoute on('onAppRoute', onAppRoute); } on('onAppEnterBackground', onAppEnterBackground); on('onAppEnterForeground', onAppEnterForeground); on('onPullDownRefresh', onPullDownRefresh); on('onTabItemTap', createCallCurrentPageHook('onTabItemTap')); on('onNavigationBarButtonTap', createCallCurrentPageHook('onNavigationBarButtonTap')); on('onNavigationBarSearchInputChanged', createCallCurrentPageHook('onNavigationBarSearchInputChanged')); on('onNavigationBarSearchInputConfirmed', createCallCurrentPageHook('onNavigationBarSearchInputConfirmed')); on('onNavigationBarSearchInputClicked', createCallCurrentPageHook('onNavigationBarSearchInputClicked')); on('onWebInvokeAppService', onWebInvokeAppService); } let supportsPassive = false; try { const opts = {}; Object.defineProperty(opts, 'passive', ({ get () { /* istanbul ignore next */ supportsPassive = true; } })); // https://github.com/facebook/flow/issues/285 window.addEventListener('test-passive', null, opts); } catch (e) {} const _toString = Object.prototype.toString; const hasOwnProperty = Object.prototype.hasOwnProperty; function isFn (fn) { return typeof fn === 'function' } function isPlainObject (obj) { return _toString.call(obj) === '[object Object]' } function hasOwn (obj, key) { return hasOwnProperty.call(obj, key) } function toRawType (val) { return _toString.call(val).slice(8, -1) } function getLen (str = '') { /* eslint-disable no-control-regex */ return ('' + str).replace(/[^\x00-\xff]/g, '**').length } const decode = decodeURIComponent; function parseQuery (query) { const res = {}; query = query.trim().replace(/^(\?|#|&)/, ''); if (!query) { return res } query.split('&').forEach(param => { const parts = param.replace(/\+/g, ' ').split('='); const key = decode(parts.shift()); const val = parts.length > 0 ? decode(parts.join('=')) : null; if (res[key] === undefined) { res[key] = val; } else if (Array.isArray(res[key])) { res[key].push(val); } else { res[key] = [res[key], val]; } }); return res } function parseTitleNView (routeOptions) { const windowOptions = routeOptions.window; const titleNView = windowOptions.titleNView; if ( // 无头 titleNView === false || titleNView === 'false' || ( windowOptions.navigationStyle === 'custom' && !isPlainObject(titleNView) ) ) { return false } const ret = { autoBackButton: !routeOptions.meta.isQuit, backgroundColor: windowOptions.navigationBarBackgroundColor || '#000000', titleText: windowOptions.navigationBarTitleText || '', titleColor: windowOptions.navigationBarTextStyle === 'black' ? '#000000' : '#ffffff' }; routeOptions.meta.statusBarStyle = windowOptions.navigationBarTextStyle === 'black' ? 'dark' : 'light'; if (isPlainObject(titleNView)) { return Object.assign(ret, titleNView) } return ret } function parsePullToRefresh (routeOptions) { const windowOptions = routeOptions.window; if (windowOptions.enablePullDownRefresh) { const pullToRefreshStyles = Object.create(null); // 初始化默认值 if (plus.os.name === 'Android') { Object.assign(pullToRefreshStyles, { support: true, style: 'circle' }); } else { Object.assign(pullToRefreshStyles, { support: true, style: 'default', height: '50px', range: '200px', contentdown: { caption: '' }, contentover: { caption: '' }, contentrefresh: { caption: '' } }); } if (windowOptions.backgroundTextStyle) { pullToRefreshStyles.color = windowOptions.backgroundTextStyle; pullToRefreshStyles.snowColor = windowOptions.backgroundTextStyle; } Object.assign(pullToRefreshStyles, windowOptions.pullToRefresh || {}); return pullToRefreshStyles } } const ANI_SHOW = 'pop-in'; const ANI_DURATION = 300; const TABBAR_HEIGHT = 56; const TITLEBAR_HEIGHT = 44; const WEBVIEW_STYLE_BLACKLIST = [ 'navigationBarBackgroundColor', 'navigationBarTextStyle', 'navigationBarTitleText', 'navigationBarShadow', 'navigationStyle', 'disableScroll', 'backgroundColor', 'backgroundTextStyle', 'enablePullDownRefresh', 'onReachBottomDistance', 'usingComponents', // 需要解析的 'titleNView', 'pullToRefresh' ]; function parseWebviewStyle (id, path, routeOptions = {}) { const webviewStyle = Object.create(null); // 合并 routeOptions.window = Object.assign( JSON.parse(JSON.stringify(__uniConfig.window || {})), routeOptions.window || {} ); Object.keys(routeOptions.window).forEach(name => { if (WEBVIEW_STYLE_BLACKLIST.indexOf(name) === -1) { webviewStyle[name] = routeOptions.window[name]; } }); const titleNView = parseTitleNView(routeOptions); if (titleNView) { if (id === 1 && __uniConfig.realEntryPagePath === path) { titleNView.autoBackButton = true; } webviewStyle.titleNView = titleNView; } const pullToRefresh = parsePullToRefresh(routeOptions); if (pullToRefresh) { if (pullToRefresh.style === 'circle') { webviewStyle.bounce = 'none'; } webviewStyle.pullToRefresh = pullToRefresh; } // 不支持 hide if (webviewStyle.popGesture === 'hide') { delete webviewStyle.popGesture; } // TODO 下拉刷新 if (path && routeOptions.meta.isNVue) { webviewStyle.uniNView = { path, defaultFontSize: __uniConfig.defaultFontSize, viewport: __uniConfig.viewport }; } if (routeOptions.meta.isTabBar) { webviewStyle.top = 0; webviewStyle.bottom = TABBAR_HEIGHT; } return webviewStyle } let id = 2; const WEBVIEW_LISTENERS = { 'pullToRefresh': 'onPullDownRefresh', 'titleNViewSearchInputChanged': 'onNavigationBarSearchInputChanged', 'titleNViewSearchInputConfirmed': 'onNavigationBarSearchInputConfirmed', 'titleNViewSearchInputClicked': 'onNavigationBarSearchInputClicked' }; function createWebview (path, routeOptions) { const webviewId = id++; const webviewStyle = parseWebviewStyle( webviewId, path, routeOptions ); if (process.env.NODE_ENV !== 'production') { console.log(`[uni-app] createWebview`, webviewId, path, webviewStyle); } const webview = plus.webview.create('', String(webviewId), webviewStyle); return webview } function initWebview (webview, routeOptions) { if (isPlainObject(routeOptions)) { const webviewStyle = parseWebviewStyle( parseInt(webview.id), '', routeOptions ); if (process.env.NODE_ENV !== 'production') { console.log(`[uni-app] updateWebview`, webviewStyle); } webview.setStyle(webviewStyle); } const { on, emit } = UniServiceJSBridge; // TODO subNVues Object.keys(WEBVIEW_LISTENERS).forEach(name => { webview.addEventListener(name, (e) => { emit(WEBVIEW_LISTENERS[name], e, parseInt(webview.id)); }); }); webview.addEventListener('resize', ({ width, height }) => { const res = { size: { windowWidth: Math.ceil(width), windowHeight: Math.ceil(height) } }; publish('onViewDidResize', res); emit('onResize', res, parseInt(webview.id)); }); // TODO 应该结束之前未完成的下拉刷新 on(webview.id + '.startPullDownRefresh', () => { webview.beginPullToRefresh(); }); on(webview.id + '.stopPullDownRefresh', () => { webview.endPullToRefresh(); }); return webview } const pages = []; function getCurrentPages$1 (returnAll) { return returnAll ? pages.slice(0) : pages.filter(page => { return !page.$page.meta.isTabBar || page.$page.meta.visible }) } /** * 首页需要主动registerPage,二级页面路由跳转时registerPage */ function registerPage ({ path, query, openType, webview }) { const routeOptions = JSON.parse(JSON.stringify(__uniRoutes.find(route => route.path === path))); if (openType === 'reLaunch' || pages.length === 0) { // pages.length===0 表示首页触发 redirectTo routeOptions.meta.isQuit = true; } if (!webview) { webview = createWebview(path, routeOptions); } else { webview = plus.webview.getWebviewById(webview.id); } if (routeOptions.meta.isTabBar) { routeOptions.meta.visible = true; } if (routeOptions.meta.isTabBar && webview.id !== '1') { const launchWebview = plus.webview.getLaunchWebview(); launchWebview && launchWebview.append(webview); } if (process.env.NODE_ENV !== 'production') { console.log(`[uni-app] registerPage`, path, webview.id); } initWebview(webview, webview.id === '1' && routeOptions); const route = path.slice(1); webview.__uniapp_route = route; pages.push({ route, options: Object.assign({}, query || {}), $getAppWebview () { return webview }, $page: { id: parseInt(webview.id), meta: routeOptions.meta, path, route, openType }, $remove () { const index = pages.findIndex(page => page === this); if (index !== -1) { pages.splice(index, 1); if (process.env.NODE_ENV !== 'production') { console.log(`[uni-app] removePage`, path, webview.id); } } } }); return webview } const callbacks = {}; const WEB_INVOKE_APPSERVICE = 'WEB_INVOKE_APPSERVICE'; // 简单处理 view 层与 service 层的通知系统 /** * 消费 view 层通知 */ function consumePlusMessage (type, args) { // 处理 web-view 组件发送的通知 if (type === WEB_INVOKE_APPSERVICE) { publish(WEB_INVOKE_APPSERVICE, args.data, args.webviewIds); return true } const callback = callbacks[type]; if (callback) { callback(args); if (!callback.keepAlive) { delete callbacks[type]; } return true } return false } /** * 注册 view 层通知 service 层事件处理 */ function registerPlusMessage (type, callback, keepAlive = true) { if (callbacks[type]) { return console.warn(`${type} 已注册:` + (callbacks[type].toString())) } callback.keepAlive = !!keepAlive; callbacks[type] = callback; } var safeArea = { get bottom () { if (plus.os.name === 'iOS') { const safeArea = plus.navigator.getSafeAreaInsets(); return safeArea ? safeArea.bottom : 0 } return 0 } }; const IMAGE_TOP = 7; const IMAGE_WIDTH = 24; const IMAGE_HEIGHT = 24; const TEXT_TOP = 36; const TEXT_SIZE = 12; const TEXT_NOICON_SIZE = 17; const TEXT_HEIGHT = 12; const IMAGE_ID = 'TABITEM_IMAGE_'; const TABBAR_VIEW_ID = 'TABBAR_VIEW_'; let view; let config; let winWidth; let itemWidth; let itemLength; let itemImageLeft; let itemRects = []; const itemIcons = []; const itemLayouts = []; const itemDot = []; const itemBadge = []; let itemClickCallback; let selected = 0; /** * tabbar显示状态 */ let visible = true; const init = function () { const list = config.list; itemLength = config.list.length; calcItemLayout(); // 计算选项卡布局 initBitmaps(list); // 初始化选项卡图标 initView(); }; let initView = function () { const viewStyles = { height: TABBAR_HEIGHT }; if (config.position === 'top') { viewStyles.top = 0; } else { viewStyles.bottom = 0; viewStyles.height += safeArea.bottom; } view = new plus.nativeObj.View(TABBAR_VIEW_ID, viewStyles, getDraws()); view.interceptTouchEvent(true); view.addEventListener('click', (e) => { if (!__uniConfig.__ready__) { // 未 ready,不允许点击 return } const x = e.clientX; const y = e.clientY; for (let i = 0; i < itemRects.length; i++) { if (isCross(x, y, itemRects[i])) { const draws = getSelectedDraws(i); const drawTab = !!draws.length; itemClickCallback && itemClickCallback(config.list[i], i, drawTab); if (drawTab) { setTimeout(() => view.draw(draws)); } break } } }); plus.globalEvent.addEventListener('orientationchange', () => { calcItemLayout(config.list); if (config.position !== 'top') { let height = TABBAR_HEIGHT + safeArea.bottom; view.setStyle({ height: height }); if (visible) { setWebviewPosition(height); } } view.draw(getDraws()); }); if (!visible) { view.hide(); } }; let isCross = function (x, y, rect) { if (x > rect.left && x < (rect.left + rect.width) && y > rect.top && y < (rect.top + rect.height)) { return true } return false }; let initBitmaps = function (list) { for (let i = 0; i < list.length; i++) { const item = list[i]; if (item.iconData) { const bitmap = new plus.nativeObj.Bitmap(IMAGE_ID + i); bitmap.loadBase64Data(item.iconData); const selectedBitmap = new plus.nativeObj.Bitmap(`${IMAGE_ID}SELECTED_${i}`); selectedBitmap.loadBase64Data(item.selectedIconData); itemIcons[i] = { icon: bitmap, selectedIcon: selectedBitmap }; } else if (item.iconPath) { itemIcons[i] = { icon: item.iconPath, selectedIcon: item.selectedIconPath }; } else { itemIcons[i] = { icon: false, selectedIcon: false }; } } }; let getDraws = function () { const backgroundColor = config.backgroundColor; const borderHeight = Math.max(0.5, 1 / plus.screen.scale); // 高分屏最少0.5 const borderTop = config.position === 'top' ? (TABBAR_HEIGHT - borderHeight) : 0; const borderStyle = config.borderStyle === 'white' ? 'rgba(255,255,255,0.33)' : 'rgba(0,0,0,0.33)'; const draws = [{ id: `${TABBAR_VIEW_ID}BG`, // 背景色 tag: 'rect', color: backgroundColor, position: { top: 0, left: 0, width: '100%', height: TABBAR_HEIGHT + safeArea.bottom } }, { id: `${TABBAR_VIEW_ID}BORDER`, tag: 'rect', color: borderStyle, position: { top: borderTop, left: 0, width: '100%', height: `${borderHeight}px` } }]; for (let i = 0; i < itemLength; i++) { const item = config.list[i]; if (i === selected) { drawTabItem(draws, i, item.text, config.selectedColor, itemIcons[i].selectedIcon); } else { drawTabItem(draws, i, item.text, config.color, itemIcons[i].icon); } } return draws }; let getSelectedDraws = function (newSelected) { if (selected === newSelected) { return false } const draws = []; const lastSelected = selected; selected = newSelected; drawTabItem(draws, lastSelected); drawTabItem(draws, selected); return draws }; /** * 获取文字宽度(全角为1) * @param {*} text */ function getFontWidth (text) { // eslint-disable-next-line return text.length - (text.match(/[\u0000-\u00ff]/g) || []).length / 2 } let calcItemLayout = function () { winWidth = plus.screen.resolutionWidth; itemWidth = winWidth / itemLength; itemImageLeft = (itemWidth - IMAGE_WIDTH) / 2; itemRects = []; let dotTop = 0; let dotLeft = 0; for (let i = 0; i < itemLength; i++) { itemRects.push({ top: 0, left: i * itemWidth, width: itemWidth, height: TABBAR_HEIGHT }); } for (let i = 0; i < itemLength; i++) { const item = config.list[i]; let imgLeft = itemWidth * i + itemImageLeft; if ((item.iconData || item.iconPath) && item.text) { // 图文 itemLayouts[i] = { text: { top: TEXT_TOP, left: `${i * itemWidth}px`, width: `${itemWidth}px`, height: TEXT_HEIGHT }, img: { top: IMAGE_TOP, left: `${imgLeft}px`, width: IMAGE_WIDTH, height: IMAGE_HEIGHT } }; dotTop = IMAGE_TOP; dotLeft = imgLeft + IMAGE_WIDTH; } else if (!(item.iconData || item.iconPath) && item.text) { // 仅文字 let textLeft = i * itemWidth; itemLayouts[i] = { text: { top: 0, left: `${textLeft}px`, width: `${itemWidth}px`, height: TABBAR_HEIGHT } }; dotTop = (44 - TEXT_NOICON_SIZE) / 2; dotLeft = textLeft + itemWidth * 0.5 + getFontWidth(item.text) * TEXT_NOICON_SIZE * 0.5; } else if ((item.iconData || item.iconPath) && !item.text) { // 仅图片 const diff = 10; let imgTop = (TABBAR_HEIGHT - IMAGE_HEIGHT - diff) / 2; let imgLeft = itemWidth * i + itemImageLeft - diff / 2; itemLayouts[i] = { img: { top: `${imgTop}px`, left: `${imgLeft}px`, width: IMAGE_WIDTH + diff, height: IMAGE_HEIGHT + diff } }; dotTop = imgTop; dotLeft = imgLeft + IMAGE_WIDTH + diff; } let height = itemBadge[i] ? 14 : 10; let badge = itemBadge[i] || '0'; let font = getFontWidth(badge) - 0.5; font = font > 1 ? 1 : font; let width = height + font * 12; width = width < height ? height : width; let itemLayout = itemLayouts[i]; if (itemLayout) { itemLayout.doc = { top: dotTop, left: `${dotLeft - width * 0.382}px`, width: `${width}px`, height: `${height}px` }; itemLayout.badge = { top: dotTop, left: `${dotLeft - width * 0.382}px`, width: `${width}px`, height: `${height}px` }; } } }; let drawTabItem = function (draws, index) { const layout = itemLayouts[index]; const item = config.list[index]; let color = config.color; let icon = itemIcons[index].icon; let dot = itemDot[index]; let badge = itemBadge[index] || ''; if (index === selected) { color = config.selectedColor; icon = itemIcons[index].selectedIcon; } if (icon) { draws.push({ id: `${TABBAR_VIEW_ID}ITEM_${index}_ICON`, tag: 'img', position: layout.img, src: icon }); } if (item.text) { draws.push({ id: `${TABBAR_VIEW_ID}ITEM_${index}_TEXT`, tag: 'font', position: layout.text, text: item.text, textStyles: { size: icon ? TEXT_SIZE : `${TEXT_NOICON_SIZE}px`, color } }); } const hiddenPosition = { letf: 0, top: 0, width: 0, height: 0 }; // 绘制小红点(角标背景) draws.push({ id: `${TABBAR_VIEW_ID}ITEM_${index}_DOT`, tag: 'rect', position: (dot || badge) ? layout.doc : hiddenPosition, rectStyles: { color: '#ff0000', radius: badge ? '7px' : '5px' } }); // 绘制角标文本 draws.push({ id: `${TABBAR_VIEW_ID}ITEM_${index}_BADGE`, tag: 'font', position: badge ? layout.badge : hiddenPosition, text: badge || ' ', textStyles: { align: 'center', verticalAlign: 'middle', color: badge ? '#ffffff' : 'rgba(0,0,0,0)', overflow: 'ellipsis', size: '10px' } }); }; /** * { "color": "#7A7E83", "selectedColor": "#3cc51f", "borderStyle": "black", "backgroundColor": "#ffffff", "list": [{ "pagePath": "page/component/index.html", "iconData": "", "selectedIconData": "", "text": "组件" }, { "pagePath": "page/API/index.html", "iconData": "", "selectedIconData": "", "text": "接口" }], "position":"bottom"//bottom|top } */ /** * 设置角标 * @param {string} type * @param {number} index * @param {string} text */ function setTabBarBadge (type, index, text) { if (type === 'none') { itemDot[index] = false; itemBadge[index] = ''; } else if (type === 'text') { itemBadge[index] = text; } else if (type === 'redDot') { itemDot[index] = true; } if (view) { calcItemLayout(config.list); view.draw(getDraws()); } } /** * 动态设置 tabBar 某一项的内容 */ function setTabBarItem (index, text, iconPath, selectedIconPath) { if (iconPath || selectedIconPath) { let itemIcon = itemIcons[index] = itemIcons[index] || {}; if (iconPath) { itemIcon.icon = getRealPath(iconPath); } if (selectedIconPath) { itemIcon.selectedIcon = getRealPath(selectedIconPath); } } if (text) { config.list[index].text = text; } view.draw(getDraws()); } /** * 动态设置 tabBar 的整体样式 * @param {Object} style 样式 */ function setTabBarStyle (style) { for (const key in style) { config[key] = style[key]; } view.draw(getDraws()); } /** * 设置tab页底部或顶部距离 * @param {*} value 距离 */ function setWebviewPosition (value) { const position = config.position === 'top' ? 'top' : 'bottom'; plus.webview.all().forEach(webview => { if (isTabBarPage(String(webview.__uniapp_route))) { webview.setStyle({ [position]: value }); } }); } /** * 隐藏 tabBar * @param {boolean} animation 是否需要动画效果 暂未支持 */ function hideTabBar (animation) { if (visible === false) { return } visible = false; if (view) { view.hide(); setWebviewPosition(0); } } /** * 显示 tabBar * @param {boolean} animation 是否需要动画效果 暂未支持 */ function showTabBar (animation) { if (visible === true) { return } visible = true; if (view) { view.show(); setWebviewPosition(TABBAR_HEIGHT + safeArea.bottom); } } var tabBar = { init (options, clickCallback) { if (options && options.list.length) { selected = options.selected || 0; config = options; config.position = 'bottom'; // 暂时强制使用bottom itemClickCallback = clickCallback; init(); return view } }, switchTab (page) { if (itemLength) { for (let i = 0; i < itemLength; i++) { if ( config.list[i].pagePath === page || config.list[i].pagePath === `${page}.html` ) { const draws = getSelectedDraws(i); if (draws.length) { view.draw(draws); } return true } } } return false }, setTabBarBadge, setTabBarItem, setTabBarStyle, hideTabBar, showTabBar, get visible () { return visible } }; let appCtx; const NETWORK_TYPES = [ 'unknown', 'none', 'ethernet', 'wifi', '2g', '3g', '4g' ]; function getApp () { return appCtx } function initGlobalListeners () { const emit = UniServiceJSBridge.emit; plus.key.addEventListener('backbutton', () => { uni.navigateBack({ from: 'backbutton' }); }); plus.globalEvent.addEventListener('pause', () => { emit('onAppEnterBackground'); }); plus.globalEvent.addEventListener('resume', () => { emit('onAppEnterForeground'); }); plus.globalEvent.addEventListener('netchange', () => { const networkType = NETWORK_TYPES[plus.networkinfo.getCurrentType()]; publish('onNetworkStatusChange', { isConnected: networkType !== 'none', networkType }); }); plus.globalEvent.addEventListener('KeyboardHeightChange', function (event) { publish('onKeyboardHeightChange', { height: event.height }); }); plus.globalEvent.addEventListener('plusMessage', function (e) { if (process.env.NODE_ENV !== 'production') { console.log('UNIAPP[plusMessage]:[' + Date.now() + ']' + JSON.stringify(e.data)); } if (e.data && e.data.type) { const type = e.data.type; consumePlusMessage(type, e.data.args || {}); } }); } function initAppLaunch (appVm) { const args = { path: __uniConfig.entryPagePath, query: {}, scene: 1001 }; callAppHook(appVm, 'onLaunch', args); callAppHook(appVm, 'onShow', args); } function initTabBar () { if (!__uniConfig.tabBar || !__uniConfig.tabBar.list.length) { return } __uniConfig.tabBar.selected = 0; const selected = __uniConfig.tabBar.list.findIndex(page => page.pagePath === __uniConfig.entryPagePath); if (selected !== -1) { // 取当前 tab 索引值 __uniConfig.tabBar.selected = selected; // 如果真实的首页与 condition 都是 tabbar,无需启用 realEntryPagePath 机制 if (__uniConfig.realEntryPagePath && isTabBarPage(__uniConfig.realEntryPagePath)) { delete __uniConfig.realEntryPagePath; } } __uniConfig.__ready__ = true; const onLaunchWebviewReady = function onLaunchWebviewReady () { const tabBarView = tabBar.init(__uniConfig.tabBar, (item, index) => { UniServiceJSBridge.emit('onTabItemTap', { index, text: item.text, pagePath: item.pagePath }); uni.switchTab({ url: '/' + item.pagePath, openType: 'switchTab', from: 'tabbar' }); }); tabBarView && plus.webview.getLaunchWebview().append(tabBarView); }; if (plus.webview.getLaunchWebview()) { onLaunchWebviewReady(); } else { registerPlusMessage('UniWebviewReady-' + plus.runtime.appid, onLaunchWebviewReady, false); } } function registerApp (appVm) { if (process.env.NODE_ENV !== 'production') { console.log(`[uni-app] registerApp`); } appCtx = appVm; appCtx.globalData = appVm.$options.globalData || {}; initOn(UniServiceJSBridge.on, { getApp, getCurrentPages: getCurrentPages$1 }); initAppLaunch(appVm); initGlobalListeners(); initTabBar(); } function parseRoutes (config) { __uniRoutes.length = 0; /* eslint-disable no-mixed-operators */ const tabBarList = (config.tabBar && config.tabBar.list || []).map(item => item.pagePath); Object.keys(config.page).forEach(function (pagePath) { const isTabBar = tabBarList.indexOf(pagePath) !== -1; const isQuit = isTabBar || (config.pages[0] === pagePath); const isNVue = !!config.page[pagePath].nvue; __uniRoutes.push({ path: '/' + pagePath, meta: { isQuit, isTabBar, isNVue }, window: config.page[pagePath].window || {} }); }); } function registerConfig (config, Vue) { Object.assign(__uniConfig, config); __uniConfig.viewport = ''; __uniConfig.defaultFontSize = ''; if (__uniConfig.nvueCompiler === 'uni-app') { __uniConfig.viewport = plus.screen.resolutionWidth; __uniConfig.defaultFontSize = __uniConfig.viewport / 20; } parseRoutes(__uniConfig); if (process.env.NODE_ENV !== 'production') { console.log(`[uni-app] registerConfig`, __uniConfig); } } const base = [ 'base64ToArrayBuffer', 'arrayBufferToBase64', 'addInterceptor', 'removeInterceptor' ]; const network = [ 'request', 'uploadFile', 'downloadFile', 'connectSocket', 'onSocketOpen', 'onSocketError', 'sendSocketMessage', 'onSocketMessage', 'closeSocket', 'onSocketClose' ]; const route = [ 'navigateTo', 'redirectTo', 'reLaunch', 'switchTab', 'navigateBack' ]; const storage = [ 'setStorage', 'setStorageSync', 'getStorage', 'getStorageSync', 'getStorageInfo', 'getStorageInfoSync', 'removeStorage', 'removeStorageSync', 'clearStorage', 'clearStorageSync' ]; const location = [ 'getLocation', 'chooseLocation', 'openLocation', 'createMapContext' ]; const media = [ 'chooseImage', 'previewImage', 'getImageInfo', 'saveImageToPhotosAlbum', 'compressImage', 'getRecorderManager', 'getBackgroundAudioManager', 'createInnerAudioContext', 'chooseVideo', 'saveVideoToPhotosAlbum', 'createVideoContext', 'createCameraContext', 'createLivePlayerContext' ]; const device = [ 'getSystemInfo', 'getSystemInfoSync', 'canIUse', 'onMemoryWarning', 'getNetworkType', 'onNetworkStatusChange', 'onAccelerometerChange', 'startAccelerometer', 'stopAccelerometer', 'onCompassChange', 'startCompass', 'stopCompass', 'onGyroscopeChange', 'startGyroscope', 'stopGyroscope', 'makePhoneCall', 'scanCode', 'setClipboardData', 'getClipboardData', 'setScreenBrightness', 'getScreenBrightness', 'setKeepScreenOn', 'onUserCaptureScreen', 'vibrateLong', 'vibrateShort', 'addPhoneContact', 'openBluetoothAdapter', 'startBluetoothDevicesDiscovery', 'onBluetoothDeviceFound', 'stopBluetoothDevicesDiscovery', 'onBluetoothAdapterStateChange', 'getConnectedBluetoothDevices', 'getBluetoothDevices', 'getBluetoothAdapterState', 'closeBluetoothAdapter', 'writeBLECharacteristicValue', 'readBLECharacteristicValue', 'onBLEConnectionStateChange', 'onBLECharacteristicValueChange', 'notifyBLECharacteristicValueChange', 'getBLEDeviceServices', 'getBLEDeviceCharacteristics', 'createBLEConnection', 'closeBLEConnection', 'onBeaconServiceChange', 'onBeaconUpdate', 'getBeacons', 'startBeaconDiscovery', 'stopBeaconDiscovery' ]; const keyboard = [ 'hideKeyboard', 'onKeyboardHeightChange' ]; const ui = [ 'showToast', 'hideToast', 'showLoading', 'hideLoading', 'showModal', 'showActionSheet', 'setNavigationBarTitle', 'setNavigationBarColor', 'showNavigationBarLoading', 'hideNavigationBarLoading', 'setTabBarItem', 'setTabBarStyle', 'hideTabBar', 'showTabBar', 'setTabBarBadge', 'removeTabBarBadge', 'showTabBarRedDot', 'hideTabBarRedDot', 'setBackgroundColor', 'setBackgroundTextStyle', 'createAnimation', 'pageScrollTo', 'onWindowResize', 'offWindowResize', 'loadFontFace', 'startPullDownRefresh', 'stopPullDownRefresh', 'createSelectorQuery', 'createIntersectionObserver' ]; const event = [ '$emit', '$on', '$once', '$off' ]; const file = [ 'saveFile', 'getSavedFileList', 'getSavedFileInfo', 'removeSavedFile', 'getFileInfo', 'openDocument', 'getFileSystemManager' ]; const canvas = [ 'createOffscreenCanvas', 'createCanvasContext', 'canvasToTempFilePath', 'canvasPutImageData', 'canvasGetImageData' ]; const third = [ 'getProvider', 'login', 'checkSession', 'getUserInfo', 'share', 'showShareMenu', 'hideShareMenu', 'requestPayment', 'subscribePush', 'unsubscribePush', 'onPush', 'offPush', 'requireNativePlugin', 'upx2px' ]; const apis = [ ...base, ...network, ...route, ...storage, ...location, ...media, ...device, ...keyboard, ...ui, ...event, ...file, ...canvas, ...third ]; var apis_1 = apis; /** * 框架内 try-catch */ function tryCatchFramework (fn) { return function () { try { return fn.apply(fn, arguments) } catch (e) { // TODO console.error(e); } } } /** * 开发者 try-catch */ function tryCatch (fn) { return function () { try { return fn.apply(fn, arguments) } catch (e) { // TODO console.error(e); } } } const HOOKS = [ 'invoke', 'success', 'fail', 'complete', 'returnValue' ]; const globalInterceptors = {}; const scopedInterceptors = {}; function mergeHook (parentVal, childVal) { const res = childVal ? parentVal ? parentVal.concat(childVal) : Array.isArray(childVal) ? childVal : [childVal] : parentVal; return res ? dedupeHooks(res) : res } function dedupeHooks (hooks) { const res = []; for (let i = 0; i < hooks.length; i++) { if (res.indexOf(hooks[i]) === -1) { res.push(hooks[i]); } } return res } function removeHook (hooks, hook) { const index = hooks.indexOf(hook); if (index !== -1) { hooks.splice(index, 1); } } function mergeInterceptorHook (interceptor, option) { Object.keys(option).forEach(hook => { if (HOOKS.indexOf(hook) !== -1 && isFn(option[hook])) { interceptor[hook] = mergeHook(interceptor[hook], option[hook]); } }); } function removeInterceptorHook (interceptor, option) { if (!interceptor || !option) { return } Object.keys(option).forEach(hook => { if (HOOKS.indexOf(hook) !== -1 && isFn(option[hook])) { removeHook(interceptor[hook], option[hook]); } }); } function addInterceptor (method, option) { if (typeof method === 'string' && isPlainObject(option)) { mergeInterceptorHook(scopedInterceptors[method] || (scopedInterceptors[method] = {}), option); } else if (isPlainObject(method)) { mergeInterceptorHook(globalInterceptors, method); } } function removeInterceptor (method, option) { if (typeof method === 'string') { if (isPlainObject(option)) { removeInterceptorHook(scopedInterceptors[method], option); } else { delete scopedInterceptors[method]; } } else if (isPlainObject(method)) { removeInterceptorHook(globalInterceptors, method); } } function wrapperHook (hook) { return function (data) { return hook(data) || data } } function isPromise (obj) { return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function' } function queue (hooks, data) { let promise = false; for (let i = 0; i < hooks.length; i++) { const hook = hooks[i]; if (promise) { promise = Promise.then(wrapperHook(hook)); } else { const res = hook(data); if (isPromise(res)) { promise = Promise.resolve(res); } if (res === false) { return { then () {} } } } } return promise || { then (callback) { return callback(data) } } } function wrapperOptions (interceptor, options = {}) { ['success', 'fail', 'complete'].forEach(name => { if (Array.isArray(interceptor[name])) { const oldCallback = options[name]; options[name] = function callbackInterceptor (res) { queue(interceptor[name], res).then((res) => { /* eslint-disable no-mixed-operators */ return isFn(oldCallback) && oldCallback(res) || res }); }; } }); return options } function wrapperReturnValue (method, returnValue) {