From 3721e393c162fc1fb2da6b62a97222a3c08a8c33 Mon Sep 17 00:00:00 2001 From: kfule Date: Fri, 8 Nov 2024 18:51:30 +0900 Subject: [PATCH 1/2] setAttr(): remove `key === "is"`, fixes #2799 --- render/render.js | 2 +- render/tests/test-attributes.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/render/render.js b/render/render.js index 6888d06f5..d59f816f5 100644 --- a/render/render.js +++ b/render/render.js @@ -676,7 +676,7 @@ module.exports = function() { } } function setAttr(vnode, key, old, value, ns) { - if (key === "key" || key === "is" || value == null || isLifecycleMethod(key) || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object") return + if (key === "key" || value == null || isLifecycleMethod(key) || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object") return if (key[0] === "o" && key[1] === "n") return updateEvent(vnode, key, value) if (key.slice(0, 6) === "xlink:") vnode.dom.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(6), value) else if (key === "style") updateStyle(vnode.dom, old, value) diff --git a/render/tests/test-attributes.js b/render/tests/test-attributes.js index 1daed5e5f..267cee26a 100644 --- a/render/tests/test-attributes.js +++ b/render/tests/test-attributes.js @@ -80,8 +80,8 @@ o.spec("attributes", function() { o(spies[0].callCount).equals(0) o(spies[2].callCount).equals(0) o(spies[3].calls).deepEquals([{this: spies[3].elem, args: ["custom", "x"]}]) - o(spies[4].calls).deepEquals([{this: spies[4].elem, args: ["custom", "x"]}]) - o(spies[5].calls).deepEquals([{this: spies[5].elem, args: ["custom", "x"]}]) + o(spies[4].calls).deepEquals([{this: spies[4].elem, args: ["is", "something-special"]} ,{this: spies[4].elem, args: ["custom", "x"]}]) + o(spies[5].calls).deepEquals([{this: spies[5].elem, args: ["is", "something-special"]} ,{this: spies[5].elem, args: ["custom", "x"]}]) }) o("when vnode is customElement with property, custom setAttribute not called", function(){ @@ -124,8 +124,8 @@ o.spec("attributes", function() { o(spies[1].callCount).equals(0) o(spies[2].callCount).equals(0) o(spies[3].callCount).equals(0) - o(spies[4].callCount).equals(0) - o(spies[5].callCount).equals(0) + o(spies[4].callCount).equals(1) // setAttribute("is", "something-special") is called + o(spies[5].callCount).equals(1) // setAttribute("is", "something-special") is called o(getters[0].callCount).equals(0) o(getters[1].callCount).equals(0) o(getters[2].callCount).equals(0) From 2ae7003f5492d4187b86244419dfb4e01f033141 Mon Sep 17 00:00:00 2001 From: kfule Date: Fri, 8 Nov 2024 18:54:07 +0900 Subject: [PATCH 2/2] swap set and removal order of attributes/style properties --- render/render.js | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/render/render.js b/render/render.js index d59f816f5..3e06418d5 100644 --- a/render/render.js +++ b/render/render.js @@ -746,11 +746,8 @@ module.exports = function() { if (old && old === attrs) { console.warn("Don't reuse attrs object, use new object for every redraw, this will throw in next major") } - if (attrs != null) { - for (var key in attrs) { - setAttr(vnode, key, old && old[key], attrs[key], ns) - } - } + // Some attributes may NOT be case-sensitive (e.g. data-***), + // so removal should be done first to prevent accidental removal for newly setting values. var val if (old != null) { for (var key in old) { @@ -759,6 +756,11 @@ module.exports = function() { } } } + if (attrs != null) { + for (var key in attrs) { + setAttr(vnode, key, old && old[key], attrs[key], ns) + } + } } function isFormAttribute(vnode, attr) { return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === activeElement(vnode.dom) || vnode.tag === "option" && vnode.dom.parentNode === activeElement(vnode.dom) @@ -800,6 +802,15 @@ module.exports = function() { } } else { // Both old & new are (different) objects. + // Remove style properties that no longer exist. + // Style properties may have two cases(dash-case and camelCase), + // so removal should be done first to prevent accidental removal for newly setting values. + for (var key in old) { + if (old[key] != null && style[key] == null) { + if (key[0] === "-" && key[1] === "-") element.style.removeProperty(key) + else element.style[key] = "" + } + } // Update style properties that have changed for (var key in style) { var value = style[key] @@ -808,13 +819,6 @@ module.exports = function() { else element.style[key] = value } } - // Remove style properties that no longer exist - for (var key in old) { - if (old[key] != null && style[key] == null) { - if (key[0] === "-" && key[1] === "-") element.style.removeProperty(key) - else element.style[key] = "" - } - } } }