【问题标题】:How best to convert a ClientRect / DomRect into a plain Object如何最好地将 ClientRect / DomRect 转换为普通对象
【发布时间】:2016-09-09 18:19:38
【问题描述】:

someElement.getBoundingClientRect() 的结果返回一个类型为ClientRect(或DomRect)的特殊对象

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

不幸的是,这个对象的行为与其他对象不太一样。

例如,在它上面使用Object.keys会返回一个空数组(我认为是因为ClientRect属性不是可枚举的

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

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

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

【问题讨论】:

  • 这是 soooo hacky,但 Object.keys(document.body.getBoundingClientRect().__proto__) 似乎在 chrome 中工作。 :P

标签: javascript dom getboundingclientrect


【解决方案1】:

我们不要把事情复杂化!

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 )
)

【讨论】:

  • 这是一个 ES6 版本:const getBoundingClientRect = (element) => { const {top, right, bottom, left, width, height, x, y} = element.getBoundingClientRect(); return {top, right, bottom, left, width, height, x, y} }
【解决方案2】:

警告: 非标准行为(不适用于 Firefox < 62,包括 ESR 60 和可能的 Chrome 以外的其他浏览器)

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

【讨论】:

  • 我认为你甚至不需要那里的Object.assign.toJSON 返回一个合适的对象(Object.keys($0.getBoundingClientRect().toJSON()) 有效)。你也每次都会得到一个新的对象! $0.getBoundingClientRect().toJSON() !== $0.getBoundingClientRect().toJSON()
  • 请记住,toJSON 不适用于 firefox 的 rect 对象
  • 抱歉,我不得不对答案投反对票,因为你没有提到它不支持 Firefox
【解决方案3】:

这是我可以忍受的:

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

【讨论】:

  • 在 Edge 中不起作用。但是当 Edge 切换到 Chromium 时,这将得到解决。
  • 作为一般规则,除非必要,否则应避免将数字转换为字符串(和返回)。字符串操作比处理数字要昂贵得多,因此如果必须多次执行此操作,性能会受到影响。
  • @MichaelJohansen,完全同意,好评论
【解决方案4】:

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

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

【讨论】:

  • 这可以而且确实有效,但与其他各种克隆方法相比,$.extend 的效率是出了名的低。见jsben.ch/#/bWfk9。正如 OP 所指出的,ClientRect 是一个特殊的对象,但大多数(所有?)其他技术都不能按预期工作,所以这里没有太多选择。
【解决方案5】:

函数式 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())

【讨论】:

    【解决方案6】:

    你可以使用Object.fromEntries()来创建你的obj。

    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;
    }
    &lt;div id="test"&gt;&lt;/div&gt;

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

    轻量级

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

    您可以根据这 4 个值计算 bottomright 的值,而 lefttop 只是 xy 的别名。

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

    【讨论】:

      猜你喜欢
      • 2016-09-14
      • 2016-08-07
      • 2016-07-13
      • 2020-01-25
      • 1970-01-01
      相关资源
      最近更新 更多