提交 018baeab 编写于 作者: fxy060608's avatar fxy060608

feat: support page selector

上级 c26c15de
......@@ -3515,8 +3515,10 @@ function normalizeRouteKey(path, id2) {
function useKeepAliveRoute() {
const route = useRoute();
const routeKey = computed(() => normalizeRouteKey(route.path, history.state.__id__ || 1));
const isTabBar = computed(() => route.meta.isTabBar);
return {
routeKey,
isTabBar,
routeCache
};
}
......@@ -3541,16 +3543,7 @@ const routeCache = {
}
};
function isTabBarVNode(vnode) {
if (!hasOwn$1(vnode, "__isTabBar")) {
const {component} = vnode;
if (component && component.refs.page) {
const vm = component.refs.page;
if (vm.$page) {
vnode.__isTabBar = vm.__isTabBar;
}
}
}
return vnode.__isTabBar;
return vnode.props.type === "tabBar";
}
function pruneRouteCache(key) {
const pageId = parseInt(key.split(SEP)[1]);
......@@ -3570,9 +3563,33 @@ function pruneRouteCache(key) {
});
}
function onPageShow(instance2, pageMeta) {
updateBodyScopeId(instance2);
updateCurPageCssVar(pageMeta);
initPageScrollListener(instance2, pageMeta);
}
function onPageReady(instance2) {
const scopeId = getScopeId(instance2);
scopeId && updateCurPageBodyScopeId(scopeId);
}
function updateCurPageBodyScopeId(scopeId) {
const pageBodyEl = document.querySelector("uni-page-body");
if (pageBodyEl) {
pageBodyEl.setAttribute(scopeId, "");
} else if (process.env.NODE_ENV !== "production") {
console.warn("uni-page-body not found");
}
}
function getScopeId(instance2) {
return instance2.type.__scopeId;
}
let curScopeId;
function updateBodyScopeId(instance2) {
const scopeId = getScopeId(instance2);
const {body} = document;
curScopeId && body.removeAttribute(curScopeId);
scopeId && body.setAttribute(scopeId, "");
curScopeId = scopeId;
}
let curScrollListener;
function initPageScrollListener(instance2, pageMeta) {
document.removeEventListener("touchmove", disableScrollListener);
......@@ -3698,13 +3715,14 @@ function setupPage(comp) {
}
const pageMeta = usePageMeta();
onBeforeMount(() => {
const {onLoad, onShow} = instance2;
onPageShow(instance2, pageMeta);
const {onLoad, onShow} = instance2;
onLoad && invokeArrayFns$1(onLoad, decodedQuery(route.query));
instance2.__isVisible = true;
onShow && invokeArrayFns$1(onShow);
});
onMounted(() => {
onPageReady(instance2);
const {onReady} = instance2;
onReady && invokeArrayFns$1(onReady);
});
......@@ -12698,14 +12716,13 @@ function removeNonTabBarPages() {
const keys = pagesMap.keys();
for (const routeKey of keys) {
const page = pagesMap.get(routeKey);
const pageMeta = page.$page.meta;
if (!pageMeta.isTabBar) {
if (!page.__isTabBar) {
removePage(routeKey);
} else {
page.$.__isActive = false;
}
}
if (curTabBarPageVm.$page.meta.isTabBar) {
if (curTabBarPageVm.__isTabBar) {
curTabBarPageVm.$.__isVisible = false;
invokeHook(curTabBarPageVm, "onHide");
}
......@@ -13447,15 +13464,20 @@ function createTabBarTsx(showTabBar2) {
function createPageVNode() {
return createVNode(__uniRoutes[0].component);
}
function createRouterViewVNode(keepAliveRoute) {
function createRouterViewVNode({
routeKey,
isTabBar,
routeCache: routeCache2
}) {
return createVNode(RouterView, null, {
default: withCtx(({
Component
}) => [(openBlock(), createBlock(KeepAlive, {
matchBy: "key",
cache: keepAliveRoute.routeCache
cache: routeCache2
}, [(openBlock(), createBlock(resolveDynamicComponent(Component), {
key: keepAliveRoute.routeKey.value
type: isTabBar.value ? "tabBar" : "",
key: routeKey.value
}))], 1032, ["cache"]))]),
_: 1
});
......
......@@ -118,19 +118,22 @@ function createPageVNode() {
return createVNode(__uniRoutes[0].component)
}
function createRouterViewVNode(
keepAliveRoute: ReturnType<typeof useKeepAliveRoute>
) {
function createRouterViewVNode({
routeKey,
isTabBar,
routeCache,
}: ReturnType<typeof useKeepAliveRoute>) {
return createVNode(RouterView, null, {
default: withCtx(({ Component }: { Component: unknown }) => [
(openBlock(),
createBlock(
KeepAlive,
{ matchBy: 'key', cache: keepAliveRoute.routeCache },
{ matchBy: 'key', cache: routeCache },
[
(openBlock(),
createBlock(resolveDynamicComponent(Component), {
key: keepAliveRoute.routeKey.value,
type: isTabBar.value ? 'tabBar' : '',
key: routeKey.value,
})),
],
1032 /* PROPS, DYNAMIC_SLOTS */,
......
......@@ -15,7 +15,7 @@ import { useRouter } from 'vue-router'
import { decodedQuery } from '@dcloudio/uni-shared'
import { LayoutComponent } from '../..'
import { initApp } from './app'
import { initPage, onPageShow } from './page'
import { initPage, onPageShow, onPageReady } from './page'
import { usePageMeta, usePageRoute } from './provide'
interface SetupComponentOptions {
......@@ -61,13 +61,14 @@ export function setupPage(comp: any) {
}
const pageMeta = usePageMeta()
onBeforeMount(() => {
const { onLoad, onShow } = instance
onPageShow(instance, pageMeta)
const { onLoad, onShow } = instance
onLoad && invokeArrayFns(onLoad, decodedQuery(route.query))
instance.__isVisible = true
onShow && invokeArrayFns(onShow)
})
onMounted(() => {
onPageReady(instance)
const { onReady } = instance
onReady && invokeArrayFns(onReady)
})
......
......@@ -6,7 +6,6 @@ import {
ComponentPublicInstance,
ComponentInternalInstance,
} from 'vue'
import { hasOwn } from '@vue/shared'
import { useRoute, RouteLocationNormalizedLoaded } from 'vue-router'
import {
invokeHook,
......@@ -120,8 +119,10 @@ export function useKeepAliveRoute() {
const routeKey = computed(() =>
normalizeRouteKey(route.path, history.state.__id__ || 1)
)
const isTabBar = computed(() => route.meta.isTabBar)
return {
routeKey,
isTabBar,
routeCache,
}
}
......@@ -162,16 +163,7 @@ const routeCache: KeepAliveCache = {
}
function isTabBarVNode(vnode: VNode): boolean {
if (!hasOwn(vnode, '__isTabBar')) {
const { component } = vnode
if (component && component.refs.page) {
const vm = component.refs.page as ComponentPublicInstance
if (vm.$page) {
;(vnode as any).__isTabBar = vm.__isTabBar
}
}
}
return (vnode as any).__isTabBar
return vnode.props!.type === 'tabBar'
}
function pruneRouteCache(key: string) {
......@@ -197,10 +189,38 @@ export function onPageShow(
instance: ComponentInternalInstance,
pageMeta: UniApp.PageRouteMeta
) {
updateBodyScopeId(instance)
updateCurPageCssVar(pageMeta)
initPageScrollListener(instance, pageMeta)
}
export function onPageReady(instance: ComponentInternalInstance) {
const scopeId = getScopeId(instance)
scopeId && updateCurPageBodyScopeId(scopeId)
}
function updateCurPageBodyScopeId(scopeId: string) {
const pageBodyEl = document.querySelector('uni-page-body')
if (pageBodyEl) {
pageBodyEl.setAttribute(scopeId, '')
} else if (__DEV__) {
console.warn('uni-page-body not found')
}
}
function getScopeId(instance: ComponentInternalInstance) {
return (instance.type as any).__scopeId
}
let curScopeId: string
function updateBodyScopeId(instance: ComponentInternalInstance) {
const scopeId = getScopeId(instance)
const { body } = document
curScopeId && body.removeAttribute(curScopeId!)
scopeId && body.setAttribute(scopeId, '')
curScopeId = scopeId!
}
let curScrollListener: (evt: Event) => any
function initPageScrollListener(
instance: ComponentInternalInstance,
......
......@@ -19,14 +19,13 @@ function removeNonTabBarPages() {
const keys = pagesMap.keys()
for (const routeKey of keys) {
const page = pagesMap.get(routeKey) as ComponentPublicInstance
const pageMeta = page.$page.meta
if (!pageMeta.isTabBar) {
if (!page.__isTabBar) {
removePage(routeKey)
} else {
page.$.__isActive = false
}
}
if (curTabBarPageVm.$page.meta.isTabBar) {
if (curTabBarPageVm.__isTabBar) {
curTabBarPageVm.$.__isVisible = false
invokeHook(curTabBarPageVm, 'onHide')
}
......
......@@ -49,6 +49,7 @@ export default /*#__PURE__*/ defineComponent({
})
return () => {
const { title, content, showCancel, confirmText, confirmColor } = props
// TODO vue3 似乎有bug,不指定passive时,应该默认加上passive:false,否则浏览器会报警告,先看看vue3 会不会修复,若不修复,可以考虑手动addEventListener
return (
<Transition name="uni-fade">
<uni-modal v-show={visible.value} onTouchmove={onEventPrevent}>
......
......@@ -4,11 +4,14 @@ import { VitePluginUniResolvedOptions } from '..'
import { uniapp } from '../utils'
export function createCss(
_options: VitePluginUniResolvedOptions
options: VitePluginUniResolvedOptions
): UserConfig['css'] {
return {
postcss: {
plugins: [uniapp(), autoprefixer()],
plugins: [
uniapp({ page: options.platform === 'h5' ? 'uni-page-body' : 'body' }),
autoprefixer(),
],
},
preprocessorOptions: {
scss: {},
......
import { Rule, Declaration, Plugin } from 'postcss'
import { extend } from '@vue/shared'
import { rule, Rule, Declaration, Plugin } from 'postcss'
import selectorParser from 'postcss-selector-parser'
import {
isBuiltInComponent,
......@@ -6,30 +7,73 @@ import {
} from '@dcloudio/uni-shared'
interface UniAppCssProcessorOptions {
page?: boolean
unit: string // 目标单位,默认rem
unitRatio: number // 单位转换比例,默认10/320
unitPrecision: number // 单位精度,默认5
page?: string
unit?: string // 目标单位,默认rem
unitRatio?: number // 单位转换比例,默认10/320
unitPrecision?: number // 单位精度,默认5
}
const defaultUniAppCssProcessorOptions = {
page: false,
page: 'body',
unit: 'rem',
unitRatio: 10 / 320,
unitPrecision: 5,
}
function transform(selector: selectorParser.Node) {
if (selector.type === 'tag' && isBuiltInComponent(selector.value)) {
selector.value = COMPONENT_SELECTOR_PREFIX + selector.value
const BG_PROPS = [
'background',
'background-clip',
'background-color',
'background-image',
'background-origin',
'background-position',
'background-repeat',
'background-size',
'background-attachment',
]
function transform(
selector: selectorParser.Node,
opts: UniAppCssProcessorOptions,
state: { bg: boolean }
) {
if (selector.type !== 'tag') {
return
}
const { value } = selector
if (isBuiltInComponent(value)) {
selector.value = COMPONENT_SELECTOR_PREFIX + value
} else if (value === 'page') {
const { page } = opts
if (!page) {
return
}
selector.value = page
if (page !== 'body') {
state.bg = true
}
}
}
function createBodyBackgroundRule(origRule: Rule) {
const bgDecls: Declaration[] = []
origRule.walkDecls((decl) => {
if (BG_PROPS.indexOf(decl.prop) !== -1) {
bgDecls.push(decl.clone())
}
})
if (bgDecls.length) {
origRule.after(rule({ selector: 'body' }).append(bgDecls))
}
}
function walkRules(opts: UniAppCssProcessorOptions) {
return (rule: Rule) => {
const state = { bg: false }
rule.selector = selectorParser((selectors) =>
selectors.walk((selector) => transform(selector))
selectors.walk((selector) => transform(selector, opts, state))
).processSync(rule.selector)
state.bg && createBodyBackgroundRule(rule)
}
}
......@@ -44,7 +88,7 @@ function toFixed(number: number, precision: number) {
return (Math.round(wholeNumber / 10) * 10) / multiplier
}
function walkDecls(opts: UniAppCssProcessorOptions) {
function walkDecls(opts: Required<UniAppCssProcessorOptions>) {
return (decl: Declaration) => {
const { value } = decl
if (value.indexOf('rpx') === -1 && value.indexOf('upx') === -1) {
......@@ -61,18 +105,14 @@ function walkDecls(opts: UniAppCssProcessorOptions) {
}
export const uniapp = (opts?: UniAppCssProcessorOptions) => {
const options = Object.assign(
{},
defaultUniAppCssProcessorOptions,
opts || {}
)
const options = extend({}, defaultUniAppCssProcessorOptions, opts || {})
return {
postcssPlugin: 'uni-app',
prepare() {
return {
OnceExit(root) {
root.walkRules(walkRules(options))
root.walkDecls(walkDecls(options))
root.walkRules(walkRules(options))
},
}
},
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册