Fix style updates to avoid unnecessary allocation (#2312)

* Fix style updates to avoid unnecessary allocation

- Drive-by: properly censor `cssFloat` -> css `float:` to match DOM
  behavior

* Document `style` syntax + custom property support. [skip ci]

* Add a missing test

* Add a few more descriptive comments.

* Update changelog [skip ci]
This commit is contained in:
Isiah Meadows 2018-12-03 14:31:08 -05:00 committed by GitHub
parent b25e8e15a0
commit 8134c51a48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 25 deletions

View file

@ -72,7 +72,7 @@
- docs: tweaks: ([#2104](https://github.com/MithrilJS/mithril.js/pull/2104) [@mikeyb](https://github.com/mikeyb), [#2205](https://github.com/MithrilJS/mithril.js/pull/2205), [@cavemansspa](https://github.com/cavemansspa), [#2250](https://github.com/MithrilJS/mithril.js/pull/2250) [@isiahmeadows](https://github.com/isiahmeadows), [#2265](https://github.com/MithrilJS/mithril.js/pull/2265), [@isiahmeadows](https://github.com/isiahmeadows)) - docs: tweaks: ([#2104](https://github.com/MithrilJS/mithril.js/pull/2104) [@mikeyb](https://github.com/mikeyb), [#2205](https://github.com/MithrilJS/mithril.js/pull/2205), [@cavemansspa](https://github.com/cavemansspa), [#2250](https://github.com/MithrilJS/mithril.js/pull/2250) [@isiahmeadows](https://github.com/isiahmeadows), [#2265](https://github.com/MithrilJS/mithril.js/pull/2265), [@isiahmeadows](https://github.com/isiahmeadows))
- render/core: avoid touching `Object.prototype.__proto__` setter with `key: "__proto__"` in certain situations ([#2251](https://github.com/MithrilJS/mithril.js/pull/2251)) - render/core: avoid touching `Object.prototype.__proto__` setter with `key: "__proto__"` in certain situations ([#2251](https://github.com/MithrilJS/mithril.js/pull/2251))
- render/core: Vnodes stored in the dom node supplied to `m.render()` are now normalized [#2266](https://github.com/MithrilJS/mithril.js/pull/2266) - render/core: Vnodes stored in the dom node supplied to `m.render()` are now normalized [#2266](https://github.com/MithrilJS/mithril.js/pull/2266)
- render/core: CSS vars can now be specified in `{style}` attributes [#2192](https://github.com/MithrilJS/mithril.js/pull/2192) - render/core: CSS vars can now be specified in `{style}` attributes ([#2192](https://github.com/MithrilJS/mithril.js/pull/2192) [@barneycarroll](https://github.com/barneycarroll)), ([#2311](https://github.com/MithrilJS/mithril.js/pull/2311) [@porsager](https://github.com/porsager)), ([#2312](https://github.com/MithrilJS/mithril.js/pull/2312) [@isiahmeadows](https://github.com/isiahmeadows))
- request: don't modify params, call `extract`/`serialize`/`deserialize` with correct `this` value ([#2288](https://github.com/MithrilJS/mithril.js/pull/2288)) - request: don't modify params, call `extract`/`serialize`/`deserialize` with correct `this` value ([#2288](https://github.com/MithrilJS/mithril.js/pull/2288))
--- ---

View file

@ -262,6 +262,8 @@ m("div[style=background:red]")
Using a string as a `style` would overwrite all inline styles in the element if it is redrawn, and not only CSS rules whose values have changed. Using a string as a `style` would overwrite all inline styles in the element if it is redrawn, and not only CSS rules whose values have changed.
You can use both hyphenated CSS property names (like `background-color`) and camel cased DOM `style` property names (like `backgroundColor`). You can also define [CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables), if your browser supports them.
Mithril does not attempt to add units to number values. It simply stringifies them. Mithril does not attempt to add units to number values. It simply stringifies them.
--- ---

View file

@ -775,38 +775,45 @@ module.exports = function($window) {
) && key in vnode.dom ) && key in vnode.dom
} }
var matchUpperCase = /[A-Z]/g
function prependDashAndLowerCase(string){
return "-" + string.toLowerCase()
}
function normalizeProp(prop) {
return "-" && prop[1] === "-"
? prop
: prop.replace(matchUpperCase, prependDashAndLowerCase)
}
//style //style
var uppercaseRegex = /[A-Z]/g
function toLowerCase(capital) { return "-" + capital.toLowerCase() }
function normalizeKey(key) {
return key[0] === "-" && key[1] === "-" ? key :
key === "cssFloat" ? "float" :
key.replace(uppercaseRegex, toLowerCase)
}
function updateStyle(element, old, style) { function updateStyle(element, old, style) {
if (old != null && style != null && typeof old === "object" && typeof style === "object" && style !== old) { if (old === style) {
// Styles are equivalent, do nothing.
} else if (style == null) {
// New style is missing, just clear it.
element.style.cssText = ""
} else if (typeof style !== "object") {
// New style is a string, let engine deal with patching.
element.style.cssText = style
} else if (old == null || typeof old !== "object") {
// `old` is missing or a string, `style` is an object.
element.style.cssText = ""
// Add new style properties
for (var key in style) {
var value = style[key]
if (value != null) element.style.setProperty(normalizeKey(key), String(value))
}
} else {
// Both old & new are (different) objects. // Both old & new are (different) objects.
// Update style properties that have changed // Update style properties that have changed
for (var key in style) { for (var key in style) {
if (style[key] !== old[key]) element.style.setProperty(normalizeProp(key), style[key]) var value = style[key]
if (value != null && (value = String(value)) !== String(old[key])) {
element.style.setProperty(normalizeKey(key), value)
}
} }
// Remove style properties that no longer exist // Remove style properties that no longer exist
for (var key in old) { for (var key in old) {
if (!(key in style)) element.style.removeProperty(normalizeProp(key)) if (old[key] != null && style[key] == null) {
element.style.removeProperty(normalizeKey(key))
} }
return
}
if (old === style) element.style.cssText = "", old = null
if (style == null) element.style.cssText = ""
else if (typeof style === "string") element.style.cssText = style
else {
if (typeof old === "string") element.style.cssText = ""
for (var key in style) {
element.style.setProperty(normalizeProp(key), style[key])
} }
} }
} }

View file

@ -45,6 +45,13 @@ o.spec("createElement", function() {
o(vnode.dom.style["--cssVar"]).equals("red") o(vnode.dom.style["--cssVar"]).equals("red")
}) })
o("censors cssFloat to float", function() {
var vnode = {tag: "a", attrs: {style: {cssFloat: "left"}}}
render(root, [vnode])
o(vnode.dom.style.float).equals("left")
})
o("creates children", function() { o("creates children", function() {
var vnode = {tag: "div", children: [{tag: "a"}, {tag: "b"}]} var vnode = {tag: "div", children: [{tag: "a"}, {tag: "b"}]}
render(root, [vnode]) render(root, [vnode])