feat(Tab): improve scrollLeftTo performance

This commit is contained in:
陈嘉涵 2019-12-16 20:57:13 +08:00
parent e9369acf26
commit f8a3669f2d
5 changed files with 35 additions and 28 deletions

View File

@ -205,7 +205,7 @@ In scrollspy mode, the list of content will be tiled
| sticky | Whether to use sticky mode | *boolean* | `false` | - | | sticky | Whether to use sticky mode | *boolean* | `false` | - |
| swipeable | Whether to switch tabs with swipe gestrue in the content | *boolean* | `false` | - | | swipeable | Whether to switch tabs with swipe gestrue in the content | *boolean* | `false` | - |
| lazy-render | Whether to enable tab content lazy render | *boolean* | `true` | - | | lazy-render | Whether to enable tab content lazy render | *boolean* | `true` | - |
| scrollspy | Whether to use scrollspy mode | *boolean* | `false` | - | | scrollspy | Whether to use scrollspy mode | *boolean* | `false` | 2.3.0 |
### Tab Props ### Tab Props

View File

@ -209,7 +209,7 @@ export default {
| sticky | 是否使用粘性定位布局 | *boolean* | `false` | - | | sticky | 是否使用粘性定位布局 | *boolean* | `false` | - |
| swipeable | 是否开启手势滑动切换 | *boolean* | `false` | - | | swipeable | 是否开启手势滑动切换 | *boolean* | `false` | - |
| lazy-render | 是否开启标签页内容延迟渲染 | *boolean* | `true` | - | | lazy-render | 是否开启标签页内容延迟渲染 | *boolean* | `true` | - |
| scrollspy | 是否开启滚动导航 | *boolean* | `false` | - | | scrollspy | 是否开启滚动导航 | *boolean* | `false` | 2.3.0 |
### Tab Props ### Tab Props

View File

@ -45,12 +45,12 @@ export default createComponent({
}, },
render(h) { render(h) {
const { slots, isActive } = this; const { slots, parent, isActive } = this;
const shouldRender = this.inited || this.parent.scrollspy || !this.parent.lazyRender; const shouldRender = this.inited || parent.scrollspy || !parent.lazyRender;
const show = this.parent.scrollspy || isActive; const show = parent.scrollspy || isActive;
const Content = shouldRender ? slots() : h(); const Content = shouldRender ? slots() : h();
if (this.parent.animated) { if (parent.animated) {
return ( return (
<div <div
role="tabpanel" role="tabpanel"

View File

@ -6,7 +6,13 @@ import { on, off } from '../utils/dom/event';
import { ParentMixin } from '../mixins/relation'; import { ParentMixin } from '../mixins/relation';
import { BindEventMixin } from '../mixins/bind-event'; import { BindEventMixin } from '../mixins/bind-event';
import { BORDER_TOP_BOTTOM } from '../utils/constant'; import { BORDER_TOP_BOTTOM } from '../utils/constant';
import { setRootScrollTop, getElementTop, getVisibleHeight, getVisibleTop } from '../utils/dom/scroll'; import {
setRootScrollTop,
getElementTop,
getVisibleHeight,
getVisibleTop
} from '../utils/dom/scroll';
import Title from './Title'; import Title from './Title';
import Content from './Content'; import Content from './Content';
import Sticky from '../sticky'; import Sticky from '../sticky';
@ -19,7 +25,7 @@ export default createComponent({
BindEventMixin(function(bind) { BindEventMixin(function(bind) {
bind(window, 'resize', this.resize, true); bind(window, 'resize', this.resize, true);
if (this.scrollspy) { if (this.scrollspy) {
bind(window, 'scroll', this.onScrollspyScroll, true); bind(window, 'scroll', this.onScroll, true);
} }
}) })
], ],
@ -142,9 +148,9 @@ export default createComponent({
scrollspy(val) { scrollspy(val) {
if (val) { if (val) {
on(window, 'scroll', this.onScrollspyScroll, true); on(window, 'scroll', this.onScroll, true);
} else { } else {
off(window, 'scroll', this.onScrollspyScroll); off(window, 'scroll', this.onScroll);
} }
} }
}, },
@ -277,7 +283,7 @@ export default createComponent({
scrollLeftTo(nav, to, immediate ? 0 : this.duration); scrollLeftTo(nav, to, immediate ? 0 : this.duration);
}, },
onScroll(params) { onSticktScroll(params) {
this.stickyFixed = params.isFixed; this.stickyFixed = params.isFixed;
this.$emit('scroll', params); this.$emit('scroll', params);
}, },
@ -296,7 +302,7 @@ export default createComponent({
} }
}, },
onScrollspyScroll() { onScroll() {
if (this.scrollspy && !this.clickedScroll) { if (this.scrollspy && !this.clickedScroll) {
const index = this.getCurrentIndexOnScroll(); const index = this.getCurrentIndexOnScroll();
this.setCurrentIndex(index); this.setCurrentIndex(index);
@ -304,20 +310,17 @@ export default createComponent({
}, },
getCurrentIndexOnScroll() { getCurrentIndexOnScroll() {
let i; const { children } = this;
for (i = 0; i < this.children.length; i++) { for (let index = 0; index < children.length; index++) {
const top = getVisibleTop(this.children[i].$el); const top = getVisibleTop(children[index].$el);
if (top > this.scrollOffset) { if (top > this.scrollOffset) {
if (i === 0) { return index === 0 ? 0 : index - 1;
return 0;
}
return i - 1;
} }
} }
return i - 1; return children.length - 1;
} }
}, },
@ -381,7 +384,7 @@ export default createComponent({
<Sticky <Sticky
container={this.$el} container={this.$el}
offsetTop={this.offsetTop} offsetTop={this.offsetTop}
onScroll={this.onScroll} onScroll={this.onSticktScroll}
> >
{Wrap} {Wrap}
</Sticky> </Sticky>

View File

@ -1,7 +1,11 @@
import { raf } from '../utils/dom/raf'; import { raf, cancelRaf } from '../utils/dom/raf';
import { getRootScrollTop, setRootScrollTop } from '../utils/dom/scroll'; import { getRootScrollTop, setRootScrollTop } from '../utils/dom/scroll';
let scrollLeftRafId: number;
export function scrollLeftTo(el: HTMLElement, to: number, duration: number) { export function scrollLeftTo(el: HTMLElement, to: number, duration: number) {
cancelRaf(scrollLeftRafId);
let count = 0; let count = 0;
const from = el.scrollLeft; const from = el.scrollLeft;
const frames = duration === 0 ? 1 : Math.round((duration * 1000) / 16); const frames = duration === 0 ? 1 : Math.round((duration * 1000) / 16);
@ -10,7 +14,7 @@ export function scrollLeftTo(el: HTMLElement, to: number, duration: number) {
el.scrollLeft += (to - from) / frames; el.scrollLeft += (to - from) / frames;
if (++count < frames) { if (++count < frames) {
raf(animate); scrollLeftRafId = raf(animate);
} }
} }
@ -19,20 +23,20 @@ export function scrollLeftTo(el: HTMLElement, to: number, duration: number) {
export function scrollTopTo(to: number, duration: number, cb: Function) { export function scrollTopTo(to: number, duration: number, cb: Function) {
let current = getRootScrollTop(); let current = getRootScrollTop();
const toDown = current < to; const isDown = current < to;
const frames = duration === 0 ? 1 : Math.round((duration * 1000) / 16); const frames = duration === 0 ? 1 : Math.round((duration * 1000) / 16);
const pxPerFrames = (to - current) / frames; const step = (to - current) / frames;
function animate() { function animate() {
current += pxPerFrames; current += step;
if ((toDown && current > to) || (!toDown && current < to)) { if ((isDown && current > to) || (!isDown && current < to)) {
current = to; current = to;
} }
setRootScrollTop(current); setRootScrollTop(current);
if ((toDown && current < to) || (!toDown && current > to)) { if ((isDown && current < to) || (!isDown && current > to)) {
raf(animate); raf(animate);
} else { } else {
cb && cb(); cb && cb();