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
0f46541a
Commit
0f46541a
authored
Sep 30, 2021
by
Sendya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: watermark
parent
02f6d46b
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
187 additions
and
212 deletions
+187
-212
README.md
README.md
+57
-91
index.tsx
src/WaterMark/index.tsx
+130
-121
No files found.
README.md
View file @
0f46541a
...
...
@@ -28,23 +28,26 @@ npm i @ant-design-vue/pro-layout@next -S
## Basic Usage
look
[
Examples
](
./examples/
)
| Use Template https://github.com/sendya/preview-pro
Recommend look
[
Examples
](
./examples/
)
|
**Use Template https://github.com/sendya/preview-pro **
### Simple Usage
First, you should add the
`@ant-design-vue/pro-layout`
that you need into the library.
```
js
// main.[js|ts]
import
'ant-design-vue/dist/antd.less'
;
// antd css
import
'@ant-design-vue/pro-layout/dist/style.css'
;
// pro-layout css or style.less
import
{
createApp
}
from
'vue'
;
import
App
from
"./App.vue"
;
import
Antd
from
'ant-design-vue'
;
import
ProLayout
,
{
PageContainer
}
from
'@ant-design-vue/pro-layout'
;
const
app
=
createApp
(
App
);
app
.
use
(
ProLayout
).
use
(
PageContainer
).
mount
(
'#app'
);
app
.
use
(
Antd
).
use
(
ProLayout
).
use
(
PageContainer
).
mount
(
'#app'
);
```
After that, you can use pro-layout in your Vue components as simply as this:
...
...
@@ -53,94 +56,36 @@ After that, you can use pro-layout in your Vue components as simply as this:
<
template
>
<pro-layout
:locale=
"locale"
v-bind=
"
state
"
v-model:openKeys=
"
bas
e.openKeys"
v-model:collapsed=
"
bas
e.collapsed"
v-model:selectedKeys=
"
bas
e.selectedKeys"
v-bind=
"
layoutConf
"
v-model:openKeys=
"
stat
e.openKeys"
v-model:collapsed=
"
stat
e.collapsed"
v-model:selectedKeys=
"
stat
e.selectedKeys"
>
<router-view
/>
</pro-layout>
</
template
>
<
script
>
import
{
defineComponent
,
reactive
}
from
'vue'
;
<
script
setup
lang=
"ts"
>
import
{
reactive
,
useRouter
}
from
'vue'
;
import
{
getMenuData
,
clearMenuItem
}
from
'@ant-design-vue/pro-layout'
;
const
locale
=
(
i18n
:
string
)
=>
i18n
;
const
router
=
useRouter
();
export
default
defineComponent
({
setup
()
{
const
router
=
useRouter
();
const
{
menuData
}
=
getMenuData
(
clearMenuItem
(
router
.
getRoutes
()));
const
base
=
reactive
({
collapsed
:
false
,
// default value
openKeys
:
[
'/dashboard'
],
selectedKeys
:
[
'/welcome'
],
})
const
state
=
reactive
({
navTheme
:
'dark'
,
layout
:
'mix'
,
splitMenus
:
false
,
menuData
,
});
return
{
locale
,
base
,
state
,
};
},
});
</
script
>
```
or
`TSX`
const
{
menuData
}
=
getMenuData
(
clearMenuItem
(
router
.
getRoutes
()));
```
tsx
import
{
defineComponent
,
reactive
}
from
'vue'
;
import
{
RouterView
}
from
'vue-router'
;
import
ProLayout
from
'@ant-design-vue/pro-layout'
;
import
'@ant-design-vue/pro-layout/dist/style.css'
;
// pro-layout css or style.less
export
default
defineComponent
({
setup
()
{
const
router
=
useRouter
();
const
{
menuData
}
=
getMenuData
(
clearMenuItem
(
router
.
getRoutes
()));
const
base
=
reactive
({
const
state
=
reactive
({
collapsed
:
false
,
// default value
openKeys
:
[
'/dashboard'
],
selectedKeys
:
[
'/welcome'
],
})
const
state
=
reactive
({
})
const
layoutConf
=
reactive
({
navTheme
:
'dark'
,
layout
:
'mix'
,
splitMenus
:
false
,
menuData
,
});
const
handleCollapse
=
(
collapsed
:
boolean
)
=>
{
base
.
collapsed
=
collapsed
;
}
const
handleSelect
=
(
selectedKeys
:
string
[])
=>
{
base
.
selectedKeys
=
selectedKeys
;
}
const
handleOpenKeys
=
(
openKeys
:
string
[])
=>
{
base
.
openKeys
=
openKeys
;
}
return
()
=>
(
<
ProLayout
{
...
state
}
{
...
base
}
locale=
{
(
i18n
:
string
)
=>
i18n
}
onCollapse=
{
handleCollapse
}
onSelect=
{
handleSelect
}
onOpenKeys=
{
handleOpenKeys
}
>
<
RouterView
/>
</
ProLayout
>
);
},
});
</
script
>
```
...
...
@@ -176,6 +121,38 @@ export default defineComponent({
| menuSubItemRender | custom render Menu.SubItem | v-slot#menuSubItemRender="{ item, icon }"
\|
({ item, icon }) => VNode | null |
| locale | i18n | Function (key: string) => string
\|
`false`
|
`false`
|
### PageContainer
| Property | Description | Type | Default Value |
| --- | --- | --- | --- |
| content | Content area | VNode
\|
v-slot | - |
| extra | Extra content area, on the right side of content | VNode
\|
v-slot | - |
| extraContent | Extra content area, on the right side of content | VNode
\|
v-slot | - |
| tabList | Tabs title list |
`Array<{key: string, tab: sting}>`
| - |
| tab-change | Switch panel callback | (key) => void | - |
| tab-active-key | The currently highlighted tab item | string | - |
### WaterMark
| Property | Description | Type | Default Value |
| ------------- | ------------------------------------- | ----------------- | ---------------------- |
| markStyle | mark style | CSSProperties | - |
| markClassName | mark class | string | - |
| gapX | Horizontal spacing between water-mark | number | 212 |
| gapY | Vertical spacing between watermark | number | 222 |
| offsetLeft | Horizontal offset | number |
`offsetTop = gapX / 2`
|
| offsetTop | Vertical offset | number |
`offsetTop = gapY / 2`
|
| | | | |
| width | | number | 120 |
| height | | number | 64 |
| rotate | Angle of rotation, unit ° | number | -22 |
| image | image src | string | - |
| zIndex | water-mark z-index | number | 9 |
| content | water-mark Content | string | - |
| fontColor | font-color | string |
`rgba(0,0,0,.15)`
|
| fontSize | font-size | string
` | `
number | 16 |
### Custom Render
...
...
@@ -248,17 +225,6 @@ export default defineComponent({
```
### PageContainer
| Property | Description | Type | Default Value |
| --- | --- | --- | --- |
| content | Content area | VNode
\|
v-slot | - |
| extra | Extra content area, on the right side of content | VNode
\|
v-slot | - |
| extraContent | Extra content area, on the right side of content | VNode
\|
v-slot | - |
| tabList | Tabs title list |
`Array<{key: string, tab: sting}>`
| - |
| tab-change | Switch panel callback | (key) => void | - |
| tab-active-key | The currently highlighted tab item | string | - |
## Build project
...
...
src/WaterMark/index.tsx
View file @
0f46541a
import
type
{
CSSProperties
,
FunctionalComponent
as
FC
}
from
'vue'
;
import
{
computed
,
ref
,
watchEffect
}
from
'vue'
;
import
{
useRouteContext
}
from
'../RouteContext'
;
import
type
{
CSSProperties
,
PropType
,
ExtractPropTypes
}
from
'vue'
import
{
defineComponent
,
computed
,
ref
,
watchEffect
}
from
'vue'
import
{
useRouteContext
}
from
'../RouteContext'
export
type
WaterMarkProps
=
{
export
type
FontStyle
=
'none'
|
'normal'
|
'italic'
|
'oblique'
export
type
FontWeight
=
'normal'
|
'light'
|
'weight'
|
number
export
const
waterMarkProps
=
{
/** ClassName 前缀 */
prefixCls
:
String
,
/** 水印样式 */
markStyle
?:
CSSProperties
;
markStyle
:
[
String
,
Object
]
as
PropType
<
CSSProperties
>
,
/** 水印类名 */
markClassName
?:
string
;
markClassName
:
String
,
/** 水印之间的水平间距 */
gapX
?:
number
;
gapX
:
Number
,
/** 水印之间的垂直间距 */
gapY
?:
number
;
gapY
:
Number
,
/** 追加的水印元素的z-index */
zIndex
?:
number
;
zIndex
:
Number
,
/** 水印的宽度 */
width
?:
number
;
width
:
Number
,
/** 水印的高度 */
height
?:
number
;
height
:
Number
,
/** 水印在canvas 画布上绘制的垂直偏移量,正常情况下,水印绘制在中间位置, 即 offsetTop = gapY / 2 */
offsetTop
?:
number
;
// 水印图片距离绘制 canvas 单元的顶部距离
offsetTop
:
Number
,
// 水印图片距离绘制 canvas 单元的顶部距离
/** 水印在canvas 画布上绘制的水平偏移量, 正常情况下,水印绘制在中间位置, 即 offsetTop = gapX / 2 */
offsetLeft
?:
number
;
offsetLeft
:
Number
,
/** 水印绘制时,旋转的角度,单位 ° */
rotate
?:
number
;
/** ClassName 前缀 */
prefixCls
?:
string
;
rotate
:
Number
,
/** 高清印图片源, 为了高清屏幕显示,建议使用 2倍或3倍图,优先使用图片渲染水印。 */
image
?:
string
;
image
:
String
,
/** 水印文字内容 */
content
?:
string
;
content
:
String
,
/** 文字颜色 */
fontColor
?:
string
;
fontColor
:
String
,
/** 文字样式 */
fontStyle
?:
'none'
|
'normal'
|
'italic'
|
'oblique'
;
fontStyle
:
String
as
PropType
<
FontStyle
>
,
/** 文字族 */
fontFamily
?:
string
;
fontFamily
:
String
,
/** 文字粗细 */
fontWeight
?:
'normal'
|
'light'
|
'weight'
|
number
;
fontWeight
:
[
String
,
Number
]
as
PropType
<
FontWeight
>
,
/** 文字大小 */
fontSize
?:
number
|
string
;
};
fontSize
:
[
String
,
Number
]
as
PropType
<
string
|
number
>
,
}
export
type
WaterMarkProps
=
Partial
<
ExtractPropTypes
<
typeof
waterMarkProps
>>
/**
* 返回当前显示设备的物理像素分辨率与CSS像素分辨率之比
*
...
...
@@ -48,7 +54,7 @@ export type WaterMarkProps = {
*/
const
getPixelRatio
=
(
context
:
any
)
=>
{
if
(
!
context
)
{
return
1
;
return
1
}
const
backingStore
=
context
.
backingStorePixelRatio
||
...
...
@@ -57,11 +63,13 @@ const getPixelRatio = (context: any) => {
context
.
msBackingStorePixelRatio
||
context
.
oBackingStorePixelRatio
||
context
.
backingStorePixelRatio
||
1
;
return
(
window
.
devicePixelRatio
||
1
)
/
backingStore
;
}
;
1
return
(
window
.
devicePixelRatio
||
1
)
/
backingStore
}
const
WaterMark
:
FC
<
WaterMarkProps
>
=
(
props
,
{
slots
})
=>
{
const
WaterMark
=
defineComponent
({
props
:
waterMarkProps
,
setup
(
props
,
{
slots
})
{
const
{
markStyle
,
markClassName
,
...
...
@@ -82,60 +90,60 @@ const WaterMark: FC<WaterMarkProps> = (props, { slots }) => {
fontSize
=
16
,
fontFamily
=
'sans-serif'
,
prefixCls
:
customizePrefixCls
,
}
=
props
;
}
=
props
const
{
getPrefixCls
}
=
useRouteContext
();
const
prefixCls
=
getPrefixCls
(
'pro-layout-watermark'
,
customizePrefixCls
);
const
wrapperCls
=
computed
(()
=>
`
${
prefixCls
}
-wrapper`
);
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
(
''
);
}
})
const
base64Url
=
ref
(
''
)
watchEffect
(()
=>
{
const
canvas
=
document
.
createElement
(
'canvas'
);
const
ctx
=
canvas
.
getContext
(
'2d'
);
const
ratio
=
getPixelRatio
(
ctx
);
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
;
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
);
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
;
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
;
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
();
};
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
();
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'
);
console
.
error
(
'当前环境不支持Canvas'
)
}
});
})
return
(
<
div
...
...
@@ -162,7 +170,8 @@ const WaterMark: FC<WaterMarkProps> = (props, { slots }) => {
}
}
/>
</
div
>
);
};
)
},
})
export
default
WaterMark
;
export
default
WaterMark
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