mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
[improvement] List: optimization boundary judgment logic (#3450)
This commit is contained in:
parent
d7a5be67fe
commit
34923c7513
@ -1,12 +1,7 @@
|
||||
import { use } from '../utils';
|
||||
import Loading from '../loading';
|
||||
import { BindEventMixin } from '../mixins/bind-event';
|
||||
import {
|
||||
getScrollTop,
|
||||
getElementTop,
|
||||
getVisibleHeight,
|
||||
getScrollEventTarget
|
||||
} from '../utils/dom/scroll';
|
||||
import { getScrollEventTarget } from '../utils/dom/scroll';
|
||||
|
||||
const [sfc, bem, t] = use('list');
|
||||
|
||||
@ -68,9 +63,19 @@ export default sfc({
|
||||
return;
|
||||
}
|
||||
|
||||
const el = this.$el;
|
||||
const { scroller } = this;
|
||||
const scrollerHeight = getVisibleHeight(scroller);
|
||||
const { $el: el, scroller, offset, direction } = this;
|
||||
let scrollerRect;
|
||||
|
||||
if (scroller.getBoundingClientRect) {
|
||||
scrollerRect = scroller.getBoundingClientRect();
|
||||
} else {
|
||||
scrollerRect = {
|
||||
top: 0,
|
||||
bottom: scroller.innerHeight
|
||||
};
|
||||
}
|
||||
|
||||
const scrollerHeight = scrollerRect.bottom - scrollerRect.top;
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (
|
||||
@ -78,32 +83,19 @@ export default sfc({
|
||||
window.getComputedStyle(el).display === 'none' ||
|
||||
el.offsetParent === null
|
||||
) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
const { offset, direction } = this;
|
||||
let isReachEdge = false;
|
||||
const placeholderRect = this.$refs.placeholder.getBoundingClientRect();
|
||||
|
||||
function isReachEdge() {
|
||||
if (el === scroller) {
|
||||
const scrollTop = getScrollTop(el);
|
||||
|
||||
if (direction === 'up') {
|
||||
return scrollTop <= offset;
|
||||
}
|
||||
|
||||
const targetBottom = scrollTop + scrollerHeight;
|
||||
return scroller.scrollHeight - targetBottom <= offset;
|
||||
}
|
||||
|
||||
if (direction === 'up') {
|
||||
return getScrollTop(scroller) - getElementTop(el) <= offset;
|
||||
}
|
||||
|
||||
const elBottom = getElementTop(el) + getVisibleHeight(el) - getElementTop(scroller);
|
||||
return elBottom - scrollerHeight <= offset;
|
||||
if (direction === 'up') {
|
||||
isReachEdge = placeholderRect.top - scrollerRect.top <= offset;
|
||||
} else {
|
||||
isReachEdge = placeholderRect.bottom - scrollerRect.bottom <= offset;
|
||||
}
|
||||
|
||||
if (isReachEdge()) {
|
||||
if (isReachEdge) {
|
||||
this.$emit('input', true);
|
||||
this.$emit('load');
|
||||
}
|
||||
@ -116,9 +108,11 @@ export default sfc({
|
||||
},
|
||||
|
||||
render(h) {
|
||||
const placeholder = <div ref="placeholder" class={bem('placeholder')}/>;
|
||||
|
||||
return (
|
||||
<div class={bem()} role="feed" aria-busy={this.loading}>
|
||||
{this.direction === 'down' && this.slots()}
|
||||
{this.direction === 'down' ? this.slots() : placeholder}
|
||||
{this.loading && (
|
||||
<div class={bem('loading')} key="loading">
|
||||
{this.slots('loading') || (
|
||||
@ -134,7 +128,7 @@ export default sfc({
|
||||
{this.errorText}
|
||||
</div>
|
||||
)}
|
||||
{this.direction === 'up' && this.slots()}
|
||||
{this.direction === 'up' ? this.slots() : placeholder}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -9,4 +9,9 @@
|
||||
line-height: @list-text-line-height;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__placeholder {
|
||||
height: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,9 @@ exports[`renders demo correctly 1`] = `
|
||||
<div class="van-pull-refresh">
|
||||
<div class="van-pull-refresh__track" style="transition: 0ms;">
|
||||
<div class="van-pull-refresh__head"></div>
|
||||
<div role="feed" class="van-list"></div>
|
||||
<div role="feed" class="van-list">
|
||||
<div class="van-list__placeholder"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import List from '..';
|
||||
import { mount, later } from '../../../test/utils';
|
||||
import { mount, later, mockGetBoundingClientRect } from '../../../test/utils';
|
||||
|
||||
function mockOffsetParent(el) {
|
||||
Object.defineProperty(el, 'offsetParent', {
|
||||
@ -33,7 +33,7 @@ test('error loaded, click error-text and reload', async () => {
|
||||
const wrapper = mount(List, {
|
||||
propsData: {
|
||||
errorText: 'Request failed. Click to reload...',
|
||||
error: true
|
||||
error: true,
|
||||
}
|
||||
});
|
||||
|
||||
@ -45,11 +45,15 @@ test('error loaded, click error-text and reload', async () => {
|
||||
expect(wrapper.emitted('input')).toBeFalsy();
|
||||
|
||||
// 模拟点击error-text的行为
|
||||
wrapper.setProps({
|
||||
error: false
|
||||
wrapper.vm.$on('update:error', val => {
|
||||
wrapper.setProps({
|
||||
error: val
|
||||
});
|
||||
});
|
||||
wrapper.vm.$emit('input', true);
|
||||
wrapper.vm.$emit('load');
|
||||
|
||||
wrapper.find('.van-list__error-text').trigger('click');
|
||||
|
||||
await later();
|
||||
|
||||
expect(wrapper.vm.$props.error).toBeFalsy();
|
||||
expect(wrapper.emitted('load')).toBeTruthy();
|
||||
@ -61,7 +65,8 @@ test('error loaded, click error-text and reload', async () => {
|
||||
test('finished', async () => {
|
||||
const wrapper = mount(List, {
|
||||
propsData: {
|
||||
finished: true
|
||||
finished: true,
|
||||
finishedText: 'Finished'
|
||||
}
|
||||
});
|
||||
|
||||
@ -70,11 +75,13 @@ test('finished', async () => {
|
||||
await later();
|
||||
expect(wrapper.emitted('load')).toBeFalsy();
|
||||
expect(wrapper.emitted('input')).toBeFalsy();
|
||||
expect(wrapper.contains('.van-list__finished-text')).toBeTruthy();
|
||||
wrapper.vm.finished = false;
|
||||
|
||||
await later();
|
||||
expect(wrapper.emitted('load')).toBeTruthy();
|
||||
expect(wrapper.emitted('input')).toBeTruthy();
|
||||
expect(wrapper.contains('.van-list__finished-text')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('immediate check false', async () => {
|
||||
@ -89,7 +96,7 @@ test('immediate check false', async () => {
|
||||
expect(wrapper.emitted('input')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('keey-alive live cycle', () => {
|
||||
test('keep-alive live cycle', () => {
|
||||
const wrapper = mount(
|
||||
{
|
||||
template: `
|
||||
@ -111,3 +118,59 @@ test('keey-alive live cycle', () => {
|
||||
wrapper.vm.show = false;
|
||||
expect(wrapper.vm.el).toBeFalsy();
|
||||
});
|
||||
|
||||
test('check the case that scroller is not window', async () => {
|
||||
const restoreMock = mockGetBoundingClientRect({
|
||||
top: 0,
|
||||
bottom: 200
|
||||
});
|
||||
|
||||
const wrapper = mount({
|
||||
template: `
|
||||
<div style="overflow-y: scroll;">
|
||||
<list ref="list"/>
|
||||
</div>
|
||||
`,
|
||||
components: { List }
|
||||
});
|
||||
|
||||
const listRef = wrapper.find({
|
||||
ref: 'list'
|
||||
});
|
||||
mockOffsetParent(listRef.vm.$el);
|
||||
|
||||
await later();
|
||||
expect(listRef.emitted('load')).toBeTruthy();
|
||||
expect(listRef.emitted('input')).toBeTruthy();
|
||||
|
||||
restoreMock();
|
||||
});
|
||||
|
||||
test('check the direction props', async () => {
|
||||
const wrapper = mount(List, {
|
||||
slots: {
|
||||
default: '<div class="list-item">list item</div>'
|
||||
},
|
||||
propsData: {
|
||||
direction: 'up'
|
||||
}
|
||||
});
|
||||
|
||||
mockOffsetParent(wrapper.vm.$el);
|
||||
|
||||
await later();
|
||||
|
||||
let children = wrapper.findAll('.van-list > div');
|
||||
expect(children.at(0).is('.van-list__placeholder')).toBeTruthy();
|
||||
expect(children.at(1).is('.list-item')).toBeTruthy();
|
||||
|
||||
// change the direction's value
|
||||
wrapper.setProps({
|
||||
direction: 'down'
|
||||
});
|
||||
|
||||
await later();
|
||||
children = wrapper.findAll('.van-list > div');
|
||||
expect(children.at(0).is('.list-item')).toBeTruthy();
|
||||
expect(children.at(1).is('.van-list__placeholder')).toBeTruthy();
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user