如何最好地将 ClientRect / DomRect 转换为普通对象

How best to convert a ClientRect / DomRect into a plain Object

someElement.getBoundingClientRect() returns special 类型 ClientRect 对象的结果(显然是 DomRect

它的结构类似于 {top: 10, right: 20, bottom: 30, left: 10, width: 10}

遗憾的是,此对象的行为与其他对象不同。

例如,在 returns 上使用 Object.keys 一个空数组(我认为是因为 ClientRect 属性不是 enumerable

我发现了一些转换为普通对象的肮脏方法:

var obj = {}
for (key in rect) {
  obj[key] = rect[key]
}

我的问题是,有没有更好的方法?

我们不要把事情想得太复杂了!

function getBoundingClientRect(element) {
  var rect = element.getBoundingClientRect();
  return {
    top: rect.top,
    right: rect.right,
    bottom: rect.bottom,
    left: rect.left,
    width: rect.width,
    height: rect.height,
    x: rect.x,
    y: rect.y
  };
}

ES2015:

const getBoundingClientRect = element => { 
  const {top, right, bottom, left, width, height, x, y} = element.getBoundingClientRect()
  return {top, right, bottom, left, width, height, x, y} 
}

console.log(
  getBoundingClientRect( document.body )
)

如果您使用 jQuery,您可以使用 extend 方法。

var obj = $.extend( {}, element.getBoundingClientRect());

Warning: non-standard behavior (doesn't work in Firefox < 62, including ESR 60 and possibly other browsers other than Chrome)

var obj = el.getBoundingClientRect().toJSON();

这是我可以忍受的东西:

const persistRect = JSON.parse(JSON.stringify(someElement.getBoundingClientRect()))

功能性 ES6 变体:

const propValueSet = (prop) => (value) => (obj) => ({...obj, [prop]: value})
const toObj = keys => obj => keys.reduce((o, k) => propValueSet(k)(obj[k])(o), {})
const getBoundingClientRect = el => toObj(['top', 'right', 'bottom', 'left', 'width', 'height', 'x', 'y'])(el.getBoundingClientRect())

您可以使用 Object.fromEntries() 来创建您的对象。

let domRec = document.getElementById('test').getBoundingClientRect();

// Convert to plain Object
let domObj = Object.fromEntries(Array.from(Object.keys(DOMRectReadOnly.prototype).filter(k => !isNaN(domRec[k])), k => [k, domRec[k]]));

// Convert back to DOMRectReadOnly
let domRec2 = DOMRectReadOnly.fromRect(domObj);

console.log('DOMRectReadOnly', domRec);
console.log('Plain Object', domObj);
console.log('DOMRectReadOnly', domRec2);
#test {
  width: 200px;
  height: 50px;
  background-color: #f00;
}
<div id="test"></div>

然而,这也会将 toJSON fn 复制到新的 obj。因此我建议过滤非数字值:.filter(k => !isNaN(domRec[k]).

轻巧

如果您只对xywidthheight感兴趣,您可以使用DOMRect 而不是 DOMRectReadOnly 并跳过 .filter() 部分。

You can calc values for bottom, right from these 4 values and left, top are just aliases for x, y.

let domRec = someElement.getBoundingClientRect();
let domObj = Object.fromEntries(Array.from(Object.keys(DOMRect.prototype), k => [k, domRec[k]]));