Migration von v0.2.x auf v2.x
v1.x und v2.x sind weitgehend API-kompatibel mit v0.2.x, es gibt jedoch einige Breaking Changes. Die Migration zu v2.x ist nahezu identisch mit der zu v1.x, daher gelten die folgenden Hinweise hauptsächlich für beide Versionen.
Für die Migration empfiehlt sich das Tool mithril-codemods, um einfache Migrationen zu automatisieren.
m.prop
entfernt
In v2.x ist m.prop()
nicht mehr Teil des Kerns, sondern wurde in eine leistungsfähigere Stream-Micro-Library ausgelagert. Informationen zur Verwendung des optionalen Streams-Moduls finden Sie in der Dokumentation.
v0.2.x
var m = require('mithril');
var num = m.prop(1);
v2.x
var m = require('mithril');
var prop = require('mithril/stream');
var num = prop(1);
var doubled = num.map(function (n) {
return n * 2;
});
m.component
entfernt
In v0.2.x konnten Komponenten entweder mit m(Component)
oder m.component(Component)
erstellt werden. v2.x unterstützt nur noch m(Component)
.
v0.2.x
// Diese sind äquivalent
m.component(Component);
m(Component);
v2.x
m(Component);
m.withAttr
entfernt
In v0.2.x konnten Event-Listener oninput: m.withAttr("value", func)
und ähnliches verwenden. In v2.x lesen Sie diese direkt aus dem target
des Events. m.withAttr
harmonierte gut mit m.prop
. Da m.prop
jedoch zugunsten einer externen Lösung entfernt wurde und v1.x keine ähnlich breite, idiomatische Verwendung von Streams aufwies, verlor m.withAttr
den größten Teil seines Nutzens.
v0.2.x
var value = m.prop('');
// In Ihrer View
m('input[type=text]', {
value: value(),
oninput: m.withAttr('value', value),
});
v2.x
var value = '';
// In Ihrer View
m('input[type=text]', {
value: value,
oninput: function (ev) {
value = ev.target.value;
},
});
m.version
entfernt
Die Angabe der Version war im Allgemeinen von geringem Nutzen. Sie können sie jederzeit selbst wieder hinzufügen. Es wird empfohlen, Feature-Erkennung zu verwenden, um zu ermitteln, welche Funktionen verfügbar sind. Die v2.x-API ist so konzipiert, dass sie dies besser ermöglicht.
config
Funktion
In v0.2.x stellte Mithril.js eine einzelne Lifecycle-Methode bereit: config
. v2.x bietet eine viel feinere Kontrolle über den Lebenszyklus eines VNodes.
v0.2.x
m('div', {
config: function (element, isInitialized) {
// wird bei jedem Neuzeichnen ausgeführt
// isInitialized ist ein boolescher Wert, der angibt, ob der Knoten dem DOM hinzugefügt wurde
},
});
v2.x
Weitere Informationen zu diesen neuen Methoden finden Sie in lifecycle-methods.md.
m('div', {
// Wird aufgerufen, bevor der DOM-Knoten erstellt wird
oninit: function (vnode) {
/*...*/
},
// Wird aufgerufen, nachdem der DOM-Knoten erstellt wurde
oncreate: function (vnode) {
/*...*/
},
// Wird aufgerufen, bevor der Knoten aktualisiert wird. Gibt false zurück, um den Vorgang abzubrechen.
onbeforeupdate: function (vnode, old) {
/*...*/
},
// Wird aufgerufen, nachdem der Knoten aktualisiert wurde
onupdate: function (vnode) {
/*...*/
},
// Wird aufgerufen, bevor der Knoten entfernt wird. Gibt ein Promise zurück, das aufgelöst wird, wenn
// der Knoten aus dem DOM entfernt werden kann
onbeforeremove: function (vnode) {
/*...*/
},
// Wird aufgerufen, bevor der Knoten entfernt wird, aber nachdem onbeforeremove done() aufgerufen hat
onremove: function (vnode) {
/*...*/
},
});
Falls verfügbar, kann auf das DOM-Element des VNodes über vnode.dom
zugegriffen werden.
Änderungen im Redraw-Verhalten
Die Rendering-Engine von Mithril.js arbeitet weiterhin auf der Basis von halbautomatischen globalen Redraws, aber einige APIs und Verhaltensweisen unterscheiden sich:
Keine Redraw-Sperren mehr
In v0.2.x erlaubte Mithril.js "Redraw-Sperren", die die Draw-Logik vorübergehend blockierten: Standardmäßig sperrte m.request
die Draw-Schleife bei der Ausführung und entsperrte sie, wenn alle ausstehenden Requests aufgelöst waren. Das gleiche Verhalten konnte manuell mit m.startComputation()
und m.endComputation()
aufgerufen werden. Die letzteren APIs und das zugehörige Verhalten wurden in v2.x ohne Ersatz entfernt. Redraw-Sperren können zu fehlerhaften UIs führen: Die Belange eines Teils der Anwendung sollten nicht die Aktualisierung anderer Teile der Ansicht verhindern.
Abbrechen des Redraws von Event-Handlern
m.mount()
und m.route()
führen nach der Ausführung eines DOM-Event-Handlers weiterhin automatisch ein Redraw durch. Das Abbrechen dieser Redraws innerhalb Ihrer Event-Handler erfolgt jetzt, indem Sie die Eigenschaft redraw
des übergebenen Event-Objekts auf false
setzen.
v0.2.x
m('div', {
onclick: function (e) {
m.redraw.strategy('none');
},
});
v2.x
m('div', {
onclick: function (e) {
e.redraw = false;
},
});
Synchrones Redraw geändert
In v0.2.x war es möglich, Mithril.js zu zwingen, sofort neu zu zeichnen, indem ein Truthy-Wert an m.redraw()
übergeben wurde. In v2.x wurde diese Funktionalität zur Verdeutlichung in zwei verschiedene Methoden aufgeteilt.
v0.2.x
m.redraw(true); // zeichnet sofort und synchron neu
v2.x
m.redraw(); // plant ein Redraw beim nächsten requestAnimationFrame-Tick
m.redraw.sync(); // ruft sofort ein Redraw auf und wartet, bis es abgeschlossen ist
m.startComputation
/m.endComputation
entfernt
Diese Methoden gelten als Antipattern und weisen eine Reihe problematischer Randfälle auf, daher wurden sie in v2.x ohne Ersatz entfernt.
Component controller
Funktion
In v2.x gibt es keine controller
Eigenschaft mehr in Components. Verwenden Sie stattdessen oninit
.
v0.2.x
m.mount(document.body, {
controller: function () {
var ctrl = this;
ctrl.fooga = 1;
},
view: function (ctrl) {
return m('p', ctrl.fooga);
},
});
v2.x
m.mount(document.body, {
oninit: function (vnode) {
vnode.state.fooga = 1;
},
view: function (vnode) {
return m('p', vnode.state.fooga);
},
});
// ODER
m.mount(document.body, {
// `this` ist standardmäßig an `vnode.state` gebunden
oninit: function (vnode) {
this.fooga = 1;
},
view: function (vnode) {
return m('p', this.fooga);
},
});
Component Argumente
In v2.x müssen die Argumente für eine Komponente ein Objekt sein. Einfache Werte wie String, Number oder Boolean werden als Text-Kindelemente behandelt. Auf Argumente wird innerhalb der Komponente zugegriffen, indem sie aus dem vnode.attrs
Objekt gelesen werden.
v0.2.x
var Component = {
controller: function (options) {
// options.fooga === 1
},
view: function (ctrl, options) {
// options.fooga === 1
},
};
m('div', m.component(Component, { fooga: 1 }));
v2.x
var Component = {
oninit: function (vnode) {
// vnode.attrs.fooga === 1
},
view: function (vnode) {
// vnode.attrs.fooga === 1
},
};
m('div', m(Component, { fooga: 1 }));
Component VNode Children
In v0.2.x wurden Component VNode Children nicht normalisiert, sondern einfach als zusätzliche Argumente übergeben, und sie wurden auch nicht vereinfacht (flattened). (Intern wurde nur eine teilweise angewendete Component zurückgegeben, die basierend auf der teilweise angewendeten Component unterschieden wurde.) In v2.x werden Component VNode Children über vnode.children
als aufgelöstes Array von Children übergeben, aber wie in v0.2.x werden die einzelnen Children selbst nicht normalisiert, noch wird das Children-Array vereinfacht.
v0.2.x
var Component = {
controller: function (value, renderProp) {
// value === "value"
// typeof renderProp === "function"
},
view: function (ctrl, value, renderProp) {
// value === "value"
// typeof renderProp === "function"
},
};
m(
'div',
m.component(Component, 'value', function (key) {
return 'child';
})
);
v2.x
var Component = {
oninit: function (vnode) {
// vnode.children[0] === "value"
// typeof vnode.children[1] === "function"
},
view: function (vnode) {
// vnode.children[0] === "value"
// typeof vnode.children[1] === "function"
},
};
m(
'div',
m(Component, 'value', function (key) {
return 'child';
})
);
DOM VNode Children
In v0.2.x wurden die Children von DOM-Knoten wörtlich dargestellt, ohne Normalisierung, abgesehen von der direkten Verwendung der Children, wenn nur ein einzelnes Array-Child vorhanden ist. Es wurde eine Struktur zurückgegeben, die eher so aussah, wobei die Strings wörtlich dargestellt wurden.
m("div", "value", ["nested"])
// Wird zu:
{
tag: "div",
attrs: {},
children: [
"value",
["nested"],
]
}
In v2.x werden die Children von DOM-VNodes zu Objekten einer einzigen konsistenten Struktur normalisiert.
m("div", "value", ["nested"])
// Wird ungefähr zu:
{
tag: "div",
attrs: null,
children: [
{tag: "#", children: "value"},
{tag: "[", children: [
{tag: "#", children: "nested"},
]},
]
}
Wenn nur ein einzelnes Text-Child in einem DOM-VNode vorhanden ist, wird stattdessen text
auf diesen Wert gesetzt.
m("div", "value")
// Wird ungefähr zu:
{
tag: "div",
attrs: null,
text: "",
children: undefined,
}
Weitere Informationen zur v2.x VNode-Struktur und zur Normalisierung finden Sie in den VNode-Dokumenten.
Die meisten VNode-Eigenschaften von v2.x werden hier der Kürze halber weggelassen.
Keys
In v0.2.x konnten Sie VNodes mit und ohne Schlüssel frei mischen.
In v2.x müssen Children-Listen von Fragmenten und Elementen entweder alle Schlüssel haben oder alle schlüssellos sein. Löcher werden für diese Prüfung ebenfalls als schlüssellos betrachtet und nicht mehr ignoriert.
Wenn Sie dies umgehen müssen, verwenden Sie das Idiom eines Fragments, das einen einzelnen VNode enthält, wie z. B. [m("div", {key: whatever})]
.
view()
Parameter
In v0.2.x erhalten View-Funktionen eine Referenz auf die Controller-Instanz und (optional) alle an die Komponente übergebenen Optionen. In v2.x wird nur der vnode
übergeben, genau wie die controller
Funktion.
v0.2.x
m.mount(document.body, {
controller: function () {},
view: function (ctrl, options) {
// ...
},
});
v2.x
m.mount(document.body, {
oninit: function (vnode) {
// ...
},
view: function (vnode) {
// Verwenden Sie vnode.state anstelle von ctrl
// Verwenden Sie vnode.attrs anstelle von options
},
});
Übergeben von Components an m()
In v0.2.x konnten Sie Components als zweites Argument von m()
ohne erforderliche Umschließung übergeben. Um die Konsistenz in v2.x sicherzustellen, müssen diese immer mit einem m()
-Aufruf umschlossen werden.
v0.2.x
m('div', Component);
v2.x
m('div', m(Component));
Übergeben von VNodes an m.mount()
und m.route()
In v0.2.x tolerierte m.mount(element, component)
VNodes als zweite Argumente anstelle von Komponenten (auch wenn dies nicht dokumentiert war). Ebenso akzeptierte m.route(element, defaultRoute, routes)
VNodes als Werte im routes
Objekt.
In v2.x sind stattdessen in beiden Fällen Components erforderlich.
v0.2.x
m.mount(element, m('i', 'hello'));
m.mount(element, m(Component, attrs));
m.route(element, '/', {
'/': m('b', 'bye'),
});
v2.x
m.mount(element, {
view: function () {
return m('i', 'hello');
},
});
m.mount(element, {
view: function () {
return m(Component, attrs);
},
});
m.route(element, '/', {
'/': {
view: function () {
return m('b', 'bye');
},
},
});
m.route.mode
In v0.2.x konnte der Routing-Modus durch Zuweisen eines Strings von "pathname"
, "hash"
oder "search"
zu m.route.mode
festgelegt werden. In v1.x wurde dies durch m.route.prefix = prefix
ersetzt, wobei prefix
ein beliebiges Präfix sein kann. Wenn es mit #
beginnt, funktioniert es im "Hash"-Modus, mit ?
für den "Search"-Modus und jedes andere Zeichen (oder die leere Zeichenkette) für den "Pathname"-Modus. Es unterstützt auch Kombinationen der oben genannten, wie m.route.prefix = "/path/#!"
oder ?#
.
Der Standardwert wurde geändert, um ein #!
(Hash-Rufzeichen)-Präfix anstelle von nur #
zu verwenden. Wenn Sie also das Standardverhalten verwendet haben und Ihre bestehenden URLs beibehalten möchten, setzen Sie m.route.prefix = "#"
bevor Sie die Routen initialisieren.
v0.2.x
m.route.mode = 'hash';
m.route.mode = 'pathname';
m.route.mode = 'search';
v2.x
// Direkte Entsprechungen:
m.route.prefix = '#';
m.route.prefix = '';
m.route.prefix = '?';
m.route()
und Anker-Tags
Die Handhabung von routingfähigen Links verwendet jetzt eine spezielle, eingebaute Komponente anstelle eines Attributs. Wenn Sie dies auf <button>
s und dergleichen verwendet haben, können Sie diesen Tag-Namen mit einem selector: "button"
-Attribut angeben.
v0.2.x
// When clicked this link will load the "/path" route instead of navigating
m('a', {
href: '/path',
config: m.route,
});
v2.x
// When clicked this link will load the "/path" route instead of navigating
m(m.route.Link, {
href: '/path',
});
Pfadvorlagen
In v1.x gab es drei separate Pfadvorlagen-Syntaxen, die, obwohl sie ähnlich waren, zwei separat entworfene Syntaxen und drei verschiedene Implementierungen hatten. Dies wurde auf ziemlich ad-hoc-Weise definiert, und Parameter wurden im Allgemeinen nicht maskiert. Jetzt wird alles entweder kodiert, wenn es :key
ist, oder roh, wenn es :key...
ist. Wenn Dinge unerwartet kodiert werden, verwenden Sie :path...
. Das ist im Wesentlichen alles.
Konkret wirkt sich dies wie folgt auf jede Methode aus:
m.request
URLs
Pfadkomponenten in v2.x werden automatisch maskiert, wenn sie interpoliert werden, und sie lesen ihre Werte aus params
. In v0.2.x würde m.request({url: "/user/:name/photos/:id", data: {name: "a/b", id: "c/d"}})
seine Anfrage mit der URL /user/a%2Fb/photos/c/d
senden. In v2.x würde die entsprechende m.request({url: "/user/:name/photos/:id", params: {name: "a/b", id: "c/d"}})
ihre Anfrage an /user/a%2Fb/photos/c%2Fd
senden. Wenn Sie absichtlich einen Schlüssel unmaskiert interpolieren wollen, verwenden Sie stattdessen :key...
.
Interpolationen in Inline-Abfragezeichenketten, wie in /api/search?q=:query
, werden in v2.x nicht durchgeführt. Übergeben Sie diese stattdessen über params
mit entsprechenden Schlüssel-Namen, ohne sie in der Abfragezeichenkette anzugeben.
Beachten Sie, dass dies auch für m.jsonp
gilt. Wenn Sie von m.request
+ dataType: "jsonp"
zu m.jsonp
migrieren, müssen Sie sich dessen ebenfalls bewusst sein.
m.route(route, params, shouldReplaceHistoryEntry)
Pfade
Diese erlauben jetzt Interpolationen und funktionieren identisch mit denen von m.request
.
m.route
Routenmuster
Pfad-Schlüssel der Form :key...
geben ihre URL in v1.x dekodiert zurück, aber in v2.x die rohe URL.
Zuvor wurden Dinge wie :key.md
fälschlicherweise akzeptiert, wobei der Wert des resultierenden Parameters auf keymd: "..."
gesetzt wurde. Dies ist nicht mehr der Fall - die .md
ist jetzt Teil des Musters, nicht des Namens.
Lesen/Schreiben der aktuellen Route
In v0.2.x erfolgte die gesamte Interaktion mit der aktuellen Route über m.route()
. In v2.x wurde dies in zwei Funktionen aufgeteilt.
v0.2.x
// Getting the current route
m.route();
// Setting a new route
m.route('/other/route');
v2.x
// Getting the current route
m.route.get();
// Setting a new route
m.route.set('/other/route');
Zugriff auf Routenparameter
In v0.2.x wurde das Lesen von Routenparametern vollständig über m.route.param()
abgewickelt. Diese API ist in v2.x weiterhin verfügbar, und zusätzlich werden alle Routenparameter als Eigenschaften im attrs
-Objekt auf dem vnode übergeben.
v0.2.x
m.route(document.body, '/booga', {
'/:attr': {
controller: function () {
m.route.param('attr'); // "booga"
},
view: function () {
m.route.param('attr'); // "booga"
},
},
});
v2.x
m.route(document.body, '/booga', {
'/:attr': {
oninit: function (vnode) {
vnode.attrs.attr; // "booga"
m.route.param('attr'); // "booga"
},
view: function (vnode) {
vnode.attrs.attr; // "booga"
m.route.param('attr'); // "booga"
},
},
});
Erstellen/Parsen von Abfragezeichenketten
v0.2.x verwendete Methoden, die von m.route
abhingen: m.route.buildQueryString()
und m.route.parseQueryString()
. In v2.x wurden diese aufgeteilt und in den Root m
verschoben.
v0.2.x
var qs = m.route.buildQueryString({ a: 1 });
var obj = m.route.parseQueryString('a=1');
v2.x
var qs = m.buildQueryString({ a: 1 });
var obj = m.parseQueryString('a=1');
Auch in v2.x wird {key: undefined}
von m.buildQueryString
und Methoden, die es verwenden, wie m.request
, als key=undefined
serialisiert. In v0.2.x wurde der Schlüssel weggelassen, und dies wurde auf m.request
übertragen. Wenn Sie sich zuvor darauf verlassen haben, ändern Sie Ihren Code, um die Schlüssel vollständig aus dem Objekt zu entfernen. Es kann sich lohnen, ein einfaches Hilfsprogramm zu verwenden, um alle Schlüssel aus einem Objekt zu entfernen, dessen Werte undefined
sind, wenn Sie dies nicht einfach tun können und das Verhalten von v0.2.x beibehalten müssen.
// Rufen Sie diese Funktion auf, um `undefined`-Parameter aus einem Objekt zu entfernen.
function omitUndefineds(object) {
var result = {};
for (var key in object) {
if ({}.hasOwnProperty.call(object, key)) {
var value = object[key];
if (Array.isArray(value)) {
result[key] = value.map(omitUndefineds);
} else if (value != null && typeof value === 'object') {
result[key] = omitUndefineds(value);
} else if (value !== undefined) {
result[key] = value;
}
}
}
return result;
}
Verhindern des Aushängens
Es ist nicht mehr möglich, das Aushängen über onunload
's e.preventDefault()
zu verhindern. Stattdessen sollten Sie explizit m.route.set
aufrufen, wenn die erwarteten Bedingungen erfüllt sind.
v0.2.x
var Component = {
controller: function () {
this.onunload = function (e) {
if (condition) e.preventDefault();
};
},
view: function () {
return m('a[href=/]', { config: m.route });
},
};
v2.x
var Component = {
view: function () {
return m('a', {
onclick: function () {
if (!condition) m.route.set('/');
},
});
},
};
Ausführen von Code beim Entfernen der Komponente
Komponenten rufen this.onunload
nicht mehr auf, wenn sie entfernt werden. Sie verwenden jetzt den standardisierten Lebenszyklus-Hook onremove
.
v0.2.x
var Component = {
controller: function () {
this.onunload = function (e) {
// ...
};
},
view: function () {
// ...
},
};
v2.x
var Component = {
onremove: function() {
// ...
}
view: function() {
// ...
}
}
m.request
Von m.request zurückgegebene Promises sind keine m.prop
Getter-Setter mehr. Darüber hinaus werden initialValue
, unwrapSuccess
und unwrapError
nicht mehr als Optionen unterstützt.
Darüber hinaus haben Anfragen keine m.startComputation
/m.endComputation
-Semantik mehr. Stattdessen werden Neuzeichnungen immer ausgelöst, wenn eine Request-Promise-Kette abgeschlossen ist (es sei denn, background: true
ist gesetzt).
Der data
-Parameter wurde jetzt in params
(Abfrageparameter, die in die URL interpoliert und an die Anfrage angehängt werden) und body
(den im zugrunde liegenden XMLHttpRequest zu sendenden Anfrageinhalt) aufgeteilt.
In v0.2.x würden Sie ein dataType: "jsonp"
verwenden, um eine JSONP-Anfrage zu initiieren. In v2.x verwenden Sie jetzt m.jsonp
, das größtenteils die gleiche API wie m.request
ohne die XMLHttpRequest-bezogenen Teile enthält.
v0.2.x
var data = m.request({
method: 'GET',
url: 'https://api.github.com/',
initialValue: [],
});
setTimeout(function () {
console.log(data());
}, 1000);
m.request({
method: 'POST',
url: 'https://api.github.com/',
data: someJson,
});
v2.x
var data = [];
m.request({
method: 'GET',
url: 'https://api.github.com/',
}).then(function (responseBody) {
data = responseBody;
});
setTimeout(function () {
console.log(data); // note: Dies ist kein Getter-Setter.
}, 1000);
m.request({
method: 'POST',
url: 'https://api.github.com/',
body: someJson,
});
// OR
var data = [];
m.request('https://api.github.com/').then(function (responseBody) {
data = responseBody;
});
setTimeout(function () {
console.log(data); // note: Dies ist kein Getter-Setter.
}, 1000);
m.request('https://api.github.com/', {
method: 'POST',
body: someJson,
});
Wenn die Option extract
an m.request
übergeben wird, wird der Rückgabewert der bereitgestellten Funktion direkt verwendet, um das Request-Promise aufzulösen, und die Rückruffunktion deserialize
wird ignoriert.
m.request
Header
In v0.2.x hat Mithril.js standardmäßig keine Header für Anfragen gesetzt. Jetzt werden bis zu zwei Header gesetzt:
Content-Type: application/json; charset=utf-8
für Anfragen mit JSON-Anfrageinhalten, die!= null
sindAccept: application/json, text/*
für Anfragen, die JSON-Antworten erwarten
Der Header Content-Type
kann einen CORS-Prefetch auslösen, da er aufgrund des angegebenen Content-Typs nicht als CORS-safelisted Request-Header gilt. Dies kann zu neuen Fehlern führen, abhängig von der CORS-Konfiguration Ihres Servers. Wenn Sie auf Probleme damit stoßen, müssen Sie diesen Header möglicherweise überschreiben, indem Sie headers: {"Content-Type": "text/plain"}
übergeben. (Der Accept
-Header löst nichts aus, sodass Sie ihn nicht überschreiben müssen.)
Die einzigen Content-Typen, die die Fetch-Spezifikation zulässt, um CORS-Prefetch-Prüfungen zu vermeiden, sind application/x-www-form-urlencoded
, multipart/form-data
und text/plain
. Es erlaubt nichts anderes und verbietet absichtlich JSON.
m.deferred
entfernt
v0.2.x verwendete ein eigenes benutzerdefiniertes asynchrones Vertragsobjekt, das als m.deferred
verfügbar gemacht wurde und als Grundlage für m.request
diente. v2.x verwendet stattdessen Promises und implementiert ein Polyfill in nicht unterstützenden Umgebungen. In Situationen, in denen Sie m.deferred
verwendet hätten, sollten Sie stattdessen Promises verwenden.
v0.2.x
var greetAsync = function () {
var deferred = m.deferred();
setTimeout(function () {
deferred.resolve('hello');
}, 1000);
return deferred.promise;
};
greetAsync()
.then(function (value) {
return value + ' world';
})
.then(function (value) {
console.log(value);
}); //logs "hello world" after 1 second
v2.x
var greetAsync = function () {
return new Promise(function (resolve) {
setTimeout(function () {
resolve('hello');
}, 1000);
});
};
greetAsync()
.then(function (value) {
return value + ' world';
})
.then(function (value) {
console.log(value);
}); //logs "hello world" after 1 second
m.sync
entfernt
Da v2.x standardkonforme Promises verwendet, ist m.sync
redundant. Verwenden Sie stattdessen Promise.all
.
v0.2.x
m.sync([
m.request({ method: 'GET', url: 'https://api.github.com/users/lhorie' }),
m.request({
method: 'GET',
url: 'https://api.github.com/users/dead-claudia',
}),
]).then(function (users) {
console.log('Contributors:', users[0].name, 'and', users[1].name);
});
v2.x
Promise.all([
m.request({ method: 'GET', url: 'https://api.github.com/users/lhorie' }),
m.request({
method: 'GET',
url: 'https://api.github.com/users/dead-claudia',
}),
]).then(function (users) {
console.log('Contributors:', users[0].name, 'and', users[1].name);
});
xlink
Namespace erforderlich
In v0.2.x war der xlink
-Namespace der einzige unterstützte Attribut-Namespace, und er wurde durch spezielles Verhalten unterstützt. Jetzt wird das Parsen von Namespaces vollständig unterstützt, und Attribute mit Namespaces sollten ihren Namespace explizit deklarieren.
v0.2.x
m(
'svg',
// the `href` attribute is namespaced automatically
m("image[href='image.gif']")
);
v2.x
m(
'svg',
// User-specified namespace on the `href` attribute
m("image[xlink:href='image.gif']")
);
Verschachtelte Arrays in Views
Arrays stellen jetzt Fragmente dar, die im virtuellen DOM von v2.x strukturell bedeutsam sind. Während verschachtelte Arrays in v0.2.x zu einer fortlaufenden Liste virtueller Knoten zum Zwecke der Unterschiedsberechnung abgeflacht würden, behält v2.x die Array-Struktur bei - die Kinder eines bestimmten Arrays werden nicht als Geschwister derer benachbarter Arrays betrachtet.
vnode
Gleichheitsprüfungen
Wenn ein vnode identisch mit dem vnode ist, der an seiner Stelle im letzten Durchlauf war, überspringt v2.x diesen Teil des Baums, ohne Mutationen zu prüfen oder Lebenszyklus-Methoden im Unterbaum auszulösen. Die Komponentendokumentation enthält weitere Details zu diesem Problem.