ResizeObserverSPI
类定义
resize-observer-polyfill/src/ResizeObserverSPI.js
ResizeObserverSPI
, 这个是真正提供观察某个元素功能的地方,SPI
应该是service provider interface
的简称。它是ResizeObserver
那三个接口真正提供功能的地方。它提供了如下的方法
observe(htmlelement)
, 开始观察某个html
元素,该元素以ResizeObservation
的形态保存于内部的一个Map
里面。unobserve(htmlelement)
, 停止观察某个html
元素disconnect()
停止观察所有的 html 元素。gatherActive()
轮询内部的ResizeObservation Map
,调用它的isActive()
方法,发现更新了元素,存放于内部的activeObservations
数组中boradcastActive()
轮询内部的ResizeObservation Map
,调用它的broadcastRect()
,更新最新值。同时调用callback
通知观察者更新。hasActive()
返回当前是否存在更新的元素。clearActive()
清除更新的元素数组。activeObservations
。
class ResizeObserverSPI {
activeObservations_ = []; //存在更新的被观察目标元素
callback_;
callbackCtx_;//传给回调函数用的this对象
controller_;
observations_ = new Map(); //注册ResizeObservation instances的集合
constructor(callback, controller, callbackCtx) {
this.callback_ = callback;
this.controller_ = controller;
this.callbackCtx_ = callbackCtx;
}
/**
* Starts observing provided element.
*/
observe(target) {
// 校验出错...
const observations = this.observations_;
// Do nothing if element is already being observed.
if (observations.has(target)) {
return;
}
// observations_ 设置存储ResizeObservation创建的实例
observations.set(target, new ResizeObservation(target));
// 触发调度器的addObserver
this.controller_.addObserver(this);
// Force the update of observations.
this.controller_.refresh();
}
/**
* Stops observing provided element.
*/
unobserve(target) {
const observations = this.observations_;
// Do nothing if element is not being observed.
if (!observations.has(target)) {
return;
}
// 移除监测的目标元素
observations.delete(target);
// 当没有监测的元素时,执行调度器controller_的removeObserver函数
if (!observations.size) {
this.controller_.removeObserver(this);
}
}
/**
* Stops observing all elements. | 停止所有元素的观察
*/
disconnect() {
// 清空activeObservations_
this.clearActive();
// 移除observations_中的所有元素 map.clear()
this.observations_.clear();
// 执行调度器controller_的removeObserver函数
this.controller_.removeObserver(this);
}
/**
* Collects observation instances the associated element of which has changed
* it's content rectangle.
*
* @returns {void}
*/
gatherActive() {
// 清空activeObservations_
this.clearActive();
this.observations_.forEach((observation) => {
// 判断被观察的target元素是否存在变化
if (observation.isActive()) {
this.activeObservations_.push(observation);
}
});
}
/**
* 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) => {
// 返回被觀察element最新的大小
return new ResizeObserverEntry(
observation.target,
// 執行observation.broadcastRect函數獲取最新的大小
observation.broadcastRect()
);
});
// 改变回调函数的this指向ctx
this.callback_.call(ctx, entries, ctx);
// 调用clearActive方法,清空activeObservations_
this.clearActive();
}
clearActive() {
//清空his.activeObservations_, his.activeObservations_ = []
this.activeObservations_.splice(0);
}
// 判断当前是否存在变更的被观察目标元素
hasActive() {
return this.activeObservations_.length > 0;
}
}
ResizeObserverEntry函數
获取真正在观察的
Element
或SVGElement
最新的大小。
class ResizeObserverEntry {
/**
* Element size of which has changed.
* Spec: https://wicg.github.io/ResizeObserver/#dom-resizeobserverentry-target
*
* @readonly
* @type {Element}
*/
target;
/**
* Element's content rectangle.
* Spec: https://wicg.github.io/ResizeObserver/#dom-resizeobserverentry-contentrect
*
* @readonly
* @type {DOMRectReadOnly}
*/
contentRect;
/**
* Creates an instance of ResizeObserverEntry.
*
* @param {Element} target - Element that is being observed.
* @param {DOMRectInit} rectInit - Data of the element's content rectangle.
*/
constructor(target, rectInit) {
const contentRect = createReadOnlyRect(rectInit);
// According to the specification following properties are not writable
// and are also not enumerable in the native implementation.
//
// Property accessors are not being used as they'd require to define a
// private WeakMap storage which may cause memory leaks in browsers that
// don't support this type of collections.
defineConfigurable(this, {target, contentRect});
}
}
createReadOnlyRect
函数
DOMRectReadOnly
接口通过详细列出DOMRect
所使用的标准属性来定义一个属性不可变的矩形。
Object.prototype
是一个对象,用于表示Object
的原型对象。几乎所有的JavaScript
对象都是Object
的实例,其原型链上最后一个就是指向Object.prototype
。一个典型的对象继承了Object.prototype
的属性和方法。
创建没有原型对象的对象,比如通过
Object.create(null)
创建,或通过Object.setPrototypeOf(obj, null)
方法来改变指定对象的原型对象。
改变
Object.prototype
的属性和方法,或给Object.prototype
添加属性和方法,都会影响到原型链上的所有对象,除非这些对象本身有定义相同的属性和方法进一步覆盖。
Object.prototype === obj.__proto__
/**
* Creates rectangle with an interface of the DOMRectReadOnly.
* Spec: https://drafts.fxtf.org/geometry/#domrectreadonly
*
* @param {DOMRectInit} rectInit - Object with rectangle's x/y coordinates and dimensions.
* @returns {DOMRectReadOnly}
*/
function createReadOnlyRect({x, y, width, height}) {
// 当浏览器支持DOMRectReadOnly便使用DOMRectReadOnly,否则用Object 构造函数
const Constr = typeof DOMRectReadOnly !== 'undefined' ? DOMRectReadOnly : Object;
// rect對象原型鏈上有Constr.prototype上的方法
const rect = Object.create(Constr.prototype);
// Rectangle's properties are not writable and non-enumerable.
defineConfigurable(rect, {
x, y, width, height,
top: y,
right: x + width,
bottom: height + y,
left: x
});
return rect;
}
defineConfigurable
函数
定义一个不可写 不可枚举的target对象
/**
* Defines non-writable/enumerable properties of the provided target object.
*
* @param {Object} target - Object for which to define properties.
* @param {Object} props - Properties to be defined.
* @returns {Object} Target object.
*/
export default (target, props) => {
for (const key of Object.keys(props)) {
Object.defineProperty(target, key, {
value: props[key],
enumerable: false,
writable: false,
configurable: true
});
}
return target;
};