Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
pro-layout
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
packages
pro-layout
Commits
c6c2a115
Commit
c6c2a115
authored
Oct 03, 2021
by
Sendya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: FooterToolbar auto margin
parent
0f46541a
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
427 additions
and
310 deletions
+427
-310
README.md
README.md
+8
-2
BasicLayout.vue
examples/layouts/BasicLayout.vue
+16
-25
BasicLayout.tsx
src/BasicLayout.tsx
+158
-82
index.tsx
src/FooterToolbar/index.tsx
+53
-51
RouteContext.tsx
src/RouteContext.tsx
+69
-48
SiderMenu.tsx
src/SiderMenu/SiderMenu.tsx
+96
-79
index.less
src/SiderMenu/index.less
+1
-0
index.tsx
src/WaterMark/index.tsx
+26
-23
No files found.
README.md
View file @
c6c2a115
...
...
@@ -224,8 +224,14 @@ const layoutConf = reactive({
</
template
>
```
### Use WaterMark
```
vue
<router-view
v-slot=
"{ Component }"
>
<WaterMark
content=
"Pro Layout"
>
<component
:is=
"Component"
/>
</WaterMark>
</router-view>
```
## Build project
...
...
examples/layouts/BasicLayout.vue
View file @
c6c2a115
...
...
@@ -6,7 +6,7 @@
v-bind=
"state"
:loading=
"loading"
: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
>
<a>
...
...
@@ -39,7 +39,7 @@
</router-link>
</
template
>
<
template
#
menuExtraRender=
"{ collapsed }"
>
<a-input-search
v-if=
"!collapsed"
/>
<a-input-search
v-if=
"!collapsed"
@
search=
"handleSearch"
/>
</
template
>
<
template
#
menuFooterRender
>
<a
...
...
@@ -67,26 +67,13 @@
</a>
</
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 -->
<router-view
/>
<router-view
v-slot=
"{ Component }"
>
<WaterMark
content=
"Pro Layout"
>
<component
:is=
"Component"
/>
</WaterMark>
</router-view>
<!-- content end -->
<FooterToolbar>
<
template
#
extra
>
...
...
@@ -120,8 +107,8 @@
<
script
lang=
"ts"
>
import
{
computed
,
defineComponent
,
reactive
,
ref
,
watchEffect
}
from
'vue'
;
import
{
useRouter
}
from
'vue-router'
;
import
{
Button
,
Input
,
Switch
,
Select
,
Avatar
,
Space
,
Badge
,
Menu
}
from
'ant-design-vue'
;
import
{
getMenuData
,
clearMenuItem
,
FooterToolbar
}
from
'@ant-design-vue/pro-layout'
;
import
{
message
,
Button
,
Input
,
Switch
,
Select
,
Avatar
,
Space
,
Badge
,
Menu
}
from
'ant-design-vue'
;
import
{
getMenuData
,
clearMenuItem
,
WaterMark
,
FooterToolbar
}
from
'@ant-design-vue/pro-layout'
;
import
type
{
RouteContextProps
}
from
'@ant-design-vue/pro-layout'
;
const
i18n
=
(
t
:
string
)
=>
t
;
...
...
@@ -130,6 +117,8 @@ export default defineComponent({
name
:
'BasicLayout'
,
components
:
{
FooterToolbar
,
WaterMark
,
[
Button
.
name
]:
Button
,
[
Input
.
name
]:
Input
,
[
Input
.
Search
.
name
]:
Input
.
Search
,
...
...
@@ -137,7 +126,6 @@ export default defineComponent({
[
Select
.
name
]:
Select
,
[
Select
.
Option
.
displayName
!
]:
Select
.
Option
,
[
Space
.
name
]:
Space
,
[
Badge
.
name
]:
Badge
,
[
Avatar
.
name
]:
Avatar
,
[
Menu
.
Item
.
name
]:
Menu
.
Item
,
...
...
@@ -161,7 +149,7 @@ export default defineComponent({
// title: 'ProLayout',
// logo: 'https://alicdn.antdv.com/v2/assets/logo.1ef800a8.svg',
navTheme
:
'dark'
,
layout
:
'
mix
'
,
layout
:
'
side
'
,
fixSiderbar
:
true
,
});
const
breadcrumb
=
computed
(()
=>
...
...
@@ -202,6 +190,9 @@ export default defineComponent({
handlePageLoadingClick
,
handleCollapsed
,
handleSearch
:
()
=>
{
message
.
info
(
'search..'
);
},
};
},
});
...
...
src/BasicLayout.tsx
View file @
c6c2a115
import
{
computed
,
reactive
,
unref
,
defineComponent
,
toRefs
}
from
'vue'
;
import
type
{
CSSProperties
,
PropType
,
ExtractPropTypes
}
from
'vue'
;
import
{
computed
,
reactive
,
unref
,
defineComponent
,
toRefs
}
from
'vue'
import
type
{
CSSProperties
,
PropType
,
ExtractPropTypes
}
from
'vue'
import
'ant-design-vue/es/layout/style'
;
import
{
Layout
}
from
'ant-design-vue'
;
import
{
withInstall
}
from
'ant-design-vue/es/_util/type'
;
import
useMediaQuery
from
'./hooks/useMediaQuery'
;
import
'ant-design-vue/es/layout/style'
import
{
Layout
}
from
'ant-design-vue'
import
{
withInstall
}
from
'ant-design-vue/es/_util/type'
import
useMediaQuery
from
'./hooks/useMediaQuery'
import
{
defaultSettingProps
}
from
'./defaultSettings'
;
import
{
provideRouteContext
,
defaultRouteContext
,
RouteContextProps
}
from
'./RouteContext'
;
import
SiderMenuWrapper
,
{
siderMenuProps
}
from
'./SiderMenu'
;
import
{
WrapContent
}
from
'./WrapContent'
;
import
globalHeaderProps
from
'./GlobalHeader/headerProps'
;
import
{
HeaderView
as
Header
,
headerViewProps
}
from
'./Header'
;
import
{
getPropsSlot
,
getPropsSlotfn
,
PropTypes
,
pick
}
from
'./utils'
;
import
type
{
BreadcrumbProps
}
from
'./RouteContext'
;
import
type
{
CustomRender
,
FormatMessage
,
WithFalse
}
from
'./typings'
;
import
{
defaultSettingProps
}
from
'./defaultSettings'
import
{
provideRouteContext
,
defaultRouteContext
,
RouteContextProps
,
}
from
'./RouteContext'
import
SiderMenuWrapper
,
{
siderMenuProps
}
from
'./SiderMenu'
import
{
WrapContent
}
from
'./WrapContent'
import
globalHeaderProps
from
'./GlobalHeader/headerProps'
import
{
HeaderView
as
Header
,
headerViewProps
}
from
'./Header'
import
{
getPropsSlot
,
getPropsSlotfn
,
PropTypes
,
getMenuFirstChildren
,
pick
,
}
from
'./utils'
import
type
{
BreadcrumbProps
}
from
'./RouteContext'
import
type
{
CustomRender
,
FormatMessage
,
WithFalse
}
from
'./typings'
import
PageLoading
from
'./PageLoading'
;
import
'./BasicLayout.less'
;
import
PageLoading
from
'./PageLoading'
import
'./BasicLayout.less'
export
const
basicLayoutProps
=
{
...
defaultSettingProps
,
...
...
@@ -30,7 +40,7 @@ export const basicLayoutProps = {
locale
:
{
type
:
[
Function
,
Boolean
]
as
PropType
<
WithFalse
<
FormatMessage
>>
,
default
()
{
return
(
s
:
string
)
=>
s
;
return
(
s
:
string
)
=>
s
},
},
/**
...
...
@@ -47,11 +57,15 @@ export const basicLayoutProps = {
default
:
()
=>
null
,
},
collapsedButtonRender
:
{
type
:
[
Function
,
Object
,
Boolean
]
as
PropType
<
WithFalse
<
(
collapsed
?:
boolean
)
=>
any
>>
,
type
:
[
Function
,
Object
,
Boolean
]
as
PropType
<
WithFalse
<
(
collapsed
?:
boolean
)
=>
any
>
>
,
default
:
()
=>
undefined
,
},
breadcrumbRender
:
{
type
:
[
Object
,
Function
,
Boolean
]
as
PropType
<
WithFalse
<
BreadcrumbProps
[
'itemRender'
]
>>
,
type
:
[
Object
,
Function
,
Boolean
]
as
PropType
<
WithFalse
<
BreadcrumbProps
[
'itemRender'
]
>
>
,
default
:
()
=>
{},
},
headerContentRender
:
{
...
...
@@ -59,18 +73,24 @@ export const basicLayoutProps = {
default
:
()
=>
undefined
,
},
headerRender
:
{
type
:
[
Object
,
Function
,
Boolean
]
as
PropType
<
WithFalse
<
(
props
:
any
/* HeaderProps */
)
=>
any
>>
,
type
:
[
Object
,
Function
,
Boolean
]
as
PropType
<
WithFalse
<
(
props
:
any
/* HeaderProps */
)
=>
any
>
>
,
default
:
()
=>
undefined
,
},
footerRender
:
{
type
:
[
Object
,
Function
,
Boolean
]
as
PropType
<
WithFalse
<
(
props
:
any
/* FooterProps */
)
=>
any
>>
,
type
:
[
Object
,
Function
,
Boolean
]
as
PropType
<
WithFalse
<
(
props
:
any
/* FooterProps */
)
=>
any
>
>
,
default
:
()
=>
undefined
,
},
colSize
:
PropTypes
.
string
,
contentStyle
:
PropTypes
.
style
,
}
;
}
export
type
BasicLayoutProps
=
Partial
<
ExtractPropTypes
<
typeof
basicLayoutProps
>>
;
export
type
BasicLayoutProps
=
Partial
<
ExtractPropTypes
<
typeof
basicLayoutProps
>
>
const
ProLayout
=
defineComponent
({
name
:
'ProLayout'
,
...
...
@@ -87,34 +107,49 @@ const ProLayout = defineComponent({
'menuClick'
,
],
setup
(
props
,
{
emit
,
slots
})
{
const
isTop
=
computed
(()
=>
props
.
layout
===
'top'
);
const
siderWidth
=
computed
(()
=>
(
props
.
collapsed
?
props
.
collapsedWidth
:
props
.
siderWidth
));
console
.
log
(
'props'
,
props
)
const
isTop
=
computed
(()
=>
props
.
layout
===
'top'
)
const
hasSide
=
computed
(
()
=>
props
.
layout
===
'mix'
||
props
.
layout
===
'side'
||
false
)
const
hasSplitMenu
=
computed
(
()
=>
props
.
layout
===
'mix'
&&
props
.
splitMenus
)
const
hasFlatMenu
=
computed
(()
=>
{
return
hasSide
.
value
&&
hasSplitMenu
.
value
})
const
siderWidth
=
computed
(()
=>
props
.
collapsed
?
props
.
collapsedWidth
:
props
.
siderWidth
)
// if on event and @event
const
onCollapse
=
(
collapsed
:
boolean
)
=>
{
emit
(
'update:collapsed'
,
collapsed
)
;
emit
(
'collapse'
,
collapsed
)
;
}
;
emit
(
'update:collapsed'
,
collapsed
)
emit
(
'collapse'
,
collapsed
)
}
const
onOpenKeys
=
(
openKeys
:
string
[]
|
false
)
=>
{
emit
(
'update:open-keys'
,
openKeys
)
;
emit
(
'openKeys'
,
openKeys
)
;
}
;
emit
(
'update:open-keys'
,
openKeys
)
emit
(
'openKeys'
,
openKeys
)
}
const
onSelect
=
(
selectedKeys
:
string
[]
|
false
)
=>
{
emit
(
'update:selected-keys'
,
selectedKeys
)
;
emit
(
'select'
,
selectedKeys
)
;
}
;
emit
(
'update:selected-keys'
,
selectedKeys
)
emit
(
'select'
,
selectedKeys
)
}
const
onMenuHeaderClick
=
(
e
:
MouseEvent
)
=>
{
emit
(
'menuHeaderClick'
,
e
)
;
}
;
emit
(
'menuHeaderClick'
,
e
)
}
const
onMenuClick
=
(
args
:
any
)
=>
{
emit
(
'menuClick'
,
args
)
;
}
;
emit
(
'menuClick'
,
args
)
}
const
colSize
=
useMediaQuery
()
;
const
colSize
=
useMediaQuery
()
const
isMobile
=
computed
(
()
=>
(
colSize
.
value
===
'sm'
||
colSize
.
value
===
'xs'
)
&&
!
props
.
disableMobile
,
);
const
baseClassName
=
computed
(()
=>
`
${
props
.
prefixCls
}
-basicLayout`
);
()
=>
(
colSize
.
value
===
'sm'
||
colSize
.
value
===
'xs'
)
&&
!
props
.
disableMobile
)
const
baseClassName
=
computed
(()
=>
`
${
props
.
prefixCls
}
-basicLayout`
)
// gen className
const
className
=
computed
(()
=>
{
return
{
...
...
@@ -124,41 +159,52 @@ const ProLayout = defineComponent({
[
`
${
baseClassName
.
value
}
-is-children`
]:
props
.
isChildrenLayout
,
[
`
${
baseClassName
.
value
}
-fix-siderbar`
]:
props
.
fixSiderbar
,
[
`
${
baseClassName
.
value
}
-
${
props
.
layout
}
`
]:
props
.
layout
,
}
;
})
;
}
})
// siderMenuDom 为空的时候,不需要 padding
const
genLayoutStyle
=
reactive
<
CSSProperties
>
({
position
:
'relative'
,
})
;
})
// if is some layout children, don't need min height
if
(
props
.
isChildrenLayout
||
(
props
.
contentStyle
&&
props
.
contentStyle
.
minHeight
))
{
genLayoutStyle
.
minHeight
=
0
;
if
(
props
.
isChildrenLayout
||
(
props
.
contentStyle
&&
props
.
contentStyle
.
minHeight
)
)
{
genLayoutStyle
.
minHeight
=
0
}
const
headerRender
=
(
p
:
BasicLayoutProps
&
{
hasSiderMenu
:
boolean
;
headerRender
:
WithFalse
<
CustomRender
>
;
rightContentRender
:
WithFalse
<
CustomRender
>
;
hasSiderMenu
:
boolean
headerRender
:
WithFalse
<
CustomRender
>
rightContentRender
:
WithFalse
<
CustomRender
>
},
matchMenuKeys
?:
string
[]
,
matchMenuKeys
?:
string
[]
):
CustomRender
|
null
=>
{
if
(
p
.
headerRender
===
false
||
p
.
pure
)
{
return
null
;
return
null
}
return
<
Header
{
...
p
}
matchMenuKeys=
{
matchMenuKeys
||
[]
}
/>
;
}
;
return
<
Header
{
...
p
}
matchMenuKeys=
{
matchMenuKeys
||
[]
}
/>
}
const
breadcrumb
=
computed
<
BreadcrumbProps
>
(()
=>
({
...
props
.
breadcrumb
,
itemRender
:
getPropsSlotfn
(
slots
,
props
,
'breadcrumbRender'
),
}));
}))
const
flatMenuData
=
computed
(
()
=>
(
hasFlatMenu
.
value
&&
props
.
selectedKeys
&&
getMenuFirstChildren
(
props
.
menuData
,
props
.
selectedKeys
[
0
]))
||
[]
)
const
routeContext
=
reactive
<
RouteContextProps
>
(
Object
.
assign
(
{
...
defaultRouteContext
},
{
...
defaultRouteContext
},
pick
(
toRefs
(
props
),
[
'locale'
,
'menuData'
,
...
...
@@ -173,14 +219,18 @@ const ProLayout = defineComponent({
// 'hasFooter',
// 'hasFooterToolbar',
// 'setHasFooterToolbar',
])
as
any
,
])
as
any
,
{
isMobile
,
siderWidth
,
breadcrumb
,
flatMenuData
,
hasSide
,
flatMenu
:
hasFlatMenu
,
}
)
)
;
provideRouteContext
(
routeContext
)
;
)
provideRouteContext
(
routeContext
)
return
()
=>
{
const
{
...
...
@@ -190,24 +240,44 @@ const ProLayout = defineComponent({
onSelect
:
propsOnSelect
,
onMenuClick
:
propsOnMenuClick
,
...
restProps
}
=
props
;
}
=
props
const
collapsedButtonRender
=
getPropsSlotfn
(
slots
,
props
,
'collapsedButtonRender'
);
const
headerContentRender
=
getPropsSlot
(
slots
,
props
,
'headerContentRender'
);
const
rightContentRender
=
getPropsSlot
(
slots
,
props
,
'rightContentRender'
);
const
customHeaderRender
=
getPropsSlot
(
slots
,
props
,
'headerRender'
);
const
menuHeaderRender
=
getPropsSlotfn
(
slots
,
props
,
'menuHeaderRender'
);
const
menuContentRender
=
getPropsSlotfn
(
slots
,
props
,
'menuContentRender'
);
const
menuExtraRender
=
getPropsSlotfn
(
slots
,
props
,
'menuExtraRender'
);
const
menuFooterRender
=
getPropsSlotfn
(
slots
,
props
,
'menuFooterRender'
);
const
footerRender
=
getPropsSlot
(
slots
,
props
,
'footerRender'
);
const
collapsedButtonRender
=
getPropsSlotfn
(
slots
,
props
,
'collapsedButtonRender'
)
const
headerContentRender
=
getPropsSlot
(
slots
,
props
,
'headerContentRender'
)
const
rightContentRender
=
getPropsSlot
(
slots
,
props
,
'rightContentRender'
)
const
customHeaderRender
=
getPropsSlot
(
slots
,
props
,
'headerRender'
)
const
menuHeaderRender
=
getPropsSlotfn
(
slots
,
props
,
'menuHeaderRender'
)
const
menuContentRender
=
getPropsSlotfn
(
slots
,
props
,
'menuContentRender'
)
const
menuExtraRender
=
getPropsSlotfn
(
slots
,
props
,
'menuExtraRender'
)
const
menuFooterRender
=
getPropsSlotfn
(
slots
,
props
,
'menuFooterRender'
)
const
footerRender
=
getPropsSlot
(
slots
,
props
,
'footerRender'
)
// menu render
const
menuItemRender
=
getPropsSlotfn
(
slots
,
props
,
'menuItemRender'
);
const
subMenuItemRender
=
getPropsSlotfn
(
slots
,
props
,
'subMenuItemRender'
);
const
menuItemRender
=
getPropsSlotfn
(
slots
,
props
,
'menuItemRender'
)
const
subMenuItemRender
=
getPropsSlotfn
(
slots
,
props
,
'subMenuItemRender'
)
const
menuRenders
=
{
menuItemRender
,
subMenuItemRender
,
}
;
}
const
headerDom
=
computed
(()
=>
headerRender
(
...
...
@@ -227,13 +297,15 @@ const ProLayout = defineComponent({
menuContentRender
:
menuContentRender
,
headerContentRender
,
headerRender
:
customHeaderRender
,
theme
:
(
props
.
navTheme
||
'dark'
).
toLocaleLowerCase
().
includes
(
'dark'
)
theme
:
(
props
.
navTheme
||
'dark'
)
.
toLocaleLowerCase
()
.
includes
(
'dark'
)
?
'dark'
:
'light'
,
},
props
.
matchMenuKeys
,
)
,
)
;
props
.
matchMenuKeys
)
)
return
(
<>
...
...
@@ -262,7 +334,11 @@ const ProLayout = defineComponent({
{
headerDom
.
value
}
<
WrapContent
isChildrenLayout=
{
props
.
isChildrenLayout
}
style=
{
props
.
disableContentMargin
?
undefined
:
props
.
contentStyle
}
style=
{
props
.
disableContentMargin
?
undefined
:
props
.
contentStyle
}
>
{
props
.
loading
?
<
PageLoading
/>
:
slots
.
default
?.()
}
</
WrapContent
>
...
...
@@ -272,9 +348,9 @@ const ProLayout = defineComponent({
</
div
>
)
}
</>
)
;
}
;
)
}
},
})
;
})
export
default
withInstall
(
ProLayout
)
;
export
default
withInstall
(
ProLayout
)
src/FooterToolbar/index.tsx
View file @
c6c2a115
import
'./index.less'
;
import
'./index.less'
import
{
computed
,
defineComponent
,
onBeforeUnmount
,
onMounted
,
PropType
}
from
'vue'
;
import
{
RouteContextProps
,
useRouteContext
}
from
'../RouteContext'
;
import
{
getMenuFirstChildren
,
getPropsSlot
,
getPropsSlotfn
}
from
'../utils'
;
import
type
{
CustomRender
}
from
'../typings'
;
import
{
computed
,
defineComponent
,
onBeforeUnmount
,
onMounted
,
unref
,
PropType
,
}
from
'vue'
import
{
RouteContextProps
,
useRouteContext
}
from
'../RouteContext'
import
{
getPropsSlotfn
}
from
'../utils'
import
type
{
CustomRender
}
from
'../typings'
export
interface
FooterToolbarProps
{
extra
?:
CustomRender
|
JSX
.
Element
;
extra
?:
CustomRender
|
JSX
.
Element
renderContent
?:
(
props
:
FooterToolbarProps
&
RouteContextProps
&
{
leftWidth
?:
string
},
dom
:
CustomRender
|
JSX
.
Element
,
)
=>
CustomRender
|
JSX
.
Element
;
getContainer
?:
(
triggerNode
:
HTMLElement
)
=>
HTMLElement
|
null
;
prefixCls
?:
string
;
dom
:
CustomRender
|
JSX
.
Element
)
=>
CustomRender
|
JSX
.
Element
getContainer
?:
(
triggerNode
:
HTMLElement
)
=>
HTMLElement
|
null
prefixCls
?:
string
}
const
footerToolbarProps
=
{
...
...
@@ -25,52 +32,47 @@ const footerToolbarProps = {
type
:
[
Function
,
Object
]
as
PropType
<
FooterToolbarProps
[
'getContainer'
]
>
,
},
prefixCls
:
{
type
:
String
as
PropType
<
string
>
},
}
;
}
const
FooterToolbar
=
defineComponent
({
name
:
'FooterToolbar'
,
props
:
footerToolbarProps
,
setup
(
props
,
{
slots
})
{
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
context
=
useRouteContext
()
const
baseClassName
=
props
.
prefixCls
||
context
.
getPrefixCls
(
'footer-bar'
)
const
hasFlatMenu
=
computed
(()
=>
{
return
unref
(
context
.
flatMenuData
).
length
>
0
})
const
width
=
computed
(()
=>
{
const
{
isMobile
,
sideWidth
,
layout
}
=
routeContext
;
if
(
!
sideWidth
||
layout
===
'top'
)
{
return
'100%'
;
const
{
isMobile
,
hasSide
,
siderWidth
,
layout
}
=
context
if
(
!
side
r
Width
||
layout
===
'top'
)
{
return
'100%'
}
if
(
!
hasSide
.
value
)
{
return
'100%'
;
console
.
log
(
'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
(()
=>
{
routeContext
.
setHasFooterToolbar
&&
routeContext
.
setHasFooterToolbar
(
true
);
})
;
context
.
setHasFooterToolbar
&&
context
.
setHasFooterToolbar
(
true
)
})
onBeforeUnmount
(()
=>
{
routeContext
.
setHasFooterToolbar
&&
routeContext
.
setHasFooterToolbar
(
false
);
})
;
context
.
setHasFooterToolbar
&&
context
.
setHasFooterToolbar
(
false
)
})
return
()
=>
{
const
extra
=
getPropsSlotfn
(
slots
,
props
,
'extra'
)
;
const
extra
=
getPropsSlotfn
(
slots
,
props
,
'extra'
)
const
dom
=
()
=>
{
return
(
<>
...
...
@@ -79,24 +81,24 @@ const FooterToolbar = defineComponent({
</
div
>
<
div
class=
{
`${baseClassName}-right`
}
>
{
slots
.
default
?.()
}
</
div
>
</>
)
;
}
;
)
}
return
(
<
div
class=
{
baseClassName
}
style=
{
{
width
:
width
.
value
}
}
>
{
props
.
renderContent
?
props
.
renderContent
(
{
...
props
,
...
routeC
ontext
,
...
c
ontext
,
leftWidth
:
width
.
value
,
},
dom
()
,
dom
()
)
:
dom
()
}
</
div
>
)
;
}
;
)
}
},
})
;
})
export
default
FooterToolbar
;
export
default
FooterToolbar
src/RouteContext.tsx
View file @
c6c2a115
import
{
InjectionKey
,
provide
,
reactive
,
Ref
,
VNodeChild
,
ComputedRef
}
from
'vue'
;
import
{
createContext
,
useContext
}
from
'./hooks/context'
;
import
{
MenuDataItem
,
FormatMessage
,
WithFalse
}
from
'./typings'
;
import
{
PureSettings
}
from
'./defaultSettings'
;
import
{
InjectionKey
,
provide
,
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
{
path
:
string
;
breadcrumbName
:
string
;
children
?:
Omit
<
Route
,
'children'
>
[]
;
path
:
string
breadcrumbName
:
string
children
?:
Omit
<
Route
,
'children'
>
[]
}
export
interface
BreadcrumbProps
{
prefixCls
?:
string
;
routes
?:
Route
[]
;
params
?:
any
;
separator
?:
VNodeChild
;
prefixCls
?:
string
routes
?:
Route
[]
params
?:
any
separator
?:
VNodeChild
itemRender
?:
(
opts
:
{
route
:
Route
;
params
:
any
;
routes
:
Array
<
Route
>
;
paths
:
Array
<
string
>
;
})
=>
VNodeChild
;
route
:
Route
params
:
any
routes
:
Array
<
Route
>
paths
:
Array
<
string
>
})
=>
VNodeChild
}
export
type
BreadcrumbListReturn
=
Pick
<
BreadcrumbProps
,
Extract
<
keyof
BreadcrumbProps
,
'routes'
|
'itemRender'
>
>
;
>
export
interface
MenuState
{
selectedKeys
:
string
[]
;
openKeys
:
string
[]
;
selectedKeys
:
string
[]
openKeys
:
string
[]
}
export
interface
RouteContextProps
extends
Partial
<
PureSettings
>
,
MenuState
{
menuData
:
MenuDataItem
[];
menuData
:
MenuDataItem
[]
flatMenuData
?:
MenuDataItem
[]
getPrefixCls
?:
(
suffixCls
?:
string
,
customizePrefixCls
?:
string
)
=>
string
;
locale
?:
WithFalse
<
FormatMessage
>
;
breadcrumb
?:
BreadcrumbListReturn
|
ComputedRef
<
BreadcrumbListReturn
>
;
isMobile
?:
boolean
;
prefixCls
?:
string
;
collapsed
?:
boolean
;
hasSideMenu
?:
boolean
;
hasHeader
?:
boolean
;
sideWidth
?:
number
;
headerHeight
?:
number
;
hasFooterToolbar
?:
boolean
;
hasFooter
?:
boolean
;
setHasFooterToolbar
?:
(
bool
:
boolean
)
=>
void
;
getPrefixCls
?:
(
suffixCls
?:
string
,
customizePrefixCls
?:
string
)
=>
string
locale
?:
WithFalse
<
FormatMessage
>
breadcrumb
?:
BreadcrumbListReturn
|
ComputedRef
<
BreadcrumbListReturn
>
isMobile
?:
boolean
prefixCls
?:
string
collapsed
?:
boolean
hasSideMenu
?:
boolean
hasHeader
?:
boolean
siderWidth
?:
number
headerHeight
?:
number
hasFooterToolbar
?:
boolean
hasFooter
?:
boolean
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
)
=>
{
if
(
customizePrefixCls
)
return
customizePrefixCls
;
return
suffixCls
?
`
${
defaultPrefixCls
}
-
${
suffixCls
}
`
:
defaultPrefixCls
;
};
export
const
getPrefixCls
=
(
suffixCls
?:
string
,
customizePrefixCls
?:
string
)
=>
{
if
(
customizePrefixCls
)
return
customizePrefixCls
return
suffixCls
?
`
${
defaultPrefixCls
}
-
${
suffixCls
}
`
:
defaultPrefixCls
}
// set default context
export
const
defaultRouteContext
=
reactive
({
...
...
@@ -65,22 +77,31 @@ export const defaultRouteContext = reactive({
locale
:
(
t
:
string
)
=>
t
,
contentWidth
:
'Fluid'
,
hasFooterToolbar
:
false
,
})
;
})
const
routeContextInjectKey
:
InjectionKey
<
RouteContextProps
>
=
Symbol
(
'route-context'
);
const
routeContextInjectKey
:
InjectionKey
<
RouteContextProps
>
=
Symbol
(
'route-context'
)
export
const
createRouteContext
=
()
=>
createContext
<
RouteContextProps
>
(
routeContextInjectKey
,
'RouteContext.Provider'
);
createContext
<
RouteContextProps
>
(
routeContextInjectKey
,
'RouteContext.Provider'
)
export
const
provideRouteContext
=
(
value
:
RouteContextProps
|
Ref
<
RouteContextProps
>
)
=>
{
provide
(
routeContextInjectKey
,
value
);
};
export
const
provideRouteContext
=
(
value
:
RouteContextProps
|
Ref
<
RouteContextProps
>
)
=>
{
provide
(
routeContextInjectKey
,
value
)
}
export
const
useRouteContext
=
()
=>
useContext
<
Required
<
RouteContextProps
>>
(
routeContextInjectKey
,
defaultRouteContext
);
useContext
<
Required
<
RouteContextProps
>>
(
routeContextInjectKey
,
defaultRouteContext
)
const
Provider
=
createRouteContext
()
;
const
Provider
=
createRouteContext
()
export
default
{
Provider
,
}
;
}
src/SiderMenu/SiderMenu.tsx
View file @
c6c2a115
...
...
@@ -5,24 +5,24 @@ import {
PropType
,
CSSProperties
,
unref
,
}
from
'vue'
;
import
'ant-design-vue/es/layout/style'
;
import
'ant-design-vue/es/menu/style'
;
import
{
Layout
,
Menu
}
from
'ant-design-vue'
;
import
{
MenuUnfoldOutlined
,
MenuFoldOutlined
}
from
'@ant-design/icons-vue'
;
import
BaseMenu
,
{
baseMenuProps
}
from
'./BaseMenu'
;
import
{
WithFalse
,
CustomRender
}
from
'../typings'
;
import
{
SiderProps
}
from
'./typings'
;
import
{
defaultSettingProps
}
from
'../defaultSettings'
;
import
{
useRouteContext
}
from
'../RouteContext'
;
import
{
PropTypes
,
getMenuFirstChildren
}
from
'../utils'
;
import
'./index.less'
;
}
from
'vue'
import
'ant-design-vue/es/layout/style'
import
'ant-design-vue/es/menu/style'
import
{
Layout
,
Menu
}
from
'ant-design-vue'
import
{
MenuUnfoldOutlined
,
MenuFoldOutlined
}
from
'@ant-design/icons-vue'
import
BaseMenu
,
{
baseMenuProps
}
from
'./BaseMenu'
import
{
WithFalse
,
CustomRender
}
from
'../typings'
import
{
SiderProps
}
from
'./typings'
import
{
defaultSettingProps
}
from
'../defaultSettings'
import
{
useRouteContext
}
from
'../RouteContext'
import
{
PropTypes
,
getMenuFirstChildren
}
from
'../utils'
import
'./index.less'
const
{
Sider
}
=
Layout
;
const
{
Sider
}
=
Layout
export
type
PrivateSiderMenuProps
=
{
matchMenuKeys
?:
string
[]
;
}
;
matchMenuKeys
?:
string
[]
}
export
const
siderMenuProps
=
{
...
defaultSettingProps
,
...
...
@@ -40,12 +40,16 @@ export const siderMenuProps = {
collapsedWidth
:
PropTypes
.
number
.
def
(
48
),
menuHeaderRender
:
{
type
:
[
Function
,
Object
]
as
PropType
<
WithFalse
<
(
logo
:
CustomRender
,
title
:
CustomRender
,
props
?:
any
)
=>
CustomRender
>
WithFalse
<
(
logo
:
CustomRender
,
title
:
CustomRender
,
props
?:
any
)
=>
CustomRender
>
>
,
default
:
()
=>
undefined
,
},
menuFooterRender
:
{
type
:
[
Function
,
Object
]
as
PropType
<
WithFalse
<
(
props
?:
any
)
=>
CustomRender
>>
,
type
:
[
Function
,
Object
]
as
PropType
<
WithFalse
<
(
props
?:
any
)
=>
CustomRender
>
>
,
default
:
()
=>
undefined
,
},
menuContentRender
:
{
...
...
@@ -55,11 +59,15 @@ export const siderMenuProps = {
default
:
()
=>
undefined
,
},
menuExtraRender
:
{
type
:
[
Function
,
Object
]
as
PropType
<
WithFalse
<
(
props
?:
any
)
=>
CustomRender
>>
,
type
:
[
Function
,
Object
]
as
PropType
<
WithFalse
<
(
props
?:
any
)
=>
CustomRender
>
>
,
default
:
()
=>
undefined
,
},
collapsedButtonRender
:
{
type
:
[
Function
,
Object
,
Boolean
]
as
PropType
<
WithFalse
<
(
collapsed
?:
boolean
)
=>
CustomRender
>>
,
type
:
[
Function
,
Object
,
Boolean
]
as
PropType
<
WithFalse
<
(
collapsed
?:
boolean
)
=>
CustomRender
>
>
,
default
:
()
=>
undefined
,
},
breakpoint
:
{
...
...
@@ -87,49 +95,52 @@ export const siderMenuProps = {
onSelect
:
{
type
:
Function
as
PropType
<
(
selectedKeys
:
WithFalse
<
string
[]
>
)
=>
void
>
,
},
}
;
}
export
type
SiderMenuProps
=
Partial
<
ExtractPropTypes
<
typeof
siderMenuProps
>>
;
export
type
SiderMenuProps
=
Partial
<
ExtractPropTypes
<
typeof
siderMenuProps
>>
export
const
defaultRenderLogo
=
(
logo
?:
CustomRender
,
logoStyle
?:
CSSProperties
):
CustomRender
=>
{
export
const
defaultRenderLogo
=
(
logo
?:
CustomRender
,
logoStyle
?:
CSSProperties
):
CustomRender
=>
{
if
(
!
logo
)
{
return
null
;
return
null
}
if
(
typeof
logo
===
'string'
)
{
return
<
img
src=
{
logo
}
alt=
"logo"
style=
{
logoStyle
}
/>
;
return
<
img
src=
{
logo
}
alt=
"logo"
style=
{
logoStyle
}
/>
}
if
(
typeof
logo
===
'function'
)
{
return
logo
()
;
return
logo
()
}
return
logo
;
}
;
return
logo
}
export
const
defaultRenderLogoAndTitle
=
(
props
:
SiderMenuProps
,
renderKey
:
string
|
undefined
=
'menuHeaderRender'
,
renderKey
:
string
|
undefined
=
'menuHeaderRender'
):
CustomRender
|
null
=>
{
const
{
logo
=
'https://gw.alipayobjects.com/zos/antfincdn/PmY%24TNNDBI/logo.svg'
,
logoStyle
,
title
,
layout
,
}
=
props
;
const
renderFunction
=
(
props
as
any
)[
renderKey
||
''
]
;
}
=
props
const
renderFunction
=
(
props
as
any
)[
renderKey
||
''
]
if
(
renderFunction
===
false
)
{
return
null
;
return
null
}
const
logoDom
=
defaultRenderLogo
(
logo
,
logoStyle
)
;
const
titleDom
=
<
h1
>
{
title
}
</
h1
>
;
const
logoDom
=
defaultRenderLogo
(
logo
,
logoStyle
)
const
titleDom
=
<
h1
>
{
title
}
</
h1
>
if
(
layout
===
'mix'
&&
renderKey
===
'menuHeaderRender'
)
{
return
null
;
return
null
}
// call menuHeaderRender
if
(
typeof
renderFunction
===
'function'
)
{
// when collapsed, no render title
return
renderFunction
(
logoDom
,
props
.
collapsed
?
null
:
titleDom
,
props
)
;
return
renderFunction
(
logoDom
,
props
.
collapsed
?
null
:
titleDom
,
props
)
}
if
(
Array
.
isArray
(
renderFunction
))
{
return
<>
{
renderFunction
}
</>
;
return
<>
{
renderFunction
}
</>
}
return
(
...
...
@@ -137,11 +148,12 @@ export const defaultRenderLogoAndTitle = (
{
logoDom
}
{
props
.
collapsed
?
null
:
titleDom
}
</
a
>
)
;
}
;
)
}
export
const
defaultRenderCollapsedButton
=
(
collapsed
?:
boolean
):
CustomRender
=>
collapsed
?
<
MenuUnfoldOutlined
/>
:
<
MenuFoldOutlined
/>;
export
const
defaultRenderCollapsedButton
=
(
collapsed
?:
boolean
):
CustomRender
=>
(
collapsed
?
<
MenuUnfoldOutlined
/>
:
<
MenuFoldOutlined
/>)
const
SiderMenu
:
FC
<
SiderMenuProps
>
=
(
props
:
SiderMenuProps
)
=>
{
const
{
...
...
@@ -158,44 +170,42 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => {
onOpenKeys
,
onSelect
,
onMenuHeaderClick
,
}
=
props
;
const
context
=
useRouteContext
();
const
{
getPrefixCls
}
=
context
;
const
baseClassName
=
getPrefixCls
(
'sider'
);
const
hasSplitMenu
=
computed
(()
=>
props
.
layout
===
'mix'
&&
props
.
splitMenus
);
const
hasSide
=
computed
(()
=>
props
.
layout
===
'mix'
||
props
.
layout
===
'side'
||
false
);
const
sTheme
=
computed
(()
=>
(
props
.
layout
===
'mix'
&&
'light'
)
||
props
.
navTheme
);
const
sSideWidth
=
computed
(()
=>
(
props
.
collapsed
?
props
.
collapsedWidth
:
props
.
siderWidth
));
}
=
props
const
context
=
useRouteContext
()
const
{
getPrefixCls
}
=
context
const
baseClassName
=
getPrefixCls
(
'sider'
)
const
hasSplitMenu
=
computed
(
()
=>
props
.
layout
===
'mix'
&&
props
.
splitMenus
)
const
sTheme
=
computed
(
()
=>
(
props
.
layout
===
'mix'
&&
'light'
)
||
props
.
navTheme
)
const
sSideWidth
=
computed
(()
=>
props
.
collapsed
?
props
.
collapsedWidth
:
props
.
siderWidth
)
const
classNames
=
computed
(()
=>
{
return
{
[
baseClassName
]:
true
,
[
`
${
baseClassName
}
-
${
sTheme
.
value
}
`
]:
true
,
[
`
${
baseClassName
}
-
${
props
.
layout
}
`
]:
true
,
[
`
${
baseClassName
}
-fixed`
]:
context
.
fixSiderbar
,
};
});
const
flatMenuData
=
computed
(
()
=>
(
hasSide
.
value
&&
hasSplitMenu
.
value
&&
getMenuFirstChildren
(
context
.
menuData
,
context
.
selectedKeys
[
0
]))
||
[],
);
}
})
const
handleSelect
=
(
$event
:
string
[])
=>
{
if
(
props
.
onSelect
)
{
if
(
unref
(
hasSplitMenu
))
{
props
.
onSelect
([
context
.
selectedKeys
[
0
],
...
$event
])
;
return
;
props
.
onSelect
([
context
.
selectedKeys
[
0
],
...
$event
])
return
}
props
.
onSelect
(
$event
)
;
props
.
onSelect
(
$event
)
}
}
;
}
// call menuHeaderRender
const
headerDom
=
defaultRenderLogoAndTitle
(
props
)
;
const
extraDom
=
menuExtraRender
&&
menuExtraRender
(
props
)
;
if
(
hasSplitMenu
.
value
&&
flatMenuData
.
value
.
length
===
0
)
{
return
null
;
const
headerDom
=
defaultRenderLogoAndTitle
(
props
)
const
extraDom
=
menuExtraRender
&&
menuExtraRender
(
props
)
if
(
hasSplitMenu
.
value
&&
unref
(
context
.
flatMenuData
)
.
length
===
0
)
{
return
null
}
const
defaultMenuDom
=
(
<
BaseMenu
...
...
@@ -203,7 +213,7 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => {
locale=
{
props
.
locale
||
context
.
locale
}
theme=
{
sTheme
.
value
===
'realDark'
?
'dark'
:
sTheme
.
value
}
mode=
"inline"
menuData=
{
hasSplitMenu
.
value
?
flatMenuData
.
value
:
context
.
menuData
}
menuData=
{
hasSplitMenu
.
value
?
context
.
flatMenuData
:
context
.
menuData
}
collapsed=
{
props
.
collapsed
}
openKeys=
{
context
.
openKeys
}
selectedKeys=
{
context
.
selectedKeys
}
...
...
@@ -216,11 +226,12 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => {
}
}
class=
{
`${baseClassName}-menu`
}
{
...
{
'
onUpdate
:
openKeys
':
(
$event
:
string
[])
=
>
onOpenKeys
&&
onOpenKeys($event),
'
onUpdate
:
openKeys
':
(
$event
:
string
[])
=
>
onOpenKeys
&&
onOpenKeys($event),
'onUpdate:selectedKeys': handleSelect,
}}
/
>
)
;
)
return (
<>
...
...
@@ -242,14 +253,16 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => {
collapsed=
{
collapsed
}
breakpoint=
{
breakpoint
||
undefined
}
onCollapse=
{
(
collapse
:
boolean
)
=>
{
if
(
props
.
isMobile
)
return
;
onCollapse
?.(
collapse
)
;
if
(
props
.
isMobile
)
return
onCollapse
?.(
collapse
)
}
}
collapsedWidth=
{
collapsedWidth
}
style=
{
{
overflow
:
'hidden'
,
paddingTop
:
props
.
layout
===
'mix'
&&
!
props
.
isMobile
?
`${props.headerHeight}px`
:
undefined
,
props
.
layout
===
'mix'
&&
!
props
.
isMobile
?
`${props.headerHeight}px`
:
undefined
,
}
}
width=
{
siderWidth
}
theme=
{
sTheme
.
value
===
'realDark'
?
'dark'
:
sTheme
.
value
}
...
...
@@ -276,7 +289,8 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => {
</
div
>
)
}
<
div
style=
"flex: 1; overflow: hidden auto;"
>
{
(
menuContentRender
&&
menuContentRender
(
props
,
defaultMenuDom
))
||
defaultMenuDom
}
{
(
menuContentRender
&&
menuContentRender
(
props
,
defaultMenuDom
))
||
defaultMenuDom
}
</
div
>
<
div
class=
{
`${baseClassName}-links`
}
>
{
collapsedButtonRender
!==
false
?
(
...
...
@@ -290,7 +304,7 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => {
// @ts-ignore
onClick=
{
()
=>
{
if
(
onCollapse
)
{
onCollapse
(
!
props
.
collapsed
)
;
onCollapse
(
!
props
.
collapsed
)
}
}
}
>
...
...
@@ -299,17 +313,20 @@ const SiderMenu: FC<SiderMenuProps> = (props: SiderMenuProps) => {
class=
{
`${baseClassName}-collapsed-button`
}
title=
{
false
}
>
{
collapsedButtonRender
&&
typeof
collapsedButtonRender
===
'function'
{
collapsedButtonRender
&&
typeof
collapsedButtonRender
===
'function'
?
collapsedButtonRender
(
collapsed
)
:
collapsedButtonRender
}
</
Menu
.
Item
>
</
Menu
>
)
:
null
}
</
div
>
{
menuFooterRender
&&
<
div
class=
{
`${baseClassName}-footer`
}
>
{
menuFooterRender
(
props
)
}
</
div
>
}
{
menuFooterRender
&&
(
<
div
class=
{
`${baseClassName}-footer`
}
>
{
menuFooterRender
(
props
)
}
</
div
>
)
}
</
Sider
>
</>
)
;
}
;
)
}
export default SiderMenu
;
export default SiderMenu
src/SiderMenu/index.less
View file @
c6c2a115
...
...
@@ -197,6 +197,7 @@
.@{ant-prefix}-menu-submenu-title {
.anticon {
transition: none;
font-size: 16px;
}
}
...
...
src/WaterMark/index.tsx
View file @
c6c2a115
...
...
@@ -68,6 +68,7 @@ const getPixelRatio = (context: any) => {
}
const
WaterMark
=
defineComponent
({
name
:
'WaterMark'
,
props
:
waterMarkProps
,
setup
(
props
,
{
slots
})
{
const
{
...
...
@@ -145,32 +146,34 @@ const WaterMark = defineComponent({
}
})
return
(
<
div
style=
{
{
position
:
'relative'
,
}
}
class=
{
wrapperCls
.
value
}
>
{
slots
.
default
?.()
}
return
()
=>
{
return
(
<
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
,
position
:
'relative'
,
}
}
/>
</
div
>
)
class=
{
wrapperCls
.
value
}
>
{
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
>
)
}
},
})
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment