@dcloudio/uni-app-plus-nvue
Version:
uni-app app-plus-nvue
1,891 lines (1,677 loc) • 237 kB
JavaScript
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) {