Commit 4ecee35a authored by Sendya's avatar Sendya Committed by 言肆

fix: layout props effects

parent 2f9d0e8d
@import '~ant-design-vue/es/style/themes/default.less';
.right-content {
height: 48px;
min-width: 100px;
padding: 0 12px;
float: right;
display: flex;
margin-left: auto;
overflow: hidden;
text-align: right;
> * {
height: 100%;
}
&.mix-dark,
&.mix-light {
color: @text-color-dark;
}
&.side-dark,
&.side-light,
&.top-light {
color: @text-color;
}
&.top-dark {
color: @text-color-dark;
}
.action {
display: flex;
align-items: center;
padding: 0 12px;
cursor: pointer;
transition: all 0.3s;
&:hover {
background: rgba(0, 0, 0, 0.055);
}
}
}
.action-overlay {
.ant-dropdown-menu-item {
min-width: 160px;
> span {
margin-right: 6px;
}
}
}
import { defineComponent } from 'vue';
import { Button, Space, Select, Switch } from 'ant-design-vue';
import { globalState as state } from '../state';
export default defineComponent({
......@@ -7,51 +7,7 @@ export default defineComponent({
return () => (
<div>
<div>Welcome</div>
<Space>
<Button
onClick={() => {
state.navTheme = state.navTheme === 'dark' ? 'light' : 'dark';
}}
>
Theme Switch
</Button>
<Select
value={state.layout}
onChange={val => {
state.layout = val;
}}
style={{ width: '150px' }}
>
<Select.Option value="side">Side</Select.Option>
<Select.Option value="top">Top</Select.Option>
<Select.Option value="mix">Mix</Select.Option>
</Select>
<Switch
checkedChildren="Fixed Header"
unCheckedChildren="UnFixed Header"
checked={state.fixedHeader}
onChange={() => {
state.fixedHeader = !state.fixedHeader;
}}
/>
<Switch
checkedChildren="Fixed SideBar"
unCheckedChildren="UnFixed SideBar"
checked={state.fixSiderbar}
onChange={() => {
state.fixSiderbar = !state.fixSiderbar;
}}
/>
<Switch
checkedChildren="Split Menus"
unCheckedChildren="Un Split Menus"
checked={state.splitMenus}
onChange={() => {
state.splitMenus = !state.splitMenus;
}}
/>
</Space>
<pre>{JSON.stringify(state, null, 2)}</pre>
<p>
<p>block</p>
...
......
This diff is collapsed.
......@@ -73,6 +73,7 @@
"@babel/runtime": "^7.11.2",
"ant-design-vue": "^2.0.0",
"lodash-es": "^4.17.20",
"omit.js": "^2.0.2",
"vue-types": "^3.0.1"
},
"files": [
......
import {
computed,
FunctionalComponent,
CSSProperties,
reactive,
unref,
provide,
defineComponent,
} from 'vue';
import { computed, CSSProperties, reactive, unref, provide, defineComponent, toRefs } from 'vue';
import 'ant-design-vue/es/layout/style';
import Layout from 'ant-design-vue/es/layout';
import { withInstall } from 'ant-design-vue/es/_util/type';
import RouteContext, { RouteContextProps } from './RouteContext';
import { RouteContextProps } from './RouteContext';
import { default as SiderMenuWrapper, SiderMenuWrapperProps } from './SiderMenu';
import { WrapContent } from './WrapContent';
import { default as Header, HeaderViewProps } from './Header';
import { VNodeType, CustomRender, WithFalse } from './typings';
import { getCustomRender, PropRenderType, PropTypes } from './utils';
import omit from 'omit.js';
import useMediaQuery from './hooks/useMediaQuery';
import './BasicLayout.less';
export const defaultPrefixCls = 'ant-pro';
const defaultI18nRender = (key: string) => key;
export type BasicLayoutProps = SiderMenuWrapperProps &
HeaderViewProps & {
pure?: boolean;
......@@ -60,34 +51,23 @@ export type BasicLayoutProps = SiderMenuWrapperProps &
const ProLayout = defineComponent({
setup(props: BasicLayoutProps, { emit, slots }) {
const {
onCollapse: propsOnCollapse,
onOpenKeys: propsOnOpenKeys,
onSelect: propsOnSelect,
contentStyle,
disableContentMargin,
isChildrenLayout: propsIsChildrenLayout,
// loading,
layout,
matchMenuKeys,
navTheme,
menuData,
// defaultCollapsed,
} = props;
const isTop = computed(() => layout === 'top');
const isTop = computed(() => props.layout === 'top');
// const isSide = computed(() => layout === 'side');
// const isMix = computed(() => layout === 'mix');
const pure = computed(() => props.pure);
const siderWidth = computed(() => (props.collapsed ? props.collapsedWidth : props.siderWidth));
// if on event and @event
const onCollapse =
(propsOnCollapse && propsOnCollapse) ||
((collapsed: boolean) => emit('update:collapsed', collapsed));
const onOpenKeys =
(propsOnOpenKeys && propsOnOpenKeys) ||
((openKeys: string[] | false) => emit('update:open-keys', openKeys));
const onSelect =
(propsOnSelect && propsOnSelect) ||
((selectedKeys: string[] | false) => emit('update:selected-keys', selectedKeys));
const onCollapse = (collapsed: boolean) => {
(props.onCollapse && props.onCollapse(collapsed)) || emit('update:collapsed', collapsed);
};
const onOpenKeys = (openKeys: string[] | false) => {
(props.onOpenKeys && props.onOpenKeys(openKeys)) || emit('update:open-keys', openKeys);
};
const onSelect = (selectedKeys: string[] | false) => {
(props.onSelect && props.onSelect(selectedKeys)) ||
emit('update:selected-keys', selectedKeys);
};
const colSize = useMediaQuery();
const isMobile = computed(
() => (colSize.value === 'sm' || colSize.value === 'xs') && !props.disableMobile,
......@@ -106,12 +86,12 @@ const ProLayout = defineComponent({
});
// siderMenuDom 为空的时候,不需要 padding
const genLayoutStyle: CSSProperties = {
const genLayoutStyle = reactive<CSSProperties>({
position: 'relative',
};
});
// if is some layout children, don't need min height
if (propsIsChildrenLayout || (contentStyle && contentStyle.minHeight)) {
if (props.isChildrenLayout || (props.contentStyle && props.contentStyle.minHeight)) {
genLayoutStyle.minHeight = 0;
}
......@@ -120,17 +100,17 @@ const ProLayout = defineComponent({
// onChange: propsOnCollapse,
// });
const headerRender = (
props: BasicLayoutProps & {
p: BasicLayoutProps & {
hasSiderMenu: boolean;
customHeaderRender: WithFalse<CustomRender>;
rightContentRender: WithFalse<CustomRender>;
},
matchMenuKeys: string[],
): VNodeType => {
if (props.headerRender === false || props.pure) {
matchMenuKeys?: string[],
): VNodeType | null => {
if (p.headerRender === false || p.pure) {
return null;
}
return <Header matchMenuKeys={matchMenuKeys} {...props} headerHeight={48} />;
return <Header matchMenuKeys={matchMenuKeys || []} {...p} headerHeight={48} />;
};
const rightContentRender = getCustomRender(props, slots, 'rightContentRender');
const customHeaderRender = getCustomRender(props, slots, 'headerRender');
......@@ -138,11 +118,12 @@ const ProLayout = defineComponent({
const footerRender = getCustomRender(props, slots, 'footerRender');
// const menuRender = getCustomRender(props, slots, 'menuRender');
const headerDom = headerRender(
const headerDom = computed(() =>
headerRender(
{
...props,
hasSiderMenu: !isTop.value,
menuData,
menuData: props.menuData,
isMobile: unref(isMobile),
onCollapse,
onOpenKeys,
......@@ -150,25 +131,36 @@ const ProLayout = defineComponent({
customHeaderRender,
rightContentRender,
headerTitleRender: menuHeaderRender,
theme: (navTheme || 'dark').toLocaleLowerCase().includes('dark') ? 'dark' : 'light',
theme: (props.navTheme || 'dark').toLocaleLowerCase().includes('dark') ? 'dark' : 'light',
},
matchMenuKeys,
props.matchMenuKeys,
),
);
const routeContext: RouteContextProps = {
const propRefs = toRefs(props);
// @ts-ignore
const routeContext: RouteContextProps = reactive({
getPrefixCls: (suffixCls?: string, customizePrefixCls?: string) => {
if (customizePrefixCls) return customizePrefixCls;
return suffixCls ? `${defaultPrefixCls}-${suffixCls}` : defaultPrefixCls;
},
i18n: (t: string): string => t,
contentWidth: 'Fluid',
menuData,
selectedKeys: props.selectedKeys || [],
openKeys: props.openKeys || [],
};
layout: propRefs.layout,
navTheme: propRefs.navTheme,
splitMenus: propRefs.splitMenus,
fixedHeader: propRefs.fixSiderbar,
fixSiderbar: propRefs.fixSiderbar,
sideWidth: siderWidth,
hasSideMenu: true,
hasFooterToolbar: false,
menuData: propRefs.menuData,
selectedKeys: propRefs.selectedKeys || [],
openKeys: propRefs.openKeys || [],
});
console.log('BasicLayout.routeContext', routeContext);
console.log('pure', pure.value);
const restProps = computed(() => omit(props, ['onCollapse', 'onOpenKeys', 'onSelect']));
provide('route-context', routeContext);
return () => (
......@@ -180,7 +172,7 @@ const ProLayout = defineComponent({
<Layout class={baseClassName.value}>
{!isTop.value && (
<SiderMenuWrapper
{...props}
{...restProps.value}
isMobile={isMobile.value}
menuHeaderRender={menuHeaderRender}
onCollapse={onCollapse}
......@@ -189,10 +181,10 @@ const ProLayout = defineComponent({
/>
)}
<Layout style={genLayoutStyle}>
{headerDom}
{headerDom.value}
<WrapContent
isChildrenLayout={propsIsChildrenLayout}
style={disableContentMargin ? null : contentStyle}
isChildrenLayout={props.isChildrenLayout}
style={props.disableContentMargin ? undefined : props.contentStyle}
>
{slots.default?.()}
</WrapContent>
......@@ -218,7 +210,7 @@ ProLayout.props = {
/* layout 的加载态 */
loading: PropTypes.bool,
/* 用于生成菜单和面包屑 请从 RouterContext 注入 */
// menuData: PropTypes.array,
menuData: PropTypes.array,
// location: PropTypes.string,
// Custom render
......@@ -279,8 +271,6 @@ ProLayout.props = {
menu: PropTypes.object,
/* 传递到 antd menu 组件的 props */
menuProps: PropTypes.object,
/* 菜单数组 */
menuData: PropTypes.object,
/* 是否分割菜单 (仅 mix 模式有效) */
splitMenus: PropTypes.bool,
selectedKeys: PropTypes.array,
......@@ -294,6 +284,7 @@ ProLayout.props = {
// onPageChange // 请使用 vue-router 监听
/* 禁止自动切换到移动页面 */
disableMobile: PropTypes.bool,
isChildrenLayout: PropTypes.bool,
} as any;
export default withInstall(ProLayout);
......@@ -14,7 +14,8 @@
line-height: 48px;
background: @component-background;
border-top: 1px solid @border-color-split;
box-shadow: @box-shadow-base;
box-shadow: 0 -6px 16px -8px rgb(0 0 0 / 8%), 0 -9px 28px 0 rgb(0 0 0 / 5%),
0 -12px 48px 16px rgb(0 0 0 / 3%);
&-left {
flex: 1;
}
......
......@@ -29,16 +29,16 @@ const FooterToolbar = defineComponent({
props: FooterToolbarProps,
setup(props, ctx) {
const { slots } = ctx;
const { getPrefixCls } = useProProvider();
const routeContext = useRouteContext();
const { getPrefixCls } = routeContext;
const baseClassName = props.prefixCls || getPrefixCls('footer-bar');
const routeContext = useRouteContext();
const width = computed(() => {
const { hasSideMenu, isMobile, sideWidth } = routeContext;
const { hasSideMenu, isMobile, sideWidth, layout } = routeContext;
if (!hasSideMenu) {
return undefined;
}
if (!sideWidth) {
if (!sideWidth || layout === 'top') {
return '100%';
}
return isMobile ? '100%' : `calc(100% - ${sideWidth}px)`;
......
......@@ -38,7 +38,7 @@ export interface RouteContextProps extends Partial<PureSettings>, MenuState {
i18n: (t: string) => string;
breadcrumb?: BreadcrumbListReturn;
menuData?: MenuDataItem[];
menuData: MenuDataItem[];
isMobile?: boolean;
prefixCls?: string;
collapsed?: boolean;
......
import { FunctionalComponent, computed, watch } from 'vue';
import { FunctionalComponent, computed } from 'vue';
import 'ant-design-vue/es/layout/style';
import Layout from 'ant-design-vue/es/layout';
import 'ant-design-vue/es/menu/style';
......@@ -51,7 +51,7 @@ export const defaultRenderLogo = (logo: VNodeType): VNodeType => {
export const defaultRenderLogoAndTitle = (
props: SiderMenuProps,
renderKey: string | undefined = 'menuHeaderRender',
): VNodeType => {
): VNodeType | null => {
const {
logo = 'https://gw.alipayobjects.com/zos/antfincdn/PmY%24TNNDBI/logo.svg',
title,
......@@ -100,7 +100,6 @@ const SiderMenu: FunctionalComponent<SiderMenuProps> = (props: SiderMenuProps) =
const context = useRouteContext();
const { getPrefixCls } = context;
const baseClassName = getPrefixCls('sider');
console.log('useRouteContext', context);
// const isMix = computed(() => props.layout === 'mix');
// const fixed = computed(() => context.fixSiderbar);
const runtimeTheme = computed(() => (props.layout === 'mix' && 'light') || props.navTheme);
......@@ -115,9 +114,9 @@ const SiderMenu: FunctionalComponent<SiderMenuProps> = (props: SiderMenuProps) =
[`${baseClassName}-fixed`]: context.fixSiderbar,
};
});
const hasSide = computed(() => props.layout === 'mix' && props.splitMenus);
const hasSide = computed(() => (props.layout === 'mix' && props.splitMenus) || false);
const flatMenuData = computed(() => {
return hasSide.value && getMenuFirstChildren(context.menuData, context.selectedKeys[0]);
return (hasSide.value && getMenuFirstChildren(context.menuData, context.selectedKeys[0])) || [];
});
// call menuHeaderRender
const headerDom = defaultRenderLogoAndTitle(props);
......@@ -125,12 +124,6 @@ const SiderMenu: FunctionalComponent<SiderMenuProps> = (props: SiderMenuProps) =
if (hasSide.value && flatMenuData.value.length === 0) {
return null;
}
watch(
() => context.selectedKeys,
n => {
console.log('watch:context', n);
},
);
const defaultMenuDom = (
<BaseMenu
prefixCls={getPrefixCls()}
......
@import '~ant-design-vue/es/style/themes/default.less';
@import '../BasicLayout.less';
@pro-layout-sider-menu-prefix-cls: ~'@{ant-prefix}-pro-sider';
......@@ -9,8 +8,10 @@
position: relative;
background-color: @layout-sider-background;
border-right: 0;
transition: background-color 0.3s, min-width 0.3s,
max-width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
transition: background-color 0.3s
/* , min-width 0.3s,
max-width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1) */;
z-index: 100;
&.@{ant-prefix}-menu-vertical .@{ant-prefix}-menu-item:not(:last-child),
......
......@@ -17,7 +17,7 @@ const SiderMenuWrapper: FunctionalComponent<SiderMenuWrapperProps> = props => {
padding: 0,
height: '100vh',
}}
onClose={() => props.onCollapse(true)}
onClose={() => props.onCollapse && props.onCollapse(true)}
width={props.siderWidth}
bodyStyle={{ height: '100vh', padding: 0, display: 'flex', flexDirection: 'row' }}
>
......
......@@ -4,8 +4,9 @@
"declaration": true,
"module": "esnext",
"target": "ES2018",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"moduleResolution": "node",
"esModuleInterop": true,
"skipLibCheck": true,
"lib": [
......
......@@ -11893,6 +11893,11 @@ omit.js@^2.0.0:
resolved "https://registry.yarnpkg.com/omit.js/-/omit.js-2.0.2.tgz#dd9b8436fab947a5f3ff214cb2538631e313ec2f"
integrity sha512-hJmu9D+bNB40YpL9jYebQl4lsTW6yEHRTroJzNLqQJYHm7c+NQnJGfZmIWh8S3q3KoaxV1aLhV6B3+0N0/kyJg==
omit.js@^2.0.2:
version "2.0.2"
resolved "https://registry.npm.taobao.org/omit.js/download/omit.js-2.0.2.tgz#dd9b8436fab947a5f3ff214cb2538631e313ec2f"
integrity sha1-3ZuENvq5R6Xz/yFMslOGMeMT7C8=
on-finished@^2.3.0, on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
......
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