diff --git a/packages/shims-uni-app.d.ts b/packages/shims-uni-app.d.ts index 9a139c22d12934b91934113d44d1dda30012d090..87457939268d3c556d53c5ace759253e8f6a095e 100644 --- a/packages/shims-uni-app.d.ts +++ b/packages/shims-uni-app.d.ts @@ -128,9 +128,11 @@ declare namespace UniApp { } interface PagesJsonPageStyle extends PagesJsonPagePlatformStyle { + disableScroll?: boolean enablePullDownRefresh?: boolean navigationBar: PageNavigationBar refreshOptions?: PageRefreshOptions + onReachBottomDistance?: number } interface PageRouteMeta extends PagesJsonPageStyle { id: number diff --git a/packages/uni-core/src/helpers/index.ts b/packages/uni-core/src/helpers/index.ts index 31ce17a81faf245d93a9e74b34403e1157076369..ba218d6f2b779de578bde2cfc78b0832332c6a17 100644 --- a/packages/uni-core/src/helpers/index.ts +++ b/packages/uni-core/src/helpers/index.ts @@ -1,5 +1,6 @@ export * from './util' export * from './icon' +export * from './scroll' export * from './getRealRoute' export * from './updateCssVar' export * from './getWindowOffset' diff --git a/packages/uni-core/src/helpers/scroll.ts b/packages/uni-core/src/helpers/scroll.ts new file mode 100644 index 0000000000000000000000000000000000000000..bfebc2a6218c49fe999edfb7c138a339c9ad42a6 --- /dev/null +++ b/packages/uni-core/src/helpers/scroll.ts @@ -0,0 +1,72 @@ +export interface CreateScrollListenerOptions { + onPageScroll?: (scrollTop: number) => void + onReachBottom?: () => void + onReachBottomDistance?: number +} +export function disableScrollListener(evt: Event) { + evt.preventDefault() +} + +let testReachBottomTimer: number +let lastScrollHeight = 0 +export function createScrollListener({ + onPageScroll, + onReachBottom, + onReachBottomDistance, +}: CreateScrollListenerOptions) { + let ticking = false + let hasReachBottom = false + let reachBottomLocking = true + const isReachBottom = () => { + const { scrollHeight } = document.documentElement + // 部分浏览器窗口高度变化后document.documentelement.clientheight不会变化,采用window.innerHeight + const windowHeight = window.innerHeight + const scrollY = window.scrollY + const isBottom = + scrollY > 0 && + scrollHeight > windowHeight && + scrollY + windowHeight + onReachBottomDistance! >= scrollHeight + // 兼容部分浏览器滚动时scroll事件不触发 + const heightChanged = + Math.abs(scrollHeight - lastScrollHeight) > onReachBottomDistance! + if (isBottom && (!hasReachBottom || heightChanged)) { + lastScrollHeight = scrollHeight + hasReachBottom = true + return true + } + + if (!isBottom && hasReachBottom) { + hasReachBottom = false + } + return false + } + const trigger = () => { + onPageScroll && onPageScroll(window.pageYOffset) + function testReachBottom() { + if (isReachBottom()) { + onReachBottom && onReachBottom() + reachBottomLocking = false + setTimeout(function () { + reachBottomLocking = true + }, 350) + return true + } + } + if (onReachBottom && reachBottomLocking) { + if (testReachBottom()) { + } else { + // 解决部分浏览器滚动中js获取窗口高度不准确导致的问题 + testReachBottomTimer = setTimeout(testReachBottom, 300) + } + } + ticking = false + } + + return function onScroll() { + clearTimeout(testReachBottomTimer) + if (!ticking) { + requestAnimationFrame(trigger) + } + ticking = true + } +} diff --git a/packages/uni-core/src/service/plugin/index.ts b/packages/uni-core/src/service/plugin/index.ts index 2df1a57fcfdf1186a9ac52d3e3538c822de3cb83..500316aa80761928bf7a2599bf7c6a9225a27f55 100644 --- a/packages/uni-core/src/service/plugin/index.ts +++ b/packages/uni-core/src/service/plugin/index.ts @@ -1,8 +1,11 @@ import { App } from 'vue' import { initAppConfig } from './appConfig' +import { initOn } from './on' import { initSubscribe } from './subscribe' export * from './page' export function initService(app: App) { - initAppConfig(app._context.config) + initOn() initSubscribe() + + initAppConfig(app._context.config) } diff --git a/packages/uni-core/src/service/plugin/on.ts b/packages/uni-core/src/service/plugin/on.ts new file mode 100644 index 0000000000000000000000000000000000000000..16e4f16e192ab72a77aa8ec8bf693e316fe8d049 --- /dev/null +++ b/packages/uni-core/src/service/plugin/on.ts @@ -0,0 +1,26 @@ +import { ComponentPublicInstance } from '@vue/runtime-core' +import { getCurrentPage, invokeHook } from './page' + +export function initOn() { + UniServiceJSBridge.on('onAppEnterForeground', onAppEnterForeground) + UniServiceJSBridge.on('onAppEnterBackground', onAppEnterBackground) +} + +function onAppEnterForeground() { + const page = getCurrentPage() + const showOptions = { + path: '', + query: {}, + } + if (page) { + showOptions.path = page.$page.route + showOptions.query = page.$page.options + } + invokeHook(getApp() as ComponentPublicInstance, 'onShow', showOptions) + invokeHook(page as ComponentPublicInstance, 'onShow') +} + +function onAppEnterBackground() { + invokeHook(getApp() as ComponentPublicInstance, 'onHide') + invokeHook(getCurrentPage() as ComponentPublicInstance, 'onHide') +} diff --git a/packages/uni-core/src/service/plugin/page.ts b/packages/uni-core/src/service/plugin/page.ts index 785544d8ec928a9688bfb53c57f9cdedd1a86f77..2fd293d1b7ea5b4e98d0cf7f1c556fc97a03dc9b 100644 --- a/packages/uni-core/src/service/plugin/page.ts +++ b/packages/uni-core/src/service/plugin/page.ts @@ -2,6 +2,17 @@ import { isString } from '@vue/shared' import { ComponentPublicInstance } from 'vue' import { invokeArrayFns } from '@dcloudio/uni-shared' +export function getPageById(id: number) { + return getCurrentPages().find((page) => page.$page.id === id) +} + +export function getPageVmById(id: number) { + const page = getPageById(id) + if (page) { + return (page as any).$vm as ComponentPublicInstance + } +} + export function getCurrentPage() { const pages = getCurrentPages() const len = pages.length diff --git a/packages/uni-core/src/service/plugin/subscribe.ts b/packages/uni-core/src/service/plugin/subscribe.ts index 0e3710f1b1fce864390f2b22c9838576eb11dd8e..d1806666ee1dec118d752da7a3bfeefeb585a581 100644 --- a/packages/uni-core/src/service/plugin/subscribe.ts +++ b/packages/uni-core/src/service/plugin/subscribe.ts @@ -1,22 +1,14 @@ -import { ComponentPublicInstance } from '@vue/runtime-core' -import { getCurrentPage, invokeHook } from './page' +import { getPageVmById, invokeHook } from './page' export function initSubscribe() { - UniServiceJSBridge.on('onAppEnterForeground', () => { - const page = getCurrentPage() - const showOptions = { - path: '', - query: {}, - } - if (page) { - showOptions.path = page.$page.route - showOptions.query = page.$page.options + UniServiceJSBridge.subscribe('onPageScroll', createPageEvent('onPageScroll')) +} + +function createPageEvent(name: string) { + return (args: unknown, pageId: number) => { + const vm = getPageVmById(pageId) + if (vm) { + invokeHook(vm, name, args) } - invokeHook(getApp() as ComponentPublicInstance, 'onShow', showOptions) - invokeHook(page as ComponentPublicInstance, 'onShow') - }) - UniServiceJSBridge.on('onAppEnterBackground', () => { - invokeHook(getApp() as ComponentPublicInstance, 'onHide') - invokeHook(getCurrentPage() as ComponentPublicInstance, 'onHide') - }) + } } diff --git a/packages/uni-h5/dist/uni-h5.esm.js b/packages/uni-h5/dist/uni-h5.esm.js index 51cb671078cea3d45dc31f7b818c06be5ee579e2..0d47670dc753e897d774d90e2fdd9e84c98086a4 100644 --- a/packages/uni-h5/dist/uni-h5.esm.js +++ b/packages/uni-h5/dist/uni-h5.esm.js @@ -1,6 +1,6 @@ import {isFunction, extend, isPlainObject, isString, isArray, hasOwn as hasOwn$1, isObject as isObject$1, capitalize, toRawType, makeMap as makeMap$1, isPromise, invokeArrayFns as invokeArrayFns$1, hyphenate} from "@vue/shared"; -import {injectHook, createVNode, inject, provide, reactive, computed, nextTick, getCurrentInstance, onBeforeMount, onMounted, onBeforeActivate, onBeforeDeactivate, openBlock, createBlock, mergeProps, toDisplayString, ref, defineComponent, resolveComponent, toHandlers, renderSlot, watch, onActivated, onBeforeUnmount, withModifiers, withDirectives, vShow, vModelDynamic, createTextVNode, createCommentVNode, Fragment, renderList, vModelText, watchEffect, withCtx, KeepAlive, resolveDynamicComponent} from "vue"; -import {once, passive, normalizeTarget, invokeArrayFns, NAVBAR_HEIGHT, removeLeadingSlash, getLen, parseQuery, decodedQuery, plusReady, debounce, PRIMARY_COLOR as PRIMARY_COLOR$1, updateElementStyle, addFont, scrollTo} from "@dcloudio/uni-shared"; +import {injectHook, createVNode, inject, provide, reactive, computed, nextTick, getCurrentInstance, onBeforeMount, onMounted, onBeforeActivate, onBeforeDeactivate, openBlock, createBlock, mergeProps, toDisplayString, ref, defineComponent, resolveComponent, toHandlers, renderSlot, watch, onActivated, onBeforeUnmount, withModifiers, withDirectives, vShow, vModelDynamic, createTextVNode, createCommentVNode, Fragment, renderList, vModelText, onDeactivated, onUnmounted, watchEffect, withCtx, KeepAlive, resolveDynamicComponent} from "vue"; +import {once, passive, normalizeTarget, invokeArrayFns, NAVBAR_HEIGHT, parseQuery, removeLeadingSlash, getLen, ON_REACH_BOTTOM_DISTANCE, decodedQuery, plusReady, debounce, PRIMARY_COLOR as PRIMARY_COLOR$1, updateElementStyle, addFont, scrollTo} from "@dcloudio/uni-shared"; import {useRoute, createRouter, createWebHistory, createWebHashHistory, useRouter, isNavigationFailure, RouterView} from "vue-router"; function applyOptions(options, instance2, publicThis) { Object.keys(options).forEach((name) => { @@ -938,6 +938,15 @@ function initAppConfig(appConfig) { extend(globalProperties, wxInstance); } } +function getPageById(id2) { + return getCurrentPages().find((page) => page.$page.id === id2); +} +function getPageVmById(id2) { + const page = getPageById(id2); + if (page) { + return page.$vm; + } +} function getCurrentPage() { const pages = getCurrentPages(); const len = pages.length; @@ -983,28 +992,42 @@ function invokeHook(vm, name, args) { const hooks = vm.$[name]; return hooks && invokeArrayFns(hooks, args); } +function initOn() { + UniServiceJSBridge.on("onAppEnterForeground", onAppEnterForeground); + UniServiceJSBridge.on("onAppEnterBackground", onAppEnterBackground); +} +function onAppEnterForeground() { + const page = getCurrentPage(); + const showOptions = { + path: "", + query: {} + }; + if (page) { + showOptions.path = page.$page.route; + showOptions.query = page.$page.options; + } + invokeHook(getApp(), "onShow", showOptions); + invokeHook(page, "onShow"); +} +function onAppEnterBackground() { + invokeHook(getApp(), "onHide"); + invokeHook(getCurrentPage(), "onHide"); +} function initSubscribe() { - UniServiceJSBridge.on("onAppEnterForeground", () => { - const page = getCurrentPage(); - const showOptions = { - path: "", - query: {} - }; - if (page) { - showOptions.path = page.$page.route; - showOptions.query = page.$page.options; + UniServiceJSBridge.subscribe("onPageScroll", createPageEvent("onPageScroll")); +} +function createPageEvent(name) { + return (args, pageId) => { + const vm = getPageVmById(pageId); + if (vm) { + invokeHook(vm, name, args); } - invokeHook(getApp(), "onShow", showOptions); - invokeHook(page, "onShow"); - }); - UniServiceJSBridge.on("onAppEnterBackground", () => { - invokeHook(getApp(), "onHide"); - invokeHook(getCurrentPage(), "onHide"); - }); + }; } function initService(app) { - initAppConfig(app._context.config); + initOn(); initSubscribe(); + initAppConfig(app._context.config); } function PolySymbol(name) { return Symbol(process.env.NODE_ENV !== "production" ? "[uni-app]: " + name : name); @@ -1040,6 +1063,64 @@ function createSvgIconVNode(path, color = "#000", size = 27) { }, null, 8, ["d", "fill"]) ], 8, ["width", "height"]); } +function disableScrollListener(evt) { + evt.preventDefault(); +} +let testReachBottomTimer; +let lastScrollHeight = 0; +function createScrollListener({ + onPageScroll, + onReachBottom, + onReachBottomDistance +}) { + let ticking = false; + let hasReachBottom = false; + let reachBottomLocking = true; + const isReachBottom = () => { + const {scrollHeight} = document.documentElement; + const windowHeight = window.innerHeight; + const scrollY = window.scrollY; + const isBottom = scrollY > 0 && scrollHeight > windowHeight && scrollY + windowHeight + onReachBottomDistance >= scrollHeight; + const heightChanged = Math.abs(scrollHeight - lastScrollHeight) > onReachBottomDistance; + if (isBottom && (!hasReachBottom || heightChanged)) { + lastScrollHeight = scrollHeight; + hasReachBottom = true; + return true; + } + if (!isBottom && hasReachBottom) { + hasReachBottom = false; + } + return false; + }; + const trigger = () => { + onPageScroll && onPageScroll(window.pageYOffset); + function testReachBottom() { + if (isReachBottom()) { + onReachBottom && onReachBottom(); + reachBottomLocking = false; + setTimeout(function() { + reachBottomLocking = true; + }, 350); + return true; + } + } + if (onReachBottom && reachBottomLocking) { + if (testReachBottom()) + ; + else { + testReachBottomTimer = setTimeout(testReachBottom, 300); + } + } + ticking = false; + }; + return function onScroll() { + clearTimeout(testReachBottomTimer); + if (!ticking) { + requestAnimationFrame(trigger); + } + ticking = true; + }; +} function getRealRoute(fromRoute, toRoute) { if (!toRoute) { toRoute = fromRoute; @@ -1112,6 +1193,24 @@ function providePageMeta(id2) { provide(pageMetaKey, pageMeta); return pageMeta; } +function usePageRoute() { + if (__UNI_FEATURE_PAGES__) { + return useRoute(); + } + const url = location.href; + const searchPos = url.indexOf("?"); + const hashPos = url.indexOf("#", searchPos > -1 ? searchPos : 0); + let query = {}; + if (searchPos > -1) { + query = parseQuery(url.slice(searchPos + 1, hashPos > -1 ? hashPos : url.length)); + } + const {meta} = __uniRoutes[0]; + return { + meta, + query, + path: "/" + meta.route + }; +} function initPageMeta(id2) { if (__UNI_FEATURE_PAGES__) { return reactive(normalizePageMeta(JSON.parse(JSON.stringify(mergePageMeta(id2, useRoute().meta))))); @@ -1205,190 +1304,6 @@ function updateCssVar(name, value) { styleObj.setProperty(name, value); } PolySymbol(process.env.NODE_ENV !== "production" ? "layout" : "l"); -const SEP = "$$"; -const currentPagesMap = new Map(); -function pruneCurrentPages() { - currentPagesMap.forEach((page, id2) => { - if (page.$.isUnmounted) { - currentPagesMap.delete(id2); - } - }); -} -function getCurrentPagesMap() { - return currentPagesMap; -} -function getCurrentPages$1() { - const curPages = []; - const pages = currentPagesMap.values(); - for (const page of pages) { - if (page.$page.meta.isTabBar) { - if (page.$.__isActive) { - curPages.push(page); - } - } else { - curPages.push(page); - } - } - return curPages; -} -function removeRouteCache(routeKey) { - const vnode = pageCacheMap.get(routeKey); - if (vnode) { - pageCacheMap.delete(routeKey); - routeCache.pruneCacheEntry(vnode); - } -} -function removePage(routeKey, removeRouteCaches = true) { - const pageVm = currentPagesMap.get(routeKey); - pageVm.$.__isUnload = true; - invokeHook(pageVm, "onUnload"); - currentPagesMap.delete(routeKey); - removeRouteCaches && removeRouteCache(routeKey); -} -let id = /* @__PURE__ */ (() => history.state && history.state.__id__ || 1)(); -function createPageState(type, __id__) { - return { - __id__: __id__ || ++id, - __type__: type - }; -} -function initPublicPage(route) { - const meta = usePageMeta(); - if (!__UNI_FEATURE_PAGES__) { - const {path: path2, alias} = __uniRoutes[0]; - return { - id: meta.id, - path: path2, - route: alias.substr(1), - fullPath: path2, - options: {}, - meta - }; - } - const {path} = route; - return { - id: meta.id, - path, - route: route.meta.route, - fullPath: route.meta.isEntry ? route.meta.pagePath : route.fullPath, - options: {}, - meta - }; -} -function initPage(vm) { - const route = vm.$route; - const page = initPublicPage(route); - vm.$vm = vm; - vm.$page = page; - currentPagesMap.set(normalizeRouteKey(page.path, page.id), vm); -} -function normalizeRouteKey(path, id2) { - return path + SEP + id2; -} -function useKeepAliveRoute() { - const route = useRoute(); - const routeKey = computed(() => normalizeRouteKey(route.path, history.state.__id__ || 1)); - return { - routeKey, - routeCache - }; -} -const pageCacheMap = new Map(); -const routeCache = { - get(key) { - return pageCacheMap.get(key); - }, - set(key, value) { - pruneRouteCache(key); - pageCacheMap.set(key, value); - }, - delete(key) { - const vnode = pageCacheMap.get(key); - if (!vnode) { - return; - } - pageCacheMap.delete(key); - }, - forEach(fn) { - pageCacheMap.forEach(fn); - } -}; -function pruneRouteCache(key) { - const pageId = parseInt(key.split(SEP)[1]); - if (!pageId) { - return; - } - routeCache.forEach((vnode, key2) => { - const cPageId = parseInt(key2.split(SEP)[1]); - if (cPageId && cPageId > pageId) { - if (__UNI_FEATURE_TABBAR__) { - const {component} = vnode; - if (component && component.refs.page && component.refs.page.$page.meta.isTabBar) { - return; - } - } - routeCache.delete(key2); - routeCache.pruneCacheEntry(vnode); - nextTick(() => pruneCurrentPages()); - } - }); -} -function initRouter(app) { - app.use(createAppRouter(createRouter(createRouterOptions()))); -} -const scrollBehavior = (_to, _from, savedPosition) => { - if (savedPosition) { - return savedPosition; - } -}; -function createRouterOptions() { - return { - history: initHistory(), - strict: !!__uniConfig.router.strict, - routes: __uniRoutes, - scrollBehavior - }; -} -function createAppRouter(router) { - return router; -} -function removeCurrentPages(delta = 1) { - const keys = getCurrentPages$1(); - const start = keys.length - 1; - const end = start - delta; - for (let i2 = start; i2 > end; i2--) { - const page = keys[i2].$page; - removePage(normalizeRouteKey(page.path, page.id), false); - } -} -function initHistory() { - const history2 = __UNI_FEATURE_ROUTER_MODE__ === "history" ? createWebHistory() : createWebHashHistory(); - history2.listen((_to, _from, info) => { - if (info.direction === "back") { - removeCurrentPages(Math.abs(info.delta)); - } - }); - return history2; -} -var index$9 = { - install(app) { - initApp$1(app); - initView(app); - initService(app); - if (__UNI_FEATURE_PAGES__) { - initRouter(app); - } - } -}; -let appVm; -function getApp$1() { - return appVm; -} -function initApp(vm) { - appVm = vm; - appVm.$vm = vm; - appVm.globalData = appVm.$options.globalData || {}; -} let tabBar; function useTabBar() { if (!tabBar) { @@ -3569,24 +3484,232 @@ function updateCurPageCssVar(pageMeta) { function normalizeWindowBottom(windowBottom) { return envMethod ? `calc(${windowBottom}px + ${envMethod}(safe-area-inset-bottom))` : `${windowBottom}px`; } -function usePageRoute() { - if (__UNI_FEATURE_PAGES__) { - return useRoute(); +const SEP = "$$"; +const currentPagesMap = new Map(); +function pruneCurrentPages() { + currentPagesMap.forEach((page, id2) => { + if (page.$.isUnmounted) { + currentPagesMap.delete(id2); + } + }); +} +function getCurrentPagesMap() { + return currentPagesMap; +} +function getCurrentPages$1() { + const curPages = []; + const pages = currentPagesMap.values(); + for (const page of pages) { + if (page.$page.meta.isTabBar) { + if (page.$.__isActive) { + curPages.push(page); + } + } else { + curPages.push(page); + } } - const url = location.href; - const searchPos = url.indexOf("?"); - const hashPos = url.indexOf("#", searchPos > -1 ? searchPos : 0); - let query = {}; - if (searchPos > -1) { - query = parseQuery(url.slice(searchPos + 1, hashPos > -1 ? hashPos : url.length)); + return curPages; +} +function removeRouteCache(routeKey) { + const vnode = pageCacheMap.get(routeKey); + if (vnode) { + pageCacheMap.delete(routeKey); + routeCache.pruneCacheEntry(vnode); } - const {meta} = __uniRoutes[0]; +} +function removePage(routeKey, removeRouteCaches = true) { + const pageVm = currentPagesMap.get(routeKey); + pageVm.$.__isUnload = true; + invokeHook(pageVm, "onUnload"); + currentPagesMap.delete(routeKey); + removeRouteCaches && removeRouteCache(routeKey); +} +let id = /* @__PURE__ */ (() => history.state && history.state.__id__ || 1)(); +function createPageState(type, __id__) { return { - meta, - query, - path: "/" + meta.route + __id__: __id__ || ++id, + __type__: type + }; +} +function initPublicPage(route) { + const meta = usePageMeta(); + if (!__UNI_FEATURE_PAGES__) { + const {path: path2, alias} = __uniRoutes[0]; + return { + id: meta.id, + path: path2, + route: alias.substr(1), + fullPath: path2, + options: {}, + meta + }; + } + const {path} = route; + return { + id: meta.id, + path, + route: route.meta.route, + fullPath: route.meta.isEntry ? route.meta.pagePath : route.fullPath, + options: {}, + meta + }; +} +function initPage(vm) { + const route = vm.$route; + const page = initPublicPage(route); + vm.$vm = vm; + vm.$page = page; + currentPagesMap.set(normalizeRouteKey(page.path, page.id), vm); +} +function normalizeRouteKey(path, id2) { + return path + SEP + id2; +} +function useKeepAliveRoute() { + const route = useRoute(); + const routeKey = computed(() => normalizeRouteKey(route.path, history.state.__id__ || 1)); + return { + routeKey, + routeCache + }; +} +const pageCacheMap = new Map(); +const routeCache = { + get(key) { + return pageCacheMap.get(key); + }, + set(key, value) { + pruneRouteCache(key); + pageCacheMap.set(key, value); + }, + delete(key) { + const vnode = pageCacheMap.get(key); + if (!vnode) { + return; + } + pageCacheMap.delete(key); + }, + forEach(fn) { + pageCacheMap.forEach(fn); + } +}; +function pruneRouteCache(key) { + const pageId = parseInt(key.split(SEP)[1]); + if (!pageId) { + return; + } + routeCache.forEach((vnode, key2) => { + const cPageId = parseInt(key2.split(SEP)[1]); + if (cPageId && cPageId > pageId) { + if (__UNI_FEATURE_TABBAR__) { + const {component} = vnode; + if (component && component.refs.page && component.refs.page.$page.meta.isTabBar) { + return; + } + } + routeCache.delete(key2); + routeCache.pruneCacheEntry(vnode); + nextTick(() => pruneCurrentPages()); + } + }); +} +function onPageShow(instance2, pageMeta) { + updateCurPageCssVar(pageMeta); + initPageScrollListener(instance2, pageMeta); +} +let curScrollListener; +function initPageScrollListener(instance2, pageMeta) { + document.removeEventListener("touchmove", disableScrollListener); + if (curScrollListener) { + document.removeEventListener("scroll", curScrollListener); + } + if (pageMeta.disableScroll) { + return document.addEventListener("touchmove", disableScrollListener); + } + const {onPageScroll, onReachBottom} = instance2; + const navigationBarTransparent = pageMeta.navigationBar.type === "transparent"; + if (!onPageScroll && !onReachBottom && !navigationBarTransparent) { + return; + } + const opts = {}; + const pageId = instance2.proxy.$page.id; + if (onPageScroll || navigationBarTransparent) { + opts.onPageScroll = createOnPageScroll(pageId, onPageScroll, navigationBarTransparent); + } + if (onReachBottom) { + opts.onReachBottomDistance = pageMeta.onReachBottomDistance || ON_REACH_BOTTOM_DISTANCE; + opts.onReachBottom = () => UniViewJSBridge.publishHandler("onReachBottom", {}, pageId); + } + curScrollListener = createScrollListener(opts); + requestAnimationFrame(() => document.addEventListener("scroll", curScrollListener)); +} +function createOnPageScroll(pageId, onPageScroll, navigationBarTransparent) { + return (scrollTop) => { + if (onPageScroll) { + UniViewJSBridge.publishHandler("onPageScroll", {scrollTop}, pageId); + } + if (navigationBarTransparent) { + UniViewJSBridge.emit(pageId + ".onPageScroll", { + scrollTop + }); + } + }; +} +function initRouter(app) { + app.use(createAppRouter(createRouter(createRouterOptions()))); +} +const scrollBehavior = (_to, _from, savedPosition) => { + if (savedPosition) { + return savedPosition; + } +}; +function createRouterOptions() { + return { + history: initHistory(), + strict: !!__uniConfig.router.strict, + routes: __uniRoutes, + scrollBehavior }; } +function createAppRouter(router) { + return router; +} +function removeCurrentPages(delta = 1) { + const keys = getCurrentPages$1(); + const start = keys.length - 1; + const end = start - delta; + for (let i2 = start; i2 > end; i2--) { + const page = keys[i2].$page; + removePage(normalizeRouteKey(page.path, page.id), false); + } +} +function initHistory() { + const history2 = __UNI_FEATURE_ROUTER_MODE__ === "history" ? createWebHistory() : createWebHashHistory(); + history2.listen((_to, _from, info) => { + if (info.direction === "back") { + removeCurrentPages(Math.abs(info.delta)); + } + }); + return history2; +} +var index$a = { + install(app) { + initApp$1(app); + initView(app); + initService(app); + if (__UNI_FEATURE_PAGES__) { + initRouter(app); + } + } +}; +let appVm; +function getApp$1() { + return appVm; +} +function initApp(vm) { + appVm = vm; + appVm.$vm = vm; + appVm.globalData = appVm.$options.globalData || {}; +} function wrapperComponentSetup(comp, {init: init2, setup, after}) { const oldSetup = comp.setup; comp.setup = (props2, ctx) => { @@ -3607,9 +3730,6 @@ function setupComponent(comp, options) { } return comp; } -function onPageShow(pageMeta) { - updateCurPageCssVar(pageMeta); -} function setupPage(comp) { return setupComponent(comp, { init: initPage, @@ -3622,7 +3742,7 @@ function setupPage(comp) { const pageMeta = usePageMeta(); onBeforeMount(() => { const {onLoad, onShow} = instance2; - onPageShow(pageMeta); + onPageShow(instance2, pageMeta); onLoad && invokeArrayFns$1(onLoad, decodedQuery(route.query)); instance2.__isVisible = true; onShow && invokeArrayFns$1(onShow); @@ -3633,7 +3753,7 @@ function setupPage(comp) { }); onBeforeActivate(() => { if (!instance2.__isVisible) { - onPageShow(pageMeta); + onPageShow(instance2, pageMeta); instance2.__isVisible = true; const {onShow} = instance2; onShow && invokeArrayFns$1(onShow); @@ -4298,7 +4418,7 @@ function useBooleanAttr(props2, keys) { }, Object.create(null)); } const uniFormKey = PolySymbol(process.env.NODE_ENV !== "production" ? "uniForm" : "uf"); -var index$8 = /* @__PURE__ */ defineComponent({ +var index$9 = /* @__PURE__ */ defineComponent({ name: "Form", setup(_props, { slots, @@ -4335,7 +4455,7 @@ function provideForm(emit) { }); return fields; } -var index$7 = /* @__PURE__ */ defineComponent({ +var index$8 = /* @__PURE__ */ defineComponent({ name: "Button", props: { id: { @@ -5883,7 +6003,7 @@ const ICONS = { c: GREY_COLOR } }; -var index$6 = /* @__PURE__ */ defineComponent({ +var index$7 = /* @__PURE__ */ defineComponent({ name: "Icon", props: { type: { @@ -5989,7 +6109,7 @@ function useResizeSensorLifecycle(rootRef, props2, update, reset) { } }); } -const props$2 = { +const props$3 = { src: { type: String, default: "" @@ -6026,9 +6146,9 @@ const IMAGE_MODES = { "bottom left": ["left bottom"], "bottom right": ["right bottom"] }; -var index$5 = /* @__PURE__ */ defineComponent({ +var index$6 = /* @__PURE__ */ defineComponent({ name: "Image", - props: props$2, + props: props$3, setup(props2, { emit }) { @@ -7605,7 +7725,7 @@ const VALUES = { backgroundColor: "#EBEBEB", activeMode: "backwards" }; -const props$1 = { +const props$2 = { percent: { type: [Number, String], default: 0, @@ -7652,9 +7772,9 @@ const props$1 = { } } }; -var index$4 = /* @__PURE__ */ defineComponent({ +var index$5 = /* @__PURE__ */ defineComponent({ name: "Progress", - props: props$1, + props: props$2, setup(props2) { const state = useProgressState(props2); _activeAnimation(state, props2); @@ -9657,7 +9777,7 @@ function normalizeText(text2, { } return text2.replace(/ /g, SPACE_UNICODE.nbsp).replace(/ /g, SPACE_UNICODE.ensp).replace(/ /g, SPACE_UNICODE.emsp).replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&").replace(/"/g, '"').replace(/'/g, "'"); } -var index$3 = /* @__PURE__ */ defineComponent({ +var index$4 = /* @__PURE__ */ defineComponent({ name: "Text", props: { selectable: { @@ -9980,7 +10100,7 @@ function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) { ], 16); } _sfc_main$3.render = _sfc_render$3; -var index$2 = /* @__PURE__ */ defineComponent({ +var index$3 = /* @__PURE__ */ defineComponent({ name: "View", props: extend({}, hoverProps), setup(props2, { @@ -10655,7 +10775,7 @@ function useContext(play, pause, seek, sendDanmu, playbackRate, requestFullScree } }); } -const props = { +const props$1 = { id: { type: String, default: "" @@ -10739,9 +10859,9 @@ const props = { default: true } }; -var index$1 = /* @__PURE__ */ defineComponent({ +var index$2 = /* @__PURE__ */ defineComponent({ name: "Video", - props, + props: props$1, emits: ["fullscreenchange", "progress", "loadedmetadata", "waiting", "error", "play", "pause", "ended", "timeupdate"], setup(props2, { emit, @@ -10950,6 +11070,74 @@ var index$1 = /* @__PURE__ */ defineComponent({ }; } }); +const props = { + src: { + type: String, + default: "" + }, + allow: String, + sandbox: String +}; +var index$1 = /* @__PURE__ */ defineComponent({ + name: "WebView", + props, + setup(props2) { + const rootRef = ref(null); + const iframe = document.createElement("iframe"); + const { + _resize + } = useWebViewSize(rootRef, iframe); + useWebViewLoader(iframe, props2, _resize); + return () => createVNode("uni-web-view", { + ref: rootRef + }, [createVNode(ResizeSensor, { + onResize: _resize + }, null, 8, ["onResize"])], 512); + } +}); +function useWebViewLoader(iframe, props2, _resize) { + props2.allow && iframe.setAttribute("allow", props2.allow); + props2.sandbox && iframe.setAttribute("sandbox", props2.sandbox); + iframe.src = getRealPath(props2.src); + document.body.appendChild(iframe); + onMounted(() => { + _resize(); + }); + onActivated(() => { + iframe.style.display = "block"; + }); + onDeactivated(() => { + iframe.style.display = "none"; + }); + onUnmounted(() => { + document.body.removeChild(iframe); + }); + watch(() => props2.src, (val) => { + iframe.src = getRealPath(val); + }); +} +function useWebViewSize(rootRef, iframe) { + const _resize = () => { + const { + top, + left, + width, + height + } = rootRef.value.getBoundingClientRect(); + updateElementStyle(iframe, { + position: "absolute", + display: "block", + border: "0", + top: top + "px", + left: left + "px", + width: width + "px", + height: height + "px" + }); + }; + return { + _resize + }; +} const UniViewJSBridge$1 = /* @__PURE__ */ extend(ViewJSBridge, { publishHandler(event2, args, pageId) { window.UniServiceJSBridge.subscribeHandler(event2, args, pageId); @@ -13929,4 +14117,4 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { ]); } _sfc_main.render = _sfc_render; -export {_sfc_main$1 as AsyncErrorComponent, _sfc_main as AsyncLoadingComponent, _sfc_main$j as Audio, index$7 as Button, _sfc_main$i as Canvas, _sfc_main$h as Checkbox, _sfc_main$g as CheckboxGroup, _sfc_main$f as Editor, index$8 as Form, index$6 as Icon, index$5 as Image, _sfc_main$e as Input, _sfc_main$d as Label, LayoutComponent, _sfc_main$c as MovableView, _sfc_main$b as Navigator, index as PageComponent, index$4 as Progress, _sfc_main$a as Radio, _sfc_main$9 as RadioGroup, ResizeSensor, _sfc_main$8 as RichText, _sfc_main$7 as ScrollView, _sfc_main$6 as Slider, _sfc_main$5 as SwiperItem, _sfc_main$4 as Switch, index$3 as Text, _sfc_main$3 as Textarea, UniServiceJSBridge$1 as UniServiceJSBridge, UniViewJSBridge$1 as UniViewJSBridge, index$1 as Video, index$2 as View, addInterceptor, arrayBufferToBase64, base64ToArrayBuffer, canIUse, chooseFile, chooseImage, chooseVideo, clearStorage, clearStorageSync, closeSocket, connectSocket, createInnerAudioContext, createIntersectionObserver, createSelectorQuery, createVideoContext, cssBackdropFilter, cssConstant, cssEnv, cssVar, downloadFile, getApp$1 as getApp, getCurrentPages$1 as getCurrentPages, getFileInfo, getImageInfo, getLocation, getNetworkType, getStorage, getStorageInfo, getStorageInfoSync, getStorageSync, getSystemInfo, getSystemInfoSync, getVideoInfo, hideKeyboard, hideLoading, hideNavigationBarLoading, hideTabBar, hideTabBarRedDot, hideToast, loadFontFace, makePhoneCall, navigateBack, navigateTo, offAccelerometerChange, offCompassChange, offNetworkStatusChange, onAccelerometerChange, onCompassChange, onNetworkStatusChange, onSocketClose, onSocketError, onSocketMessage, onSocketOpen, onTabBarMidButtonTap, openDocument, pageScrollTo, index$9 as plugin, promiseInterceptor, reLaunch, redirectTo, removeInterceptor, removeStorage, removeStorageSync, removeTabBarBadge, request, sendSocketMessage, setNavigationBarColor, setNavigationBarTitle, setStorage, setStorageSync, setTabBarBadge, setTabBarItem, setTabBarStyle, setupApp, setupPage, showActionSheet, showLoading, showModal, showNavigationBarLoading, showTabBar, showTabBarRedDot, showToast, startAccelerometer, startCompass, startPullDownRefresh, stopAccelerometer, stopCompass, stopPullDownRefresh, switchTab, uni$1 as uni, uploadFile, upx2px, useCustomEvent, useOn, usePageRoute, useSubscribe, useUserAction, vibrateLong, vibrateShort}; +export {_sfc_main$1 as AsyncErrorComponent, _sfc_main as AsyncLoadingComponent, _sfc_main$j as Audio, index$8 as Button, _sfc_main$i as Canvas, _sfc_main$h as Checkbox, _sfc_main$g as CheckboxGroup, _sfc_main$f as Editor, index$9 as Form, index$7 as Icon, index$6 as Image, _sfc_main$e as Input, _sfc_main$d as Label, LayoutComponent, _sfc_main$c as MovableView, _sfc_main$b as Navigator, index as PageComponent, index$5 as Progress, _sfc_main$a as Radio, _sfc_main$9 as RadioGroup, ResizeSensor, _sfc_main$8 as RichText, _sfc_main$7 as ScrollView, _sfc_main$6 as Slider, _sfc_main$5 as SwiperItem, _sfc_main$4 as Switch, index$4 as Text, _sfc_main$3 as Textarea, UniServiceJSBridge$1 as UniServiceJSBridge, UniViewJSBridge$1 as UniViewJSBridge, index$2 as Video, index$3 as View, index$1 as WebView, addInterceptor, arrayBufferToBase64, base64ToArrayBuffer, canIUse, chooseFile, chooseImage, chooseVideo, clearStorage, clearStorageSync, closeSocket, connectSocket, createInnerAudioContext, createIntersectionObserver, createSelectorQuery, createVideoContext, cssBackdropFilter, cssConstant, cssEnv, cssVar, downloadFile, getApp$1 as getApp, getCurrentPages$1 as getCurrentPages, getFileInfo, getImageInfo, getLocation, getNetworkType, getStorage, getStorageInfo, getStorageInfoSync, getStorageSync, getSystemInfo, getSystemInfoSync, getVideoInfo, hideKeyboard, hideLoading, hideNavigationBarLoading, hideTabBar, hideTabBarRedDot, hideToast, loadFontFace, makePhoneCall, navigateBack, navigateTo, offAccelerometerChange, offCompassChange, offNetworkStatusChange, onAccelerometerChange, onCompassChange, onNetworkStatusChange, onSocketClose, onSocketError, onSocketMessage, onSocketOpen, onTabBarMidButtonTap, openDocument, pageScrollTo, index$a as plugin, promiseInterceptor, reLaunch, redirectTo, removeInterceptor, removeStorage, removeStorageSync, removeTabBarBadge, request, sendSocketMessage, setNavigationBarColor, setNavigationBarTitle, setStorage, setStorageSync, setTabBarBadge, setTabBarItem, setTabBarStyle, setupApp, setupPage, showActionSheet, showLoading, showModal, showNavigationBarLoading, showTabBar, showTabBarRedDot, showToast, startAccelerometer, startCompass, startPullDownRefresh, stopAccelerometer, stopCompass, stopPullDownRefresh, switchTab, uni$1 as uni, uploadFile, upx2px, useCustomEvent, useOn, useSubscribe, useUserAction, vibrateLong, vibrateShort}; diff --git a/packages/uni-h5/src/framework/components/layout/index.tsx b/packages/uni-h5/src/framework/components/layout/index.tsx index f601a3f702d9162852f3931b25aeb23ba5683e33..f5b928ce62d719c81619c6fc5d9502d7b6082f7d 100644 --- a/packages/uni-h5/src/framework/components/layout/index.tsx +++ b/packages/uni-h5/src/framework/components/layout/index.tsx @@ -17,8 +17,8 @@ import { import { RouterView, useRoute } from 'vue-router' -import { useTabBar } from '../../plugin/state' -import { useKeepAliveRoute } from '../../plugin/page' +import { useTabBar } from '../../setup/state' +import { useKeepAliveRoute } from '../../setup/page' import TabBar from './tabBar' diff --git a/packages/uni-h5/src/framework/components/layout/tabBar.tsx b/packages/uni-h5/src/framework/components/layout/tabBar.tsx index f90d1998d84a969d2e3601e7a2186de9fe8e8283..acddf67fafa7d871362bd7d8761323e98d6e905b 100644 --- a/packages/uni-h5/src/framework/components/layout/tabBar.tsx +++ b/packages/uni-h5/src/framework/components/layout/tabBar.tsx @@ -6,7 +6,7 @@ import { OnTabBarMidButtonTap, } from '@dcloudio/uni-api' import { getRealPath } from '../../../platform' -import { useTabBar } from '../../plugin/state' +import { useTabBar } from '../../setup/state' import { cssBackdropFilter } from '../../../service/api/base/canIUse' import { normalizeWindowBottom } from '../../../helpers/cssVar' diff --git a/packages/uni-h5/src/framework/components/page/index.ts b/packages/uni-h5/src/framework/components/page/index.ts index d17c150e37eceab1b97695bb6446b7f324b9cfbc..c84d6f741d440cb7a0533d947cc03c7bd4047e06 100644 --- a/packages/uni-h5/src/framework/components/page/index.ts +++ b/packages/uni-h5/src/framework/components/page/index.ts @@ -10,7 +10,7 @@ import { import PageHead from './pageHead' import PageBody from './pageBody' -import { providePageMeta } from '../../plugin/provide' +import { providePageMeta } from '../../setup/provide' export default defineComponent({ name: 'Page', diff --git a/packages/uni-h5/src/framework/components/page/page-refresh/component.vue b/packages/uni-h5/src/framework/components/page/page-refresh/component.vue index e1556c7fe636bb2f518b85ad5f2d53e9d58b0586..390cb144080acb154eada8fa477a9076037d6dc3 100644 --- a/packages/uni-h5/src/framework/components/page/page-refresh/component.vue +++ b/packages/uni-h5/src/framework/components/page/page-refresh/component.vue @@ -36,7 +36,7 @@