【问题标题】:Restrict access to 'style' property in JavaScript限制对 JavaScript 中“样式”属性的访问
【发布时间】:2014-04-20 21:10:10
【问题描述】:

我开始开发一个小型 JavaScript 库,我希望仅通过我的 API 来设置 HTML 元素的样式(因为出于某种原因,我需要完全控制样式)。

所以我想让 style 属性不可访问(我的 API 将通过我的 style 别名访问它 - 这不是一个理想的解决方案,但对于像 jQuery 这样的其他库,它可以做到这一点)。

如果我写这个(灵感来自this topic):

var box = document.getElementById('someElementId');
Object.defineProperty(box, 'style', {
    get: function() {
        throw 'you cant access style property';
    }
});
box.style.color = 'red';

它仅适用于box 元素。

是否可以对 Webkit、Firefox 和 IE9+ 中的所有(现有和未来)元素执行此操作?

我也试过这个:

Object.defineProperty(HTMLElement, 'style', {...

但没有运气。

任何帮助将不胜感激!

编辑

正如@Teemu 建议的那样,我可以写HTMLElement.prototype 而不是HTMLElement,它在FF 和IE 中运行良好,但在Chrome 中不行。它看起来像Chrome bug。可惜……

Edit2 - 我为什么需要它

我想要开发的库的主要目标是允许以下写作风格:

element.setWidth('parent.width / 2 - 10');

在这种情况下,element 的宽度应该对 parent 的宽度的每次变化做出反应。
但由于onresize 事件仅适用于window 对象(this article 似乎已过时), 我可以“聆听”修改 .style.width 属性的唯一方法是执行我自己的样式 API。
而且我想限制(或至少显示警告)直接style 修改,因为它会破坏元素的行为。

【问题讨论】:

  • 只是好奇,如果样式无法访问,您的 API 将如何设置它?
  • Object.defineProperty(HTMLElement.prototype, 'style', {...}) 可以解决问题。那么你将如何在你的 API 中设置style,我不知道......
  • @Zub How is that? - 我明白了,它在 Chrome 中不起作用,但在 IE 和 FF 中可以正常工作。
  • 为什么你认为这是一个错误? DOM 级别 2 将“样式”定义为只读 属性w3.org/TR/DOM-Level-2-Style/css.html#CSS-htmlelementcss 只是因为某些浏览器选择在 HTMLElement.prototype 和其他浏览器上将样式实现为 getter/setter — 作为元素对象的直接属性(@ Chrome 中的 987654343@)并不意味着它是一个错误。这只是一个实现细节。
  • @Zub 是的,您需要单独密封每个元素。或者覆盖所有返回元素的方法(createElementgetElementById 等)以返回已经密封的元素。但这是一个更大的蠕虫罐,所以我不建议你去那里。

标签: javascript dom prototype ecmascript-5


【解决方案1】:

从 cmets 可以看出,限制对 style 属性的访问可能不是一个好方法。但我从您的问题中了解到,您尝试走这条路的原因是 resize 事件仅针对 window 对象触发。

如果您能够通过调整任何元素的大小事件来规避整个限制问题,那么我建议您查看 Ben Alman 的 jQuery resize event 插件。我不确定您是否想使用 jQuery 进行开发,但即使您不这样做,阅读该插件的代码也可能是值得的。基本上,它所做的是将侦听器的哈希表映射到他们正在侦听的元素,然后在轮询循环中(使用setTimeoutsetInterval)检查该映射中元素的大小。如果它在间隔期间(默认为 250 毫秒)发生了变化,它会触发侦听器本身。它工作得相当好。该特定插件挂钩到 jQuery 的事件系统,但您可以制作自己的 addResizeEvent 函数或类似的东西。

编辑:重新阅读您的问题后,我突然意识到您似乎正在尝试开发一些机制来处理 CSS 框模型的缺点,例如当你给一个元素 5px 的填充和 50% 的宽度时,它最终会比父容器的一半宽 10 个像素。如果是这种情况,请考虑box-sizing: border-box

【讨论】:

  • 是的,我想到了setInterval。但是这种方法存在一个问题。假设我们有一种情况,B 元素的宽度取决于 A 元素的宽度。我们改变 A 的宽度,在 100 毫秒内我们想要得到 B 的宽度。由于setInterval 回调是以250ms 的间隔被调用的,所以我们不能说此时B 宽度是否已经更新。有时我们会得到一个旧值,有时是新值。我敢打赌,这种“有时”的东西会让每个程序员都发疯:)这就是为什么我决定不在其中使用setInterval
  • 是的,如果您使用 setInterval,您的 API 中的 setWidth() 调用只需向某个堆栈添加一个操作,并且在轮询循环中您需要按顺序处理它们。但是box-sizing: border-box 呢?它似乎可以解决您需要执行 setWidth(parent.width / 2 -10) 之类的大多数情况。
  • parent.width / 2 -10的情况下可以。但是如果我们有更复杂的表达式,例如parent.width - #someEl.height + #someOtherEl.paddingLeft + 50,它不会成功。当然这是人为的例子,但它展示了这种表达式的灵活性
  • 您对 API 的意图是什么?你想解决哪个问题?
  • 我想创建允许编写上述表达式的布局库。我想禁止访问style 属性,因为正如我所提到的,它可能会破坏元素的行为。但是由于我不能跨浏览器,我可能会放弃这个想法,禁止style,并寻找其他方法来保持元素行为有序。我会接受你的回答,因为我感谢你的努力。非常感谢您的帮助:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-25
  • 1970-01-01
相关资源
最近更新 更多