Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lzb_79
uni-app
提交
cae888e8
U
uni-app
项目概览
lzb_79
/
uni-app
与 Fork 源项目一致
Fork自
DCloud / uni-app
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
uni-app
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
cae888e8
编写于
5月 24, 2021
作者:
D
DCloud_LXH
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor: scroll-view
上级
58ddc008
变更
5
展开全部
隐藏空白更改
内联
并排
Showing
5 changed file
with
1463 addition
and
1549 deletion
+1463
-1549
packages/uni-components/src/components/index.ts
packages/uni-components/src/components/index.ts
+1
-1
packages/uni-components/src/components/scroll-view/index.tsx
packages/uni-components/src/components/scroll-view/index.tsx
+616
-0
packages/uni-components/src/components/scroll-view/index.vue
packages/uni-components/src/components/scroll-view/index.vue
+0
-525
packages/uni-h5/dist/uni-h5.cjs.js
packages/uni-h5/dist/uni-h5.cjs.js
+370
-534
packages/uni-h5/dist/uni-h5.es.js
packages/uni-h5/dist/uni-h5.es.js
+476
-489
未找到文件。
packages/uni-components/src/components/index.ts
浏览文件 @
cae888e8
...
...
@@ -19,7 +19,7 @@ import Radio from './radio/index'
import
RadioGroup
from
'
./radio-group/index
'
import
ResizeSensor
from
'
./resize-sensor/index
'
import
RichText
from
'
./rich-text
'
import
ScrollView
from
'
./scroll-view/index
.vue
'
import
ScrollView
from
'
./scroll-view/index
'
import
Slider
from
'
./slider/index
'
import
Swiper
from
'
./swiper/index
'
import
SwiperItem
from
'
./swiper-item/index
'
...
...
packages/uni-components/src/components/scroll-view/index.tsx
0 → 100644
浏览文件 @
cae888e8
import
{
Ref
,
ref
,
ExtractPropTypes
,
computed
,
reactive
,
onMounted
,
onBeforeUnmount
,
onActivated
,
watch
,
}
from
'
vue
'
import
{
passive
}
from
'
@dcloudio/uni-shared
'
import
{
initScrollBounce
,
disableScrollBounce
}
from
'
../../helpers/scroll
'
import
{
useCustomEvent
,
CustomEventTrigger
,
EmitEvent
,
}
from
'
../../helpers/useEvent
'
import
{
defineBuiltInComponent
}
from
'
@dcloudio/uni-components
'
type
HTMLRef
=
Ref
<
HTMLElement
|
null
>
type
Props
=
ExtractPropTypes
<
typeof
props
>
type
RefreshState
=
'
refreshing
'
|
'
restore
'
|
'
pulling
'
|
''
interface
State
{
lastScrollTop
:
number
lastScrollLeft
:
number
lastScrollToUpperTime
:
number
lastScrollToLowerTime
:
number
refresherHeight
:
number
refreshRotate
:
number
refreshState
:
RefreshState
}
const
passiveOptions
=
passive
(
true
)
const
props
=
{
scrollX
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
scrollY
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
upperThreshold
:
{
type
:
[
Number
,
String
],
default
:
50
,
},
lowerThreshold
:
{
type
:
[
Number
,
String
],
default
:
50
,
},
scrollTop
:
{
type
:
[
Number
,
String
],
default
:
0
,
},
scrollLeft
:
{
type
:
[
Number
,
String
],
default
:
0
,
},
scrollIntoView
:
{
type
:
String
,
default
:
''
,
},
scrollWithAnimation
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
enableBackToTop
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
refresherEnabled
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
refresherThreshold
:
{
type
:
Number
,
default
:
45
,
},
refresherDefaultStyle
:
{
type
:
String
,
default
:
'
back
'
,
},
refresherBackground
:
{
type
:
String
,
default
:
'
#fff
'
,
},
refresherTriggered
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
}
export
default
/*#__PURE__*/
defineBuiltInComponent
({
name
:
'
ScrollView
'
,
compatConfig
:
{
MODE
:
3
,
},
props
,
emits
:
[
'
scroll
'
,
'
scrolltoupper
'
,
'
scrolltolower
'
,
'
refresherabort
'
],
setup
(
props
,
{
emit
,
slots
})
{
const
rootRef
:
HTMLRef
=
ref
(
null
)
const
main
:
HTMLRef
=
ref
(
null
)
const
wrap
:
HTMLRef
=
ref
(
null
)
const
content
:
HTMLRef
=
ref
(
null
)
const
refresherinner
:
HTMLRef
=
ref
(
null
)
const
trigger
=
useCustomEvent
<
EmitEvent
<
typeof
emit
>>
(
rootRef
,
emit
)
const
{
state
,
scrollTopNumber
,
scrollLeftNumber
}
=
useScrollViewState
(
props
)
useScrollViewLoader
(
props
,
state
,
scrollTopNumber
,
scrollLeftNumber
,
trigger
,
rootRef
,
main
,
content
)
return
()
=>
{
const
{
scrollX
,
refresherEnabled
,
refresherBackground
,
refresherDefaultStyle
,
}
=
props
const
{
refresherHeight
,
refreshState
,
refreshRotate
}
=
state
return
(
<
uni
-
scroll
-
view
ref
=
{
rootRef
}
>
<
div
ref
=
{
wrap
}
class
=
"uni-scroll-view"
>
<
div
ref
=
{
main
}
style
=
{
{
overflowX
:
scrollX
?
'
auto
'
:
'
hidden
'
,
overflowY
:
scrollY
?
'
auto
'
:
'
hidden
'
,
}
}
class
=
"uni-scroll-view"
>
<
div
ref
=
{
content
}
class
=
"uni-scroll-view-content"
>
{
refresherEnabled
?
(
<
div
ref
=
{
refresherinner
}
style
=
{
{
backgroundColor
:
refresherBackground
,
height
:
refresherHeight
+
'
px
'
,
}
}
class
=
"uni-scroll-view-refresher"
>
{
refresherDefaultStyle
!==
'
none
'
?
(
<
div
class
=
"uni-scroll-view-refresh"
>
<
div
class
=
"uni-scroll-view-refresh-inner"
>
{
refreshState
==
'
pulling
'
?
(
<
svg
style
=
{
{
transform
:
'
rotate(
'
+
refreshRotate
+
'
deg)
'
,
}
}
fill
=
"#2BD009"
class
=
"uni-scroll-view-refresh__icon"
width
=
"24"
height
=
"24"
viewBox
=
"0 0 24 24"
>
<
path
d
=
"M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"
/>
<
path
d
=
"M0 0h24v24H0z"
fill
=
"none"
/>
</
svg
>
)
:
null
}
{
refreshState
==
'
refreshing
'
?
(
<
svg
class
=
"uni-scroll-view-refresh__spinner"
width
=
"24"
height
=
"24"
viewBox
=
"25 25 50 50"
>
<
circle
cx
=
"50"
cy
=
"50"
r
=
"20"
fill
=
"none"
style
=
"color: #2bd009"
stroke
-
width
=
"3"
/>
</
svg
>
)
:
null
}
</
div
>
</
div
>
)
:
null
}
{
refresherDefaultStyle
==
'
none
'
?
slots
.
refresher
&&
slots
.
refresher
()
:
null
}
</
div
>
)
:
null
}
{
slots
.
default
&&
slots
.
default
()
}
</
div
>
</
div
>
</
div
>
</
uni
-
scroll
-
view
>
)
}
},
})
function
useScrollViewState
(
props
:
Props
)
{
const
scrollTopNumber
=
computed
(()
=>
{
return
Number
(
props
.
scrollTop
)
||
0
})
const
scrollLeftNumber
=
computed
(()
=>
{
return
Number
(
props
.
scrollLeft
)
||
0
})
const
state
:
State
=
reactive
({
lastScrollTop
:
scrollTopNumber
.
value
,
lastScrollLeft
:
scrollLeftNumber
.
value
,
lastScrollToUpperTime
:
0
,
lastScrollToLowerTime
:
0
,
refresherHeight
:
0
,
refreshRotate
:
0
,
refreshState
:
''
,
})
return
{
state
,
scrollTopNumber
,
scrollLeftNumber
,
}
}
function
useScrollViewLoader
(
props
:
Props
,
state
:
State
,
scrollTopNumber
:
Ref
<
number
>
,
scrollLeftNumber
:
Ref
<
number
>
,
trigger
:
CustomEventTrigger
,
rootRef
:
HTMLRef
,
main
:
HTMLRef
,
content
:
HTMLRef
)
{
let
_lastScrollTime
=
0
let
_innerSetScrollTop
=
false
let
_innerSetScrollLeft
=
false
let
__transitionEnd
=
()
=>
{}
const
upperThresholdNumber
=
computed
(()
=>
{
var
val
=
Number
(
props
.
upperThreshold
)
return
isNaN
(
val
)
?
50
:
val
})
const
lowerThresholdNumber
=
computed
(()
=>
{
var
val
=
Number
(
props
.
lowerThreshold
)
return
isNaN
(
val
)
?
50
:
val
})
function
scrollTo
(
t
:
number
,
n
:
'
x
'
|
'
y
'
)
{
var
i
=
main
.
value
!
t
<
0
?
(
t
=
0
)
:
n
===
'
x
'
&&
t
>
i
.
scrollWidth
-
i
.
offsetWidth
?
(
t
=
i
.
scrollWidth
-
i
.
offsetWidth
)
:
n
===
'
y
'
&&
t
>
i
.
scrollHeight
-
i
.
offsetHeight
&&
(
t
=
i
.
scrollHeight
-
i
.
offsetHeight
)
var
r
=
0
var
o
=
''
n
===
'
x
'
?
(
r
=
i
.
scrollLeft
-
t
)
:
n
===
'
y
'
&&
(
r
=
i
.
scrollTop
-
t
)
if
(
r
!==
0
)
{
content
.
value
!
.
style
.
transition
=
'
transform .3s ease-out
'
content
.
value
!
.
style
.
webkitTransition
=
'
-webkit-transform .3s ease-out
'
if
(
n
===
'
x
'
)
{
o
=
'
translateX(
'
+
r
+
'
px) translateZ(0)
'
}
else
{
n
===
'
y
'
&&
(
o
=
'
translateY(
'
+
r
+
'
px) translateZ(0)
'
)
}
content
.
value
!
.
removeEventListener
(
'
transitionend
'
,
__transitionEnd
)
content
.
value
!
.
removeEventListener
(
'
webkitTransitionEnd
'
,
__transitionEnd
)
__transitionEnd
=
()
=>
_transitionEnd
(
t
,
n
)
content
.
value
!
.
addEventListener
(
'
transitionend
'
,
__transitionEnd
)
content
.
value
!
.
addEventListener
(
'
webkitTransitionEnd
'
,
__transitionEnd
)
if
(
n
===
'
x
'
)
{
// if (e !== 'ios') {
i
.
style
.
overflowX
=
'
hidden
'
// }
}
else
if
(
n
===
'
y
'
)
{
i
.
style
.
overflowY
=
'
hidden
'
}
content
.
value
!
.
style
.
transform
=
o
content
.
value
!
.
style
.
webkitTransform
=
o
}
}
function
_handleScroll
(
$event
:
MouseEvent
)
{
if
(
$event
.
timeStamp
-
_lastScrollTime
>
20
)
{
_lastScrollTime
=
$event
.
timeStamp
const
target
=
$event
.
target
as
HTMLElement
trigger
(
'
scroll
'
,
$event
,
{
scrollLeft
:
target
.
scrollLeft
,
scrollTop
:
target
.
scrollTop
,
scrollHeight
:
target
.
scrollHeight
,
scrollWidth
:
target
.
scrollWidth
,
deltaX
:
state
.
lastScrollLeft
-
target
.
scrollLeft
,
deltaY
:
state
.
lastScrollTop
-
target
.
scrollTop
,
})
if
(
props
.
scrollY
)
{
if
(
target
.
scrollTop
<=
upperThresholdNumber
.
value
&&
state
.
lastScrollTop
-
target
.
scrollTop
>
0
&&
$event
.
timeStamp
-
state
.
lastScrollToUpperTime
>
200
)
{
trigger
(
'
scrolltoupper
'
,
$event
,
{
direction
:
'
top
'
,
})
state
.
lastScrollToUpperTime
=
$event
.
timeStamp
}
if
(
target
.
scrollTop
+
target
.
offsetHeight
+
lowerThresholdNumber
.
value
>=
target
.
scrollHeight
&&
state
.
lastScrollTop
-
target
.
scrollTop
<
0
&&
$event
.
timeStamp
-
state
.
lastScrollToLowerTime
>
200
)
{
trigger
(
'
scrolltolower
'
,
$event
,
{
direction
:
'
bottom
'
,
})
state
.
lastScrollToLowerTime
=
$event
.
timeStamp
}
}
if
(
props
.
scrollX
)
{
if
(
target
.
scrollLeft
<=
upperThresholdNumber
.
value
&&
state
.
lastScrollLeft
-
target
.
scrollLeft
>
0
&&
$event
.
timeStamp
-
state
.
lastScrollToUpperTime
>
200
)
{
trigger
(
'
scrolltoupper
'
,
$event
,
{
direction
:
'
left
'
,
})
state
.
lastScrollToUpperTime
=
$event
.
timeStamp
}
if
(
target
.
scrollLeft
+
target
.
offsetWidth
+
lowerThresholdNumber
.
value
>=
target
.
scrollWidth
&&
state
.
lastScrollLeft
-
target
.
scrollLeft
<
0
&&
$event
.
timeStamp
-
state
.
lastScrollToLowerTime
>
200
)
{
trigger
(
'
scrolltolower
'
,
$event
,
{
direction
:
'
right
'
,
})
state
.
lastScrollToLowerTime
=
$event
.
timeStamp
}
}
state
.
lastScrollTop
=
target
.
scrollTop
state
.
lastScrollLeft
=
target
.
scrollLeft
}
}
function
_scrollTopChanged
(
val
:
number
)
{
if
(
props
.
scrollY
)
{
if
(
_innerSetScrollTop
)
{
_innerSetScrollTop
=
false
}
else
{
if
(
props
.
scrollWithAnimation
)
{
scrollTo
(
val
,
'
y
'
)
}
else
{
main
.
value
!
.
scrollTop
=
val
}
}
}
}
function
_scrollLeftChanged
(
val
:
number
)
{
if
(
props
.
scrollX
)
{
if
(
_innerSetScrollLeft
)
{
_innerSetScrollLeft
=
false
}
else
{
if
(
props
.
scrollWithAnimation
)
{
scrollTo
(
val
,
'
x
'
)
}
else
{
main
.
value
!
.
scrollLeft
=
val
}
}
}
}
function
_scrollIntoViewChanged
(
val
:
string
)
{
if
(
val
)
{
if
(
!
/^
[
_a-zA-Z
][
-_a-zA-Z0-9:
]
*$/
.
test
(
val
))
{
console
.
error
(
`id error: scroll-into-view=
${
val
}
`
)
return
}
var
element
=
rootRef
.
value
!
.
querySelector
(
'
#
'
+
val
)
if
(
element
)
{
var
mainRect
=
main
.
value
!
.
getBoundingClientRect
()
var
elRect
=
element
.
getBoundingClientRect
()
if
(
props
.
scrollX
)
{
var
left
=
elRect
.
left
-
mainRect
.
left
var
scrollLeft
=
main
.
value
!
.
scrollLeft
var
x
=
scrollLeft
+
left
if
(
props
.
scrollWithAnimation
)
{
scrollTo
(
x
,
'
x
'
)
}
else
{
main
.
value
!
.
scrollLeft
=
x
}
}
if
(
props
.
scrollY
)
{
var
top
=
elRect
.
top
-
mainRect
.
top
var
scrollTop
=
main
.
value
!
.
scrollTop
var
y
=
scrollTop
+
top
if
(
props
.
scrollWithAnimation
)
{
scrollTo
(
y
,
'
y
'
)
}
else
{
main
.
value
!
.
scrollTop
=
y
}
}
}
}
}
function
_transitionEnd
(
val
:
number
,
type
:
'
x
'
|
'
y
'
)
{
content
.
value
!
.
style
.
transition
=
''
content
.
value
!
.
style
.
webkitTransition
=
''
content
.
value
!
.
style
.
transform
=
''
content
.
value
!
.
style
.
webkitTransform
=
''
let
_main
=
main
.
value
!
if
(
type
===
'
x
'
)
{
_main
.
style
.
overflowX
=
props
.
scrollX
?
'
auto
'
:
'
hidden
'
_main
.
scrollLeft
=
val
}
else
if
(
type
===
'
y
'
)
{
_main
.
style
.
overflowY
=
props
.
scrollY
?
'
auto
'
:
'
hidden
'
_main
.
scrollTop
=
val
}
content
.
value
!
.
removeEventListener
(
'
transitionend
'
,
__transitionEnd
)
content
.
value
!
.
removeEventListener
(
'
webkitTransitionEnd
'
,
__transitionEnd
)
}
function
_setRefreshState
(
_state
:
RefreshState
)
{
switch
(
_state
)
{
case
'
refreshing
'
:
state
.
refresherHeight
=
props
.
refresherThreshold
trigger
(
'
refresherrefresh
'
,
{}
as
Event
,
{})
break
case
'
restore
'
:
state
.
refresherHeight
=
0
trigger
(
'
refresherrestore
'
,
{}
as
Event
,
{})
break
}
state
.
refreshState
=
_state
}
/* function getScrollPosition() {
const _main = main.value!
return {
scrollLeft: _main.scrollLeft,
scrollTop: _main.scrollTop,
scrollHeight: _main.scrollHeight,
scrollWidth: _main.scrollWidth,
}
} */
onMounted
(()
=>
{
_scrollTopChanged
(
scrollTopNumber
.
value
)
_scrollLeftChanged
(
scrollLeftNumber
.
value
)
_scrollIntoViewChanged
(
props
.
scrollIntoView
)
let
__handleScroll
=
function
(
event
:
Event
)
{
// Unable to preventDefault inside passive event listener invocation.
// event.preventDefault();
event
.
stopPropagation
()
_handleScroll
(
event
as
MouseEvent
)
}
let
touchStart
:
{
x
:
number
y
:
number
}
=
{
x
:
0
,
y
:
0
,
}
let
needStop
:
boolean
|
null
=
null
let
__handleTouchMove
=
function
(
_event
:
Event
)
{
const
event
=
_event
as
TouchEvent
var
x
=
event
.
touches
[
0
].
pageX
var
y
=
event
.
touches
[
0
].
pageY
var
_main
=
main
.
value
!
if
(
needStop
===
null
)
{
if
(
Math
.
abs
(
x
-
touchStart
.
x
)
>
Math
.
abs
(
y
-
touchStart
.
y
))
{
// 横向滑动
if
(
self
.
scrollX
)
{
if
(
_main
.
scrollLeft
===
0
&&
x
>
touchStart
.
x
)
{
needStop
=
false
return
}
else
if
(
_main
.
scrollWidth
===
_main
.
offsetWidth
+
_main
.
scrollLeft
&&
x
<
touchStart
.
x
)
{
needStop
=
false
return
}
needStop
=
true
}
else
{
needStop
=
false
}
}
else
{
// 纵向滑动
if
(
self
.
scrollY
)
{
if
(
_main
.
scrollTop
===
0
&&
y
>
touchStart
.
y
)
{
needStop
=
false
return
}
else
if
(
_main
.
scrollHeight
===
_main
.
offsetHeight
+
_main
.
scrollTop
&&
y
<
touchStart
.
y
)
{
needStop
=
false
return
}
needStop
=
true
}
else
{
needStop
=
false
}
}
}
if
(
needStop
)
{
event
.
stopPropagation
()
}
if
(
props
.
refresherEnabled
&&
state
.
refreshState
===
'
pulling
'
)
{
const
dy
=
y
-
touchStart
.
y
state
.
refresherHeight
=
dy
let
rotate
=
dy
/
props
.
refresherThreshold
if
(
rotate
>
1
)
{
rotate
=
1
}
else
{
rotate
=
rotate
*
360
}
state
.
refreshRotate
=
rotate
trigger
(
'
refresherpulling
'
,
event
,
{
deltaY
:
dy
,
})
}
}
let
__handleTouchStart
=
function
(
_event
:
Event
)
{
const
event
=
_event
as
TouchEvent
if
(
event
.
touches
.
length
===
1
)
{
disableScrollBounce
({
disable
:
true
,
})
needStop
=
null
touchStart
=
{
x
:
event
.
touches
[
0
].
pageX
,
y
:
event
.
touches
[
0
].
pageY
,
}
if
(
props
.
refresherEnabled
&&
state
.
refreshState
!==
'
refreshing
'
&&
main
.
value
!
.
scrollTop
===
0
)
{
state
.
refreshState
=
'
pulling
'
}
}
}
let
__handleTouchEnd
=
function
(
_event
:
Event
)
{
const
event
=
_event
as
TouchEvent
touchStart
=
{
x
:
0
,
y
:
0
,
}
disableScrollBounce
({
disable
:
false
,
})
if
(
state
.
refresherHeight
>=
props
.
refresherThreshold
)
{
_setRefreshState
(
'
refreshing
'
)
}
else
{
state
.
refresherHeight
=
0
trigger
(
'
refresherabort
'
,
event
,
{})
}
}
main
.
value
!
.
addEventListener
(
'
touchstart
'
,
__handleTouchStart
,
passiveOptions
)
main
.
value
!
.
addEventListener
(
'
touchmove
'
,
__handleTouchMove
,
passiveOptions
)
main
.
value
!
.
addEventListener
(
'
scroll
'
,
__handleScroll
,
passiveOptions
)
main
.
value
!
.
addEventListener
(
'
touchend
'
,
__handleTouchEnd
,
passiveOptions
)
initScrollBounce
()
onBeforeUnmount
(()
=>
{
main
.
value
!
.
removeEventListener
(
'
touchstart
'
,
__handleTouchStart
)
main
.
value
!
.
removeEventListener
(
'
touchmove
'
,
__handleTouchMove
)
main
.
value
!
.
removeEventListener
(
'
scroll
'
,
__handleScroll
)
main
.
value
!
.
removeEventListener
(
'
touchend
'
,
__handleTouchEnd
)
})
})
onActivated
(()
=>
{
// 还原 scroll-view 滚动位置
props
.
scrollY
&&
(
main
.
value
!
.
scrollTop
=
state
.
lastScrollTop
)
props
.
scrollX
&&
(
main
.
value
!
.
scrollLeft
=
state
.
lastScrollLeft
)
})
watch
(
scrollTopNumber
,
(
val
)
=>
{
_scrollTopChanged
(
val
)
})
watch
(
scrollLeftNumber
,
(
val
)
=>
{
_scrollLeftChanged
(
val
)
})
watch
(
()
=>
props
.
scrollIntoView
,
(
val
)
=>
{
_scrollIntoViewChanged
(
val
)
}
)
watch
(
()
=>
props
.
refresherTriggered
,
(
val
)
=>
{
// TODO
if
(
val
===
true
)
{
_setRefreshState
(
'
refreshing
'
)
}
else
if
(
val
===
false
)
{
_setRefreshState
(
'
restore
'
)
}
}
)
}
packages/uni-components/src/components/scroll-view/index.vue
已删除
100644 → 0
浏览文件 @
58ddc008
<
template
>
<uni-scroll-view
ref=
"rootRef"
>
<div
ref=
"wrap"
class=
"uni-scroll-view"
>
<div
ref=
"main"
:style=
"
{
'overflow-x': scrollX ? 'auto' : 'hidden',
'overflow-y': scrollY ? 'auto' : 'hidden',
}"
class="uni-scroll-view"
>
<div
ref=
"content"
class=
"uni-scroll-view-content"
>
<div
v-if=
"refresherEnabled"
ref=
"refresherinner"
:style=
"
{
'background-color': refresherBackground,
height: refresherHeight + 'px',
}"
class="uni-scroll-view-refresher"
>
<div
v-if=
"refresherDefaultStyle !== 'none'"
class=
"uni-scroll-view-refresh"
>
<div
class=
"uni-scroll-view-refresh-inner"
>
<svg
v-if=
"refreshState == 'pulling'"
:style=
"
{ transform: 'rotate(' + refreshRotate + 'deg)' }"
fill="#2BD009"
class="uni-scroll-view-refresh__icon"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path
d=
"M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"
/>
<path
d=
"M0 0h24v24H0z"
fill=
"none"
/>
</svg>
<svg
v-if=
"refreshState == 'refreshing'"
class=
"uni-scroll-view-refresh__spinner"
width=
"24"
height=
"24"
viewBox=
"25 25 50 50"
>
<circle
cx=
"50"
cy=
"50"
r=
"20"
fill=
"none"
style=
"color: #2bd009"
stroke-width=
"3"
/>
</svg>
</div>
</div>
<slot
v-if=
"refresherDefaultStyle == 'none'"
name=
"refresher"
/>
</div>
<slot
/>
</div>
</div>
</div>
</uni-scroll-view>
</
template
>
<
script
>
import
{
ref
}
from
"
vue
"
;
import
{
passive
}
from
"
@dcloudio/uni-shared
"
;
import
{
initScrollBounce
,
disableScrollBounce
}
from
"
../../helpers/scroll
"
;
import
{
useCustomEvent
}
from
"
../../helpers/useEvent
"
;
const
passiveOptions
=
passive
(
true
);
// const PULLING = 'pulling'
// const REFRESHING = 'refreshing'
export
default
{
name
:
"
ScrollView
"
,
compatConfig
:
{
MODE
:
3
},
props
:
{
scrollX
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
scrollY
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
upperThreshold
:
{
type
:
[
Number
,
String
],
default
:
50
,
},
lowerThreshold
:
{
type
:
[
Number
,
String
],
default
:
50
,
},
scrollTop
:
{
type
:
[
Number
,
String
],
default
:
0
,
},
scrollLeft
:
{
type
:
[
Number
,
String
],
default
:
0
,
},
scrollIntoView
:
{
type
:
String
,
default
:
""
,
},
scrollWithAnimation
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
enableBackToTop
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
refresherEnabled
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
refresherThreshold
:
{
type
:
Number
,
default
:
45
,
},
refresherDefaultStyle
:
{
type
:
String
,
default
:
"
back
"
,
},
refresherBackground
:
{
type
:
String
,
default
:
"
#fff
"
,
},
refresherTriggered
:
{
type
:
[
Boolean
,
String
],
default
:
false
,
},
},
data
()
{
return
{
lastScrollTop
:
this
.
scrollTopNumber
,
lastScrollLeft
:
this
.
scrollLeftNumber
,
lastScrollToUpperTime
:
0
,
lastScrollToLowerTime
:
0
,
refresherHeight
:
0
,
refreshRotate
:
0
,
refreshState
:
""
,
};
},
computed
:
{
upperThresholdNumber
()
{
var
val
=
Number
(
this
.
upperThreshold
);
return
isNaN
(
val
)
?
50
:
val
;
},
lowerThresholdNumber
()
{
var
val
=
Number
(
this
.
lowerThreshold
);
return
isNaN
(
val
)
?
50
:
val
;
},
scrollTopNumber
()
{
return
Number
(
this
.
scrollTop
)
||
0
;
},
scrollLeftNumber
()
{
return
Number
(
this
.
scrollLeft
)
||
0
;
},
},
watch
:
{
scrollTopNumber
(
val
)
{
this
.
_scrollTopChanged
(
val
);
},
scrollLeftNumber
(
val
)
{
this
.
_scrollLeftChanged
(
val
);
},
scrollIntoView
(
val
)
{
this
.
_scrollIntoViewChanged
(
val
);
},
refresherTriggered
(
val
)
{
// TODO
if
(
val
===
true
)
{
this
.
_setRefreshState
(
"
refreshing
"
);
}
else
if
(
val
===
false
)
{
this
.
_setRefreshState
(
"
restore
"
);
}
},
},
mounted
()
{
this
.
$trigger
=
useCustomEvent
(
{
value
:
this
.
rootRef
,
},
this
.
$emit
);
var
self
=
this
;
this
.
_attached
=
true
;
this
.
_scrollTopChanged
(
this
.
scrollTopNumber
);
this
.
_scrollLeftChanged
(
this
.
scrollLeftNumber
);
this
.
_scrollIntoViewChanged
(
this
.
scrollIntoView
);
this
.
__handleScroll
=
function
(
event
)
{
// Unable to preventDefault inside passive event listener invocation.
// event.preventDefault();
event
.
stopPropagation
();
self
.
_handleScroll
.
bind
(
self
,
event
)();
};
var
touchStart
=
null
;
var
needStop
=
null
;
this
.
__handleTouchMove
=
function
(
event
)
{
var
x
=
event
.
touches
[
0
].
pageX
;
var
y
=
event
.
touches
[
0
].
pageY
;
var
main
=
self
.
main
;
if
(
needStop
===
null
)
{
if
(
Math
.
abs
(
x
-
touchStart
.
x
)
>
Math
.
abs
(
y
-
touchStart
.
y
))
{
// 横向滑动
if
(
self
.
scrollX
)
{
if
(
main
.
scrollLeft
===
0
&&
x
>
touchStart
.
x
)
{
needStop
=
false
;
return
;
}
else
if
(
main
.
scrollWidth
===
main
.
offsetWidth
+
main
.
scrollLeft
&&
x
<
touchStart
.
x
)
{
needStop
=
false
;
return
;
}
needStop
=
true
;
}
else
{
needStop
=
false
;
}
}
else
{
// 纵向滑动
if
(
self
.
scrollY
)
{
if
(
main
.
scrollTop
===
0
&&
y
>
touchStart
.
y
)
{
needStop
=
false
;
return
;
}
else
if
(
main
.
scrollHeight
===
main
.
offsetHeight
+
main
.
scrollTop
&&
y
<
touchStart
.
y
)
{
needStop
=
false
;
return
;
}
needStop
=
true
;
}
else
{
needStop
=
false
;
}
}
}
if
(
needStop
)
{
event
.
stopPropagation
();
}
if
(
self
.
refresherEnabled
&&
self
.
refreshState
===
"
pulling
"
)
{
const
dy
=
y
-
touchStart
.
y
;
self
.
refresherHeight
=
dy
;
let
rotate
=
dy
/
self
.
refresherThreshold
;
if
(
rotate
>
1
)
{
rotate
=
1
;
}
else
{
rotate
=
rotate
*
360
;
}
self
.
refreshRotate
=
rotate
;
self
.
$trigger
(
"
refresherpulling
"
,
event
,
{
deltaY
:
dy
,
});
}
};
this
.
__handleTouchStart
=
function
(
event
)
{
if
(
event
.
touches
.
length
===
1
)
{
disableScrollBounce
({
disable
:
true
,
});
needStop
=
null
;
touchStart
=
{
x
:
event
.
touches
[
0
].
pageX
,
y
:
event
.
touches
[
0
].
pageY
,
};
if
(
self
.
refresherEnabled
&&
self
.
refreshState
!==
"
refreshing
"
&&
self
.
main
.
scrollTop
===
0
)
{
self
.
refreshState
=
"
pulling
"
;
}
}
};
this
.
__handleTouchEnd
=
function
(
event
)
{
touchStart
=
null
;
disableScrollBounce
({
disable
:
false
,
});
if
(
self
.
refresherHeight
>=
self
.
refresherThreshold
)
{
self
.
_setRefreshState
(
"
refreshing
"
);
}
else
{
self
.
refresherHeight
=
0
;
self
.
$trigger
(
"
refresherabort
"
,
event
,
{});
}
};
this
.
main
.
addEventListener
(
"
touchstart
"
,
this
.
__handleTouchStart
,
passiveOptions
);
this
.
main
.
addEventListener
(
"
touchmove
"
,
this
.
__handleTouchMove
,
passiveOptions
);
this
.
main
.
addEventListener
(
"
scroll
"
,
this
.
__handleScroll
,
passiveOptions
);
this
.
main
.
addEventListener
(
"
touchend
"
,
this
.
__handleTouchEnd
,
passiveOptions
);
initScrollBounce
();
},
activated
()
{
// 还原 scroll-view 滚动位置
this
.
scrollY
&&
(
this
.
main
.
scrollTop
=
this
.
lastScrollTop
);
this
.
scrollX
&&
(
this
.
main
.
scrollLeft
=
this
.
lastScrollLeft
);
},
beforeUnmount
()
{
this
.
main
.
removeEventListener
(
"
touchstart
"
,
this
.
__handleTouchStart
,
passiveOptions
);
this
.
main
.
removeEventListener
(
"
touchmove
"
,
this
.
__handleTouchMove
,
passiveOptions
);
this
.
main
.
removeEventListener
(
"
scroll
"
,
this
.
__handleScroll
,
passiveOptions
);
this
.
main
.
removeEventListener
(
"
touchend
"
,
this
.
__handleTouchEnd
,
passiveOptions
);
},
methods
:
{
scrollTo
:
function
(
t
,
n
)
{
var
i
=
this
.
main
;
t
<
0
?
(
t
=
0
)
:
n
===
"
x
"
&&
t
>
i
.
scrollWidth
-
i
.
offsetWidth
?
(
t
=
i
.
scrollWidth
-
i
.
offsetWidth
)
:
n
===
"
y
"
&&
t
>
i
.
scrollHeight
-
i
.
offsetHeight
&&
(
t
=
i
.
scrollHeight
-
i
.
offsetHeight
);
var
r
=
0
;
var
o
=
""
;
n
===
"
x
"
?
(
r
=
i
.
scrollLeft
-
t
)
:
n
===
"
y
"
&&
(
r
=
i
.
scrollTop
-
t
);
if
(
r
!==
0
)
{
this
.
content
.
style
.
transition
=
"
transform .3s ease-out
"
;
this
.
content
.
style
.
webkitTransition
=
"
-webkit-transform .3s ease-out
"
;
if
(
n
===
"
x
"
)
{
o
=
"
translateX(
"
+
r
+
"
px) translateZ(0)
"
;
}
else
{
n
===
"
y
"
&&
(
o
=
"
translateY(
"
+
r
+
"
px) translateZ(0)
"
);
}
this
.
content
.
removeEventListener
(
"
transitionend
"
,
this
.
__transitionEnd
);
this
.
content
.
removeEventListener
(
"
webkitTransitionEnd
"
,
this
.
__transitionEnd
);
this
.
__transitionEnd
=
this
.
_transitionEnd
.
bind
(
this
,
t
,
n
);
this
.
content
.
addEventListener
(
"
transitionend
"
,
this
.
__transitionEnd
);
this
.
content
.
addEventListener
(
"
webkitTransitionEnd
"
,
this
.
__transitionEnd
);
if
(
n
===
"
x
"
)
{
// if (e !== 'ios') {
i
.
style
.
overflowX
=
"
hidden
"
;
// }
}
else
if
(
n
===
"
y
"
)
{
i
.
style
.
overflowY
=
"
hidden
"
;
}
this
.
content
.
style
.
transform
=
o
;
this
.
content
.
style
.
webkitTransform
=
o
;
}
},
_handleScroll
:
function
(
$event
)
{
if
(
!
(
$event
.
timeStamp
-
this
.
_lastScrollTime
<
20
))
{
this
.
_lastScrollTime
=
$event
.
timeStamp
;
const
target
=
$event
.
target
;
this
.
$trigger
(
"
scroll
"
,
$event
,
{
scrollLeft
:
target
.
scrollLeft
,
scrollTop
:
target
.
scrollTop
,
scrollHeight
:
target
.
scrollHeight
,
scrollWidth
:
target
.
scrollWidth
,
deltaX
:
this
.
lastScrollLeft
-
target
.
scrollLeft
,
deltaY
:
this
.
lastScrollTop
-
target
.
scrollTop
,
});
if
(
this
.
scrollY
)
{
if
(
target
.
scrollTop
<=
this
.
upperThresholdNumber
&&
this
.
lastScrollTop
-
target
.
scrollTop
>
0
&&
$event
.
timeStamp
-
this
.
lastScrollToUpperTime
>
200
)
{
this
.
$trigger
(
"
scrolltoupper
"
,
$event
,
{
direction
:
"
top
"
,
});
this
.
lastScrollToUpperTime
=
$event
.
timeStamp
;
}
if
(
target
.
scrollTop
+
target
.
offsetHeight
+
this
.
lowerThresholdNumber
>=
target
.
scrollHeight
&&
this
.
lastScrollTop
-
target
.
scrollTop
<
0
&&
$event
.
timeStamp
-
this
.
lastScrollToLowerTime
>
200
)
{
this
.
$trigger
(
"
scrolltolower
"
,
$event
,
{
direction
:
"
bottom
"
,
});
this
.
lastScrollToLowerTime
=
$event
.
timeStamp
;
}
}
if
(
this
.
scrollX
)
{
if
(
target
.
scrollLeft
<=
this
.
upperThresholdNumber
&&
this
.
lastScrollLeft
-
target
.
scrollLeft
>
0
&&
$event
.
timeStamp
-
this
.
lastScrollToUpperTime
>
200
)
{
this
.
$trigger
(
"
scrolltoupper
"
,
$event
,
{
direction
:
"
left
"
,
});
this
.
lastScrollToUpperTime
=
$event
.
timeStamp
;
}
if
(
target
.
scrollLeft
+
target
.
offsetWidth
+
this
.
lowerThresholdNumber
>=
target
.
scrollWidth
&&
this
.
lastScrollLeft
-
target
.
scrollLeft
<
0
&&
$event
.
timeStamp
-
this
.
lastScrollToLowerTime
>
200
)
{
this
.
$trigger
(
"
scrolltolower
"
,
$event
,
{
direction
:
"
right
"
,
});
this
.
lastScrollToLowerTime
=
$event
.
timeStamp
;
}
}
this
.
lastScrollTop
=
target
.
scrollTop
;
this
.
lastScrollLeft
=
target
.
scrollLeft
;
}
},
_scrollTopChanged
:
function
(
val
)
{
if
(
this
.
scrollY
)
{
if
(
this
.
_innerSetScrollTop
)
{
this
.
_innerSetScrollTop
=
false
;
}
else
{
if
(
this
.
scrollWithAnimation
)
{
this
.
scrollTo
(
val
,
"
y
"
);
}
else
{
this
.
main
.
scrollTop
=
val
;
}
}
}
},
_scrollLeftChanged
:
function
(
val
)
{
if
(
this
.
scrollX
)
{
if
(
this
.
_innerSetScrollLeft
)
{
this
.
_innerSetScrollLeft
=
false
;
}
else
{
if
(
this
.
scrollWithAnimation
)
{
this
.
scrollTo
(
val
,
"
x
"
);
}
else
{
this
.
main
.
scrollLeft
=
val
;
}
}
}
},
_scrollIntoViewChanged
:
function
(
val
)
{
if
(
val
)
{
if
(
!
/^
[
_a-zA-Z
][
-_a-zA-Z0-9:
]
*$/
.
test
(
val
))
{
console
.
error
(
`id error: scroll-into-view=
${
val
}
`
);
return
;
}
var
element
=
this
.
rootRef
.
querySelector
(
"
#
"
+
val
);
if
(
element
)
{
var
mainRect
=
this
.
main
.
getBoundingClientRect
();
var
elRect
=
element
.
getBoundingClientRect
();
if
(
this
.
scrollX
)
{
var
left
=
elRect
.
left
-
mainRect
.
left
;
var
scrollLeft
=
this
.
main
.
scrollLeft
;
var
x
=
scrollLeft
+
left
;
if
(
this
.
scrollWithAnimation
)
{
this
.
scrollTo
(
x
,
"
x
"
);
}
else
{
this
.
main
.
scrollLeft
=
x
;
}
}
if
(
this
.
scrollY
)
{
var
top
=
elRect
.
top
-
mainRect
.
top
;
var
scrollTop
=
this
.
main
.
scrollTop
;
var
y
=
scrollTop
+
top
;
if
(
this
.
scrollWithAnimation
)
{
this
.
scrollTo
(
y
,
"
y
"
);
}
else
{
this
.
main
.
scrollTop
=
y
;
}
}
}
}
},
_transitionEnd
:
function
(
val
,
type
)
{
this
.
content
.
style
.
transition
=
""
;
this
.
content
.
style
.
webkitTransition
=
""
;
this
.
content
.
style
.
transform
=
""
;
this
.
content
.
style
.
webkitTransform
=
""
;
var
main
=
this
.
main
;
if
(
type
===
"
x
"
)
{
main
.
style
.
overflowX
=
this
.
scrollX
?
"
auto
"
:
"
hidden
"
;
main
.
scrollLeft
=
val
;
}
else
if
(
type
===
"
y
"
)
{
main
.
style
.
overflowY
=
this
.
scrollY
?
"
auto
"
:
"
hidden
"
;
main
.
scrollTop
=
val
;
}
this
.
content
.
removeEventListener
(
"
transitionend
"
,
this
.
__transitionEnd
);
this
.
content
.
removeEventListener
(
"
webkitTransitionEnd
"
,
this
.
__transitionEnd
);
},
_setRefreshState
(
state
)
{
switch
(
state
)
{
case
"
refreshing
"
:
this
.
refresherHeight
=
this
.
refresherThreshold
;
this
.
$trigger
(
"
refresherrefresh
"
,
{},
{});
break
;
case
"
restore
"
:
this
.
refresherHeight
=
0
;
this
.
$trigger
(
"
refresherrestore
"
,
{},
{});
break
;
}
this
.
refreshState
=
state
;
},
getScrollPosition
()
{
const
main
=
this
.
main
;
return
{
scrollLeft
:
main
.
scrollLeft
,
scrollTop
:
main
.
scrollTop
,
scrollHeight
:
main
.
scrollHeight
,
scrollWidth
:
main
.
scrollWidth
,
};
},
},
setup
(
props
)
{
const
rootRef
=
ref
(
null
);
const
main
=
ref
(
null
);
const
content
=
ref
(
null
);
return
{
rootRef
,
main
,
content
,
};
},
};
</
script
>
packages/uni-h5/dist/uni-h5.cjs.js
浏览文件 @
cae888e8
此差异已折叠。
点击以展开。
packages/uni-h5/dist/uni-h5.es.js
浏览文件 @
cae888e8
此差异已折叠。
点击以展开。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录