提交 4d6768e7 编写于 作者: fxy060608's avatar fxy060608

feat: preloadPage

上级 fe19f569
......@@ -204,7 +204,8 @@ const third = [
'getCurrentSubNVue',
'setPageMeta',
'onNativeEventReceive',
'sendNativeEvent'
'sendNativeEvent',
'preloadPage'
]
const ad = [
......
......@@ -215,7 +215,8 @@ var serviceContext = (function () {
'getCurrentSubNVue',
'setPageMeta',
'onNativeEventReceive',
'sendNativeEvent'
'sendNativeEvent',
'preloadPage'
];
const ad = [
......@@ -1625,7 +1626,7 @@ var serviceContext = (function () {
getProvider: getProvider
});
function encodeQueryString (url) {
function encodeQueryString(url) {
if (typeof url !== 'string') {
return url
}
......@@ -1648,9 +1649,9 @@ var serviceContext = (function () {
query.split('&').forEach(param => {
const parts = param.replace(/\+/g, ' ').split('=');
const key = parts.shift();
const val = parts.length > 0
? parts.join('=')
: '';
const val = parts.length > 0 ?
parts.join('=') :
'';
params.push(key + '=' + encodeURIComponent(val));
});
......@@ -1658,8 +1659,8 @@ var serviceContext = (function () {
return params.length ? url + '?' + params.join('&') : url
}
function createValidator (type) {
return function validator (url, params) {
function createValidator(type) {
return function validator(url, params) {
// 格式化为绝对路径路由
url = getRealRoute(url);
......@@ -1687,7 +1688,7 @@ var serviceContext = (function () {
// switchTab不允许传递参数,reLaunch到一个tabBar页面是可以的
if (
type === 'switchTab' &&
(type === 'switchTab' || type === 'preloadPage') &&
routeOptions.meta.isTabBar &&
params.openType !== 'appLaunch'
) {
......@@ -1702,6 +1703,22 @@ var serviceContext = (function () {
// 参数格式化
params.url = encodeQueryString(url);
if (type === 'preloadPage') {
{
if (!routeOptions.meta.isNVue) {
return 'can not preload vue page'
}
}
if (routeOptions.meta.isTabBar) {
const pages = getCurrentPages(true);
const tabBarPagePath = (routeOptions.alias || routeOptions.path).substr(1);
if (pages.find(page => page.route === tabBarPagePath)) {
return 'tabBar page `' + tabBarPagePath + '` already exists'
}
}
return
}
// 主要拦截目标为用户快速点击时触发的多次跳转,该情况,通常前后 url 是一样的
if (navigatorLock === url) {
return `${navigatorLock} locked`
......@@ -1716,24 +1733,24 @@ var serviceContext = (function () {
let navigatorLock;
function createProtocol (type, extras = {}) {
function createProtocol(type, extras = {}) {
return Object.assign({
url: {
type: String,
required: true,
validator: createValidator(type)
},
beforeAll () {
beforeAll() {
navigatorLock = '';
}
}, extras)
}
function createAnimationProtocol (animationTypes) {
function createAnimationProtocol(animationTypes) {
return {
animationType: {
type: String,
validator (type) {
validator(type) {
if (type && animationTypes.indexOf(type) === -1) {
return '`' + type + '` is not supported for `animationType` (supported values are: `' + animationTypes.join(
'`|`') + '`)'
......@@ -1769,7 +1786,7 @@ var serviceContext = (function () {
const navigateBack = Object.assign({
delta: {
type: Number,
validator (delta, params) {
validator(delta, params) {
delta = parseInt(delta) || 1;
params.delta = Math.min(getCurrentPages().length - 1, delta);
}
......@@ -1786,7 +1803,15 @@ var serviceContext = (function () {
'pop-out',
'none'
]
));
));
const preloadPage = {
url: {
type: String,
required: true,
validator: createValidator('preloadPage')
}
};
var require_context_module_0_23 = /*#__PURE__*/Object.freeze({
__proto__: null,
......@@ -1794,7 +1819,8 @@ var serviceContext = (function () {
reLaunch: reLaunch,
navigateTo: navigateTo,
switchTab: switchTab,
navigateBack: navigateBack
navigateBack: navigateBack,
preloadPage: preloadPage
});
const getStorage = {
......@@ -8079,7 +8105,7 @@ var serviceContext = (function () {
}
}
function createWebview (path, routeOptions, query) {
function createWebview (path, routeOptions, query, extras = {}) {
if (routeOptions.meta.isNVue) {
const webviewId = id$1++;
const webviewStyle = parseWebviewStyle(
......@@ -8093,9 +8119,9 @@ var serviceContext = (function () {
}
// android 需要使用
webviewStyle.isTab = !!routeOptions.meta.isTabBar;
return plus.webview.create('', String(webviewId), webviewStyle, {
return plus.webview.create('', String(webviewId), webviewStyle, Object.assign({
nvue: true
})
}, extras))
}
if (id$1 === 2) { // 如果首页非 nvue,则直接返回 Launch Webview
return plus.webview.getLaunchWebview()
......@@ -8347,22 +8373,43 @@ var serviceContext = (function () {
const pages = [];
function getCurrentPages$1 (returnAll) {
function getCurrentPages$1(returnAll) {
return returnAll ? pages.slice(0) : pages.filter(page => {
return !page.$page.meta.isTabBar || page.$page.meta.visible
})
}
const preloadWebviews = {};
function preloadWebview$1({
url,
path,
query
}) {
if (!preloadWebviews[url]) {
const routeOptions = JSON.parse(JSON.stringify(__uniRoutes.find(route => route.path === path)));
preloadWebviews[url] = createWebview(path, routeOptions, query, {
__preload__: true,
__query__: JSON.stringify(query)
});
}
return preloadWebviews[url]
}
/**
* 首页需要主动registerPage,二级页面路由跳转时registerPage
*/
function registerPage ({
function registerPage({
url,
path,
query,
openType,
webview
}) {
if (preloadWebviews[url]) {
webview = preloadWebviews[url];
delete preloadWebviews[url];
}
const routeOptions = JSON.parse(JSON.stringify(__uniRoutes.find(route => route.path === path)));
if (
......@@ -8405,7 +8452,7 @@ var serviceContext = (function () {
const pageInstance = {
route,
options: Object.assign({}, query || {}),
$getAppWebview () {
$getAppWebview() {
// 重要,不能直接返回 webview 对象,因为 plus 可能会被二次替换,返回的 webview 对象内部的 plus 不正确
// 导致 webview.getStyle 等逻辑出错(旧的 webview 内部 plus 被释放)
return plus.webview.getWebviewById(webview.id)
......@@ -8417,7 +8464,7 @@ var serviceContext = (function () {
route,
openType
},
$remove () {
$remove() {
const index = pages.findIndex(page => page === this);
if (index !== -1) {
if (!webview.nvue) {
......@@ -8430,16 +8477,20 @@ var serviceContext = (function () {
}
},
// 兼容小程序框架
selectComponent (selector) {
selectComponent(selector) {
return this.$vm.selectComponent(selector)
},
selectAllComponents (selector) {
selectAllComponents(selector) {
return this.$vm.selectAllComponents(selector)
}
};
pages.push(pageInstance);
// if (webview.__preload__) {
// // TODO 触发 onShow 以及绑定vm,page 关系
// }
// 首页是 nvue 时,在 registerPage 时,执行路由堆栈
if (webview.id === '1' && webview.nvue) {
if (
......@@ -8449,7 +8500,7 @@ var serviceContext = (function () {
) {
plus.navigator.closeSplashscreen();
}
__uniConfig.onReady(function () {
__uniConfig.onReady(function() {
navigateFinish();
});
}
......@@ -8729,6 +8780,24 @@ var serviceContext = (function () {
}, openType === 'appLaunch');
}
function preloadPage$1({
url
}, callbackId) {
const urls = url.split('?');
const path = urls[0];
const query = parseQuery(urls[1] || '');
const webview = preloadWebview$1({
url,
path,
query
});
invoke$1(callbackId, {
id: webview.id,
url,
errMsg: 'preloadPage:ok'
});
}
const STORAGE_DATA_TYPE = '__TYPE';
const STORAGE_KEYS = 'uni-storage-keys';
......@@ -9653,6 +9722,7 @@ var serviceContext = (function () {
reLaunch: reLaunch$1,
redirectTo: redirectTo$1,
switchTab: switchTab$1,
preloadPage: preloadPage$1,
setStorage: setStorage$1,
setStorageSync: setStorageSync$1,
getStorage: getStorage$1,
......
......@@ -838,5 +838,14 @@
"setPageMeta": [
"/core/service/api/ui/set-page-meta.js",
[]
],
"preloadPage": [
"/platforms/h5/service/api/route/route.js",
[
[
"/core/helpers/protocol/route/route.js",
"preloadPage"
]
]
]
}
\ No newline at end of file
......@@ -357,7 +357,8 @@ var baseApi = /*#__PURE__*/Object.freeze({
});
// 不支持的 API 列表
const todos = [
const todos = [
'preloadPage'
// 'getRecorderManager',
// 'getBackgroundAudioManager',
// 'createInnerAudioContext',
......@@ -444,6 +445,7 @@ const protocols = { // 需要做转换的 API 列表
request: {
name: my.canIUse('request') ? 'request' : 'httpRequest',
args (fromArgs) {
const method = fromArgs.method || 'GET';
if (!fromArgs.header) { // 默认增加 header 参数,方便格式化 content-type
fromArgs.header = {};
}
......@@ -461,8 +463,8 @@ const protocols = { // 需要做转换的 API 列表
}
},
data (data) {
// 钉钉在content-type为application/json时,不会自动序列化
if (my.dd && headers['content-type'].indexOf('application/json') === 0) {
// 钉钉小程序在content-type为application/json时需上传字符串形式data,使用my.dd在真机运行钉钉小程序时不能正确判断
if (my.canIUse('saveFileToDingTalk') && method.toUpperCase() === 'POST' && headers['content-type'].indexOf('application/json') === 0 && isPlainObject(data)) {
return {
name: 'data',
value: JSON.stringify(data)
......
......@@ -391,7 +391,8 @@ var previewImage = {
};
// 不支持的 API 列表
const todos = [
const todos = [
'preloadPage'
// 'hideKeyboard',
// 'onGyroscopeChange',
// 'startGyroscope',
......
......@@ -393,7 +393,8 @@ var previewImage = {
const protocols = {
previewImage
};
const todos = [
const todos = [
'preloadPage'
// 'startBeaconDiscovery',
// 'stopBeaconDiscovery',
// 'getBeacons',
......
......@@ -391,7 +391,8 @@ var previewImage = {
};
// 不支持的 API 列表
const todos = [
const todos = [
'preloadPage'
// 'createCameraContext',
// 'createLivePlayerContext',
// 'getSavedFileInfo',
......
......@@ -411,7 +411,8 @@ const protocols = {
}
};
const todos = [
'vibrate'
'vibrate',
'preloadPage'
];
const canIUses = [];
......
......@@ -408,7 +408,8 @@ global.__uniConfig.debug = ${manifestJson.debug === true};
global.__uniConfig.networkTimeout = ${JSON.stringify(networkTimeoutConfig)};
global.__uniConfig.sdkConfigs = ${JSON.stringify(sdkConfigs)};
global.__uniConfig.qqMapKey = ${JSON.stringify(qqMapKey)};
global.__uniConfig.nvue = ${JSON.stringify({ 'flex-direction': getFlexDirection(manifestJson['app-plus']) })}
global.__uniConfig.nvue = ${JSON.stringify({ 'flex-direction': getFlexDirection(manifestJson['app-plus']) })}
global.__uniConfig.__webpack_chunk_load__ = __webpack_chunk_load__
${genRegisterPageVueComponentsCode(pageComponents)}
global.__uniRoutes=[${genPageRoutes(pageComponents).concat(genSystemRoutes()).join(',')}]
global.UniApp && new global.UniApp();
......
......@@ -62,7 +62,7 @@ function createValidator (type) {
// switchTab不允许传递参数,reLaunch到一个tabBar页面是可以的
if (
type === 'switchTab' &&
(type === 'switchTab' || type === 'preloadPage') &&
routeOptions.meta.isTabBar &&
params.openType !== 'appLaunch'
) {
......@@ -77,6 +77,22 @@ function createValidator (type) {
// 参数格式化
params.url = encodeQueryString(url)
if (type === 'preloadPage') {
if (__PLATFORM__ === 'app-plus') {
if (!routeOptions.meta.isNVue) {
return 'can not preload vue page'
}
}
if (routeOptions.meta.isTabBar) {
const pages = getCurrentPages(true)
const tabBarPagePath = (routeOptions.alias || routeOptions.path).substr(1)
if (pages.find(page => page.route === tabBarPagePath)) {
return 'tabBar page `' + tabBarPagePath + '` already exists'
}
}
return
}
// 主要拦截目标为用户快速点击时触发的多次跳转,该情况,通常前后 url 是一样的
if (navigatorLock === url) {
return `${navigatorLock} locked`
......@@ -161,4 +177,12 @@ export const navigateBack = Object.assign({
'pop-out',
'none'
]
))
))
export const preloadPage = {
url: {
type: String,
required: true,
validator: createValidator('preloadPage')
}
}
......@@ -58,6 +58,7 @@ export * from './route/navigate-to'
export * from './route/re-launch'
export * from './route/redirect-to'
export * from './route/switch-tab'
export * from './route/preload-page'
export * from './storage/storage'
......
import {
parseQuery
} from 'uni-shared'
import {
invoke
} from '../../bridge'
import {
preloadWebview
} from '../../framework/page'
export function preloadPage ({
url
}, callbackId) {
const urls = url.split('?')
const path = urls[0]
const query = parseQuery(urls[1] || '')
const webview = preloadWebview({
url,
path,
query
})
invoke(callbackId, {
id: webview.id,
url,
errMsg: 'preloadPage:ok'
})
}
......@@ -21,6 +21,23 @@ export function getCurrentPages (returnAll) {
})
}
const preloadWebviews = {}
export function preloadWebview ({
url,
path,
query
}) {
if (!preloadWebviews[url]) {
const routeOptions = JSON.parse(JSON.stringify(__uniRoutes.find(route => route.path === path)))
preloadWebviews[url] = createWebview(path, routeOptions, query, {
__preload__: true,
__query__: JSON.stringify(query)
})
}
return preloadWebviews[url]
}
/**
* 首页需要主动registerPage,二级页面路由跳转时registerPage
*/
......@@ -31,6 +48,10 @@ export function registerPage ({
openType,
webview
}) {
if (preloadWebviews[url]) {
webview = preloadWebviews[url]
delete preloadWebviews[url]
}
const routeOptions = JSON.parse(JSON.stringify(__uniRoutes.find(route => route.path === path)))
if (
......@@ -108,6 +129,10 @@ export function registerPage ({
pages.push(pageInstance)
// if (webview.__preload__) {
// // TODO 触发 onShow 以及绑定vm,page 关系
// }
// 首页是 nvue 时,在 registerPage 时,执行路由堆栈
if (webview.id === '1' && webview.nvue) {
if (
......
......@@ -69,7 +69,7 @@ function getDebugRefresh (path, query, routeOptions) {
}
}
export function createWebview (path, routeOptions, query) {
export function createWebview (path, routeOptions, query, extras = {}) {
if (routeOptions.meta.isNVue) {
const webviewId = id++
const webviewStyle = parseWebviewStyle(
......@@ -83,9 +83,9 @@ export function createWebview (path, routeOptions, query) {
}
// android 需要使用
webviewStyle.isTab = !!routeOptions.meta.isTabBar
return plus.webview.create('', String(webviewId), webviewStyle, {
return plus.webview.create('', String(webviewId), webviewStyle, Object.assign({
nvue: true
})
}, extras))
}
if (id === 2) { // 如果首页非 nvue,则直接返回 Launch Webview
return plus.webview.getLaunchWebview()
......
......@@ -2,6 +2,10 @@ import {
hasLifecycleHook
} from 'uni-helpers/index'
const {
invokeCallbackHandler: invoke
} = UniServiceJSBridge
function onAppRoute (type, {
url,
delta,
......@@ -27,26 +31,26 @@ function onAppRoute (type, {
})
break
case 'navigateBack':
{
let canBack = true
const pages = getCurrentPages()
if (pages.length) {
const page = pages[pages.length - 1]
if (hasLifecycleHook(page.$options, 'onBackPress') && page.__call_hook('onBackPress', {
from
}) === true) {
canBack = false
}
}
if (canBack) {
if (delta > 1) {
router._$delta = delta
}
router.go(-delta, {
animationType,
animationDuration
})
}
{
let canBack = true
const pages = getCurrentPages()
if (pages.length) {
const page = pages[pages.length - 1]
if (hasLifecycleHook(page.$options, 'onBackPress') && page.__call_hook('onBackPress', {
from
}) === true) {
canBack = false
}
}
if (canBack) {
if (delta > 1) {
router._$delta = delta
}
router.go(-delta, {
animationType,
animationDuration
})
}
}
break
case 'reLaunch':
......@@ -88,4 +92,21 @@ export function reLaunch (args) {
export function switchTab (args) {
return onAppRoute('switchTab', args)
}
export function preloadPage ({
url
}, callbackId) {
const path = url.split('?')[0].replace(/\//g, '-')
__uniConfig.__webpack_chunk_load__(path.substr(1)).then(() => {
invoke(callbackId, {
url,
errMsg: 'preloadPage:ok'
})
}).catch(err => {
invoke(callbackId, {
url,
errMsg: 'preloadPage:fail ' + err
})
})
}
......@@ -2,7 +2,8 @@ import {
isPlainObject
} from 'uni-shared'
// 不支持的 API 列表
const todos = [
const todos = [
'preloadPage'
// 'getRecorderManager',
// 'getBackgroundAudioManager',
// 'createInnerAudioContext',
......
import previewImage from '../../../mp-weixin/helpers/normalize-preview-image'
// 不支持的 API 列表
const todos = [
const todos = [
'preloadPage'
// 'hideKeyboard',
// 'onGyroscopeChange',
// 'startGyroscope',
......
......@@ -2,7 +2,8 @@ import previewImage from '../../../mp-weixin/helpers/normalize-preview-image'
export const protocols = {
previewImage
}
export const todos = [
export const todos = [
'preloadPage'
// 'startBeaconDiscovery',
// 'stopBeaconDiscovery',
// 'getBeacons',
......
import previewImage from '../../../mp-weixin/helpers/normalize-preview-image'
// 不支持的 API 列表
const todos = [
const todos = [
'preloadPage'
// 'createCameraContext',
// 'createLivePlayerContext',
// 'getSavedFileInfo',
......
......@@ -21,6 +21,7 @@ export const protocols = {
}
}
export const todos = [
'vibrate'
'vibrate',
'preloadPage'
]
export const canIUses = []
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册