recalculate width while resize (#4676)

+ close #4645
 + throttleByAnimationFrameDecorator as a function decorator
This commit is contained in:
陆离 2017-01-26 11:23:54 +08:00 committed by GitHub
parent 879bc9320c
commit 5cd111d486
4 changed files with 68 additions and 10 deletions

View File

@ -1,3 +1,14 @@
function requestAnimationFramePolyfill() {
let lastTime = 0;
return function(callback) {
const currTime = new Date().getTime();
const timeToCall = Math.max(0, 16 - (currTime - lastTime));
const id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
export default function getRequestAnimationFrame() {
if (typeof window === 'undefined') {
return () => {};
@ -8,5 +19,5 @@ export default function getRequestAnimationFrame() {
const prefix = ['moz', 'ms', 'webkit'].filter(key => `${key}RequestAnimationFrame` in window)[0];
return prefix
? window[`${prefix}RequestAnimationFrame`]
: callback => setTimeout(callback, 1000 / 60);
: requestAnimationFramePolyfill();
}

View File

@ -0,0 +1,42 @@
import getRequestAnimationFrame from '../_util/getRequestAnimationFrame';
const reqAnimFrame = getRequestAnimationFrame();
export default function throttleByAnimationFrame(fn, threshhold = 250) {
let last;
return function() {
const self = this;
const args = arguments;
reqAnimFrame(timestamp => {
if (!last || timestamp - last > threshhold) {
last = timestamp;
fn.apply(self, args);
}
});
};
}
export function throttleByAnimationFrameDecorator(threshhold = 250) {
return function(target, key, descriptor) {
let fn = descriptor.value;
let definingProperty = false;
return {
configurable: true,
get() {
if (definingProperty || this === target.prototype || this.hasOwnProperty(key)) {
return fn;
}
let boundFn = throttleByAnimationFrame(fn.bind(this), threshhold);
definingProperty = true;
Object.defineProperty(this, key, {
value: boundFn,
configurable: true,
writable: true,
});
definingProperty = false;
return boundFn;
},
};
};
}

View File

@ -5,6 +5,7 @@ import classNames from 'classnames';
import shallowequal from 'shallowequal';
import omit from 'omit.js';
import getScroll from '../_util/getScroll';
import { throttleByAnimationFrameDecorator } from '../_util/throttleByAnimationFrame';
function getTargetRect(target): ClientRect {
return target !== window ?
@ -96,18 +97,16 @@ export default class Affix extends React.Component<AffixProps, any> {
});
}
setPlaceholderStyle(e, placeholderStyle) {
setPlaceholderStyle(placeholderStyle) {
const originalPlaceholderStyle = this.state.placeholderStyle;
if (e.type === 'resize') {
return;
}
if (shallowequal(placeholderStyle, originalPlaceholderStyle)) {
return;
}
this.setState({ placeholderStyle });
}
updatePosition = (e) => {
@throttleByAnimationFrameDecorator(250)
updatePosition(e) {
let { offsetTop, offsetBottom, offset, target = getDefaultTarget } = this.props;
const targetNode = target();
@ -145,7 +144,7 @@ export default class Affix extends React.Component<AffixProps, any> {
left: targetRect.left + elemOffset.left,
width: affixNode.offsetWidth,
});
this.setPlaceholderStyle(e, {
this.setPlaceholderStyle({
width: affixNode.offsetWidth,
height: affixNode.offsetHeight,
});
@ -161,13 +160,18 @@ export default class Affix extends React.Component<AffixProps, any> {
left: targetRect.left + elemOffset.left,
width: affixNode.offsetWidth,
});
this.setPlaceholderStyle(e, {
this.setPlaceholderStyle({
width: affixNode.offsetWidth,
height: affixNode.offsetHeight,
});
} else {
this.setAffixStyle(e, null);
this.setPlaceholderStyle(e, null);
const { affixStyle } = this.state;
if (e.type === 'resize' && affixStyle && affixStyle.position === 'fixed' && affixNode.offsetWidth) {
this.setAffixStyle(e, {...affixStyle, width: affixNode.offsetWidth });
} else {
this.setAffixStyle(e, null);
}
this.setPlaceholderStyle(null);
}
}

View File

@ -3,6 +3,7 @@
"strictNullChecks": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"jsx": "preserve",
"target": "es6"
},