Commit c6c2a115 authored by Sendya's avatar Sendya

fix: FooterToolbar auto margin

parent 0f46541a
...@@ -224,8 +224,14 @@ const layoutConf = reactive({ ...@@ -224,8 +224,14 @@ const layoutConf = reactive({
</template> </template>
``` ```
### Use WaterMark
```vue
<router-view v-slot="{ Component }">
<WaterMark content="Pro Layout">
<component :is="Component" />
</WaterMark>
</router-view>
```
## Build project ## Build project
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
v-bind="state" v-bind="state"
:loading="loading" :loading="loading"
:breadcrumb="{ routes: breadcrumb }" :breadcrumb="{ routes: breadcrumb }"
iconfont-url="//at.alicdn.com/t/font_2804900_26tw52dc2pl.js" iconfont-url="//at.alicdn.com/t/font_2804900_nzigh7z84gc.js"
> >
<template #menuHeaderRender> <template #menuHeaderRender>
<a> <a>
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
</router-link> </router-link>
</template> </template>
<template #menuExtraRender="{ collapsed }"> <template #menuExtraRender="{ collapsed }">
<a-input-search v-if="!collapsed" /> <a-input-search v-if="!collapsed" @search="handleSearch" />
</template> </template>
<template #menuFooterRender> <template #menuFooterRender>
<a <a
...@@ -67,26 +67,13 @@ ...@@ -67,26 +67,13 @@
</a> </a>
</template> </template>
<!-- custom menu-item -->
<template #menuItemRender="{ item, icon }">
<a-menu-item
:key="item.path"
:disabled="item.meta?.disabled"
:danger="item.meta?.danger"
:icon="icon"
>
<router-link :to="{ path: item.path }">
<span class="ant-pro-menu-item">
<a-badge count="5" dot>
<span class="ant-pro-menu-item-title">{{ item.meta.title }}</span>
</a-badge>
</span>
</router-link>
</a-menu-item>
</template>
<!-- content begin --> <!-- content begin -->
<router-view /> <router-view v-slot="{ Component }">
<WaterMark content="Pro Layout">
<component :is="Component" />
</WaterMark>
</router-view>
<!-- content end --> <!-- content end -->
<FooterToolbar> <FooterToolbar>
<template #extra> <template #extra>
...@@ -120,8 +107,8 @@ ...@@ -120,8 +107,8 @@
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, reactive, ref, watchEffect } from 'vue'; import { computed, defineComponent, reactive, ref, watchEffect } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { Button, Input, Switch, Select, Avatar, Space, Badge, Menu } from 'ant-design-vue'; import { message, Button, Input, Switch, Select, Avatar, Space, Badge, Menu } from 'ant-design-vue';
import { getMenuData, clearMenuItem, FooterToolbar } from '@ant-design-vue/pro-layout'; import { getMenuData, clearMenuItem, WaterMark, FooterToolbar } from '@ant-design-vue/pro-layout';
import type { RouteContextProps } from '@ant-design-vue/pro-layout'; import type { RouteContextProps } from '@ant-design-vue/pro-layout';
const i18n = (t: string) => t; const i18n = (t: string) => t;
...@@ -130,6 +117,8 @@ export default defineComponent({ ...@@ -130,6 +117,8 @@ export default defineComponent({
name: 'BasicLayout', name: 'BasicLayout',
components: { components: {
FooterToolbar, FooterToolbar,
WaterMark,
[Button.name]: Button, [Button.name]: Button,
[Input.name]: Input, [Input.name]: Input,
[Input.Search.name]: Input.Search, [Input.Search.name]: Input.Search,
...@@ -137,7 +126,6 @@ export default defineComponent({ ...@@ -137,7 +126,6 @@ export default defineComponent({
[Select.name]: Select, [Select.name]: Select,
[Select.Option.displayName!]: Select.Option, [Select.Option.displayName!]: Select.Option,
[Space.name]: Space, [Space.name]: Space,
[Badge.name]: Badge, [Badge.name]: Badge,
[Avatar.name]: Avatar, [Avatar.name]: Avatar,
[Menu.Item.name]: Menu.Item, [Menu.Item.name]: Menu.Item,
...@@ -161,7 +149,7 @@ export default defineComponent({ ...@@ -161,7 +149,7 @@ export default defineComponent({
// title: 'ProLayout', // title: 'ProLayout',
// logo: 'https://alicdn.antdv.com/v2/assets/logo.1ef800a8.svg', // logo: 'https://alicdn.antdv.com/v2/assets/logo.1ef800a8.svg',
navTheme: 'dark', navTheme: 'dark',
layout: 'mix', layout: 'side',
fixSiderbar: true, fixSiderbar: true,
}); });
const breadcrumb = computed(() => const breadcrumb = computed(() =>
...@@ -202,6 +190,9 @@ export default defineComponent({ ...@@ -202,6 +190,9 @@ export default defineComponent({
handlePageLoadingClick, handlePageLoadingClick,
handleCollapsed, handleCollapsed,
handleSearch: () => {
message.info('search..');
},
}; };
}, },
}); });
......
This diff is collapsed.
import './index.less'; import './index.less'
import { computed, defineComponent, onBeforeUnmount, onMounted, PropType } from 'vue'; import {
import { RouteContextProps, useRouteContext } from '../RouteContext'; computed,
import { getMenuFirstChildren, getPropsSlot, getPropsSlotfn } from '../utils'; defineComponent,
import type { CustomRender } from '../typings'; onBeforeUnmount,
onMounted,
unref,
PropType,
} from 'vue'
import { RouteContextProps, useRouteContext } from '../RouteContext'
import { getPropsSlotfn } from '../utils'
import type { CustomRender } from '../typings'
export interface FooterToolbarProps { export interface FooterToolbarProps {
extra?: CustomRender | JSX.Element; extra?: CustomRender | JSX.Element
renderContent?: ( renderContent?: (
props: FooterToolbarProps & RouteContextProps & { leftWidth?: string }, props: FooterToolbarProps & RouteContextProps & { leftWidth?: string },
dom: CustomRender | JSX.Element, dom: CustomRender | JSX.Element
) => CustomRender | JSX.Element; ) => CustomRender | JSX.Element
getContainer?: (triggerNode: HTMLElement) => HTMLElement | null; getContainer?: (triggerNode: HTMLElement) => HTMLElement | null
prefixCls?: string; prefixCls?: string
} }
const footerToolbarProps = { const footerToolbarProps = {
...@@ -25,52 +32,47 @@ const footerToolbarProps = { ...@@ -25,52 +32,47 @@ const footerToolbarProps = {
type: [Function, Object] as PropType<FooterToolbarProps['getContainer']>, type: [Function, Object] as PropType<FooterToolbarProps['getContainer']>,
}, },
prefixCls: { type: String as PropType<string> }, prefixCls: { type: String as PropType<string> },
}; }
const FooterToolbar = defineComponent({ const FooterToolbar = defineComponent({
name: 'FooterToolbar', name: 'FooterToolbar',
props: footerToolbarProps, props: footerToolbarProps,
setup(props, { slots }) { setup(props, { slots }) {
const routeContext = useRouteContext(); const context = useRouteContext()
const { getPrefixCls } = routeContext; const baseClassName = props.prefixCls || context.getPrefixCls('footer-bar')
const baseClassName = props.prefixCls || getPrefixCls('footer-bar');
// matchMenuKeys const hasFlatMenu = computed(() => {
const matchMenuChildrenSize = computed( return unref(context.flatMenuData).length > 0
() => })
(
(routeContext.menuData &&
getMenuFirstChildren(
routeContext.menuData,
(routeContext.selectedKeys && routeContext.selectedKeys[0]) || undefined,
)) ||
[]
).length,
);
const hasSide = computed(() => {
return routeContext.layout === 'mix' && routeContext.splitMenus
? matchMenuChildrenSize.value > 0
: true;
});
const width = computed(() => { const width = computed(() => {
const { isMobile, sideWidth, layout } = routeContext; const { isMobile, hasSide, siderWidth, layout } = context
if (!sideWidth || layout === 'top') { if (!siderWidth || layout === 'top') {
return '100%'; return '100%'
} }
if (!hasSide.value) { console.log(
return '100%'; 'x',
unref(siderWidth),
'hasFlatMenu',
unref(hasFlatMenu),
'hasSide',
unref(context.hasSide)
)
if (!hasFlatMenu.value && !unref(hasSide)) {
return '100%'
} }
return isMobile ? '100%' : `calc(100% - ${sideWidth}px)`; console.log('x2', unref(context.hasSide))
}); return isMobile ? '100%' : `calc(100% - ${siderWidth}px)`
})
onMounted(() => { onMounted(() => {
routeContext.setHasFooterToolbar && routeContext.setHasFooterToolbar(true); context.setHasFooterToolbar && context.setHasFooterToolbar(true)
}); })
onBeforeUnmount(() => { onBeforeUnmount(() => {
routeContext.setHasFooterToolbar && routeContext.setHasFooterToolbar(false); context.setHasFooterToolbar && context.setHasFooterToolbar(false)
}); })
return () => { return () => {
const extra = getPropsSlotfn(slots, props, 'extra'); const extra = getPropsSlotfn(slots, props, 'extra')
const dom = () => { const dom = () => {
return ( return (
<> <>
...@@ -79,24 +81,24 @@ const FooterToolbar = defineComponent({ ...@@ -79,24 +81,24 @@ const FooterToolbar = defineComponent({
</div> </div>
<div class={`${baseClassName}-right`}>{slots.default?.()}</div> <div class={`${baseClassName}-right`}>{slots.default?.()}</div>
</> </>
); )
}; }
return ( return (
<div class={baseClassName} style={{ width: width.value }}> <div class={baseClassName} style={{ width: width.value }}>
{props.renderContent {props.renderContent
? props.renderContent( ? props.renderContent(
{ {
...props, ...props,
...routeContext, ...context,
leftWidth: width.value, leftWidth: width.value,
}, },
dom(), dom()
) )
: dom()} : dom()}
</div> </div>
); )
}; }
}, },
}); })
export default FooterToolbar; export default FooterToolbar
import { InjectionKey, provide, reactive, Ref, VNodeChild, ComputedRef } from 'vue'; import {
import { createContext, useContext } from './hooks/context'; InjectionKey,
import { MenuDataItem, FormatMessage, WithFalse } from './typings'; provide,
import { PureSettings } from './defaultSettings'; reactive,
Ref,
VNodeChild,
ComputedRef,
} from 'vue'
import { createContext, useContext } from './hooks/context'
import { MenuDataItem, FormatMessage, WithFalse } from './typings'
import { PureSettings } from './defaultSettings'
export interface Route { export interface Route {
path: string; path: string
breadcrumbName: string; breadcrumbName: string
children?: Omit<Route, 'children'>[]; children?: Omit<Route, 'children'>[]
} }
export interface BreadcrumbProps { export interface BreadcrumbProps {
prefixCls?: string; prefixCls?: string
routes?: Route[]; routes?: Route[]
params?: any; params?: any
separator?: VNodeChild; separator?: VNodeChild
itemRender?: (opts: { itemRender?: (opts: {
route: Route; route: Route
params: any; params: any
routes: Array<Route>; routes: Array<Route>
paths: Array<string>; paths: Array<string>
}) => VNodeChild; }) => VNodeChild
} }
export type BreadcrumbListReturn = Pick< export type BreadcrumbListReturn = Pick<
BreadcrumbProps, BreadcrumbProps,
Extract<keyof BreadcrumbProps, 'routes' | 'itemRender'> Extract<keyof BreadcrumbProps, 'routes' | 'itemRender'>
>; >
export interface MenuState { export interface MenuState {
selectedKeys: string[]; selectedKeys: string[]
openKeys: string[]; openKeys: string[]
} }
export interface RouteContextProps extends Partial<PureSettings>, MenuState { export interface RouteContextProps extends Partial<PureSettings>, MenuState {
menuData: MenuDataItem[]; menuData: MenuDataItem[]
flatMenuData?: MenuDataItem[]
getPrefixCls?: (suffixCls?: string, customizePrefixCls?: string) => string; getPrefixCls?: (suffixCls?: string, customizePrefixCls?: string) => string
locale?: WithFalse<FormatMessage>; locale?: WithFalse<FormatMessage>
breadcrumb?: BreadcrumbListReturn | ComputedRef<BreadcrumbListReturn>; breadcrumb?: BreadcrumbListReturn | ComputedRef<BreadcrumbListReturn>
isMobile?: boolean; isMobile?: boolean
prefixCls?: string; prefixCls?: string
collapsed?: boolean; collapsed?: boolean
hasSideMenu?: boolean; hasSideMenu?: boolean
hasHeader?: boolean; hasHeader?: boolean
sideWidth?: number; siderWidth?: number
headerHeight?: number; headerHeight?: number
hasFooterToolbar?: boolean; hasFooterToolbar?: boolean
hasFooter?: boolean; hasFooter?: boolean
setHasFooterToolbar?: (bool: boolean) => void; hasSide?: boolean
setHasFooterToolbar?: (bool: boolean) => void
/* 附加属性 */ /* 附加属性 */
[key: string]: any; [key: string]: any
} }
export const defaultPrefixCls = 'ant-pro'; export const defaultPrefixCls = 'ant-pro'
export const getPrefixCls = (suffixCls?: string, customizePrefixCls?: string) => { export const getPrefixCls = (
if (customizePrefixCls) return customizePrefixCls; suffixCls?: string,
return suffixCls ? `${defaultPrefixCls}-${suffixCls}` : defaultPrefixCls; customizePrefixCls?: string
}; ) => {
if (customizePrefixCls) return customizePrefixCls
return suffixCls ? `${defaultPrefixCls}-${suffixCls}` : defaultPrefixCls
}
// set default context // set default context
export const defaultRouteContext = reactive({ export const defaultRouteContext = reactive({
...@@ -65,22 +77,31 @@ export const defaultRouteContext = reactive({ ...@@ -65,22 +77,31 @@ export const defaultRouteContext = reactive({
locale: (t: string) => t, locale: (t: string) => t,
contentWidth: 'Fluid', contentWidth: 'Fluid',
hasFooterToolbar: false, hasFooterToolbar: false,
}); })
const routeContextInjectKey: InjectionKey<RouteContextProps> = Symbol('route-context'); const routeContextInjectKey: InjectionKey<RouteContextProps> =
Symbol('route-context')
export const createRouteContext = () => export const createRouteContext = () =>
createContext<RouteContextProps>(routeContextInjectKey, 'RouteContext.Provider'); createContext<RouteContextProps>(
routeContextInjectKey,
'RouteContext.Provider'
)
export const provideRouteContext = (value: RouteContextProps | Ref<RouteContextProps>) => { export const provideRouteContext = (
provide(routeContextInjectKey, value); value: RouteContextProps | Ref<RouteContextProps>
}; ) => {
provide(routeContextInjectKey, value)
}
export const useRouteContext = () => export const useRouteContext = () =>
useContext<Required<RouteContextProps>>(routeContextInjectKey, defaultRouteContext); useContext<Required<RouteContextProps>>(
routeContextInjectKey,
defaultRouteContext
)
const Provider = createRouteContext(); const Provider = createRouteContext()
export default { export default {
Provider, Provider,
}; }
This diff is collapsed.
...@@ -197,6 +197,7 @@ ...@@ -197,6 +197,7 @@
.@{ant-prefix}-menu-submenu-title { .@{ant-prefix}-menu-submenu-title {
.anticon { .anticon {
transition: none; transition: none;
font-size: 16px;
} }
} }
......
...@@ -68,6 +68,7 @@ const getPixelRatio = (context: any) => { ...@@ -68,6 +68,7 @@ const getPixelRatio = (context: any) => {
} }
const WaterMark = defineComponent({ const WaterMark = defineComponent({
name: 'WaterMark',
props: waterMarkProps, props: waterMarkProps,
setup(props, { slots }) { setup(props, { slots }) {
const { const {
...@@ -145,32 +146,34 @@ const WaterMark = defineComponent({ ...@@ -145,32 +146,34 @@ const WaterMark = defineComponent({
} }
}) })
return ( return () => {
<div return (
style={{
position: 'relative',
}}
class={wrapperCls.value}
>
{slots.default?.()}
<div <div
class={waterMakrCls.value}
style={{ style={{
zIndex, position: 'relative',
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%',
backgroundSize: `${gapX + width}px`,
pointerEvents: 'none',
backgroundRepeat: 'repeat',
backgroundImage: `url('${base64Url.value}')`,
...markStyle,
}} }}
/> class={wrapperCls.value}
</div> >
) {slots.default?.()}
<div
class={waterMakrCls.value}
style={{
zIndex,
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%',
backgroundSize: `${gapX + width}px`,
pointerEvents: 'none',
backgroundRepeat: 'repeat',
backgroundImage: `url('${base64Url.value}')`,
...markStyle,
}}
/>
</div>
)
}
}, },
}) })
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment