perf: removed forced reflow ("layout thrashing") by reading testEl.offsetWidth in a separate animation frame

This commit is contained in:
Philipp Eichhorn 2018-05-22 14:14:02 +02:00
parent 92e968462c
commit 8ab0387857
3 changed files with 22 additions and 14 deletions

View file

@ -127,16 +127,20 @@ export default class Input {
this.element.value.length >= (this.placeholderValue.length / 1.25)) || this.element.value.length >= (this.placeholderValue.length / 1.25)) ||
enforceWidth enforceWidth
) { ) {
this.element.style.width = this.calcWidth(); this.calcWidth((width) => {
this.element.style.width = width;
});
} }
} else { } else {
// If there is no placeholder, resize input to contents // If there is no placeholder, resize input to contents
this.element.style.width = this.calcWidth(); this.calcWidth((width) => {
this.element.style.width = width;
});
} }
} }
calcWidth() { calcWidth(callback) {
return calcWidthOfInput(this.element); return calcWidthOfInput(this.element, callback);
} }
setActiveDescendant(activeDescendantID) { setActiveDescendant(activeDescendantID) {

View file

@ -271,7 +271,7 @@ describe('components/input', () => {
const inputWidth = '200px'; const inputWidth = '200px';
beforeEach(() => { beforeEach(() => {
calcWidthStub = stub(instance, 'calcWidth').returns(inputWidth); calcWidthStub = stub(instance, 'calcWidth').callsArgWith(0, inputWidth);
}); });
afterEach(() => { afterEach(() => {

View file

@ -482,10 +482,10 @@ export const strToEl = (function() {
}()); }());
/** /**
* Sets the width of a passed input based on its value * Determines the width of a passed input based on its value and passes
* @return {Number} Width of input * it to the supplied callback function.
*/ */
export const calcWidthOfInput = (input) => { export const calcWidthOfInput = (input, callback) => {
const value = input.value || input.placeholder; const value = input.value || input.placeholder;
let width = input.offsetWidth; let width = input.offsetWidth;
@ -514,14 +514,18 @@ export const calcWidthOfInput = (input) => {
document.body.appendChild(testEl); document.body.appendChild(testEl);
if (value && testEl.offsetWidth !== input.offsetWidth) { requestAnimationFrame(() => {
width = testEl.offsetWidth + 4; if (value && testEl.offsetWidth !== input.offsetWidth) {
} width = testEl.offsetWidth + 4;
}
document.body.removeChild(testEl); document.body.removeChild(testEl);
callback.call(this, `${width}px`);
});
} else {
callback.call(this, `${width}px`);
} }
return `${width}px`;
}; };
/** /**