Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
京东前端
nutui
提交
e8391332
N
nutui
项目概览
京东前端
/
nutui
通知
37
Star
4
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
N
nutui
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
e8391332
编写于
3月 17, 2021
作者:
richard_1015
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'next' of
https://github.com/jdf2e/nutui
into next
上级
3f17ac3c
cc74341f
变更
6
显示空白变更内容
内联
并排
Showing
6 changed file
with
164 addition
and
195 deletion
+164
-195
src/config.json
src/config.json
+1
-1
src/packages/infiniteloading/demo.vue
src/packages/infiniteloading/demo.vue
+16
-22
src/packages/infiniteloading/doc.md
src/packages/infiniteloading/doc.md
+30
-33
src/packages/infiniteloading/index.scss
src/packages/infiniteloading/index.scss
+4
-4
src/packages/infiniteloading/index.vue
src/packages/infiniteloading/index.vue
+109
-135
src/styles/variables.scss
src/styles/variables.scss
+4
-0
未找到文件。
src/config.json
浏览文件 @
e8391332
...
...
@@ -160,7 +160,7 @@
"version"
:
"3.0.0"
,
"name"
:
"Notify"
,
"type"
:
"component"
,
"cName"
:
"
methods
"
,
"cName"
:
"
消息通知
"
,
"desc"
:
"在页面顶部展示消息提示,支持函数调用和组件调用两种方式"
,
"sort"
:
4
,
"show"
:
true
,
...
...
src/packages/infiniteloading/demo.vue
浏览文件 @
e8391332
...
...
@@ -4,10 +4,10 @@
<nut-cell>
<ul
class=
"infiniteUl"
id=
"scroll"
>
<nut-infiniteloading
container
I
d=
"scroll"
:use
W
indow=
"false"
:has
M
ore=
"hasMore"
@
load
M
ore=
"loadMore"
container
-i
d=
"scroll"
:use
-w
indow=
"false"
:has
-m
ore=
"hasMore"
@
load
-m
ore=
"loadMore"
>
<li
class=
"infiniteLi"
...
...
@@ -23,11 +23,12 @@
<nut-cell>
<ul
class=
"infiniteUl"
id=
"refreshScroll"
>
<nut-infiniteloading
containerId=
"refreshScroll"
:useWindow=
"false"
:isOpenRefresh=
"true"
:hasMore=
"refreshHasMore"
@
loadMore=
"refreshLoadMore"
pull-icon=
"JD"
container-id=
"refreshScroll"
:use-window=
"false"
:is-open-refresh=
"true"
:has-more=
"refreshHasMore"
@
load-more=
"refreshLoadMore"
@
refresh=
"refresh"
>
<li
...
...
@@ -44,10 +45,12 @@
<nut-cell>
<ul
class=
"infiniteUl"
id=
"customScroll"
>
<nut-infiniteloading
containerId=
"customScroll"
:useWindow=
"false"
:hasMore=
"customHasMore"
@
loadMore=
"customLoadMore"
load-txt=
"loading"
load-more-txt=
"没有啦~"
container-id=
"customScroll"
:use-window=
"false"
:has-more=
"customHasMore"
@
load-more=
"customLoadMore"
>
<li
class=
"infiniteLi"
...
...
@@ -55,15 +58,6 @@
:key=
"index"
>
{{
item
}}
</li
>
<template
v-slot:loading
>
<div
class=
"loading"
>
<span>
加载中...
</span>
</div>
</
template
>
<
template
v-slot:unloadMore
>
<div
class=
"unload-more"
>
没有数据啦 ~~
</div>
</
template
>
</nut-infiniteloading>
</ul>
</nut-cell>
...
...
src/packages/infiniteloading/doc.md
浏览文件 @
e8391332
...
...
@@ -22,9 +22,9 @@
<ul
class=
"infiniteUl"
id=
"scroll"
>
<nut-infiniteloading
containerId =
'scroll'
:use
W
indow=
'false'
:has
M
ore=
"hasMore"
@
load
M
ore=
"loadMore"
:use
-w
indow=
'false'
:has
-m
ore=
"hasMore"
@
load
-m
ore=
"loadMore"
>
<li
class=
"infiniteLi"
v-for=
"(item, index) in defultList"
:key=
"index"
>
{{item}}
</li>
</nut-infiniteloading>
...
...
@@ -62,11 +62,12 @@ setup() {
```
html
<ul
class=
"infiniteUl"
id=
"refreshScroll"
>
<nut-infiniteloading
containerId=
"refreshScroll"
:useWindow=
"false"
:isOpenRefresh=
"true"
:hasMore=
"refreshHasMore"
@
loadMore=
"refreshLoadMore"
pull-icon=
"JD"
container-id=
"refreshScroll"
:use-window=
"false"
:is-open-refresh=
"true"
:has-more=
"refreshHasMore"
@
load-more=
"refreshLoadMore"
@
refresh=
"refresh"
>
<li
...
...
@@ -119,10 +120,10 @@ setup() {
```
html
<ul
class=
"infiniteUl"
id=
"customScroll"
>
<nut-infiniteloading
container
I
d =
'customScroll'
:use
W
indow=
'false'
:has
M
ore=
"customHasMore"
@
load
M
ore=
"customLoadMore"
container
-i
d =
'customScroll'
:use
-w
indow=
'false'
:has
-m
ore=
"customHasMore"
@
load
-m
ore=
"customLoadMore"
>
<li
class=
"infiniteLi"
v-for=
"(item, index) in customList"
:key=
"index"
>
{{item}}
</li>
<template
v-slot:loading
>
...
...
@@ -170,27 +171,23 @@ setup() {
| 参数 | 说明 | 类型 | 默认值 |
|--------------|----------------------------------|--------|------------------|
| hasMore | 是否还有更多数据 | Boolean | true |
| threshold | 距离底部多远加载 | Number | 200 |
| useWindow | 将滚动侦听器添加到 window 否则侦听组件的父节点 | Boolean | true |
| useCapture | 是否使用捕获模式 true 捕获 false 冒泡 | Boolean | false |
| containerId | 在 useWindow 属性为 false 的时候,自定义设置节点ID | String | '' |
| unloadMoreTxt | “没有更多数”据展示文案 | String | '哎呀,这里是底部了啦' |
| isOpenRefresh | 是否开启下拉刷新 | Boolean | false |
### Slot
| name | 说明 |
|--------|----------------|
| loading | 自定义“加载中”的展示形式 |
| unloadMore | 自定义“没有更多数据”的展示形式 |
| refreshLoading | 自定义下拉刷新中“加载中”的展示形式 |
| has-more | 是否还有更多数据 | Boolean |
`true`
|
| threshold | 距离底部多远加载 | Number |
`200`
|
| use-window | 将滚动侦听器添加到 window 否则侦听组件的父节点 | Boolean |
`true`
|
| use-capture | 是否使用捕获模式 true 捕获 false 冒泡 | Boolean |
`false`
|
| container-id | 在 useWindow 属性为 false 的时候,自定义设置节点ID | String |
`''`
|
| load-more-txt | “没有更多数”据展示文案 | String |
`'哎呀,这里是底部了啦'`
|
| is-open-refresh | 是否开启下拉刷新 | Boolean |
`false`
|
| pull-icon | 下拉刷新
[
图标名称
](
#/icon
)
| String |
`https://img10.360buyimg.com/imagetools/jfs/t1/169863/6/4565/6306/60125948E7e92774e/40b3a0cf42852bcb.png`
|
| pull-txt | 下拉刷新提示文案 | String |
`松手刷新`
|
| load-icon | 上拉加载
[
图标名称
](
#/icon
)
| Boolean |
`https://img10.360buyimg.com/imagetools/jfs/t1/169863/6/4565/6306/60125948E7e92774e/40b3a0cf42852bcb.png`
|
| load-txt | 上拉加载提示文案 | String |
`加载中...`
|
### Events
| 事件名 | 说明 | 回调参数 |
|--------|----------------|--------------|
| load
M
ore | 继续加载的回调函数 | done 函数,用于关闭加载中状态 |
| scroll
C
hange | 实时监听滚动高度 | 滚动高度 |
| load
-m
ore | 继续加载的回调函数 | done 函数,用于关闭加载中状态 |
| scroll
-c
hange | 实时监听滚动高度 | 滚动高度 |
| refresh | 下拉刷新事件回调 | done 函数,用于关闭加载中状态 |
\ No newline at end of file
src/packages/infiniteloading/index.scss
浏览文件 @
e8391332
...
...
@@ -20,7 +20,7 @@
}
.top-text
{
font-size
:
10px
;
color
:
rgba
(
128
,
128
,
128
,
1
)
;
color
:
$text-color
;
}
}
}
...
...
@@ -28,8 +28,8 @@
display
:
block
;
width
:
100%
;
padding-top
:
16px
;
font-size
:
12px
;
color
:
rgba
(
200
,
200
,
200
,
1
)
;
font-size
:
$font-size-small
;
color
:
$infinite-bottom-color
;
text-align
:
center
;
.bottom-box
{
...
...
@@ -40,7 +40,7 @@
}
.bottom-text
{
font-size
:
10px
;
color
:
rgba
(
128
,
128
,
128
,
1
)
;
color
:
$text-color
;
}
}
}
...
...
src/packages/infiniteloading/index.vue
浏览文件 @
e8391332
<
template
>
<view-block
class=
"nut-infiniteloading
"
:class=
"classes
"
ref=
"scroller"
@
touchstart=
"touchStart"
@
touchmove=
"touchMove"
@
touchend=
"touchEnd"
>
<view-block
class=
"nut-infinite-top"
ref=
"refreshTop"
:style=
"getStyle"
>
<view-block
class=
"top-box"
v-if=
"!slotRefreshLoading"
>
<nut-icon
class=
"top-img"
name=
"https://img10.360buyimg.com/imagetools/jfs/t1/169863/6/4565/6306/60125948E7e92774e/40b3a0cf42852bcb.png"
></nut-icon>
<view-block
class=
"top-text"
>
松开刷新
</view-block>
<view-block
class=
"top-box"
>
<nut-icon
class=
"top-img"
:name=
"pullIcon"
></nut-icon>
<view-block
class=
"top-text"
>
{{
pullTxt
}}
</view-block>
</view-block>
<slot
name=
"refreshLoading"
v-else
></slot>
</view-block>
<view-block
class=
"nut-infinite-container"
><slot></slot></view-block>
<view-block
class=
"nut-infinite-container"
>
<slot></slot>
</view-block>
<view-block
class=
"nut-infinite-bottom"
>
<template
v-if=
"isInfiniting"
>
<view-block
v-if=
"!slotLoading"
class=
"bottom-box"
>
<nut-icon
class=
"bottom-img"
name=
"https://img10.360buyimg.com/imagetools/jfs/t1/169863/6/4565/6306/60125948E7e92774e/40b3a0cf42852bcb.png"
></nut-icon>
<view-block
class=
"bottom-text"
>
加载中···
</view-block>
<view-block
class=
"bottom-box"
>
<nut-icon
class=
"bottom-img"
:name=
"loadIcon"
></nut-icon>
<view-block
class=
"bottom-text"
>
{{
loadTxt
}}
</view-block>
</view-block>
<slot
name=
"loading"
v-else
></slot>
</
template
>
<
template
v-else-if=
"!hasMore"
>
<view-block
class=
"tips"
v-if=
"!slotUnloadMore"
>
{{
unloadMoreTxt
}}
</view-block>
<slot
name=
"unloadMore"
v-else
></slot>
<view-block
class=
"tips"
>
{{
loadMoreTxt
}}
</view-block>
</
template
>
</view-block>
</view-block>
</template>
<
script
lang=
"ts"
>
import
{
ref
,
toRefs
,
onMounted
,
onUnmounted
,
...
...
@@ -63,7 +51,25 @@ export default create({
type
:
Number
,
default
:
200
},
unloadMoreTxt
:
{
pullIcon
:
{
type
:
String
,
default
:
'
https://img10.360buyimg.com/imagetools/jfs/t1/169863/6/4565/6306/60125948E7e92774e/40b3a0cf42852bcb.png
'
},
pullTxt
:
{
type
:
String
,
default
:
'
松开刷新
'
},
loadIcon
:
{
type
:
String
,
default
:
'
https://img10.360buyimg.com/imagetools/jfs/t1/169863/6/4565/6306/60125948E7e92774e/40b3a0cf42852bcb.png
'
},
loadTxt
:
{
type
:
String
,
default
:
'
加载中···
'
},
loadMoreTxt
:
{
type
:
String
,
default
:
'
哎呀,这里是底部了啦
'
},
...
...
@@ -84,63 +90,43 @@ export default create({
default
:
false
}
},
emits
:
[
'
scroll
Change
'
,
'
loadM
ore
'
,
'
refresh
'
],
emits
:
[
'
scroll
-change
'
,
'
load-m
ore
'
,
'
refresh
'
],
setup
(
props
,
{
emit
,
slots
})
{
console
.
log
(
'
componentName
'
,
componentName
);
const
{
hasMore
,
threshold
,
containerId
,
useWindow
,
useCapture
,
isOpenRefresh
}
=
toRefs
(
props
);
let
scrollEl
:
Window
|
HTMLElement
=
window
;
const
scroller
=
ref
<
null
|
HTMLElement
>
(
null
);
const
refreshTop
=
ref
<
null
|
HTMLElement
>
(
null
);
const
beforeScrollTop
=
ref
(
0
);
const
isTouching
=
ref
(
false
);
const
isInfiniting
=
ref
(
false
);
const
refreshMaxH
=
ref
(
0
);
const
slot
=
reactive
({
slotLoading
:
false
,
slotUnloadMore
:
false
,
slotRefreshLoading
:
false
});
const
pageStart
=
reactive
({
const
state
=
reactive
({
scrollEl
:
window
as
Window
|
HTMLElement
|
(
Node
&
ParentNode
),
scroller
:
null
as
null
|
HTMLElement
,
refreshTop
:
null
as
null
|
HTMLElement
,
beforeScrollTop
:
0
,
isTouching
:
false
,
isInfiniting
:
false
,
refreshMaxH
:
0
,
y
:
0
,
x
:
0
,
distance
:
0
});
const
classes
=
computed
(()
=>
{
const
prefixCls
=
componentName
;
return
{
[
prefixCls
]:
true
};
});
const
getStyle
=
computed
(()
=>
{
const
style
:
CSSProperties
=
{};
if
(
pageStart
.
distance
<
0
)
{
style
.
height
=
0
+
'
px
'
;
}
else
{
style
.
height
=
pageStart
.
distance
+
'
px
'
;
}
if
(
isTouching
.
value
)
{
style
.
transition
=
`height 0s cubic-bezier(0.25,0.1,0.25,1)`
;
}
else
{
style
.
transition
=
`height 0.2s cubic-bezier(0.25,0.1,0.25,1)`
;
}
return
style
;
return
{
height
:
state
.
distance
<
0
?
`0px`
:
`
${
state
.
distance
}
px`
,
transition
:
state
.
isTouching
?
`height 0s cubic-bezier(0.25,0.1,0.25,1)`
:
`height 0.2s cubic-bezier(0.25,0.1,0.25,1)`
};
});
/** 获取监听自定义滚动节点 */
const
getParentElement
=
el
=>
{
if
(
containerId
.
value
!=
''
)
{
return
document
.
querySelector
(
`#
${
containerId
.
value
}
`
);
}
return
el
&&
el
.
parentNode
;
const
getParentElement
=
(
el
:
HTMLElement
)
=>
{
return
!!
props
.
containerId
?
document
.
querySelector
(
`#
${
props
.
containerId
}
`
)
:
el
&&
el
.
parentNode
;
};
const
requestAniFrame
=
()
=>
{
...
...
@@ -152,7 +138,7 @@ export default create({
}
);
};
/** 获取滚动条高度 */
const
getWindowScrollTop
=
()
=>
{
return
window
.
pageYOffset
!==
undefined
?
window
.
pageYOffset
...
...
@@ -163,24 +149,22 @@ export default create({
).
scrollTop
;
};
const
calculateTopPosition
=
el
=>
{
if
(
!
el
)
{
return
0
;
}
return
el
.
offsetTop
+
calculateTopPosition
(
el
.
offsetParent
);
const
calculateTopPosition
=
(
el
:
HTMLElement
):
number
=>
{
return
!
el
?
0
:
el
.
offsetTop
+
calculateTopPosition
(
el
.
offsetParent
as
HTMLElement
);
};
/** 判断是否滚动到底部 */
const
isScrollAtBottom
=
()
=>
{
let
offsetDistance
=
0
;
let
resScrollTop
=
0
;
let
direction
=
'
down
'
;
// 滚动的方向
let
direction
=
'
down
'
;
const
windowScrollTop
=
getWindowScrollTop
();
if
(
useWindow
.
value
)
{
if
(
s
croller
.
value
)
{
if
(
props
.
useWindow
)
{
if
(
s
tate
.
scroller
)
{
offsetDistance
=
calculateTopPosition
(
s
croller
.
value
)
+
s
croller
.
value
.
offsetHeight
-
calculateTopPosition
(
s
tate
.
scroller
)
+
s
tate
.
scroller
.
offsetHeight
-
windowScrollTop
-
window
.
innerHeight
;
}
...
...
@@ -190,119 +174,109 @@ export default create({
scrollHeight
,
clientHeight
,
scrollTop
}
=
scrollEl
as
HTMLElement
;
}
=
s
tate
.
s
crollEl
as
HTMLElement
;
offsetDistance
=
scrollHeight
-
clientHeight
-
scrollTop
;
resScrollTop
=
scrollTop
;
}
if
(
beforeScrollTop
.
value
>
resScrollTop
)
{
if
(
state
.
beforeScrollTop
>
resScrollTop
)
{
direction
=
'
up
'
;
}
else
{
direction
=
'
down
'
;
}
beforeScrollTop
.
value
=
resScrollTop
;
state
.
beforeScrollTop
=
resScrollTop
;
emit
(
'
scroll
C
hange
'
,
resScrollTop
);
emit
(
'
scroll
-c
hange
'
,
resScrollTop
);
return
offsetDistance
<=
threshold
.
value
&&
direction
==
'
down
'
;
return
offsetDistance
<=
props
.
threshold
&&
direction
==
'
down
'
;
};
const
infiniteDone
=
()
=>
{
isInfiniting
.
value
=
false
;
state
.
isInfiniting
=
false
;
};
/** 滚动函数 */
const
handleScroll
=
()
=>
{
requestAniFrame
()(()
=>
{
if
(
!
isScrollAtBottom
()
||
!
hasMore
.
value
||
isInfiniting
.
value
)
{
if
(
!
isScrollAtBottom
()
||
!
props
.
hasMore
||
state
.
isInfiniting
)
{
return
false
;
}
else
{
console
.
log
(
'
无限加载更多
'
);
isInfiniting
.
value
=
true
;
emit
(
'
loadMore
'
,
infiniteDone
);
state
.
isInfiniting
=
true
;
emit
(
'
load-more
'
,
infiniteDone
);
}
});
};
/** 滚动监听 */
const
scrollListener
=
()
=>
{
s
crollEl
.
addEventListener
(
'
scroll
'
,
handleScroll
,
useCapture
.
valu
e
);
s
tate
.
scrollEl
.
addEventListener
(
'
scroll
'
,
handleScroll
,
props
.
useCaptur
e
);
};
/** 下拉加载完成回到初始状态 */
const
refreshDone
=
()
=>
{
pageStart
.
distance
=
0
;
isTouching
.
value
=
false
;
state
.
distance
=
0
;
state
.
isTouching
=
false
;
};
const
touchStart
=
event
=>
{
const
touchStart
=
(
event
:
TouchEvent
)
=>
{
if
(
beforeScrollTop
.
value
==
0
&&
!
isTouching
.
value
&&
isOpenRefresh
.
value
state
.
beforeScrollTop
==
0
&&
!
state
.
isTouching
&&
props
.
isOpenRefresh
)
{
pageStart
.
y
=
event
.
touches
[
0
].
pageY
;
isTouching
.
value
=
true
;
state
.
y
=
event
.
touches
[
0
].
pageY
;
state
.
isTouching
=
true
;
const
childHeight
=
((
refreshTop
.
value
as
HTMLElement
)
const
childHeight
=
((
state
.
refreshTop
as
HTMLElement
)
.
firstElementChild
as
HTMLElement
).
offsetHeight
;
refreshMaxH
.
value
=
Math
.
floor
(
childHeight
*
1
+
10
);
state
.
refreshMaxH
=
Math
.
floor
(
childHeight
*
1
+
10
);
}
};
const
touchMove
=
event
=>
{
pageStart
.
distance
=
event
.
touches
[
0
].
pageY
-
pageStart
.
y
;
const
touchMove
=
(
event
:
TouchEvent
)
=>
{
state
.
distance
=
event
.
touches
[
0
].
pageY
-
state
.
y
;
if
(
pageStart
.
distance
>
0
&&
isTouching
.
value
)
{
if
(
state
.
distance
>
0
&&
state
.
isTouching
)
{
event
.
preventDefault
();
if
(
pageStart
.
distance
>=
refreshMaxH
.
value
)
pageStart
.
distance
=
refreshMaxH
.
value
;
if
(
state
.
distance
>=
state
.
refreshMaxH
)
state
.
distance
=
state
.
refreshMaxH
;
}
else
{
pageStart
.
distance
=
0
;
isTouching
.
value
=
false
;
state
.
distance
=
0
;
state
.
isTouching
=
false
;
}
};
const
touchEnd
=
()
=>
{
if
(
pageStart
.
distance
<
refreshMaxH
.
value
)
{
pageStart
.
distance
=
0
;
if
(
state
.
distance
<
state
.
refreshMaxH
)
{
state
.
distance
=
0
;
}
else
{
emit
(
'
refresh
'
,
refreshDone
);
}
};
/** 生命周期 首次加载 */
onMounted
(()
=>
{
const
parentElement
=
getParentElement
(
scroller
);
let
scrollElCopy
=
window
;
if
(
useWindow
.
value
===
false
)
{
scrollElCopy
=
parentElement
;
}
scrollEl
=
scrollElCopy
;
const
parentElement
=
getParentElement
(
state
.
scroller
as
HTMLElement
)
as
Node
&
ParentNode
;
state
.
scrollEl
=
props
.
useWindow
?
window
:
parentElement
;
scrollListener
();
slot
.
slotUnloadMore
=
slots
.
unloadMore
?
true
:
false
;
slot
.
slotLoading
=
slots
.
loading
?
true
:
false
;
slot
.
slotRefreshLoading
=
slots
.
refreshLoading
?
true
:
false
;
});
/** 移除监听 */
onUnmounted
(()
=>
{
scrollEl
.
removeEventListener
(
'
scroll
'
,
handleScroll
,
useCapture
.
value
);
state
.
scrollEl
.
removeEventListener
(
'
scroll
'
,
handleScroll
,
props
.
useCapture
);
});
return
{
scroller
,
refreshTop
,
classes
,
...
toRefs
(
state
)
,
touchStart
,
touchMove
,
touchEnd
,
getStyle
,
isInfiniting
,
...
toRefs
(
slot
)
getStyle
};
}
});
...
...
src/styles/variables.scss
浏览文件 @
e8391332
...
...
@@ -215,6 +215,10 @@ $notify-warning-background-color: linear-gradient(
$tabbar-active-color
:
$primary-color
;
//infiniteloading
$infinite-bottom-color
:
#c8c8c8
;
view-block
{
display
:
block
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录