Commit 00a7ea0c authored by Sendya's avatar Sendya Committed by 言肆

fix: global state

parent 4ecee35a
This diff is collapsed.
......@@ -7,7 +7,7 @@ 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 { getCustomRender, getMenuFirstChildren, PropRenderType, PropTypes } from './utils';
import omit from 'omit.js';
import useMediaQuery from './hooks/useMediaQuery';
import './BasicLayout.less';
......@@ -153,7 +153,6 @@ const ProLayout = defineComponent({
fixedHeader: propRefs.fixSiderbar,
fixSiderbar: propRefs.fixSiderbar,
sideWidth: siderWidth,
hasSideMenu: true,
hasFooterToolbar: false,
menuData: propRefs.menuData,
selectedKeys: propRefs.selectedKeys || [],
......
import { computed, defineComponent, onBeforeUnmount, onMounted, PropType, VNodeChild } from 'vue';
import { useProProvider } from '../ProProvider';
import { RouteContextProps, useRouteContext } from '../RouteContext';
import { getMenuFirstChildren } from '../utils';
import './index.less';
export interface FooterToolbarProps {
......@@ -32,15 +32,31 @@ const FooterToolbar = defineComponent({
const routeContext = useRouteContext();
const { getPrefixCls } = routeContext;
const baseClassName = props.prefixCls || getPrefixCls('footer-bar');
// matchMenuKeys
const matchMenuChildrenSize = computed(
() =>
(
(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 { hasSideMenu, isMobile, sideWidth, layout } = routeContext;
if (!hasSideMenu) {
return undefined;
}
const { isMobile, sideWidth, layout } = routeContext;
if (!sideWidth || layout === 'top') {
return '100%';
}
if (!hasSide.value) {
return '100%';
}
return isMobile ? '100%' : `calc(100% - ${sideWidth}px)`;
});
......
import type { CSSProperties, FunctionalComponent as FC } from 'vue';
import { computed, ref, watchEffect } from 'vue';
import { useRouteContext } from '../RouteContext';
export type WaterMarkProps = {
/** 水印样式 */
markStyle?: CSSProperties;
/** 水印类名 */
markClassName?: string;
/** 水印之间的水平间距 */
gapX?: number;
/** 水印之间的垂直间距 */
gapY?: number;
/** 追加的水印元素的z-index */
zIndex?: number;
/** 水印的宽度 */
width?: number;
/** 水印的高度 */
height?: number;
/** 水印在canvas 画布上绘制的垂直偏移量,正常情况下,水印绘制在中间位置, 即 offsetTop = gapY / 2 */
offsetTop?: number; // 水印图片距离绘制 canvas 单元的顶部距离
/** 水印在canvas 画布上绘制的水平偏移量, 正常情况下,水印绘制在中间位置, 即 offsetTop = gapX / 2 */
offsetLeft?: number;
/** 水印绘制时,旋转的角度,单位 ° */
rotate?: number;
/** ClassName 前缀 */
prefixCls?: string;
/** 高清印图片源, 为了高清屏幕显示,建议使用 2倍或3倍图,优先使用图片渲染水印。 */
image?: string;
/** 水印文字内容 */
content?: string;
/** 文字颜色 */
fontColor?: string;
/** 文字样式 */
fontStyle?: 'none' | 'normal' | 'italic' | 'oblique';
/** 文字族 */
fontFamily?: string;
/** 文字粗细 */
fontWeight?: 'normal' | 'light' | 'weight' | number;
/** 文字大小 */
fontSize?: number | string;
};
/**
* 返回当前显示设备的物理像素分辨率与CSS像素分辨率之比
*
* @param context
* @see api 有些废弃了,其实类型 CanvasRenderingContext2D
*/
const getPixelRatio = (context: any) => {
if (!context) {
return 1;
}
const backingStore =
context.backingStorePixelRatio ||
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio ||
1;
return (window.devicePixelRatio || 1) / backingStore;
};
const WaterMark: FC<WaterMarkProps> = (props, { slots }) => {
const {
markStyle,
markClassName,
// antd 内容层 zIndex 基本上在 10 以下 https://github.com/ant-design/ant-design/blob/6192403b2ce517c017f9e58a32d58774921c10cd/components/style/themes/default.less#L335
zIndex = 9,
gapX = 212,
gapY = 222,
width = 120,
height = 64,
rotate = -22, // 默认旋转 -22 度
image,
content,
offsetLeft,
offsetTop,
fontStyle = 'normal',
fontWeight = 'normal',
fontColor = 'rgba(0,0,0,.15)',
fontSize = 16,
fontFamily = 'sans-serif',
prefixCls: customizePrefixCls,
} = props;
const { getPrefixCls } = useRouteContext();
const prefixCls = getPrefixCls('pro-layout-watermark', customizePrefixCls);
const wrapperCls = computed(() => `${prefixCls}-wrapper`);
const waterMakrCls = computed(() => {
return {
[`${prefixCls}`]: prefixCls,
[`${markClassName}`]: markClassName,
};
});
const base64Url = ref('');
watchEffect(() => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const ratio = getPixelRatio(ctx);
const canvasWidth = `${(gapX + width) * ratio}px`;
const canvasHeight = `${(gapY + height) * ratio}px`;
const canvasOffsetLeft = offsetLeft || gapX / 2;
const canvasOffsetTop = offsetTop || gapY / 2;
canvas.setAttribute('width', canvasWidth);
canvas.setAttribute('height', canvasHeight);
if (ctx) {
// 旋转字符 rotate
ctx.translate(canvasOffsetLeft * ratio, canvasOffsetTop * ratio);
ctx.rotate((Math.PI / 180) * Number(rotate));
const markWidth = width * ratio;
const markHeight = height * ratio;
if (image) {
const img = new Image();
img.crossOrigin = 'anonymous';
img.referrerPolicy = 'no-referrer';
img.src = image;
img.onload = () => {
ctx.drawImage(img, 0, 0, markWidth, markHeight);
base64Url.value = canvas.toDataURL();
};
} else if (content) {
const markSize = Number(fontSize) * ratio;
ctx.font = `${fontStyle} normal ${fontWeight} ${markSize}px/${markHeight}px ${fontFamily}`;
ctx.fillStyle = fontColor;
ctx.fillText(content, 0, 0);
base64Url.value = canvas.toDataURL();
}
} else {
// eslint-disable-next-line no-console
console.error('当前环境不支持Canvas');
}
});
return (
<div
style={{
position: 'relative',
}}
class={wrapperCls}
>
{slots.default?.()}
<div
class={waterMakrCls}
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>
);
};
export default WaterMark;
......@@ -20,5 +20,6 @@ export {
SelectInfo,
baseMenuProps,
} from './SiderMenu/BaseMenu';
export { default as WaterMark } from './WaterMark/index';
export { default } from './BasicLayout';
......@@ -73,8 +73,10 @@ export function flatMap(menusData: MenuDataItem[]): MenuDataItem[] {
.filter(item => item);
}
export function getMenuFirstChildren(menus: MenuDataItem[], key: string) {
return (menus[menus.findIndex(menu => menu.path === key)] || {}).children || [];
export function getMenuFirstChildren(menus: MenuDataItem[], key?: string) {
return key === undefined
? []
: (menus[menus.findIndex(menu => menu.path === key)] || {}).children || [];
}
export const PropRenderType = {
......
......@@ -11888,16 +11888,11 @@ obuf@^1.0.0, obuf@^1.1.2:
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
omit.js@^2.0.0:
omit.js@^2.0.0, omit.js@^2.0.2:
version "2.0.2"
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