Migrace z v1.x
Verze v2.x je téměř zcela API-kompatibilní s v1.x, ale existují některé zásadní změny.
Přiřazování do vnode.state
Ve verzi v1.x jste mohli manipulovat s vnode.state
a přiřazovat mu libovolné hodnoty. Ve verzi v2.x dojde k chybě, pokud se pokusíte vnode.state
změnit přímo. Migrace je obvykle jednoduchá: změňte odkazy na vnode.state
na vnode.state.foo
a zvolte pro foo
vhodný název (například count
, pokud se jedná o aktuální hodnotu čítače).
v1.x
var Counter = {
oninit: function (vnode) {
vnode.state = 0;
},
view: function (vnode) {
return m('.counter', [
m(
'button',
{
onclick: function () {
vnode.state--;
},
},
'-'
),
vnode.state,
m(
'button',
{
onclick: function () {
vnode.state++;
},
},
'+'
),
]);
},
};
v2.x
var Counter = {
oninit: function (vnode) {
vnode.state.count = 0;
},
view: function (vnode) {
return m('.counter', [
m(
'button',
{
onclick: function () {
vnode.state.count--;
},
},
'-'
),
vnode.state.count,
m(
'button',
{
onclick: function () {
vnode.state.count++;
},
},
'+'
),
]);
},
};
Když byla poprvé vydána verze v1.0, třídní a closure komponenty neexistovaly, takže se jednoduše používalo vnode.tag
. Tento implementační detail umožňoval přímou manipulaci s vnode.tag
a někteří vývojáři se na to začali spoléhat. Dokumentace to na některých místech dokonce naznačovala. Nyní je situace jiná a správa stavu je jednodušší, protože existuje pouze jeden odkaz na stav, nikoli dva.
Změny v kotvách routování
Ve verzi v1.x jste používali oncreate: m.route.link
(a případně onupdate: m.route.link
, pokud se odkaz mohl změnit) jako lifecycle hook na vnode, který měl být routován. Ve verzi v2.x nyní používáte m.route.Link
komponentu. Selektor lze určit pomocí atributu selector:
, pokud jste používali něco jiného než m("a", ...)
. Další možnosti lze specifikovat pomocí options:
, odkaz lze zakázat pomocí disabled:
a další atributy lze specifikovat inline, včetně href:
(povinné). Samotný selector:
může obsahovat jakýkoli selektor platný jako první argument pro m
a atributy [href=...]
a [disabled]
lze specifikovat v selektoru i v běžných možnostech.
v1.x
m('a', {
href: '/path',
oncreate: m.route.link,
});
m('button', {
href: '/path',
oncreate: m.route.link,
});
m('button.btn[href=/path]', {
oncreate: m.route.link,
});
v2.x
m(m.route.Link, {
href: '/path',
});
m(m.route.Link, {
selector: 'button',
href: '/path',
});
m(m.route.Link, {
selector: 'button.btn[href=/path]',
});
Změny v chybách m.request
Ve verzi v1.x m.request
parsoval chyby z JSON odpovědí a přiřazoval vlastnosti parsovaného objektu do objektu chyby. Pokud jste tedy obdrželi odpověď se stavem 403 a tělem {"code": "backoff", "timeout": 1000}
, chyba by měla dvě vlastnosti: err.code = "backoff"
a err.timeout = 1000
.
Ve verzi v2.x je celá odpověď přiřazena do vlastnosti response
objektu chyby a vlastnost code
obsahuje stavový kód. Pokud jste tedy obdrželi odpověď se stavem 403 a tělem {"code": "backoff", "timeout": 1000}
, chyba by měla dvě vlastnosti: err.response = {code: "backoff", timeout: 1000}
a err.code = 403
.
m.withAttr
odstraněno
Ve verzi v1.x mohli posluchači událostí používat oninput: m.withAttr("value", func)
a podobně. Ve verzi v2.x stačí hodnotu číst přímo z cíle události. Funkce m.withAttr
dobře fungovala se streamy, ale protože se idiom m.withAttr("value", stream)
nepoužíval zdaleka tak často jako m.withAttr("value", prop)
, ztratil m.withAttr
většinu své užitečnosti, a proto byl odstraněn.
v1.x
var value = '';
// In your view
m('input[type=text]', {
value: value(),
oninput: m.withAttr('value', function (v) {
value = v;
}),
});
// OR
var value = m.stream('');
// In your view
m('input[type=text]', {
value: value(),
oninput: m.withAttr('value', value),
});
v2.x
var value = '';
// In your view
m('input[type=text]', {
value: value,
oninput: function (ev) {
value = ev.target.value;
},
});
// OR
var value = m.stream('');
// In your view
m('input[type=text]', {
value: value(),
oninput: function (ev) {
value(ev.target.value);
},
});
m.route.prefix
Ve verzi v1.x byla m.route.prefix
funkce volaná pomocí m.route.prefix(prefix)
. Nyní je to vlastnost, kterou nastavujete pomocí m.route.prefix = prefix
.
v1.x
m.route.prefix('/root');
v2.x
m.route.prefix = '/root';
m.request
/m.jsonp
params a body
data
a useBody
byly refaktorovány do params
(parametry dotazu interpolované do URL a připojené k požadavku) a body
(tělo k odeslání v podkladovém XHR). To vám dává mnohem lepší kontrolu nad odesílaným požadavkem a umožňuje vám jak interpolovat parametry dotazu u požadavků POST
, tak vytvářet požadavky GET
s tělem.
m.jsonp
, který nemá žádné smysluplné "tělo", používá pouze params
, takže přejmenování data
na params
je pro tuto metodu dostačující.
v1.x
m.request('https://example.com/api/user/:id', {
method: 'GET',
data: { id: user.id },
});
m.request('https://example.com/api/user/create', {
method: 'POST',
data: userData,
});
v2.x
m.request('https://example.com/api/user/:id', {
method: 'GET',
params: { id: user.id },
});
m.request('https://example.com/api/user/create', {
method: 'POST',
body: userData,
});
Šablony cest
Ve verzi v1.x existovaly tři samostatné syntaxe šablon cest, které, i když byly podobné, měly 2 samostatně navržené syntaxe a 3 různé implementace. Bylo to definováno poměrně ad-hoc způsobem a parametry obecně nebyly escapovány. Nyní je vše buď zakódováno, pokud je to :key
, nebo ponecháno beze změny, pokud je to :key...
. Pokud dochází k neočekávanému zakódování, použijte :path...
. Je to tak jednoduché.
Konkrétně, jak to ovlivňuje každou metodu:
m.request
a m.jsonp
URL, m.route.set
cesty
Ve verzi v2.x jsou komponenty cest při interpolaci automaticky escapovány. Předpokládejme, že vyvoláte m.route.set("/user/:name/photos/:id", {name: user.name, id: user.id})
. Dříve, pokud měl user
hodnotu {name: "a/b", id: "c/d"}
, nastavilo by to cestu na /user/a%2Fb/photos/c/d
, ale nyní ji nastaví na /user/a%2Fb/photos/c%2Fd
. Pokud potřebujete klíč interpolovat bez escapování, použijte místo toho :key...
.
Klíče ve verzi v2.x nemohou obsahovat žádné instance .
nebo -
. Ve verzi v1.x mohly obsahovat cokoli jiného než /
.
Interpolace v inline query strings, jako v /api/search?q=:query
, se ve verzi v2.x neprovádí. Místo toho je předejte pomocí params
s příslušnými názvy klíčů, aniž byste je specifikovali v query string.
m.route
vzory cest
Klíče cest ve tvaru :key...
vracely ve verzi v1.x URL dekódované, ale ve verzi v2.x vrací URL v nezměněné podobě.
Dříve byly věci jako :key.md
chybně akceptovány, přičemž výsledná hodnota parametru byla nastavena na keymd: "..."
. To již neplatí - .md
je nyní součástí vzoru, nikoli názvu.
Pořadí volání životního cyklu
Ve verzi v1.x byly háčky životního cyklu atributů na komponentních vnodech volány před vlastními háčky životního cyklu komponenty ve všech případech. Ve verzi v2.x tomu tak je pouze pro onbeforeupdate
. Proto může být nutné váš kód upravit.
v1.x
var Comp = {
oncreate: function () {
console.log('Component oncreate');
},
view: function () {
return m('div');
},
};
m.mount(document.body, {
view: function () {
return m(Comp, {
oncreate: function () {
console.log('Attrs oncreate');
},
});
},
});
// Logs:
// Attrs oncreate
// Component oncreate
v2.x
var Comp = {
oncreate: function () {
console.log('Component oncreate');
},
view: function () {
return m('div');
},
};
m.mount(document.body, {
view: function () {
return m(Comp, {
oncreate: function () {
console.log('Attrs oncreate');
},
});
},
});
// Logs:
// Component oncreate
// Attrs oncreate
Synchronizace m.redraw
m.redraw()
ve verzi v2.x je vždy asynchronní. Můžete explicitně požádat o synchronní překreslení pomocí m.redraw.sync()
, pokud právě neprobíhá žádné jiné překreslení.
Přednost atributů selektoru
Ve verzi v1.x měly atributy selektoru přednost před atributy specifikovanými v objektu atributů. Například m("[a=b]", {a: "c"}).attrs
vracelo {a: "b"}
.
Ve verzi v2.x mají atributy specifikované v objektu atributů přednost před atributy selektoru. Například m("[a=b]", {a: "c"}).attrs
vrátí {a: "c"}
.
Je třeba poznamenat, že se jedná o návrat k chování ve verzi v0.2.x.
Normalizace potomků
Ve verzi v1.x byli potomci komponentních vnode normalizováni jako ostatní vnode. Ve verzi v2.x tomu tak již není a budete to muset odpovídajícím způsobem naplánovat. To nemá vliv na normalizaci provedenou při renderování.
m.request
hlavičky
Ve verzi v1.x Mithril.js nastavoval tyto dvě hlavičky u všech požadavků jiných než GET
, ale pouze pokud byla nastavena hodnota useBody
na true
(výchozí) a platily ostatní uvedené podmínky:
Content-Type: application/json; charset=utf-8
pro požadavky s JSON tělyAccept: application/json, text/*
pro požadavky očekávající JSON odpovědi
Ve verzi v2.x Mithril.js nastaví první hlavičku pro všechny požadavky s JSON těly, které jsou != null
, a jinak ji ve výchozím nastavení vynechá. Toto se provádí nezávisle na zvolené metodě, včetně požadavků GET
.
První ze dvou hlaviček, Content-Type
, spouští CORS preflight request, protože není CORS-safelisted request header kvůli zadanému typu obsahu, a to by mohlo zavést nové chyby v závislosti na tom, jak je CORS nakonfigurován na vašem serveru. Pokud se setkáte s problémy, můžete tuto hlavičku přepsat pomocí headers: {"Content-Type": "text/plain"}
. (Hlavička Accept
nic nespouští, takže ji nemusíte přepisovat.)
Jediné typy obsahu, které specifikace Fetch umožňuje vyhnout se kontrolám CORS preflight, jsou application/x-www-form-urlencoded
, multipart/form-data
a text/plain
. Nepovoluje nic jiného a záměrně zakazuje JSON.
Parametry dotazu v hash strings v routách
Ve verzi v1.x jste mohli specifikovat parametry dotazu pro routy jak v query string, tak v hash string, takže m.route.set("/route?foo=1&bar=2")
, m.route.set("/route?foo=1#bar=2")
a m.route.set("/route#foo=1&bar=2")
byly všechny ekvivalentní a atributy z nich extrahované by byly {foo: "1", bar: "2"}
.
Ve verzi v2.x je obsah hash strings ignorován, ale zachován. Takže atributy extrahované z každého z nich by byly tyto:
m.route.set("/route?foo=1&bar=2")
→{foo: "1", bar: "2"}
m.route.set("/route?foo=1#bar=2")
→{foo: "1"}
m.route.set("/route#foo=1&bar=2")
→{}
Je to proto, že adresy URL jako https://example.com/#!/route#key
jsou technicky neplatné podle specifikace URL a byly neplatné i podle RFC, který jí předcházel. Jejich povolení je pouze zvláštností specifikace HTML.
Zkrátka, nepoužívejte neplatné adresy URL.
Klíče
Ve verzi v1.x jste mohli volně kombinovat klíčované a neklíčované vnode. Pokud je první uzel klíčovaný, provedl se klíčovaný diff, za předpokladu, že každý prvek má klíč a jednoduše ignoroval díry, jak postupoval. Jinak se provedl iterativní diff, a pokud má uzel klíč, zkontrolovalo se, zda se nezměnil současně s kontrolou tagů a podobných věcí.
Ve verzi v2.x musí být seznamy potomků fragmentů i prvků buď všechny klíčované, nebo všechny neklíčované. Díry jsou pro účely této kontroly také považovány za neklíčované - již je neignoruje.
Pokud to potřebujete obejít, použijte idiom fragmentu obsahujícího jeden vnode, jako [m("div", {key: whatever})]
.
m.version
odstraněno
Obecně sloužila k malému užitku a vždy si ji můžete přidat zpět. Měli byste upřednostňovat detekci funkcí pro zjištění, jaké funkce jsou k dispozici, a API v2.x je navrženo tak, aby to lépe umožnilo.