在上一章的最后,我们分析到了ResizeObserverSPI的broadcastActive方法。
/**
* Invokes initial callback function with a list of ResizeObserverEntry
* instances collected from active resize observations.
*
* @returns {void}
*/
broadcastActive() {
// Do nothing if observer doesn't have active observations.
if (!this.hasActive()) {
return;
}
const ctx = this.callbackCtx_;
// Create ResizeObserverEntry instance for every active observation.
const entries = this.activeObservations_.map(observation => {
return new ResizeObserverEntry(
observation.target,
observation.broadcastRect()
);
});
this.callback_.call(ctx, entries, ctx);
this.clearActive();
}
对activeObservations_应用map函数,利用处于活动状态的ResizeObservation实例创建ResizeObserverEntry。我们得先搞清楚ResizeObservation类是如何工作的。
/**
* Creates an instance of ResizeObservation.
*
* @param {Element} target - Element to be observed.
*/
constructor(target) {
this.target = target;
}
首先,这个类在构建时,内部的target被赋值为外部传入的HTML元素。
observations.set(target, new ResizeObservation(target));
当SPI的gatherActive方法被调用,每一个被遍历的ResizeObservation都会调用isActive方法返回元素的宽度、高度是否发生了变化。
/**
* Updates content rectangle and tells whether it's width or height properties
* have changed since the last broadcast.
*
* @returns {boolean}
*/
isActive() {
const rect = getContentRect(this.target);
this.contentRect_ = rect;
return (
rect.width !== this.broadcastWidth ||
rect.height !== this.broadcastHeight
);
}
可以看出,该方法调用了geometry.js中的getContentRect方法返回当前元素的x、y、宽度、高度。如果相较上一次发生了变化。这个方法就会返回true,在SPI类中,这个ResizeObservation实例也就会被记录为activeObservations_并被更新。
return new ResizeObserverEntry(
observation.target,
observation.broadcastRect()
);
当控制器对某个ResizeObserverSPI调用broadcastActive方法时,其内部会创建一个ResizeObserverEntry数组。创建ResizeObserverEntry时会使用ResizeObservation实例的broadcastRect方法。
/**
* Updates 'broadcastWidth' and 'broadcastHeight' properties with a data
* from the corresponding properties of the last observed content rectangle.
*
* @returns {DOMRectInit} Last observed content rectangle.
*/
broadcastRect() {
const rect = this.contentRect_;
this.broadcastWidth = rect.width;
this.broadcastHeight = rect.height;
return rect;
}
由于isActive函数的执行时间是在控制器创建的节流函数以内,所以broadcastRect可以复用刚刚算好的contentRect_。而contentRect_在 isActive方法中是通过调用geometry.js中的getContentRect方法算出的。
/**
* Calcul