Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
basic-vue-admin
概览
概览
详情
活动
周期分析
版本库
存储库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Basic
basic-vue-admin
Commits
305630e3
提交
305630e3
authored
6月 11, 2021
作者:
Vben
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(preview): added createImgPreview picture preview function
上级
3f6920f7
隐藏空白字符变更
内嵌
并排
正在显示
18 个修改的文件
包含
428 行增加
和
442 行删除
+428
-442
CHANGELOG.zh_CN.md
CHANGELOG.zh_CN.md
+1
-0
ApiSelect.vue
src/components/Form/src/components/ApiSelect.vue
+0
-1
FormAction.vue
src/components/Form/src/components/FormAction.vue
+0
-2
FormItem.vue
src/components/Form/src/components/FormItem.vue
+5
-9
RadioButtonGroup.vue
src/components/Form/src/components/RadioButtonGroup.vue
+2
-1
useAdvanced.ts
src/components/Form/src/hooks/useAdvanced.ts
+0
-2
useAutoFocus.ts
src/components/Form/src/hooks/useAutoFocus.ts
+9
-3
useForm.ts
src/components/Form/src/hooks/useForm.ts
+3
-5
useFormEvents.ts
src/components/Form/src/hooks/useFormEvents.ts
+0
-2
useFormValues.ts
src/components/Form/src/hooks/useFormValues.ts
+0
-2
form.ts
src/components/Form/src/types/form.ts
+0
-1
index.ts
src/components/Form/src/types/index.ts
+0
-2
Functional.vue
src/components/Preview/src/Functional.vue
+404
-273
functional.ts
src/components/Preview/src/functional.ts
+3
-5
index.less
src/components/Preview/src/index.less
+0
-118
props.ts
src/components/Preview/src/props.ts
+0
-15
typing.ts
src/components/Preview/src/typing.ts
+0
-0
index.vue
src/views/demo/feat/img-preview/index.vue
+1
-1
没有找到文件。
CHANGELOG.zh_CN.md
浏览文件 @
305630e3
...
...
@@ -9,6 +9,7 @@
-
**CropperImage**
`Cropper`
头像裁剪新增圆形裁剪功能
-
**CropperAvatar**
新增头像上传组件
-
**Drawer**
`useDrawer`
新增
`closeDrawer`
函数
-
**Preview**
新增
`createImgPreview`
图片预览函数
### 🐛 Bug Fixes
...
...
src/components/Form/src/components/ApiSelect.vue
浏览文件 @
305630e3
...
...
@@ -26,7 +26,6 @@
import
{
useRuleFormItem
}
from
'/@/hooks/component/useFormItem'
;
import
{
useAttrs
}
from
'/@/hooks/core/useAttrs'
;
import
{
get
,
omit
}
from
'lodash-es'
;
import
{
LoadingOutlined
}
from
'@ant-design/icons-vue'
;
import
{
useI18n
}
from
'/@/hooks/web/useI18n'
;
import
{
propTypes
}
from
'/@/utils/propTypes'
;
...
...
src/components/Form/src/components/FormAction.vue
浏览文件 @
305630e3
...
...
@@ -40,13 +40,11 @@
<
script
lang=
"ts"
>
import
type
{
ColEx
}
from
'../types/index'
;
import
type
{
ButtonProps
}
from
'ant-design-vue/es/button/buttonTypes'
;
import
{
defineComponent
,
computed
,
PropType
}
from
'vue'
;
import
{
Form
,
Col
}
from
'ant-design-vue'
;
import
{
Button
}
from
'/@/components/Button'
;
import
{
BasicArrow
}
from
'/@/components/Basic/index'
;
import
{
useFormContext
}
from
'../hooks/useFormContext'
;
import
{
useI18n
}
from
'/@/hooks/web/useI18n'
;
import
{
propTypes
}
from
'/@/utils/propTypes'
;
...
...
src/components/Form/src/components/FormItem.vue
浏览文件 @
305630e3
...
...
@@ -4,17 +4,14 @@
import
type
{
FormSchema
}
from
'../types/form'
;
import
type
{
ValidationRule
}
from
'ant-design-vue/lib/form/Form'
;
import
type
{
TableActionType
}
from
'/@/components/Table'
;
import
{
defineComponent
,
computed
,
unref
,
toRefs
}
from
'vue'
;
import
{
Form
,
Col
}
from
'ant-design-vue'
;
import
{
componentMap
}
from
'../componentMap'
;
import
{
BasicHelp
}
from
'/@/components/Basic'
;
import
{
isBoolean
,
isFunction
,
isNull
}
from
'/@/utils/is'
;
import
{
getSlot
}
from
'/@/utils/helper/tsxHelper'
;
import
{
createPlaceholderMessage
,
setComponentRuleType
}
from
'../helper'
;
import
{
upperFirst
,
cloneDeep
}
from
'lodash-es'
;
import
{
useItemLabelWidth
}
from
'../hooks/useLabelWidth'
;
import
{
useI18n
}
from
'/@/hooks/web/useI18n'
;
...
...
@@ -91,7 +88,6 @@
if
(
isBoolean
(
dynamicDisabled
))
{
disabled
=
dynamicDisabled
;
}
if
(
isFunction
(
dynamicDisabled
))
{
disabled
=
dynamicDisabled
(
unref
(
getValues
));
}
...
...
@@ -276,7 +272,6 @@
:
{
default
:
()
=>
renderComponentContent
,
};
return
<
Comp
{...
compAttr
}
>
{
compSlot
}
<
/Comp>
;
}
...
...
@@ -317,7 +312,6 @@
};
const
showSuffix
=
!!
suffix
;
const
getSuffix
=
isFunction
(
suffix
)
?
suffix
(
unref
(
getValues
))
:
suffix
;
return
(
...
...
@@ -338,16 +332,18 @@
<
/Form.Item
>
);
}
return
()
=>
{
const
{
colProps
=
{},
colSlot
,
renderColContent
,
component
}
=
props
.
schema
;
if
(
!
componentMap
.
has
(
component
))
return
null
;
if
(
!
componentMap
.
has
(
component
))
{
return
null
;
}
const
{
baseColProps
=
{}
}
=
props
.
formProps
;
const
realColProps
=
{
...
baseColProps
,
...
colProps
};
const
{
isIfShow
,
isShow
}
=
getShow
();
const
values
=
unref
(
getValues
);
const
getContent
=
()
=>
{
return
colSlot
?
getSlot
(
slots
,
colSlot
,
values
)
...
...
src/components/Form/src/components/RadioButtonGroup.vue
浏览文件 @
305630e3
<!--
* @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
-->
<
template
>
<RadioGroup
v-bind=
"attrs"
v-model:value=
"state"
button-style=
"solid"
>
<template
v-for=
"item in getOptions"
:key=
"`$
{item.value}`">
...
...
@@ -17,6 +16,7 @@
import
{
isString
}
from
'/@/utils/is'
;
import
{
useRuleFormItem
}
from
'/@/hooks/component/useFormItem'
;
import
{
useAttrs
}
from
'/@/hooks/core/useAttrs'
;
type
OptionsItem
=
{
label
:
string
;
value
:
string
|
number
|
boolean
;
disabled
?:
boolean
};
type
RadioItem
=
string
|
OptionsItem
;
...
...
@@ -39,6 +39,7 @@
const
attrs
=
useAttrs
();
// Embedded in the form, just use the hook binding to perform form verification
const
[
state
]
=
useRuleFormItem
(
props
);
// Processing options value
const
getOptions
=
computed
(():
OptionsItem
[]
=>
{
const
{
options
}
=
props
;
...
...
src/components/Form/src/hooks/useAdvanced.ts
浏览文件 @
305630e3
...
...
@@ -2,10 +2,8 @@ import type { ColEx } from '../types';
import
type
{
AdvanceState
}
from
'../types/hooks'
;
import
type
{
ComputedRef
,
Ref
}
from
'vue'
;
import
type
{
FormProps
,
FormSchema
}
from
'../types/form'
;
import
{
computed
,
unref
,
watch
}
from
'vue'
;
import
{
isBoolean
,
isFunction
,
isNumber
,
isObject
}
from
'/@/utils/is'
;
import
{
useBreakpoint
}
from
'/@/hooks/event/useBreakpoint'
;
import
{
useDebounceFn
}
from
'@vueuse/core'
;
...
...
src/components/Form/src/hooks/useAutoFocus.ts
浏览文件 @
305630e3
...
...
@@ -16,16 +16,22 @@ export async function useAutoFocus({
isInitedDefault
,
}:
UseAutoFocusContext
)
{
watchEffect
(
async
()
=>
{
if
(
unref
(
isInitedDefault
)
||
!
unref
(
getProps
).
autoFocusFirstItem
)
return
;
if
(
unref
(
isInitedDefault
)
||
!
unref
(
getProps
).
autoFocusFirstItem
)
{
return
;
}
await
nextTick
();
const
schemas
=
unref
(
getSchema
);
const
formEl
=
unref
(
formElRef
);
const
el
=
(
formEl
as
any
)?.
$el
as
HTMLElement
;
if
(
!
formEl
||
!
el
||
!
schemas
||
schemas
.
length
===
0
)
return
;
if
(
!
formEl
||
!
el
||
!
schemas
||
schemas
.
length
===
0
)
{
return
;
}
const
firstItem
=
schemas
[
0
];
// Only open when the first form item is input type
if
(
!
firstItem
.
component
.
includes
(
'Input'
))
return
;
if
(
!
firstItem
.
component
.
includes
(
'Input'
))
{
return
;
}
const
inputEl
=
el
.
querySelector
(
'.ant-row:first-child input'
)
as
Nullable
<
HTMLInputElement
>
;
if
(
!
inputEl
)
return
;
...
...
src/components/Form/src/hooks/useForm.ts
浏览文件 @
305630e3
import
type
{
FormProps
,
FormActionType
,
UseFormReturnType
,
FormSchema
}
from
'../types/form'
;
import
type
{
NamePath
}
from
'ant-design-vue/lib/form/interface'
;
import
type
{
DynamicProps
}
from
'/#/utils'
;
import
{
ref
,
onUnmounted
,
unref
,
nextTick
,
watch
}
from
'vue'
;
import
{
isProdMode
}
from
'/@/utils/env'
;
import
{
error
}
from
'/@/utils/log'
;
import
{
getDynamicProps
}
from
'/@/utils'
;
import
type
{
FormProps
,
FormActionType
,
UseFormReturnType
,
FormSchema
}
from
'../types/form'
;
import
type
{
NamePath
}
from
'ant-design-vue/lib/form/interface'
;
import
type
{
DynamicProps
}
from
'/#/utils'
;
export
declare
type
ValidateFields
=
(
nameList
?:
NamePath
[])
=>
Promise
<
Recordable
>
;
type
Props
=
Partial
<
DynamicProps
<
FormProps
>>
;
...
...
src/components/Form/src/hooks/useFormEvents.ts
浏览文件 @
305630e3
import
type
{
ComputedRef
,
Ref
}
from
'vue'
;
import
type
{
FormProps
,
FormSchema
,
FormActionType
}
from
'../types/form'
;
import
type
{
NamePath
}
from
'ant-design-vue/lib/form/interface'
;
import
{
unref
,
toRaw
}
from
'vue'
;
import
{
isArray
,
isFunction
,
isObject
,
isString
}
from
'/@/utils/is'
;
import
{
deepMerge
}
from
'/@/utils'
;
import
{
dateItemType
,
handleInputNumberValue
}
from
'../helper'
;
...
...
src/components/Form/src/hooks/useFormValues.ts
浏览文件 @
305630e3
import
{
isArray
,
isFunction
,
isObject
,
isString
,
isNullOrUnDef
}
from
'/@/utils/is'
;
import
{
dateUtil
}
from
'/@/utils/dateUtil'
;
import
{
unref
}
from
'vue'
;
import
type
{
Ref
,
ComputedRef
}
from
'vue'
;
import
type
{
FormProps
,
FormSchema
}
from
'../types/form'
;
import
{
set
}
from
'lodash-es'
;
interface
UseFormValuesContext
{
...
...
src/components/Form/src/types/form.ts
浏览文件 @
305630e3
import
type
{
NamePath
,
RuleObject
}
from
'ant-design-vue/lib/form/interface'
;
import
type
{
VNode
}
from
'vue'
;
import
type
{
ButtonProps
as
AntdButtonProps
}
from
'ant-design-vue/es/button/buttonTypes'
;
import
type
{
FormItem
}
from
'./formItem'
;
import
type
{
ColEx
,
ComponentType
}
from
'./index'
;
import
type
{
TableActionType
}
from
'/@/components/Table/src/types/table'
;
...
...
src/components/Form/src/types/index.ts
浏览文件 @
305630e3
...
...
@@ -90,9 +90,7 @@ export type ComponentType =
|
'InputCountDown'
|
'Select'
|
'ApiSelect'
|
'SelectOptGroup'
|
'TreeSelect'
|
'Transfer'
|
'RadioButtonGroup'
|
'RadioGroup'
|
'Checkbox'
...
...
src/components/Preview/src/
index.tsx
→
src/components/Preview/src/
Functional.vue
浏览文件 @
305630e3
import
'./index.less'
;
import
{
defineComponent
,
ref
,
unref
,
computed
,
reactive
,
watchEffect
}
from
'vue'
;
// @ts-ignore
import
{
basicProps
}
from
'./props'
;
// @ts-ignore
import
{
Props
}
from
'./types'
;
import
{
CloseOutlined
,
LeftOutlined
,
RightOutlined
}
from
'@ant-design/icons-vue'
;
// import { Spin } from 'ant-design-vue';
import
resumeSvg
from
'/@/assets/svg/preview/resume.svg'
;
import
rotateSvg
from
'/@/assets/svg/preview/p-rotate.svg'
;
import
scaleSvg
from
'/@/assets/svg/preview/scale.svg'
;
import
unScaleSvg
from
'/@/assets/svg/preview/unscale.svg'
;
import
unRotateSvg
from
'/@/assets/svg/preview/unrotate.svg'
;
enum
StatueEnum
{
LOADING
,
DONE
,
FAIL
,
}
interface
ImgState
{
currentUrl
:
string
;
imgScale
:
number
;
imgRotate
:
number
;
imgTop
:
number
;
imgLeft
:
number
;
currentIndex
:
number
;
status
:
StatueEnum
;
moveX
:
number
;
moveY
:
number
;
show
:
boolean
;
}
const
prefixCls
=
'img-preview'
;
export
default
defineComponent
({
name
:
'ImagePreview'
,
props
:
basicProps
,
setup
(
props
:
Props
)
{
const
imgState
=
reactive
<
ImgState
>
({
currentUrl
:
''
,
imgScale
:
1
,
imgRotate
:
0
,
imgTop
:
0
,
imgLeft
:
0
,
status
:
StatueEnum
.
LOADING
,
currentIndex
:
0
,
moveX
:
0
,
moveY
:
0
,
show
:
props
.
show
,
});
const
wrapElRef
=
ref
<
HTMLDivElement
|
null
>
(
null
);
const
imgElRef
=
ref
<
HTMLImageElement
|
null
>
(
null
);
// 初始化
function
init
()
{
initMouseWheel
();
const
{
index
,
imageList
}
=
props
;
if
(
!
imageList
||
!
imageList
.
length
)
{
throw
new
Error
(
'imageList is undefined'
);
<
script
lang=
"tsx"
>
import
{
defineComponent
,
ref
,
unref
,
computed
,
reactive
,
watchEffect
}
from
'vue'
;
import
{
Props
}
from
'./typing'
;
import
{
CloseOutlined
,
LeftOutlined
,
RightOutlined
}
from
'@ant-design/icons-vue'
;
import
resumeSvg
from
'/@/assets/svg/preview/resume.svg'
;
import
rotateSvg
from
'/@/assets/svg/preview/p-rotate.svg'
;
import
scaleSvg
from
'/@/assets/svg/preview/scale.svg'
;
import
unScaleSvg
from
'/@/assets/svg/preview/unscale.svg'
;
import
unRotateSvg
from
'/@/assets/svg/preview/unrotate.svg'
;
enum
StatueEnum
{
LOADING
,
DONE
,
FAIL
,
}
interface
ImgState
{
currentUrl
:
string
;
imgScale
:
number
;
imgRotate
:
number
;
imgTop
:
number
;
imgLeft
:
number
;
currentIndex
:
number
;
status
:
StatueEnum
;
moveX
:
number
;
moveY
:
number
;
show
:
boolean
;
}
const
props
=
{
show
:
{
type
:
Boolean
as
PropType
<
boolean
>
,
default
:
false
,
},
imageList
:
{
type
:
[
Array
]
as
PropType
<
string
[]
>
,
default
:
null
,
},
index
:
{
type
:
Number
as
PropType
<
number
>
,
default
:
0
,
},
};
const
prefixCls
=
'img-preview'
;
export
default
defineComponent
({
name
:
'ImagePreview'
,
props
,
setup
(
props
:
Props
)
{
const
imgState
=
reactive
<
ImgState
>
({
currentUrl
:
''
,
imgScale
:
1
,
imgRotate
:
0
,
imgTop
:
0
,
imgLeft
:
0
,
status
:
StatueEnum
.
LOADING
,
currentIndex
:
0
,
moveX
:
0
,
moveY
:
0
,
show
:
props
.
show
,
});
const
wrapElRef
=
ref
<
HTMLDivElement
|
null
>
(
null
);
const
imgElRef
=
ref
<
HTMLImageElement
|
null
>
(
null
);
// 初始化
function
init
()
{
initMouseWheel
();
const
{
index
,
imageList
}
=
props
;
if
(
!
imageList
||
!
imageList
.
length
)
{
throw
new
Error
(
'imageList is undefined'
);
}
imgState
.
currentIndex
=
index
;
handleIChangeImage
(
imageList
[
index
]);
}
imgState
.
currentIndex
=
index
;
handleIChangeImage
(
imageList
[
index
]);
}
// 重置
function
initState
()
{
imgState
.
imgScale
=
1
;
imgState
.
imgRotate
=
0
;
imgState
.
imgTop
=
0
;
imgState
.
imgLeft
=
0
;
}
// 重置
function
initState
()
{
imgState
.
imgScale
=
1
;
imgState
.
imgRotate
=
0
;
imgState
.
imgTop
=
0
;
imgState
.
imgLeft
=
0
;
}
// 初始化鼠标滚轮事件
function
initMouseWheel
()
{
const
wrapEl
=
unref
(
wrapElRef
);
if
(
!
wrapEl
)
{
return
;
// 初始化鼠标滚轮事件
function
initMouseWheel
()
{
const
wrapEl
=
unref
(
wrapElRef
);
if
(
!
wrapEl
)
{
return
;
}
(
wrapEl
as
any
).
onmousewheel
=
scrollFunc
;
// 火狐浏览器没有onmousewheel事件,用DOMMouseScroll代替
document
.
body
.
addEventListener
(
'DOMMouseScroll'
,
scrollFunc
);
// 禁止火狐浏览器下拖拽图片的默认事件
document
.
ondragstart
=
function
()
{
return
false
;
};
}
(
wrapEl
as
any
).
onmousewheel
=
scrollFunc
;
// 火狐浏览器没有onmousewheel事件,用DOMMouseScroll代替
document
.
body
.
addEventListener
(
'DOMMouseScroll'
,
scrollFunc
);
// 禁止火狐浏览器下拖拽图片的默认事件
document
.
ondragstart
=
function
()
{
return
false
;
};
}
// 监听鼠标滚轮
function
scrollFunc
(
e
:
any
)
{
e
=
e
||
window
.
event
;
e
.
delta
=
e
.
wheelDelta
||
-
e
.
detail
;
// 监听鼠标滚轮
function
scrollFunc
(
e
:
any
)
{
e
=
e
||
window
.
event
;
e
.
delta
=
e
.
wheelDelta
||
-
e
.
detail
;
e
.
preventDefault
();
if
(
e
.
delta
>
0
)
{
// 滑轮向上滚动
scaleFunc
(
0.015
);
e
.
preventDefault
();
if
(
e
.
delta
>
0
)
{
// 滑轮向上滚动
scaleFunc
(
0.015
);
}
if
(
e
.
delta
<
0
)
{
// 滑轮向下滚动
scaleFunc
(
-
0.015
);
}
}
if
(
e
.
delta
<
0
)
{
// 滑轮向下滚动
scaleFunc
(
-
0.015
);
// 缩放函数
function
scaleFunc
(
num
:
number
)
{
if
(
imgState
.
imgScale
<=
0.2
&&
num
<
0
)
return
;
imgState
.
imgScale
+=
num
;
}
}
// 缩放函数
function
scaleFunc
(
num
:
number
)
{
if
(
imgState
.
imgScale
<=
0.2
&&
num
<
0
)
return
;
imgState
.
imgScale
+=
num
;
}
// 旋转图片
function
rotateFunc
(
deg
:
number
)
{
imgState
.
imgRotate
+=
deg
;
}
// 旋转图片
function
rotateFunc
(
deg
:
number
)
{
imgState
.
imgRotate
+=
deg
;
}
// 鼠标事件
function
handleMouseUp
()
{
const
imgEl
=
unref
(
imgElRef
);
if
(
!
imgEl
)
return
;
imgEl
.
onmousemove
=
null
;
}
// 鼠标事件
function
handleMouseUp
()
{
const
imgEl
=
unref
(
imgElRef
);
if
(
!
imgEl
)
return
;
imgEl
.
onmousemove
=
null
;
}
// 更换图片
function
handleIChangeImage
(
url
:
string
)
{
imgState
.
status
=
StatueEnum
.
LOADING
;
const
img
=
new
Image
();
img
.
src
=
url
;
img
.
onload
=
()
=>
{
imgState
.
currentUrl
=
url
;
imgState
.
status
=
StatueEnum
.
DONE
;
};
img
.
onerror
=
()
=>
{
imgState
.
status
=
StatueEnum
.
FAIL
;
};
}
// 更换图片
function
handleIChangeImage
(
url
:
string
)
{
imgState
.
status
=
StatueEnum
.
LOADING
;
const
img
=
new
Image
();
img
.
src
=
url
;
img
.
onload
=
()
=>
{
imgState
.
currentUrl
=
url
;
imgState
.
status
=
StatueEnum
.
DONE
;
};
img
.
onerror
=
()
=>
{
imgState
.
status
=
StatueEnum
.
FAIL
;
};
}
// 关闭
function
handleClose
(
e
:
MouseEvent
)
{
e
&&
e
.
stopPropagation
();
imgState
.
show
=
false
;
// 移除火狐浏览器下的鼠标滚动事件
document
.
body
.
removeEventListener
(
'DOMMouseScroll'
,
scrollFunc
);
// 恢复火狐及Safari浏览器下的图片拖拽
document
.
ondragstart
=
null
;
}
// 关闭
function
handleClose
(
e
:
MouseEvent
)
{
e
&&
e
.
stopPropagation
();
imgState
.
show
=
false
;
// 移除火狐浏览器下的鼠标滚动事件
document
.
body
.
removeEventListener
(
'DOMMouseScroll'
,
scrollFunc
);
// 恢复火狐及Safari浏览器下的图片拖拽
document
.
ondragstart
=
null
;
}
// 图片复原
function
resume
()
{
initState
();
}
// 图片复原
function
resume
()
{
initState
();
}
// 上一页下一页
function
handleChange
(
direction
:
'left'
|
'right'
)
{
const
{
currentIndex
}
=
imgState
;
const
{
imageList
}
=
props
;
if
(
direction
===
'left'
)
{
imgState
.
currentIndex
--
;
if
(
currentIndex
<=
0
)
{
imgState
.
currentIndex
=
imageList
.
length
-
1
;
// 上一页下一页
function
handleChange
(
direction
:
'left'
|
'right'
)
{
const
{
currentIndex
}
=
imgState
;
const
{
imageList
}
=
props
;
if
(
direction
===
'left'
)
{
imgState
.
currentIndex
--
;
if
(
currentIndex
<=
0
)
{
imgState
.
currentIndex
=
imageList
.
length
-
1
;
}
}
if
(
direction
===
'right'
)
{
imgState
.
currentIndex
++
;
if
(
currentIndex
>=
imageList
.
length
-
1
)
{
imgState
.
currentIndex
=
0
;
}
}
handleIChangeImage
(
imageList
[
imgState
.
currentIndex
]);
}
if
(
direction
===
'right'
)
{
imgState
.
currentIndex
++
;
if
(
currentIndex
>=
imageList
.
length
-
1
)
{
imgState
.
currentIndex
=
0
;
function
handleAddMoveListener
(
e
:
MouseEvent
)
{
e
=
e
||
window
.
event
;
imgState
.
moveX
=
e
.
clientX
;
imgState
.
moveY
=
e
.
clientY
;
const
imgEl
=
unref
(
imgElRef
);
if
(
imgEl
)
{
imgEl
.
onmousemove
=
moveFunc
;
}
}
handleIChangeImage
(
imageList
[
imgState
.
currentIndex
]);
function
moveFunc
(
e
:
MouseEvent
)
{
e
=
e
||
window
.
event
;
e
.
preventDefault
();
const
movementX
=
e
.
clientX
-
imgState
.
moveX
;
const
movementY
=
e
.
clientY
-
imgState
.
moveY
;
imgState
.
imgLeft
+=
movementX
;
imgState
.
imgTop
+=
movementY
;
imgState
.
moveX
=
e
.
clientX
;
imgState
.
moveY
=
e
.
clientY
;
}
// 获取图片样式
const
getImageStyle
=
computed
(()
=>
{
const
{
imgScale
,
imgRotate
,
imgTop
,
imgLeft
}
=
imgState
;
return
{
transform
:
`scale(
${
imgScale
}
) rotate(
${
imgRotate
}
deg)`
,
marginTop
:
`
${
imgTop
}
px`
,
marginLeft
:
`
${
imgLeft
}
px`
,
};
});
const
getIsMultipleImage
=
computed
(()
=>
{
const
{
imageList
}
=
props
;
return
imageList
.
length
>
1
;
});
watchEffect
(()
=>
{
if
(
props
.
show
)
{
init
();
}
if
(
props
.
imageList
)
{
initState
();
}
});
const
renderClose
=
()
=>
{
return
(
<
div
class
=
{
`
${
prefixCls
}
__close`
}
onClick
=
{
handleClose
}
>
<
CloseOutlined
class
=
{
`
${
prefixCls
}
__close-icon`
}
/
>
<
/div
>
);
};
const
renderIndex
=
()
=>
{
if
(
!
unref
(
getIsMultipleImage
))
{
return
null
;
}
const
{
currentIndex
}
=
imgState
;
const
{
imageList
}
=
props
;
return
(
<
div
class
=
{
`
${
prefixCls
}
__index`
}
>
{
currentIndex
+
1
}
/ {imageList.length
}
<
/div
>
);
};
const
renderController
=
()
=>
{
return
(
<
div
class
=
{
`
${
prefixCls
}
__controller`
}
>
<
div
class
=
{
`
${
prefixCls
}
__controller-item`
}
onClick
=
{()
=>
scaleFunc
(
-
0.15
)}
>
<
img
src
=
{
unScaleSvg
}
/
>
<
/div
>
<
div
class
=
{
`
${
prefixCls
}
__controller-item`
}
onClick
=
{()
=>
scaleFunc
(
0.15
)}
>
<
img
src
=
{
scaleSvg
}
/
>
<
/div
>
<
div
class
=
{
`
${
prefixCls
}
__controller-item`
}
onClick
=
{
resume
}
>
<
img
src
=
{
resumeSvg
}
/
>
<
/div
>
<
div
class
=
{
`
${
prefixCls
}
__controller-item`
}
onClick
=
{()
=>
rotateFunc
(
-
90
)}
>
<
img
src
=
{
unRotateSvg
}
/
>
<
/div
>
<
div
class
=
{
`
${
prefixCls
}
__controller-item`
}
onClick
=
{()
=>
rotateFunc
(
90
)}
>
<
img
src
=
{
rotateSvg
}
/
>
<
/div
>
<
/div
>
);
};
const
renderArrow
=
(
direction
:
'left'
|
'right'
)
=>
{
if
(
!
unref
(
getIsMultipleImage
))
{
return
null
;
}
return
(
<
div
class
=
{[
`
${
prefixCls
}
__arrow`
,
direction
]}
onClick
=
{()
=>
handleChange
(
direction
)}
>
{
direction
===
'left'
?
<
LeftOutlined
/>
:
<
RightOutlined
/>
}
<
/div
>
);
};
return
()
=>
{
return
(
imgState
.
show
&&
(
<
div
class
=
{
prefixCls
}
ref
=
{
wrapElRef
}
onMouseup
=
{
handleMouseUp
}
>
<
div
class
=
{
`
${
prefixCls
}
-content`
}
>
{
/*<Spin*/
}
{
/* indicator={<LoadingOutlined style="font-size: 24px" spin />}*/
}
{
/* spinning={true}*/
}
{
/* class={[*/
}
{
/* `${prefixCls}-image`,*/
}
{
/* {*/
}
{
/* hidden: imgState.status !== StatueEnum.LOADING,*/
}
{
/* },*/
}
{
/* ]}*/
}
{
/*/>*/
}
<
img
style
=
{
unref
(
getImageStyle
)}
class
=
{[
`
${
prefixCls
}
-image`
,
imgState
.
status
===
StatueEnum
.
DONE
?
''
:
'hidden'
,
]}
ref
=
{
imgElRef
}
src
=
{
imgState
.
currentUrl
}
onMousedown
=
{
handleAddMoveListener
}
/
>
{
renderClose
()}
{
renderIndex
()}
{
renderController
()}
{
renderArrow
(
'left'
)}
{
renderArrow
(
'right'
)}
<
/div
>
<
/div
>
)
);
};
},
});
</
script
>
<
style
lang=
"less"
>
.img-preview
{
position
:
fixed
;
top
:
0
;
right
:
0
;
bottom
:
0
;
left
:
0
;
z-index
:
@
preview-comp-z-index
;
background
:
rgba
(
0
,
0
,
0
,
0.5
);
user-select
:
none
;
&-content
{
display
:
flex
;
width
:
100%
;
height
:
100%
;
color
:
@
white
;
justify-content
:
center
;
align-items
:
center
;
}
&
-image
{
cursor
:
pointer
;
transition
:
transform
0.3s
;
}
function
handleAddMoveListener
(
e
:
MouseEvent
)
{
e
=
e
||
window
.
event
;
imgState
.
moveX
=
e
.
clientX
;
imgState
.
moveY
=
e
.
clientY
;
const
imgEl
=
unref
(
imgElRef
);
if
(
imgEl
)
{
imgEl
.
onmousemove
=
moveFunc
;
&
__close
{
position
:
absolute
;
top
:
-40px
;
right
:
-40px
;
width
:
80px
;
height
:
80px
;
overflow
:
hidden
;
color
:
@
white
;
cursor
:
pointer
;
background-color
:
rgba
(
0
,
0
,
0
,
0.5
);
border-radius
:
50%
;
transition
:
all
0.2s
;
&-icon
{
position
:
absolute
;
top
:
46px
;
left
:
16px
;
font-size
:
16px
;
}
&
:hover
{
background-color
:
rgba
(
0
,
0
,
0
,
0.8
);
}
}
function
moveFunc
(
e
:
MouseEvent
)
{
e
=
e
||
window
.
event
;
e
.
preventDefault
()
;
const
movementX
=
e
.
clientX
-
imgState
.
moveX
;
const
movementY
=
e
.
clientY
-
imgState
.
moveY
;
imgState
.
imgLeft
+=
movementX
;
imgState
.
imgTop
+=
movementY
;
imgState
.
moveX
=
e
.
clientX
;
imgState
.
moveY
=
e
.
clientY
;
&
__index
{
position
:
absolute
;
bottom
:
5%
;
left
:
50%
;
padding
:
0
22px
;
font-size
:
16px
;
background
:
rgba
(
109
,
109
,
109
,
0.6
)
;
border-radius
:
15px
;
transform
:
translateX
(
-50%
)
;
}
// 获取图片样式
const
getImageStyle
=
computed
(()
=>
{
const
{
imgScale
,
imgRotate
,
imgTop
,
imgLeft
}
=
imgState
;
return
{
transform
:
`scale(
${
imgScale
}
) rotate(
${
imgRotate
}
deg)`
,
marginTop
:
`
${
imgTop
}
px`
,
marginLeft
:
`
${
imgLeft
}
px`
,
};
});
&
__controller
{
position
:
absolute
;
bottom
:
10%
;
left
:
50%
;
display
:
flex
;
width
:
260px
;
height
:
44px
;
padding
:
0
22px
;
margin-left
:
-139px
;
background
:
rgba
(
109
,
109
,
109
,
0.6
);
border-radius
:
22px
;
justify-content
:
center
;
&-item
{
display
:
flex
;
height
:
100%
;
padding
:
0
9px
;
font-size
:
24px
;
cursor
:
pointer
;
transition
:
all
0.2s
;
const
getIsMultipleImage
=
computed
(()
=>
{
const
{
imageList
}
=
props
;
return
imageList
.
length
>
1
;
});
&:hover
{
transform
:
scale
(
1.2
);
}
watchEffect
(()
=>
{
if
(
props
.
show
)
{
init
();
img
{
width
:
1em
;
}
}
if
(
props
.
imageList
)
{
initState
();
}
&
__arrow
{
position
:
absolute
;
top
:
50%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
width
:
50px
;
height
:
50px
;
font-size
:
28px
;
cursor
:
pointer
;
background-color
:
rgba
(
0
,
0
,
0
,
0.5
);
border-radius
:
50%
;
transition
:
all
0.2s
;
&:hover
{
background-color
:
rgba
(
0
,
0
,
0
,
0.8
);
}
});
const
renderClose
=
()
=>
{
return
(
<
div
class=
{
`${prefixCls}__close`
}
onClick=
{
handleClose
}
>
<
CloseOutlined
class=
{
`${prefixCls}__close-icon`
}
/>
</
div
>
);
};
const
renderIndex
=
()
=>
{
if
(
!
unref
(
getIsMultipleImage
))
{
return
null
;
&
.left
{
left
:
50px
;
}
const
{
currentIndex
}
=
imgState
;
const
{
imageList
}
=
props
;
return
(
<
div
class=
{
`${prefixCls}__index`
}
>
{
currentIndex
+
1
}
/
{
imageList
.
length
}
</
div
>
);
};
const
renderController
=
()
=>
{
return
(
<
div
class=
{
`${prefixCls}__controller`
}
>
<
div
class=
{
`${prefixCls}__controller-item`
}
onClick=
{
()
=>
scaleFunc
(
-
0.15
)
}
>
<
img
src=
{
unScaleSvg
}
/>
</
div
>
<
div
class=
{
`${prefixCls}__controller-item`
}
onClick=
{
()
=>
scaleFunc
(
0.15
)
}
>
<
img
src=
{
scaleSvg
}
/>
</
div
>
<
div
class=
{
`${prefixCls}__controller-item`
}
onClick=
{
resume
}
>
<
img
src=
{
resumeSvg
}
/>
</
div
>
<
div
class=
{
`${prefixCls}__controller-item`
}
onClick=
{
()
=>
rotateFunc
(
-
90
)
}
>
<
img
src=
{
unRotateSvg
}
/>
</
div
>
<
div
class=
{
`${prefixCls}__controller-item`
}
onClick=
{
()
=>
rotateFunc
(
90
)
}
>
<
img
src=
{
rotateSvg
}
/>
</
div
>
</
div
>
);
};
const
renderArrow
=
(
direction
:
'left'
|
'right'
)
=>
{
if
(
!
unref
(
getIsMultipleImage
))
{
return
null
;
&
.right
{
right
:
50px
;
}
return
(
<
div
class=
{
[
`${prefixCls}__arrow`
,
direction
]
}
onClick=
{
()
=>
handleChange
(
direction
)
}
>
{
direction
===
'left'
?
<
LeftOutlined
/>
:
<
RightOutlined
/>
}
</
div
>
);
};
return
()
=>
{
return
(
imgState
.
show
&&
(
<
div
class=
{
prefixCls
}
ref=
{
wrapElRef
}
onMouseup=
{
handleMouseUp
}
>
<
div
class=
{
`${prefixCls}-content`
}
>
{
/*<Spin*/
}
{
/* indicator={<LoadingOutlined style="font-size: 24px" spin />}*/
}
{
/* spinning={true}*/
}
{
/* class={[*/
}
{
/* `${prefixCls}-image`,*/
}
{
/* {*/
}
{
/* hidden: imgState.status !== StatueEnum.LOADING,*/
}
{
/* },*/
}
{
/* ]}*/
}
{
/*/>*/
}
<
img
style=
{
unref
(
getImageStyle
)
}
class=
{
[
`${prefixCls}-image`
,
imgState
.
status
===
StatueEnum
.
DONE
?
''
:
'hidden'
]
}
ref=
{
imgElRef
}
src=
{
imgState
.
currentUrl
}
onMousedown=
{
handleAddMoveListener
}
/>
{
renderClose
()
}
{
renderIndex
()
}
{
renderController
()
}
{
renderArrow
(
'left'
)
}
{
renderArrow
(
'right'
)
}
</
div
>
</
div
>
)
);
};
},
});
}
}
</
style
>
src/components/Preview/src/functional.ts
浏览文件 @
305630e3
import
ImgPreview
from
'./index'
;
import
type
{
Options
,
Props
}
from
'./typing'
;
import
ImgPreview
from
'./Functional.vue'
;
import
{
isClient
}
from
'/@/utils/is'
;
import
type
{
Options
,
Props
}
from
'./types'
;
import
{
createVNode
,
render
}
from
'vue'
;
let
instance
:
any
=
null
;
let
instance
:
ReturnType
<
typeof
createVNode
>
|
null
=
null
;
export
function
createImgPreview
(
options
:
Options
)
{
if
(
!
isClient
)
return
;
const
{
imageList
,
show
=
true
,
index
=
0
}
=
options
;
...
...
src/components/Preview/src/index.less
deleted
100644 → 0
浏览文件 @
3f6920f7
.img-preview {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: @preview-comp-z-index;
background: rgba(0, 0, 0, 0.5);
user-select: none;
&-content {
display: flex;
width: 100%;
height: 100%;
color: @white;
justify-content: center;
align-items: center;
}
&-image {
cursor: pointer;
transition: transform 0.3s;
}
&__close {
position: absolute;
top: -40px;
right: -40px;
width: 80px;
height: 80px;
overflow: hidden;
color: @white;
cursor: pointer;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 50%;
transition: all 0.2s;
&-icon {
position: absolute;
top: 46px;
left: 16px;
font-size: 16px;
}
&:hover {
background-color: rgba(0, 0, 0, 0.8);
}
}
&__index {
position: absolute;
bottom: 5%;
left: 50%;
padding: 0 22px;
font-size: 16px;
background: rgba(109, 109, 109, 0.6);
border-radius: 15px;
transform: translateX(-50%);
}
&__controller {
position: absolute;
bottom: 10%;
left: 50%;
display: flex;
width: 260px;
height: 44px;
padding: 0 22px;
margin-left: -139px;
background: rgba(109, 109, 109, 0.6);
border-radius: 22px;
justify-content: center;
&-item {
display: flex;
height: 100%;
padding: 0 9px;
font-size: 24px;
cursor: pointer;
transition: all 0.2s;
&:hover {
transform: scale(1.2);
}
img {
width: 1em;
}
}
}
&__arrow {
position: absolute;
top: 50%;
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
font-size: 28px;
cursor: pointer;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 50%;
transition: all 0.2s;
&:hover {
background-color: rgba(0, 0, 0, 0.8);
}
&.left {
left: 50px;
}
&.right {
right: 50px;
}
}
}
src/components/Preview/src/props.ts
deleted
100644 → 0
浏览文件 @
3f6920f7
import
{
PropType
}
from
'vue'
;
export
const
basicProps
=
{
show
:
{
type
:
Boolean
as
PropType
<
boolean
>
,
default
:
false
,
},
imageList
:
{
type
:
[
Array
]
as
PropType
<
string
[]
>
,
default
:
null
,
},
index
:
{
type
:
Number
as
PropType
<
number
>
,
default
:
0
,
},
};
src/components/Preview/src/typ
es
.ts
→
src/components/Preview/src/typ
ing
.ts
浏览文件 @
305630e3
File moved
src/views/demo/feat/img-preview/index.vue
浏览文件 @
305630e3
<
template
>
<PageWrapper
title=
"图片预览示例"
>
<p
@
click=
"openImg"
>
打开图片
</p>
<ImagePreview
:imageList=
"imgList"
/>
<a-button
@
click=
"openImg"
type=
"primary"
>
无预览图
</a-button>
</PageWrapper>
</
template
>
<
script
lang=
"ts"
>
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论