简体   繁体   English

为什么更新 DOM 元素的样式属性时 object 传播失败但 Object.assign 成功?

[英]Why does object spread fail but Object.assign succeeds when updating a DOM element's style attribute?

Context语境

When using vanilla js to update a DOM element's style attribute, why does object spread fail to update whilst Object.assign succeeds?使用 vanilla js 更新 DOM 元素的style属性时,为什么 object spread 更新失败而Object.assign成功?

Eg, in the included code snippet, objectAssignDirect and objectAssignIndirect correctly set background-color whilst objectSpread incorrectly resets the result div 's background-color .例如,在包含的代码片段中, objectAssignDirectobjectAssignIndirect正确设置了background-color ,而objectSpread错误地重置了结果divbackground-color

Questions问题

  1. Why does this happen?为什么会这样? (is this due to cloning issues or properties such as inherited properties not being copied?) (这是由于克隆问题还是未复制继承属性等属性?)
  2. Is there a way to replicate Object.assign 's desired behaviour with object spread?有没有办法通过 object 传播来复制Object.assign的所需行为?

References参考

There are several discussions comparing Object.assign and object spread but none seem to address this strange behaviour:有几个讨论比较Object.assign和 object 传播,但似乎没有一个解决这个奇怪的行为:

 // Using `Object.assign` directly. const objectAssignDirect = () => { Object.assign(document.querySelector('.myClass').style, { backgroundColor: 'red' }); // Works. console.log('Result should be red'); } // Updating using `Object.assign` with variable. const objectAssignIndirect = () => { const myElement = document.querySelector('.myClass') Object.assign(myElement.style, { backgroundColor: 'blue' }); // Works. console.log('Result should be blue'); } // Using object spread with variable. const objectSpread = () => { const myElement = document.querySelector('.myClass') myElement.style = {...myElement.style, backgroundColor: 'green' }; // Fails. console.log('Result should be green'); }
 body { font-size: 2em; }.myClass { width: 100%; height: 50px; background-color: black; color: white; border: 4px solid black; text-align: center; padding: 10px; } button { padding: 15px; margin: 30px; color: white; border-radius: 20px; }.red { background-color: red; }.blue { background-color: blue; }.green { background-color: green; }
 <div style="display:flex;justify-content:center;"> <button class="red" onclick="objectAssignDirect();">Use <code>Object.assign</code> directly</button> <button class="blue" onclick="objectAssignIndirect();">Use <code>Object.assign</code> indirectly</button> <button class="green" onclick="objectSpread();">Use object spread</button> </div> <div class="myClass">Result</div>

Why does this happen?为什么会这样?

style is a read-only property, and cannot be assigned to a new value. style是只读属性,不能赋值给新值。

element.style = { ...element.style, backgroundColor: 'green' };

Creates a shallow copy of element.style , adds/updates the property backgroundColor and assigns the copy back to element.style .创建element.style的浅表副本,添加/更新属性backgroundColor并将副本分配回element.style For this reason it fails, because you cannot assign element.style a new value.由于这个原因,它失败了,因为你不能为element.style分配一个新值。

Object.assign(element.style, { backgroundColor: 'green' });

Assigns each property/value pair in the second argument to element.style .将第二个参数中的每个属性/值对分配给element.style It does not create a copy of element.style , but mutates the element.style object.它不会创建element.style的副本,但会改变element.style object。

Is there a way to replicate Object.assign 's desired behaviour with object spread?有没有办法通过 object 传播来复制Object.assign的所需行为?

No, object spread is used only in object literals, which will always result in a new object being created.不,object 传播仅用于 object 文字,这将始终导致创建新的 object。 You cannot update an existing object using object spread.您无法使用 object 扩展更新现有的 object。

Assiging directly to the .style tag of an element will not result in the style changing.直接分配给元素的.style标记不会导致样式更改。 Instead, it'll fail silently:相反,它会默默地失败:

 foo.style = { backgroundColor: 'green' }; console.log(foo.style.backgroundColor);
 <div id="foo">foo</div>

You have to assign to a property of the existing .style (the existing CSSStyleDeclaration) in order to invoke the setter that results in the DOM changing.您必须分配给现有.style的属性(现有 CSSStyleDeclaration)才能调用导致 DOM 更改的设置器。 You can't try to reassign the style attribute entirely with something else, because then you won't be invoking the special setter on the CSSStyleDeclaration.您不能尝试用其他东西完全重新分配style属性,因为这样您就不会调用 CSSStyleDeclaration 上的特殊设置器。 Doing {...myElement.style } creates a new plain object, not a CSSStyleDeclaration.执行{...myElement.style }会创建一个新的普通 object,而不是 CSSStyleDeclaration。 Object.assign works in both of your original snippets because it'll invoke setters. Object.assign在您的两个原始片段中都有效,因为它会调用设置器。

For another example of this sort of behavior:对于此类行为的另一个示例:

 const obj = Object.create({ style: { set someProp(arg) { console.log('Setter invoked; changing DOM'); } }}); console.log('Invokes setter:'); obj.style.someProp = 'newVal'; console.log("Doesn't invoke setter:"); obj.style = { someProp: 'newVal' };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM