Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
DCloud
uni-app
提交
ba3de478
U
uni-app
项目概览
DCloud
/
uni-app
大约 1 个月 前同步成功
通知
702
Star
38705
Fork
3642
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
7
列表
看板
标记
里程碑
合并请求
1
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
uni-app
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
7
Issue
7
列表
看板
标记
里程碑
合并请求
1
合并请求
1
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
ba3de478
编写于
4月 20, 2021
作者:
fxy060608
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: Image
上级
ceb5c350
变更
8
展开全部
隐藏空白更改
内联
并排
Showing
8 changed file
with
1443 addition
and
625 deletion
+1443
-625
package.json
package.json
+1
-1
packages/uni-components/src/components/image/index.tsx
packages/uni-components/src/components/image/index.tsx
+194
-109
packages/uni-components/src/components/image/index.vue
packages/uni-components/src/components/image/index.vue
+0
-183
packages/uni-components/src/components/index.ts
packages/uni-components/src/components/index.ts
+1
-1
packages/uni-components/src/helpers/useEvent.ts
packages/uni-components/src/helpers/useEvent.ts
+6
-3
packages/uni-h5/dist/uni-h5.esm.js
packages/uni-h5/dist/uni-h5.esm.js
+349
-295
packages/vite-plugin-uni/package.json
packages/vite-plugin-uni/package.json
+2
-2
yarn.lock
yarn.lock
+890
-31
未找到文件。
package.json
浏览文件 @
ba3de478
...
...
@@ -69,7 +69,7 @@
"
size-limit
"
:
"
^4.10.1
"
,
"
ts-jest
"
:
"
^26.4.4
"
,
"
typescript
"
:
"
~4.1.3
"
,
"
vite
"
:
"
^2.
1.5
"
,
"
vite
"
:
"
^2.
2.1
"
,
"
vue
"
:
"
3.0.11
"
,
"
yorkie
"
:
"
^2.0.0
"
}
...
...
packages/uni-components/src/components/image/index.tsx
浏览文件 @
ba3de478
import
{
ref
,
defineComponent
,
computed
,
Ref
,
watchEffect
,
watch
,
onMoun
ted
,
compu
ted
,
reactive
,
onMounted
,
onBeforeUnmount
,
defineComponent
,
ExtractPropTypes
,
}
from
'
vue
'
import
{
getRealPath
}
from
'
@dcloudio/uni-platform
'
import
{
useCustomEvent
}
from
'
../../helpers/useEvent
'
import
{
CustomEventTrigger
,
useCustomEvent
}
from
'
../../helpers/useEvent
'
import
ResizeSensor
from
'
../resize-sensor/index.vue
'
const
props
=
{
src
:
{
type
:
String
,
default
:
''
,
},
mode
:
{
type
:
String
,
default
:
'
scaleToFill
'
,
},
lazyLoad
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
draggable
:
{
type
:
Boolean
,
default
:
true
,
},
}
type
ImageProps
=
ExtractPropTypes
<
typeof
props
>
type
ImageState
=
ReturnType
<
typeof
useImageState
>
type
FixSize
=
ReturnType
<
typeof
useImageSize
>
[
'
fixSize
'
]
type
ResetSize
=
ReturnType
<
typeof
useImageSize
>
[
'
resetSize
'
]
const
FIX_MODES
=
{
widthFix
:
[
'
width
'
,
'
height
'
],
heightFix
:
[
'
height
'
,
'
width
'
],
}
const
IMAGE_MODES
=
{
aspectFit
:
[
'
center center
'
,
'
contain
'
],
aspectFill
:
[
'
center center
'
,
'
cover
'
],
widthFix
:
[,
'
100% 100%
'
],
heightFix
:
[,
'
100% 100%
'
],
top
:
[
'
center top
'
],
bottom
:
[
'
center bottom
'
],
center
:
[
'
center center
'
],
left
:
[
'
left center
'
],
right
:
[
'
right center
'
],
'
top left
'
:
[
'
left top
'
],
'
top right
'
:
[
'
right top
'
],
'
bottom left
'
:
[
'
left bottom
'
],
'
bottom right
'
:
[
'
right bottom
'
],
}
export
default
/*#__PURE__*/
defineComponent
({
name
:
'
Image
'
,
props
:
{
src
:
{
type
:
String
,
default
:
''
,
},
mode
:
{
type
:
String
,
default
:
'
scaleToFill
'
,
},
lazyLoad
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
draggable
:
{
type
:
Boolean
,
default
:
true
,
},
},
props
,
setup
(
props
,
{
emit
})
{
const
rootRef
=
ref
(
null
)
const
src
=
useImageSrc
(
props
)
const
modeStyle
=
useImageMode
(
props
,
src
)
const
rootRef
=
ref
<
HTMLElement
|
null
>
(
null
)
const
state
=
useImageState
(
rootRef
,
props
)
const
trigger
=
useCustomEvent
(
rootRef
,
emit
)
const
{
fixSize
,
resetSize
}
=
useImageSize
(
rootRef
,
props
,
state
)
useImageLoader
(
state
,
{
trigger
,
fixSize
,
resetSize
,
})
return
()
=>
{
const
{
mode
}
=
props
const
imgSrc
=
src
.
valu
e
const
{
imgSrc
,
modeStyle
}
=
stat
e
return
(
<
uni
-
image
ref
=
{
rootRef
}
>
<
div
ref
=
"content"
style
=
{
modeStyle
.
value
}
/>
{
imgSrc
&&
<
img
src
=
{
imgSrc
}
/>
}
{
(
mode
===
'
widthFix
'
||
mode
===
'
heightFix
'
)
&&
<
ResizeSensor
/>
}
<
div
style
=
{
modeStyle
}
/>
{
imgSrc
&&
<
img
src
=
{
imgSrc
}
draggable
=
{
props
.
draggable
}
/>
}
{
FIX_MODES
[
mode
as
keyof
typeof
FIX_MODES
]
&&
(
<
ResizeSensor
onResize
=
{
fixSize
}
/>
)
}
</
uni
-
image
>
)
}
},
})
function
useImageData
()
{
return
reactive
({
originalWidth
:
0
,
originalHeight
:
0
,
originalStyle
:
{
width
:
''
,
height
:
''
},
src
:
''
,
})
}
function
loadImage
(
src
:
string
)
{}
function
useImageSrc
(
props
:
{
src
:
string
})
{
const
src
=
computed
(()
=>
getRealPath
(
props
.
src
))
watch
(
()
=>
props
.
src
,
()
=>
{
// loadImage
}
)
return
src
}
const
IMAGE_MODES
=
{
aspectFit
:
[
'
contain
'
,
'
center center
'
],
aspectFill
:
[
'
cover
'
,
'
center center
'
],
widthFix
:
[
'
100% 100%
'
],
heightFix
:
[
'
100% 100%
'
],
top
:
[,
'
center top
'
],
bottom
:
[,
'
center bottom
'
],
center
:
[,
'
center center
'
],
left
:
[,
'
left center
'
],
right
:
[,
'
right center
'
],
'
top left
'
:
[,
'
left top
'
],
'
top right
'
:
[,
'
right top
'
],
'
bottom left
'
:
[,
'
left bottom
'
],
'
bottom right
'
:
[,
'
right bottom
'
],
}
function
useImageMode
(
props
:
{
mode
:
string
},
rootRef
:
Ref
,
src
:
Ref
<
string
>
)
{
const
style
=
computed
(()
=>
{
function
useImageState
(
rootRef
:
Ref
<
HTMLElement
|
null
>
,
props
:
ImageProps
)
{
const
imgSrc
=
ref
(
''
)
const
modeStyleRef
=
computed
(()
=>
{
let
size
=
'
auto
'
let
position
=
''
const
opts
=
IMAGE_MODES
[
props
.
mode
as
keyof
typeof
IMAGE_MODES
]
if
(
opts
)
{
}
else
{
size
=
'
100% 100%
'
if
(
!
opts
)
{
position
=
'
0% 0%
'
size
=
'
100% 100%
'
}
else
{
opts
[
0
]
&&
(
position
=
opts
[
0
])
opts
[
1
]
&&
(
size
=
opts
[
1
])
}
const
srcVal
=
s
rc
.
value
const
srcVal
=
imgS
rc
.
value
return
`background-image:
${
srcVal
?
'
url("
'
+
srcVal
+
'
")
'
:
'
none
'
}
;background-position:
${
position
}
;background-size:
${
size
}
;background-repeat:no-repeat;`
})
const
ratio
=
ref
(
0
)
const
origWidth
=
ref
(
0
)
const
origHeight
=
ref
(
0
)
const
state
=
reactive
({
rootEl
:
rootRef
,
src
:
computed
(()
=>
getRealPath
(
props
.
src
)),
origWidth
:
0
,
origHeight
:
0
,
origStyle
:
{
width
:
''
,
height
:
''
},
modeStyle
:
modeStyleRef
,
imgSrc
,
})
onMounted
(()
=>
{
const
root
Val
=
rootRef
.
value
as
HTMLElement
const
style
=
root
Val
.
style
origWidth
.
value
=
Number
(
style
.
width
)
||
0
origHeight
.
value
=
Number
(
style
.
height
)
||
0
const
root
El
=
rootRef
.
value
!
const
style
=
root
El
!
.
style
state
.
origWidth
=
Number
(
style
.
width
)
||
0
state
.
origHeight
=
Number
(
style
.
height
)
||
0
})
watch
(
()
=>
props
.
mode
,
()
=>
{
// const { mode } = props
// fixSize(rootRef.value as HTMLElement, props.mode)
// TODO
// resetSize()
return
state
}
function
useImageLoader
(
state
:
ImageState
,
{
trigger
,
fixSize
,
resetSize
,
}:
{
fixSize
:
FixSize
resetSize
:
ResetSize
trigger
:
CustomEventTrigger
}
)
{
let
img
:
HTMLImageElement
|
null
const
loadImage
=
(
src
:
string
)
=>
{
if
(
!
src
)
{
resetImage
()
resetSize
()
return
}
if
(
!
img
)
{
img
=
new
Image
()
}
img
.
onload
=
(
evt
)
=>
{
const
{
width
,
height
}
=
img
!
state
.
origWidth
=
width
state
.
origHeight
=
height
state
.
imgSrc
=
src
fixSize
()
resetImage
()
trigger
(
'
load
'
,
evt
,
{
width
,
height
,
})
}
img
.
onerror
=
(
evt
)
=>
{
const
{
src
}
=
state
state
.
origWidth
=
0
state
.
origHeight
=
0
state
.
imgSrc
=
''
resetImage
()
trigger
(
'
error
'
,
evt
as
Event
,
{
errMsg
:
`GET
${
src
}
404 (Not Found)`
,
})
}
img
.
src
=
src
}
const
resetImage
=
()
=>
{
if
(
img
)
{
img
.
onload
=
null
img
.
onerror
=
null
img
=
null
}
}
watch
(
()
=>
state
.
src
,
(
value
)
=>
loadImage
(
value
)
)
return
style
onMounted
(()
=>
loadImage
(
state
.
src
))
onBeforeUnmount
(()
=>
resetImage
())
}
const
isChrome
=
navigator
.
vendor
===
'
Google Inc.
'
function
fixNumber
(
num
:
number
)
{
// fix: 解决 Chrome 浏览器上某些情况下导致 1px 缝隙的问题
if
(
typeof
navigator
&&
navigator
.
vendor
===
'
Google Inc.
'
&&
num
>
10
)
{
if
(
isChrome
&&
num
>
10
)
{
num
=
Math
.
round
(
num
/
2
)
*
2
}
return
num
}
function
fixSize
(
el
:
HTMLElement
,
mode
:
string
,
ratio
:
number
)
{
if
(
!
ratio
)
{
return
}
const
rect
=
el
.
getBoundingClientRect
()
if
(
mode
===
'
widthFix
'
)
{
const
width
=
rect
.
width
if
(
width
)
{
el
.
style
.
height
=
fixNumber
(
width
/
ratio
)
+
'
px
'
function
useImageSize
(
rootRef
:
Ref
<
HTMLElement
|
null
>
,
props
:
ImageProps
,
state
:
ImageState
)
{
const
fixSize
=
()
=>
{
const
{
mode
}
=
props
const
names
=
FIX_MODES
[
mode
as
keyof
typeof
FIX_MODES
]
if
(
!
names
)
{
return
}
const
{
origWidth
,
origHeight
}
=
state
const
ratio
=
origWidth
&&
origHeight
?
origWidth
/
origHeight
:
0
if
(
!
ratio
)
{
return
}
}
else
if
(
mode
===
'
heightFix
'
)
{
const
height
=
rect
.
height
if
(
height
)
{
el
.
style
.
width
=
fixNumber
(
height
*
ratio
)
+
'
px
'
const
rootEl
=
rootRef
.
value
!
const
rect
=
rootEl
.
getBoundingClientRect
()
const
value
=
rect
[
names
[
0
]
as
keyof
DOMRect
]
as
number
if
(
value
)
{
rootEl
.
style
[
names
[
1
]
as
'
height
'
|
'
width
'
]
=
fixNumber
(
value
/
ratio
)
+
'
px
'
}
}
}
function
resetSize
(
el
:
HTMLElement
,
width
:
string
,
height
:
string
)
{
const
style
=
el
.
style
style
.
width
=
width
style
.
height
=
height
const
resetSize
=
()
=>
{
const
{
style
}
=
rootRef
.
value
!
const
{
origStyle
:
{
width
,
height
},
}
=
state
style
.
width
=
width
style
.
height
=
height
}
watch
(
()
=>
props
.
mode
,
(
value
,
oldValue
)
=>
{
if
(
FIX_MODES
[
oldValue
as
keyof
typeof
FIX_MODES
])
{
resetSize
()
}
if
(
FIX_MODES
[
value
as
keyof
typeof
FIX_MODES
])
{
fixSize
()
}
}
)
return
{
fixSize
,
resetSize
,
}
}
packages/uni-components/src/components/image/index.vue
已删除
100644 → 0
浏览文件 @
ceb5c350
<
template
>
<uni-image
v-bind=
"$attrs"
>
<div
ref=
"content"
:style=
"modeStyle"
/>
<img
:src=
"realImagePath"
/>
<ResizeSensor
v-if=
"mode === 'widthFix'"
ref=
"sensor"
@
resize=
"_resize"
/>
</uni-image>
</
template
>
<
script
>
import
ResizeSensor
from
'
../resize-sensor/index.vue
'
import
{
getRealPath
}
from
'
@dcloudio/uni-platform
'
export
default
{
name
:
'
Image
'
,
props
:
{
src
:
{
type
:
String
,
default
:
''
,
},
mode
:
{
type
:
String
,
default
:
'
scaleToFill
'
,
},
// TODO 懒加载
lazyLoad
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
},
data
()
{
return
{
originalWidth
:
0
,
originalHeight
:
0
,
availHeight
:
''
,
}
},
computed
:
{
ratio
()
{
return
this
.
originalWidth
&&
this
.
originalHeight
?
this
.
originalWidth
/
this
.
originalHeight
:
0
},
realImagePath
()
{
return
getRealPath
(
this
.
src
)
},
modeStyle
()
{
let
size
=
'
auto
'
let
position
=
''
const
repeat
=
'
no-repeat
'
switch
(
this
.
mode
)
{
case
'
aspectFit
'
:
size
=
'
contain
'
position
=
'
center center
'
break
case
'
aspectFill
'
:
size
=
'
cover
'
position
=
'
center center
'
break
case
'
widthFix
'
:
size
=
'
100% 100%
'
break
case
'
top
'
:
position
=
'
center top
'
break
case
'
bottom
'
:
position
=
'
center bottom
'
break
case
'
center
'
:
position
=
'
center center
'
break
case
'
left
'
:
position
=
'
left center
'
break
case
'
right
'
:
position
=
'
right center
'
break
case
'
top left
'
:
position
=
'
left top
'
break
case
'
top right
'
:
position
=
'
right top
'
break
case
'
bottom left
'
:
position
=
'
left bottom
'
break
case
'
bottom right
'
:
position
=
'
right bottom
'
break
default
:
size
=
'
100% 100%
'
position
=
'
0% 0%
'
break
}
return
`background-position:
${
position
}
;background-size:
${
size
}
;background-repeat:
${
repeat
}
;`
},
},
watch
:
{
src
(
newValue
,
oldValue
)
{
this
.
_setContentImage
()
this
.
_loadImage
()
},
mode
(
newValue
,
oldValue
)
{
if
(
oldValue
===
'
widthFix
'
)
{
this
.
$el
.
style
.
height
=
this
.
availHeight
}
if
(
newValue
===
'
widthFix
'
&&
this
.
ratio
)
{
this
.
_fixSize
()
}
},
},
components
:
{
ResizeSensor
,
},
mounted
()
{
this
.
availHeight
=
this
.
$el
.
style
.
height
||
''
this
.
_setContentImage
()
if
(
!
this
.
realImagePath
)
{
return
}
this
.
_loadImage
()
},
methods
:
{
_resize
()
{
if
(
this
.
mode
===
'
widthFix
'
)
{
this
.
_fixSize
()
}
},
_fixSize
()
{
const
elWidth
=
this
.
_getWidth
()
if
(
elWidth
)
{
let
height
=
elWidth
/
this
.
ratio
// fix: 解决 Chrome 浏览器上某些情况下导致 1px 缝隙的问题
if
(
typeof
navigator
&&
navigator
.
vendor
===
'
Google Inc.
'
&&
height
>
10
)
{
height
=
Math
.
round
(
height
/
2
)
*
2
}
this
.
$el
.
style
.
height
=
height
+
'
px
'
}
},
_setContentImage
()
{
this
.
$refs
.
content
.
style
.
backgroundImage
=
this
.
src
?
`url("
${
this
.
realImagePath
}
")`
:
'
none
'
},
_loadImage
()
{
const
_self
=
this
const
img
=
new
Image
()
img
.
onload
=
function
(
$event
)
{
_self
.
originalWidth
=
this
.
width
_self
.
originalHeight
=
this
.
height
if
(
_self
.
mode
===
'
widthFix
'
)
{
_self
.
_fixSize
()
}
_self
.
$trigger
(
'
load
'
,
$event
,
{
width
:
this
.
width
,
height
:
this
.
height
,
})
}
img
.
onerror
=
function
(
$event
)
{
_self
.
$trigger
(
'
error
'
,
$event
,
{
errMsg
:
`GET
${
_self
.
src
}
404 (Not Found)`
,
})
}
img
.
src
=
this
.
realImagePath
},
_getWidth
()
{
const
computedStyle
=
window
.
getComputedStyle
(
this
.
$el
)
const
borderWidth
=
(
parseFloat
(
computedStyle
.
borderLeftWidth
,
10
)
||
0
)
+
(
parseFloat
(
computedStyle
.
borderRightWidth
,
10
)
||
0
)
const
paddingWidth
=
(
parseFloat
(
computedStyle
.
paddingLeft
,
10
)
||
0
)
+
(
parseFloat
(
computedStyle
.
paddingRight
,
10
)
||
0
)
return
this
.
$el
.
offsetWidth
-
borderWidth
-
paddingWidth
},
},
}
</
script
>
\ No newline at end of file
packages/uni-components/src/components/index.ts
浏览文件 @
ba3de478
...
...
@@ -6,7 +6,7 @@ import CheckboxGroup from './checkbox-group/index.vue'
import
Editor
from
'
./editor/index.vue
'
import
Form
from
'
./form/index
'
import
Icon
from
'
./icon/index
'
import
Image
from
'
./image/index
.vue
'
import
Image
from
'
./image/index
'
import
Input
from
'
./input/index.vue
'
import
Label
from
'
./label/index.vue
'
// import MovableArea from './movable-area/index.vue'
...
...
packages/uni-components/src/helpers/useEvent.ts
浏览文件 @
ba3de478
import
{
Ref
,
SetupContext
}
from
'
vue
'
type
EventDetail
=
Record
<
string
,
any
>
export
type
CustomEventTrigger
=
ReturnType
<
typeof
useCustomEvent
>
export
function
useCustomEvent
(
ref
:
Ref
,
emit
:
SetupContext
[
'
emit
'
])
{
export
function
useCustomEvent
(
ref
:
Ref
<
HTMLElement
|
null
>
,
emit
:
SetupContext
[
'
emit
'
]
)
{
return
(
name
:
string
,
evt
:
Event
,
detail
?:
EventDetail
)
=>
{
emit
(
name
,
...
...
@@ -16,10 +20,9 @@ function normalizeDataset(el: HTMLElement) {
}
function
normalizeTarget
(
el
:
HTMLElement
):
WechatMiniprogram
.
Target
{
const
{
id
,
tagName
,
offsetTop
,
offsetLeft
}
=
el
const
{
id
,
offsetTop
,
offsetLeft
}
=
el
return
{
id
,
tagName
,
dataset
:
normalizeDataset
(
el
),
offsetTop
,
offsetLeft
,
...
...
packages/uni-h5/dist/uni-h5.esm.js
浏览文件 @
ba3de478
此差异已折叠。
点击以展开。
packages/vite-plugin-uni/package.json
浏览文件 @
ba3de478
...
...
@@ -36,8 +36,8 @@
"peerDependencies"
:
{
"@dcloudio/uni-cli-shared"
:
"^3.0.0"
,
"@dcloudio/uni-shared"
:
"^3.0.0"
,
"@vue/shared"
:
"^3.0.1
0
"
,
"vite"
:
"^2.
1.5
"
"@vue/shared"
:
"^3.0.1
1
"
,
"vite"
:
"^2.
2.1
"
},
"devDependencies"
:
{
"@types/mime"
:
"^2.0.3"
,
...
...
yarn.lock
浏览文件 @
ba3de478
此差异已折叠。
点击以展开。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录