diff --git a/build/rollup.config.app.js b/build/rollup.config.app.js index f3b09216db2aa8ff1313dbb31a08c0750df33cca..e343eb8975ef12ecf43fff69ff459a8e41ae2e3e 100644 --- a/build/rollup.config.app.js +++ b/build/rollup.config.app.js @@ -1,6 +1,8 @@ const path = require('path') const alias = require('rollup-plugin-alias') const replace = require('rollup-plugin-replace') +const resolve = require('rollup-plugin-node-resolve') +const commonjs = require('rollup-plugin-commonjs') const requireContext = require('./rollup-plugin-require-context') let input = 'src/platforms/app-plus/service/uni/create-instance-context.js' @@ -25,6 +27,8 @@ module.exports = { input, output, plugins: [ + resolve(), + commonjs(), requireContext(), alias({ 'uni-core': path.resolve(__dirname, '../src/core'), diff --git a/package.json b/package.json index 65eac1fffe973b0d68912aaa3e8a7b294adfb431..b315fb6cbd0f5fc1463de2bf80ce38b1ba66e441 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,10 @@ "jsdom": "^13.0.0", "jsdom-global": "^3.0.2", "jsonfile": "^5.0.0", - "rollup": "^0.67.4", + "rollup": "^1.17.0", "rollup-plugin-alias": "^1.4.0", + "rollup-plugin-commonjs": "^10.0.1", + "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-replace": "^2.1.0", "strip-json-comments": "^2.0.1", "vue": "^2.6.8", @@ -108,4 +110,4 @@ "main": "index.js", "description": "", "author": "" -} +} diff --git a/packages/uni-app-plus-nvue/dist/index.js b/packages/uni-app-plus-nvue/dist/index.js index eed1a583ad2414659422204e8e46da329b33bda4..769f9fcb486830104dd6a1eeb7859301bce3df28 100644 --- a/packages/uni-app-plus-nvue/dist/index.js +++ b/packages/uni-app-plus-nvue/dist/index.js @@ -420,14 +420,25 @@ function initWebview (webview, instanceContext, routeOptions) { webview.setStyle(webviewStyle); } + + const { + on, + emit + } = instanceContext.UniServiceJSBridge; + // TODO subNVues Object.keys(WEBVIEW_LISTENERS).forEach(name => { webview.addEventListener(name, (e) => { - instanceContext.UniServiceJSBridge.emit(WEBVIEW_LISTENERS[name], e, parseInt(webview.id)); + emit(WEBVIEW_LISTENERS[name], e, parseInt(webview.id)); }); }); - instanceContext.UniServiceJSBridge.on(webview.id + '.stopPullDownRefresh', () => { + // TODO 应该结束之前未完成的下拉刷新 + on(webview.id + '.startPullDownRefresh', () => { + webview.beginPullToRefresh(); + }); + + on(webview.id + '.stopPullDownRefresh', () => { webview.endPullToRefresh(); }); @@ -469,7 +480,7 @@ function createHolder (webview, { const pages = []; -function getCurrentPages$1 () { +function getCurrentPages () { return pages } /** @@ -662,12 +673,173 @@ function initOn (on, { on('onWebInvokeAppService', onWebInvokeAppService); } +let waiting; +let waitingTimeout; +let toast = false; +let toastTimeout; + +function initPopup (on, { + plus +}) { + on('onShowToast', showToast); + on('onHideToast', hideToast); + on('onShowLoading', showToast); + on('onHideLoading', hideToast); + on('onShowModal', showModal); + on('onShowActionSheet', showActionSheet); + + function showToast ({ + title = '', + icon = 'success', + image = '', + duration = 1500, + mask = false, + position = '' + }) { + if (position) { + if (toast) { + toastTimeout && clearTimeout(toastTimeout); + plus.nativeUI.closeToast(); + } + if (waiting) { + waitingTimeout && clearTimeout(waitingTimeout); + waiting.close(); + } + if (~['top', 'center', 'bottom'].indexOf(position)) { + let richText = `${title}`; + plus.nativeUI.toast(richText, { + verticalAlign: position, + type: 'richtext' + }); + toast = true; + toastTimeout = setTimeout(() => { + hideToast(); + }, 2000); + return + } + console.warn('uni.showToast 传入的 "position" 值 "' + position + '" 无效'); + } + + if (duration) { + if (waiting) { + waitingTimeout && clearTimeout(waitingTimeout); + waiting.close(); + } + if (toast) { + toastTimeout && clearTimeout(toastTimeout); + plus.nativeUI.closeToast(); + } + if (icon && !~['success', 'loading', 'none'].indexOf(icon)) { + icon = 'success'; + } + const waitingOptions = { + modal: mask, + back: 'transmit', + padding: '10px', + size: '16px' // 固定字体大小 + }; + if (!image && (!icon || icon === 'none')) { // 无图 + // waitingOptions.width = '120px' + // waitingOptions.height = '40px' + waitingOptions.loading = { + display: 'none' + }; + } else { // 有图 + waitingOptions.width = '140px'; + waitingOptions.height = '112px'; + } + if (image) { + waitingOptions.loading = { + display: 'block', + height: '55px', + icon: image, + interval: duration + }; + } else { + if (icon === 'success') { + waitingOptions.loading = { + display: 'block', + height: '55px', + icon: '__uniappsuccess.png', + interval: duration + }; + } + } + + waiting = plus.nativeUI.showWaiting(title, waitingOptions); + waitingTimeout = setTimeout(() => { + hideToast(); + }, duration); + } + } + + function hideToast () { + if (toast) { + toastTimeout && clearTimeout(toastTimeout); + plus.nativeUI.closeToast(); + toast = false; + } + if (waiting) { + waitingTimeout && clearTimeout(waitingTimeout); + waiting.close(); + waiting = null; + waitingTimeout = null; + } + } + + function showModal ({ + title = '', + content = '', + showCancel = true, + cancelText = '取消', + cancelColor = '#000000', + confirmText = '确定', + confirmColor = '#3CC51F' + }, callback) { + plus.nativeUI.confirm(content, (e) => { + if (showCancel) { + callback(e.index === 1 ? 'confirm' : 'cancel'); + } else { + callback(e.index === 0 ? 'confirm' : 'cancel'); + } + }, title, showCancel ? [cancelText, confirmText] : [confirmText]); + } + + function showActionSheet ({ + itemList = [], + itemColor = '#000000', + title = '' + }, callback) { + const options = { + buttons: itemList.map(item => ({ + title: item + })) + }; + if (title) { + options.title = title; + } + + if (plus.os.name === 'iOS') { + options.cancel = '取消'; + } + + plus.nativeUI.actionSheet(options, (e) => { + if (e.index > 0) { + callback(e.index - 1); + } else { + callback(-1); + } + }); + } +} + let bridge; -function initServiceJSBridge (Vue, instanceContext) { +function initServiceJSBridge (Vue, instanceContext) { if (bridge) { return bridge } + const Emitter = new Vue(); bridge = { @@ -678,10 +850,13 @@ function initServiceJSBridge (Vue, instanceContext) { }; initOn(bridge.on, instanceContext); + initPopup(bridge.on, instanceContext); return bridge } +let uni$1; + function createInstanceContext (instanceContext) { const { weex, @@ -689,10 +864,25 @@ function createInstanceContext (instanceContext) { WeexPlus } = instanceContext; const plus = new WeexPlus(weex); + const UniServiceJSBridge = initServiceJSBridge(Vue, { + plus, getApp, - getCurrentPages: getCurrentPages$1 + getCurrentPages }); + + if (!uni$1) { + uni$1 = createUniInstance( + weex, + plus, + uniConfig, + uniRoutes, + UniServiceJSBridge, + getApp, + getCurrentPages + ); + } + return { __uniConfig: uniConfig, __uniRoutes: uniRoutes, @@ -706,17 +896,9 @@ function createInstanceContext (instanceContext) { return registerPage(page, instanceContext) }, plus, - uni: createUniInstance( - weex, - plus, - uniConfig, - uniRoutes, - UniServiceJSBridge, - getApp, - getCurrentPages$1 - ), + uni: uni$1, getApp, - getCurrentPages: getCurrentPages$1, + getCurrentPages, UniServiceJSBridge } } diff --git a/packages/uni-app-plus-nvue/dist/index.legacy.js b/packages/uni-app-plus-nvue/dist/index.legacy.js index 68180cebf2ee4f304d9c4ee791871bba4eff6049..523f33900a2dd77bc2f3596deddaf4befb0440c8 100644 --- a/packages/uni-app-plus-nvue/dist/index.legacy.js +++ b/packages/uni-app-plus-nvue/dist/index.legacy.js @@ -181,7 +181,7 @@ const CALLBACKS = [SUCCESS, FAIL, COMPLETE]; const UNIAPP_SERVICE_NVUE_ID = '__uniapp__service'; -function noop$1 () { +function noop () { } /** @@ -409,10 +409,10 @@ function initPostMessage (nvue) { function initTitleNView (nvue) { const eventMaps = { - onNavigationBarButtonTap: noop$1, - onNavigationBarSearchInputChanged: noop$1, - onNavigationBarSearchInputConfirmed: noop$1, - onNavigationBarSearchInputClicked: noop$1 + onNavigationBarButtonTap: noop, + onNavigationBarSearchInputChanged: noop, + onNavigationBarSearchInputConfirmed: noop, + onNavigationBarSearchInputClicked: noop }; nvue.requireModule('globalEvent').addEventListener('plusMessage', e => { if (eventMaps[e.data.type]) { diff --git a/packages/uni-app-plus-nvue/dist/uni.js b/packages/uni-app-plus-nvue/dist/uni.js index fdaeedbd88beceb64642bf2d4c02b5db143bcba6..84f5568eec274dfa21f55f3d7e61898bb57b90f5 100644 --- a/packages/uni-app-plus-nvue/dist/uni.js +++ b/packages/uni-app-plus-nvue/dist/uni.js @@ -51,9 +51,85 @@ function tryCatch (fn) { } } +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 @@ -150,7 +226,20 @@ function invokeApi (method, api, options, ...params) { } } return api(options, ...params) -} +} + +const promiseInterceptor = { + returnValue (res) { + if (!isPromise(res)) { + return res + } + return res.then(res => { + return res[1] + }).catch(res => { + return res[0] + }) + } +}; const SYNC_API_RE = /^\$|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; @@ -1766,6 +1855,313 @@ function wrapper (name, invokeMethod, extras) { } } +// 尽早将 invokeCallbackHandler 挂在 UniServiceJSBridge 中 +UniServiceJSBridge.invokeCallbackHandler = invokeCallbackHandler; + +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; + +const base64ToArrayBuffer$1 = base64Arraybuffer_2; +const arrayBufferToBase64$1 = base64Arraybuffer_1; + +var platformSchema = {}; + +// TODO 待处理其他 API 的检测 + +function canIUse$1 (schema) { + if (hasOwn(platformSchema, schema)) { + return platformSchema[schema] + } + return true +} + +const interceptors = { + promiseInterceptor +}; + +/** + * 查看位置 + * @param {*} param0 + * @param {*} callbackId + */ +function openLocation$1 ({ + latitude, + longitude, + scale, + name, + address +}, callbackId) { + const { + invokeCallbackHandler: invoke + } = UniServiceJSBridge; + + getApp().$router.push({ + type: 'navigateTo', + path: '/open-location', + query: { + latitude, + longitude, + scale, + name, + address + } + }, function () { + invoke(callbackId, { + errMsg: 'openLocation:ok' + }); + }, function () { + invoke(callbackId, { + errMsg: 'openLocation:fail' + }); + }); +} +/** + * 选择位置 + * @param {*} callbackId + */ +function chooseLocation (options, callbackId) { + const { + invokeCallbackHandler: invoke + } = UniServiceJSBridge; + getApp().$router.push({ + type: 'navigateTo', + path: '/choose-location' + }, function () { + var fn = data => { + UniServiceJSBridge.unsubscribe('onChooseLocation', fn); + if (data) { + invoke(callbackId, Object.assign(data, { + errMsg: 'chooseLocation:ok' + })); + } else { + invoke(callbackId, { + errMsg: 'chooseLocation:fail' + }); + } + }; + UniServiceJSBridge.subscribe('onChooseLocation', fn); + }, function () { + invoke(callbackId, { + errMsg: 'chooseLocation:fail' + }); + }); +} + +function setNavigationBar (type, args) { + const pages = getCurrentPages(); + if (pages.length) { + const page = pages[pages.length - 1].$holder; + + switch (type) { + case 'setNavigationBarColor': + const { + frontColor, + backgroundColor, + animation + } = args; + + const { + duration, + timingFunc + } = animation; + + if (frontColor) { + page.navigationBar.textColor = frontColor === '#000000' ? 'black' : 'white'; + } + if (backgroundColor) { + page.navigationBar.backgroundColor = backgroundColor; + } + page.navigationBar.duration = duration + 'ms'; + page.navigationBar.timingFunc = timingFunc; + break + case 'showNavigationBarLoading': + page.navigationBar.loading = true; + break + case 'hideNavigationBarLoading': + page.navigationBar.loading = false; + break + case 'setNavigationBarTitle': + const { + title + } = args; + page.navigationBar.titleText = title; + break + } + } + return {} +} + +function setNavigationBarColor$1 (args) { + return setNavigationBar('setNavigationBarColor', args) +} + +function showNavigationBarLoading () { + return setNavigationBar('showNavigationBarLoading') +} + +function hideNavigationBarLoading () { + return setNavigationBar('hideNavigationBarLoading') +} + +function setNavigationBarTitle$1 (args) { + return setNavigationBar('setNavigationBarTitle', args) +} + +function pageScrollTo$1 (args) { + const pages = getCurrentPages(); + if (pages.length) { + UniServiceJSBridge.publishHandler('pageScrollTo', args, pages[pages.length - 1].$page.id); + } + return {} +} + +let pageId; + +function startPullDownRefresh () { + if (pageId) { + UniServiceJSBridge.emit(pageId + '.stopPullDownRefresh', {}, pageId); + } + const pages = getCurrentPages(); + if (pages.length) { + pageId = pages[pages.length - 1].$page.id; + UniServiceJSBridge.emit(pageId + '.startPullDownRefresh', {}, pageId); + } + return {} +} + +function stopPullDownRefresh () { + if (pageId) { + UniServiceJSBridge.emit(pageId + '.stopPullDownRefresh', {}, pageId); + pageId = null; + } else { + const pages = getCurrentPages(); + if (pages.length) { + pageId = pages[pages.length - 1].$page.id; + UniServiceJSBridge.emit(pageId + '.stopPullDownRefresh', {}, pageId); + } + } + return {} +} + +const { + emit, + invokeCallbackHandler: invoke +} = UniServiceJSBridge; + +function showModal$1 (args, callbackId) { + emit('onShowModal', args, function (type) { + invoke(callbackId, { + [type]: true + }); + }); +} + +function showToast$1 (args) { + emit('onShowToast', args); + return {} +} + +function hideToast () { + emit('onHideToast'); + return {} +} + +function showLoading$1 (args) { + emit('onShowLoading', args); + return {} +} + +function hideLoading () { + emit('onHideLoading'); + return {} +} + +function showActionSheet$1 (args, callbackId) { + emit('onShowActionSheet', args, function (tapIndex) { + if (tapIndex === -1) { + invoke(callbackId, { + errMsg: 'showActionSheet:fail cancel' + }); + } else { + invoke(callbackId, { + tapIndex + }); + } + }); +} + function hasLifecycleHook (vueOptions = {}, hook) { return Array.isArray(vueOptions[hook]) && vueOptions[hook].length } @@ -1856,100 +2252,157 @@ function switchTab$1 (args) { return onAppRoute('switchTab', args) } -function pageScrollTo$1 (args) { - const pages = getCurrentPages(); - if (pages.length) { - UniServiceJSBridge.publishHandler('pageScrollTo', args, pages[pages.length - 1].$page.id); +function getStorageHolder () { + return plus.storage +} + +function setStorage$1 ({ + key, + data +} = {}) { + const storageHolder = getStorageHolder(); + const value = { + type: typeof data === 'object' ? 'object' : 'string', + data: data + }; + storageHolder.setItem(key, JSON.stringify(value)); + const keyList = storageHolder.getItem('uni-storage-keys'); + if (!keyList) { + storageHolder.setItem('uni-storage-keys', JSON.stringify([key])); + } else { + const keys = JSON.parse(keyList); + if (keys.indexOf(key) < 0) { + keys.push(key); + storageHolder.setItem('uni-storage-keys', JSON.stringify(keys)); + } + } + return { + errMsg: 'setStorage:ok' } - return {} } -let pageId; +function setStorageSync$1 (key, data) { + setStorage$1({ + key, + data + }); +} -function startPullDownRefresh () { - if (pageId) { - UniServiceJSBridge.emit(pageId + '.stopPullDownRefresh', {}, pageId); - } - const pages = getCurrentPages(); - if (pages.length) { - pageId = pages[pages.length - 1].$page.id; - UniServiceJSBridge.emit(pageId + '.startPullDownRefresh', {}, pageId); +function getStorage ({ + key +} = {}) { + const data = getStorageHolder().getItem(key); + return data ? { + data: JSON.parse(data).data, + errMsg: 'getStorage:ok' + } : { + data: '', + errMsg: 'getStorage:fail' } - return {} } -function stopPullDownRefresh () { - if (pageId) { - UniServiceJSBridge.emit(pageId + '.stopPullDownRefresh', {}, pageId); - pageId = null; - } else { - const pages = getCurrentPages(); - if (pages.length) { - pageId = pages[pages.length - 1].$page.id; - UniServiceJSBridge.emit(pageId + '.stopPullDownRefresh', {}, pageId); - } +function getStorageSync (key) { + const res = getStorage({ + key + }); + return res.data +} + +function removeStorage ({ + key +} = {}) { + const storageHolder = getStorageHolder(); + const keyList = storageHolder.getItem('uni-storage-keys'); + if (keyList) { + const keys = JSON.parse(keyList); + const index = keys.indexOf(key); + keys.splice(index, 1); + storageHolder.setItem('uni-storage-keys', JSON.stringify(keys)); + } + storageHolder.removeItem(key); + return { + errMsg: 'removeStorage:ok' } - return {} -} - -function setNavigationBar (type, args) { - const pages = getCurrentPages(); - if (pages.length) { - const page = pages[pages.length - 1].$holder; +} - switch (type) { - case 'setNavigationBarColor': - const { - frontColor, - backgroundColor, - animation - } = args; - - const { - duration, - timingFunc - } = animation; +function removeStorageSync (key) { + removeStorage({ + key + }); +} - if (frontColor) { - page.navigationBar.textColor = frontColor === '#000000' ? 'black' : 'white'; - } - if (backgroundColor) { - page.navigationBar.backgroundColor = backgroundColor; - } - page.navigationBar.duration = duration + 'ms'; - page.navigationBar.timingFunc = timingFunc; - break - case 'showNavigationBarLoading': - page.navigationBar.loading = true; - break - case 'hideNavigationBarLoading': - page.navigationBar.loading = false; - break - case 'setNavigationBarTitle': - const { - title - } = args; - page.navigationBar.titleText = title; - break - } +function clearStorage () { + getStorageHolder().clear(); + return { + errMsg: 'clearStorage:ok' } - return {} -} +} -function setNavigationBarColor$1 (args) { - return setNavigationBar('setNavigationBarColor', args) +function clearStorageSync () { + clearStorage(); } -function showNavigationBarLoading () { - return setNavigationBar('showNavigationBarLoading') +function getStorageInfo () { // TODO 暂时先不做大小的转换 + const keyList = getStorageHolder().getItem('uni-storage-keys'); + return keyList ? { + keys: JSON.parse(keyList), + currentSize: 0, + limitSize: 0, + errMsg: 'getStorageInfo:ok' + } : { + keys: '', + currentSize: 0, + limitSize: 0, + errMsg: 'getStorageInfo:fail' + } } -function hideNavigationBarLoading () { - return setNavigationBar('hideNavigationBarLoading') +function getStorageInfoSync () { + const res = getStorageInfo(); + delete res.errMsg; + return res +} + +const EPS = 1e-4; +const BASE_DEVICE_WIDTH = 750; +let isIOS = false; +let deviceWidth = 0; +let deviceDPR = 0; + +function checkDeviceWidth () { + const { + platform, + pixelRatio, + windowWidth + } = uni.getSystemInfoSync(); + + deviceWidth = windowWidth; + deviceDPR = pixelRatio; + isIOS = platform === 'ios'; } -function setNavigationBarTitle$1 (args) { - return setNavigationBar('setNavigationBarTitle', args) +function upx2px (number, newDeviceWidth) { + if (deviceWidth === 0) { + checkDeviceWidth(); + } + + number = Number(number); + if (number === 0) { + return 0 + } + let result = (number / BASE_DEVICE_WIDTH) * (newDeviceWidth || deviceWidth); + if (result < 0) { + result = -result; + } + result = Math.floor(result + EPS); + if (result === 0) { + if (deviceDPR === 1 || !isIOS) { + return 1 + } else { + return 0.5 + } + } + return number < 0 ? -result : result } @@ -1958,15 +2411,41 @@ var api = /*#__PURE__*/Object.freeze({ pageScrollTo: pageScrollTo$1, startPullDownRefresh: startPullDownRefresh, stopPullDownRefresh: stopPullDownRefresh, + base64ToArrayBuffer: base64ToArrayBuffer$1, + arrayBufferToBase64: arrayBufferToBase64$1, + canIUse: canIUse$1, + interceptors: interceptors, + addInterceptor: addInterceptor, + removeInterceptor: removeInterceptor, + openLocation: openLocation$1, + chooseLocation: chooseLocation, + setNavigationBarColor: setNavigationBarColor$1, + showNavigationBarLoading: showNavigationBarLoading, + hideNavigationBarLoading: hideNavigationBarLoading, + setNavigationBarTitle: setNavigationBarTitle$1, + showModal: showModal$1, + showToast: showToast$1, + hideToast: hideToast, + showLoading: showLoading$1, + hideLoading: hideLoading, + showActionSheet: showActionSheet$1, redirectTo: redirectTo$1, navigateTo: navigateTo$1, navigateBack: navigateBack$1, reLaunch: reLaunch$1, switchTab: switchTab$1, - setNavigationBarColor: setNavigationBarColor$1, - showNavigationBarLoading: showNavigationBarLoading, - hideNavigationBarLoading: hideNavigationBarLoading, - setNavigationBarTitle: setNavigationBarTitle$1 + setStorage: setStorage$1, + setStorageSync: setStorageSync$1, + getStorage: getStorage, + getStorageSync: getStorageSync, + removeStorage: removeStorage, + removeStorageSync: removeStorageSync, + clearStorage: clearStorage, + clearStorageSync: clearStorageSync, + getStorageInfo: getStorageInfo, + getStorageInfoSync: getStorageInfoSync, + checkDeviceWidth: checkDeviceWidth, + upx2px: upx2px }); const uni$1 = Object.create(null); diff --git a/src/core/service/api/storage.js b/src/core/service/api/storage.js index 17ae98136fc0330e83ddd31ac319c099f0312867..acfa7de880e8cd73afb0057dd25f3e34fba78c5c 100644 --- a/src/core/service/api/storage.js +++ b/src/core/service/api/storage.js @@ -1,20 +1,28 @@ +function getStorageHolder () { + if (__PLATFORM__ === 'h5') { + return localStorage + } + return plus.storage +} + export function setStorage ({ key, data } = {}) { - let value = { + const storageHolder = getStorageHolder() + const value = { type: typeof data === 'object' ? 'object' : 'string', data: data } - localStorage.setItem(key, JSON.stringify(value)) - let keyList = localStorage.getItem('uni-storage-keys') + storageHolder.setItem(key, JSON.stringify(value)) + const keyList = storageHolder.getItem('uni-storage-keys') if (!keyList) { - localStorage.setItem('uni-storage-keys', JSON.stringify([key])) + storageHolder.setItem('uni-storage-keys', JSON.stringify([key])) } else { - let keys = JSON.parse(keyList) + const keys = JSON.parse(keyList) if (keys.indexOf(key) < 0) { keys.push(key) - localStorage.setItem('uni-storage-keys', JSON.stringify(keys)) + storageHolder.setItem('uni-storage-keys', JSON.stringify(keys)) } } return { @@ -23,13 +31,16 @@ export function setStorage ({ } export function setStorageSync (key, data) { - setStorage({ key, data }) + setStorage({ + key, + data + }) } export function getStorage ({ key } = {}) { - let data = localStorage.getItem(key) + const data = getStorageHolder().getItem(key) return data ? { data: JSON.parse(data).data, errMsg: 'getStorage:ok' @@ -40,42 +51,48 @@ export function getStorage ({ } export function getStorageSync (key) { - const res = getStorage({ key }) + const res = getStorage({ + key + }) return res.data } export function removeStorage ({ key } = {}) { - let keyList = localStorage.getItem('uni-storage-keys') + const storageHolder = getStorageHolder() + const keyList = storageHolder.getItem('uni-storage-keys') if (keyList) { - let keys = JSON.parse(keyList) - let index = keys.indexOf(key) + const keys = JSON.parse(keyList) + const index = keys.indexOf(key) keys.splice(index, 1) - localStorage.setItem('uni-storage-keys', JSON.stringify(keys)) + storageHolder.setItem('uni-storage-keys', JSON.stringify(keys)) } - localStorage.removeItem(key) + storageHolder.removeItem(key) return { errMsg: 'removeStorage:ok' } } export function removeStorageSync (key) { - removeStorage({ key }) + removeStorage({ + key + }) } export function clearStorage () { - localStorage.clear() + getStorageHolder().clear() return { errMsg: 'clearStorage:ok' } } + export function clearStorageSync () { clearStorage() } export function getStorageInfo () { // TODO 暂时先不做大小的转换 - let keyList = localStorage.getItem('uni-storage-keys') + const keyList = getStorageHolder().getItem('uni-storage-keys') return keyList ? { keys: JSON.parse(keyList), currentSize: 0, @@ -93,4 +110,4 @@ export function getStorageInfoSync () { const res = getStorageInfo() delete res.errMsg return res -} +} diff --git a/src/platforms/app-plus-nvue/helpers/can-i-use.js b/src/platforms/app-plus-nvue/helpers/can-i-use.js new file mode 100644 index 0000000000000000000000000000000000000000..b1c6ea436a540020ff61f01dea449d5b39367b27 --- /dev/null +++ b/src/platforms/app-plus-nvue/helpers/can-i-use.js @@ -0,0 +1 @@ +export default {} diff --git a/src/platforms/app-plus/helpers/can-i-use.js b/src/platforms/app-plus/helpers/can-i-use.js new file mode 100644 index 0000000000000000000000000000000000000000..b1c6ea436a540020ff61f01dea449d5b39367b27 --- /dev/null +++ b/src/platforms/app-plus/helpers/can-i-use.js @@ -0,0 +1 @@ +export default {} diff --git a/src/platforms/app-plus/service/uni/api.js b/src/platforms/app-plus/service/uni/api.js index 302e59bd175d67d9d819e278d375013645eaa55a..105621699f23564a2ee98648edf941b5222d62cc 100644 --- a/src/platforms/app-plus/service/uni/api.js +++ b/src/platforms/app-plus/service/uni/api.js @@ -1,10 +1,17 @@ -export * from 'uni-core/service/api/route' - +export * from 'uni-core/service/api/base64' +export * from 'uni-core/service/api/can-i-use' +export * from 'uni-core/service/api/interceptor' +export * from 'uni-core/service/api/location' +export * from 'uni-core/service/api/navigation-bar' + export { pageScrollTo, startPullDownRefresh, stopPullDownRefresh } - from 'uni-core/service/api/page-event' - -export * from 'uni-core/service/api/navigation-bar' + from 'uni-core/service/api/page-event' + +export * from 'uni-core/service/api/popup' +export * from 'uni-core/service/api/route' +export * from 'uni-core/service/api/storage' +export * from 'uni-core/service/api/upx2px' diff --git a/src/platforms/app-plus/service/uni/bridge.js b/src/platforms/app-plus/service/uni/bridge.js index 665c9b531345a4a42aff826132a4b60d111603b2..08f216e57689f6b2c234ba9ef0f2afe6ad3d01c7 100644 --- a/src/platforms/app-plus/service/uni/bridge.js +++ b/src/platforms/app-plus/service/uni/bridge.js @@ -1,11 +1,13 @@ import initOn from 'uni-core/service/bridge/on' +import initPopup from './popup' let bridge -export function initServiceJSBridge (Vue, instanceContext) { +export function initServiceJSBridge (Vue, instanceContext) { if (bridge) { return bridge } + const Emitter = new Vue() bridge = { @@ -16,6 +18,7 @@ export function initServiceJSBridge (Vue, instanceContext) { } initOn(bridge.on, instanceContext) + initPopup(bridge.on, instanceContext) return bridge } diff --git a/src/platforms/app-plus/service/uni/create-instance-context.js b/src/platforms/app-plus/service/uni/create-instance-context.js index b3bc76920b45418c585720d1eab29620109b1613..82a6110ebcf95699349d372c86459b7f23d49ce1 100644 --- a/src/platforms/app-plus/service/uni/create-instance-context.js +++ b/src/platforms/app-plus/service/uni/create-instance-context.js @@ -22,6 +22,8 @@ import { initServiceJSBridge } from './bridge' +let uni + export function createInstanceContext (instanceContext) { const { weex, @@ -29,10 +31,25 @@ export function createInstanceContext (instanceContext) { WeexPlus } = instanceContext const plus = new WeexPlus(weex) + const UniServiceJSBridge = initServiceJSBridge(Vue, { + plus, getApp, getCurrentPages }) + + if (!uni) { + uni = createUniInstance( + weex, + plus, + uniConfig, + uniRoutes, + UniServiceJSBridge, + getApp, + getCurrentPages + ) + } + return { __uniConfig: uniConfig, __uniRoutes: uniRoutes, @@ -46,15 +63,7 @@ export function createInstanceContext (instanceContext) { return registerPage(page, instanceContext) }, plus, - uni: createUniInstance( - weex, - plus, - uniConfig, - uniRoutes, - UniServiceJSBridge, - getApp, - getCurrentPages - ), + uni, getApp, getCurrentPages, UniServiceJSBridge diff --git a/src/platforms/app-plus/service/uni/index.js b/src/platforms/app-plus/service/uni/index.js index 3acaa391d582c78122b5ebe85eaaab210a3a0cb2..c4a218f282a6cb3345aa69ca456cbc670d4a471c 100644 --- a/src/platforms/app-plus/service/uni/index.js +++ b/src/platforms/app-plus/service/uni/index.js @@ -1,3 +1,5 @@ +import './polyfill' + import { wrapper } from 'uni-helpers/api' diff --git a/src/platforms/app-plus/service/uni/polyfill.js b/src/platforms/app-plus/service/uni/polyfill.js new file mode 100644 index 0000000000000000000000000000000000000000..c00b2505d610eb20f6f6a70069a448e8fdacd649 --- /dev/null +++ b/src/platforms/app-plus/service/uni/polyfill.js @@ -0,0 +1,5 @@ +import { + invokeCallbackHandler +} from 'uni-helpers/api' +// 尽早将 invokeCallbackHandler 挂在 UniServiceJSBridge 中 +UniServiceJSBridge.invokeCallbackHandler = invokeCallbackHandler diff --git a/src/platforms/app-plus/service/uni/popup.js b/src/platforms/app-plus/service/uni/popup.js new file mode 100644 index 0000000000000000000000000000000000000000..1bd1a3c27506313a91ac3af0319f8e20ed18ebcb --- /dev/null +++ b/src/platforms/app-plus/service/uni/popup.js @@ -0,0 +1,159 @@ +let waiting +let waitingTimeout +let toast = false +let toastTimeout + +export default function initPopup (on, { + plus +}) { + on('onShowToast', showToast) + on('onHideToast', hideToast) + on('onShowLoading', showToast) + on('onHideLoading', hideToast) + on('onShowModal', showModal) + on('onShowActionSheet', showActionSheet) + + function showToast ({ + title = '', + icon = 'success', + image = '', + duration = 1500, + mask = false, + position = '' + }) { + if (position) { + if (toast) { + toastTimeout && clearTimeout(toastTimeout) + plus.nativeUI.closeToast() + } + if (waiting) { + waitingTimeout && clearTimeout(waitingTimeout) + waiting.close() + } + if (~['top', 'center', 'bottom'].indexOf(position)) { + let richText = `${title}` + plus.nativeUI.toast(richText, { + verticalAlign: position, + type: 'richtext' + }) + toast = true + toastTimeout = setTimeout(() => { + hideToast() + }, 2000) + return + } + console.warn('uni.showToast 传入的 "position" 值 "' + position + '" 无效') + } + + if (duration) { + if (waiting) { + waitingTimeout && clearTimeout(waitingTimeout) + waiting.close() + } + if (toast) { + toastTimeout && clearTimeout(toastTimeout) + plus.nativeUI.closeToast() + } + if (icon && !~['success', 'loading', 'none'].indexOf(icon)) { + icon = 'success' + } + const waitingOptions = { + modal: mask, + back: 'transmit', + padding: '10px', + size: '16px' // 固定字体大小 + } + if (!image && (!icon || icon === 'none')) { // 无图 + // waitingOptions.width = '120px' + // waitingOptions.height = '40px' + waitingOptions.loading = { + display: 'none' + } + } else { // 有图 + waitingOptions.width = '140px' + waitingOptions.height = '112px' + } + if (image) { + waitingOptions.loading = { + display: 'block', + height: '55px', + icon: image, + interval: duration + } + } else { + if (icon === 'success') { + waitingOptions.loading = { + display: 'block', + height: '55px', + icon: '__uniappsuccess.png', + interval: duration + } + } + } + + waiting = plus.nativeUI.showWaiting(title, waitingOptions) + waitingTimeout = setTimeout(() => { + hideToast() + }, duration) + } + } + + function hideToast () { + if (toast) { + toastTimeout && clearTimeout(toastTimeout) + plus.nativeUI.closeToast() + toast = false + } + if (waiting) { + waitingTimeout && clearTimeout(waitingTimeout) + waiting.close() + waiting = null + waitingTimeout = null + } + } + + function showModal ({ + title = '', + content = '', + showCancel = true, + cancelText = '取消', + cancelColor = '#000000', + confirmText = '确定', + confirmColor = '#3CC51F' + }, callback) { + plus.nativeUI.confirm(content, (e) => { + if (showCancel) { + callback(e.index === 1 ? 'confirm' : 'cancel') + } else { + callback(e.index === 0 ? 'confirm' : 'cancel') + } + }, title, showCancel ? [cancelText, confirmText] : [confirmText]) + } + + function showActionSheet ({ + itemList = [], + itemColor = '#000000', + title = '' + }, callback) { + const options = { + buttons: itemList.map(item => ({ + title: item + })) + } + if (title) { + options.title = title + } + + if (plus.os.name === 'iOS') { + options.cancel = '取消' + } + + plus.nativeUI.actionSheet(options, (e) => { + if (e.index > 0) { + callback(e.index - 1) + } else { + callback(-1) + } + }) + } +} diff --git a/src/platforms/app-plus/service/uni/webview/index.js b/src/platforms/app-plus/service/uni/webview/index.js index 01da64691418d7cce91f6e08c3c5e01f56372a0a..020d9fbe59b5a65147ce967617ba92634176a862 100644 --- a/src/platforms/app-plus/service/uni/webview/index.js +++ b/src/platforms/app-plus/service/uni/webview/index.js @@ -54,14 +54,25 @@ export function initWebview (webview, instanceContext, routeOptions) { webview.setStyle(webviewStyle) } + + const { + on, + emit + } = instanceContext.UniServiceJSBridge + // TODO subNVues Object.keys(WEBVIEW_LISTENERS).forEach(name => { webview.addEventListener(name, (e) => { - instanceContext.UniServiceJSBridge.emit(WEBVIEW_LISTENERS[name], e, parseInt(webview.id)) + emit(WEBVIEW_LISTENERS[name], e, parseInt(webview.id)) }) }) - instanceContext.UniServiceJSBridge.on(webview.id + '.stopPullDownRefresh', () => { + // TODO 应该结束之前未完成的下拉刷新 + on(webview.id + '.startPullDownRefresh', () => { + webview.beginPullToRefresh() + }) + + on(webview.id + '.stopPullDownRefresh', () => { webview.endPullToRefresh() }) diff --git a/yarn.lock b/yarn.lock index bd05bc13c33d253de11cc86e03073c14496d5005..3426110527d3e7e872fc73bcc02f23d020639db7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -695,6 +695,10 @@ version "12.6.2" resolved "https://registry.npm.taobao.org/@types/node/download/@types/node-12.6.2.tgz?cache=0&sync_timestamp=1562715341943&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-12.6.2.tgz#a5ccec6abb6060d5f20d256fb03ed743e9774999" +"@types/node@^12.6.2": + version "12.6.8" + resolved "https://registry.npm.taobao.org/@types/node/download/@types/node-12.6.8.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-12.6.8.tgz#e469b4bf9d1c9832aee4907ba8a051494357c12c" + "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.npm.taobao.org/@types/normalize-package-data/download/@types/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" @@ -703,6 +707,12 @@ version "1.5.2" resolved "https://registry.npm.taobao.org/@types/q/download/@types/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" +"@types/resolve@0.0.8": + version "0.0.8" + resolved "https://registry.npm.taobao.org/@types/resolve/download/@types/resolve-0.0.8.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fresolve%2Fdownload%2F%40types%2Fresolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" + dependencies: + "@types/node" "*" + "@vue/babel-helper-vue-jsx-merge-props@^1.0.0": version "1.0.0" resolved "https://registry.npm.taobao.org/@vue/babel-helper-vue-jsx-merge-props/download/@vue/babel-helper-vue-jsx-merge-props-1.0.0.tgz#048fe579958da408fb7a8b2a3ec050b50a661040" @@ -1767,6 +1777,10 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" +builtin-modules@^3.1.0: + version "3.1.0" + resolved "https://registry.npm.taobao.org/builtin-modules/download/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484" + builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.npm.taobao.org/builtin-status-codes/download/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" @@ -4480,6 +4494,10 @@ is-glob@^4.0.0, is-glob@^4.0.1: dependencies: is-extglob "^2.1.1" +is-module@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/is-module/download/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" + is-number@^3.0.0: version "3.0.0" resolved "https://registry.npm.taobao.org/is-number/download/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -4524,6 +4542,12 @@ is-promise@^2.1.0: version "2.1.0" resolved "https://registry.npm.taobao.org/is-promise/download/is-promise-2.1.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-promise%2Fdownload%2Fis-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" +is-reference@^1.1.2: + version "1.1.3" + resolved "https://registry.npm.taobao.org/is-reference/download/is-reference-1.1.3.tgz#e99059204b66fdbe09305cfca715a29caa5c8a51" + dependencies: + "@types/estree" "0.0.39" + is-regex@^1.0.4: version "1.0.4" resolved "https://registry.npm.taobao.org/is-regex/download/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" @@ -6670,7 +6694,7 @@ resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.npm.taobao.org/resolve-url/download/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" -resolve@^1.10.0, resolve@^1.11.0, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.8.1: +resolve@^1.10.0, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.8.1: version "1.11.1" resolved "https://registry.npm.taobao.org/resolve/download/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" dependencies: @@ -6722,6 +6746,26 @@ rollup-plugin-alias@^1.4.0: dependencies: slash "^3.0.0" +rollup-plugin-commonjs@^10.0.1: + version "10.0.1" + resolved "https://registry.npm.taobao.org/rollup-plugin-commonjs/download/rollup-plugin-commonjs-10.0.1.tgz#fbfcadf4ce2e826068e056a9f5c19287d9744ddf" + dependencies: + estree-walker "^0.6.1" + is-reference "^1.1.2" + magic-string "^0.25.2" + resolve "^1.11.0" + rollup-pluginutils "^2.8.1" + +rollup-plugin-node-resolve@^5.2.0: + version "5.2.0" + resolved "https://registry.npm.taobao.org/rollup-plugin-node-resolve/download/rollup-plugin-node-resolve-5.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frollup-plugin-node-resolve%2Fdownload%2Frollup-plugin-node-resolve-5.2.0.tgz#730f93d10ed202473b1fb54a5997a7db8c6d8523" + dependencies: + "@types/resolve" "0.0.8" + builtin-modules "^3.1.0" + is-module "^1.0.0" + resolve "^1.11.1" + rollup-pluginutils "^2.8.1" + rollup-plugin-replace@^2.1.0: version "2.2.0" resolved "https://registry.npm.taobao.org/rollup-plugin-replace/download/rollup-plugin-replace-2.2.0.tgz#f41ae5372e11e7a217cde349c8b5d5fd115e70e3" @@ -6729,18 +6773,19 @@ rollup-plugin-replace@^2.1.0: magic-string "^0.25.2" rollup-pluginutils "^2.6.0" -rollup-pluginutils@^2.6.0: +rollup-pluginutils@^2.6.0, rollup-pluginutils@^2.8.1: version "2.8.1" resolved "https://registry.npm.taobao.org/rollup-pluginutils/download/rollup-pluginutils-2.8.1.tgz#8fa6dd0697344938ef26c2c09d2488ce9e33ce97" dependencies: estree-walker "^0.6.1" -rollup@^0.67.4: - version "0.67.4" - resolved "https://registry.npm.taobao.org/rollup/download/rollup-0.67.4.tgz#8ed6b0993337f84ec8a0387f824fa6c197e833ec" +rollup@^1.17.0: + version "1.17.0" + resolved "https://registry.npm.taobao.org/rollup/download/rollup-1.17.0.tgz#47ee8b04514544fc93b39bae06271244c8db7dfa" dependencies: "@types/estree" "0.0.39" - "@types/node" "*" + "@types/node" "^12.6.2" + acorn "^6.2.0" run-async@^2.2.0: version "2.3.0"