v1.x'ten v2.x'e Geçiş
v2.x, v1.x ile neredeyse tamamen API uyumludur, ancak bazı uyumsuz değişiklikler bulunmaktadır.
vnode.state
'e Atama
v1.x'te, vnode.state
'i manipüle edebilir ve istediğiniz her şeyi atayabilirdiniz. v2.x'te, değiştirilmesi durumunda bir hata fırlatılır. Geçiş süreci farklılık gösterebilir. Çoğu durumda, vnode.state
referanslarını vnode.state.foo
şeklinde değiştirmek yeterli olacaktır; foo
için uygun bir ad seçebilirsiniz (örneğin, bir sayacın mevcut değeri için count
gibi).
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++;
},
},
'+'
),
]);
},
};
v1.0 ilk yayınlandığında, sınıf ve kapanış bileşenleri mevcut değildi, bu yüzden sadece vnode.tag
'den ihtiyacı olanı çekiyordu. Bu uygulama detayı, bunu yapmanıza izin veren şeydi ve bazıları buna güvenmeye başladı. Ayrıca, belgeler içindeki bazı yerlerde mümkün olduğu ima ediliyordu. Şimdi, işler farklı ve bu, bir uygulama açısından yönetmeyi biraz daha kolaylaştırıyor, çünkü state'e (durum) iki değil, sadece bir referans var.
Rota bağlantılarındaki değişiklikler
v1.x'te, yönlendirilebilen vnode üzerinde yaşam döngüsü kancaları olarak oncreate: m.route.link
ve bağlantı değişebilirse onupdate: m.route.link
kullanıyordunuz. v2.x'te artık bir m.route.Link
bileşeni kullanmalısınız. Seçici, selector:
özelliği ile belirtilebilir. Seçenekler options:
ile, devre dışı bırakma disabled:
ile yapılabilir. href:
(zorunlu) dahil diğer özellikler de doğrudan eklenebilir. selector:
'ın kendisi, m
için ilk argüman olarak geçerli herhangi bir seçiciyi içerebilir ve [href=...]
ve [disabled]
özellikleri, normal seçeneklerin yanı sıra seçicide de belirtilebilir.
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]',
});
m.request
hatalarındaki değişiklikler
v1.x'te, m.request
, JSON çağrılarından hataları ayrıştırır ve ortaya çıkan ayrıştırılmış nesnenin özelliklerini yanıta atardı. Örneğin, 403 durum kodu ve {"code": "backoff", "timeout": 1000}
içeriğine sahip bir yanıt alırsanız, hata nesnesinde err.code = "backoff"
ve err.timeout = 1000
şeklinde iki ek özellik bulunurdu.
v2.x'te, yanıt bunun yerine sonuçta bir response
özelliğine atanır ve bir code
özelliği durum kodunu içerir. Yani, 403 durumu ve {"code": "backoff", "timeout": 1000}
gövdesiyle bir yanıt aldıysanız, hataya iki özellik atanmış olurdu: err.response = {code: "backoff", timeout: 1000}
ve err.code = 403
.
m.withAttr
kaldırıldı
v1.x'te, olay dinleyicileri oninput: m.withAttr("value", func)
gibi ifadeleri kullanabiliyordu. v2.x'te, bunları doğrudan olayın hedefinden okumanız gerekir. Akışlarla iyi sinerji oluşturdu, ancak m.withAttr("value", stream)
kullanımı, m.withAttr("value", prop)
kadar yaygın olmadığı için, m.withAttr
kullanışlılığının çoğunu kaybetti ve bu nedenle kaldırıldı.
v1.x
var value = '';
// Görünümünüzde (Şablonunuzda)
m('input[type=text]', {
value: value(),
oninput: m.withAttr('value', function (v) {
value = v;
}),
});
// VEYA
var value = m.stream('');
// Görünümünüzde (Şablonunuzda)
m('input[type=text]', {
value: value(),
oninput: m.withAttr('value', value),
});
v2.x
var value = '';
// Görünümünüzde (Şablonunuzda)
m('input[type=text]', {
value: value,
oninput: function (ev) {
value = ev.target.value;
},
});
// VEYA
var value = m.stream('');
// Görünümünüzde (Şablonunuzda)
m('input[type=text]', {
value: value(),
oninput: function (ev) {
value(ev.target.value);
},
});
m.route.prefix
v1.x'te, m.route.prefix
, m.route.prefix(prefix)
ile çağrılan bir fonksiyondur. Artık m.route.prefix = prefix
aracılığıyla ayarladığınız bir özelliktir.
v1.x
m.route.prefix('/root');
v2.x
m.route.prefix = '/root';
m.request
/m.jsonp
parametreleri ve gövdesi
data
ve useBody
özellikleri, params
(URL'ye eklenen sorgu parametreleri) ve body
(XHR ile gönderilecek veri) olarak ayrıldı. Bu, gönderilen gerçek istek üzerinde çok daha iyi kontrol sağlar ve hem POST
istekleriyle sorgu parametrelerine yerleştirmenize hem de gövdeli GET
istekleri oluşturmanıza olanak tanır.
Anlamlı bir "gövdesi" olmayan m.jsonp
, yalnızca params
kullanır, bu nedenle data
'yı params
olarak yeniden adlandırmak bu yöntem için yeterlidir.
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,
});
Yol şablonları
v1.x'te, benzer olmalarına rağmen, 2 ayrı tasarlanmış sözdizimi ve 3 farklı uygulaması olan üç ayrı yol şablonu sözdizimi vardı. Oldukça geçici bir şekilde tanımlanmıştı ve parametreler genellikle güvenli hale getirilmiyordu. Şimdi, her şey ya :key
ise kodlanır, ya da :key...
ise hamdır (işlenmemiştir). Bir şeyler beklenmedik şekilde kodlanmışsa, :path...
kullanın. Bu kadar basit.
Somut olarak, bunun her yöntemi nasıl etkilediği aşağıdadır:
m.request
ve m.jsonp
URL'leri, m.route.set
yolları
v2.x'teki yol bileşenleri, yerleştirildiğinde otomatik olarak escape edilir. m.route.set("/user/:name/photos/:id", {name: user.name, id: user.id})
çağırdığınızı varsayalım. Daha önce, user
, {name: "a/b", id: "c/d"}
ise, bu rotayı /user/a%2Fb/photos/c/d
olarak ayarlardı, ancak şimdi /user/a%2Fb/photos/c%2Fd
olarak ayarlayacaktır. Bir anahtarın işlenmeden yerleştirilmesini isterseniz, bunun yerine :key...
kullanın.
v2.x'teki anahtarlar, .
veya -
örneklerini içeremez. v1.x'te, /
dışındaki her şeyi içerebilirlerdi.
/api/search?q=:query
gibi satır içi sorgu dizelerindeki yerleştirmeler, v2.x'te gerçekleştirilmez. Bunun yerine, bunları sorgu dizesinde belirtmeden, uygun anahtar adlarıyla params
aracılığıyla iletin.
m.route
rota kalıpları
:key...
biçimindeki yol anahtarları, v1.x'te URL'si çözülmüş olarak döner, ancak v2.x'te ham URL'yi döndürür.
Daha önce, :key.md
gibi şeyler hatalı bir şekilde kabul ediliyordu ve sonuçtaki parametrenin değeri keymd: "..."
olarak ayarlanıyordu. Artık durum böyle değil - .md
artık kalıbın bir parçası, adın değil.
Yaşam döngüsü çağrı sırası
v1.x'te, bileşen vnode'larındaki özelliklere ait yaşam döngüsü fonksiyonları, her zaman bileşenin kendi yaşam döngüsü fonksiyonlarından önce çalıştırılırdı. v2.x'te, bu yalnızca onbeforeupdate
için geçerlidir. Bu nedenle, kodunuzu buna göre ayarlamanız gerekebilir.
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');
},
});
},
});
// Çıktı:
// 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');
},
});
},
});
// Çıktı:
// Component oncreate
// Attrs oncreate
m.redraw
senkronizasyonu
v2.x'teki m.redraw()
her zaman asenkron çalışır. Eğer halihazırda bir yeniden çizim işlemi yoksa, m.redraw.sync()
ile senkron bir yeniden çizim tetikleyebilirsiniz.
Seçici özellik önceliği
v1.x'te, seçici özellikleri, özellikler nesnesinde belirtilen özelliklere göre öncelikliydi. Örneğin, m("[a=b]", {a: "c"}).attrs
, {a: "b"}
döndürdü.
v2.x'te, özellikler nesnesinde belirtilen özellikler, seçici özelliklerine göre önceliklidir. Örneğin, m("[a=b]", {a: "c"}).attrs
, {a: "c"}
döndürür.
Bunun teknik olarak v0.2.x davranışına geri dönmek olduğunu unutmayın.
Alt düğüm normalleştirme
v1.x'te, bileşen vnode'larının alt öğeleri de diğer vnode'lar gibi normalleştiriliyordu. v2.x'te, artık durum böyle değil ve buna göre plan yapmanız gerekecek. Bu, render üzerinde yapılan normalleştirmeyi etkilemez.
m.request
üstbilgileri
v1.x'te, Mithril.js bu iki üstbilgiyi tüm GET
olmayan isteklerde ayarladı; ancak yalnızca useBody
true
(varsayılan) olarak ayarlandığında ve diğer koşullar geçerli olduğunda:
- JSON gövdeli istekler için
Content-Type: application/json; charset=utf-8
- JSON yanıtları bekleyen istekler için
Accept: application/json, text/*
v2.x'te, Mithril.js, JSON verisi içeren tüm istekler için Content-Type
başlığını otomatik olarak ayarlar (değer null
değilse). Bu davranış, kullanılan HTTP metodundan (GET, POST vb.) bağımsızdır.
İki başlıktan ilki olan Content-Type
, belirtilen içerik türü nedeniyle CORS güvenli listesinde olmayan bir istek başlığı olmadığından bir CORS ön getirmesini tetikleyecektir ve bu, sunucunuzda CORS'un nasıl yapılandırıldığına bağlı olarak yeni hatalar ortaya çıkarabilir. Bununla ilgili sorunlarla karşılaşırsanız, headers: {"Content-Type": "text/plain"}
ileterek söz konusu başlığı geçersiz kılmanız gerekebilir. ( Accept
başlığı hiçbir şeyi tetiklemez, bu nedenle bunu geçersiz kılmanız gerekmez.)
Fetch belirtimi, CORS ön getirme kontrollerinden kaçınmasına izin verdiği tek içerik türleri application/x-www-form-urlencoded
, multipart/form-data
ve text/plain
'dir. Başka hiçbir şeye izin vermez ve kasıtlı olarak JSON'a izin vermez.
Rotalardaki hash dizelerindeki sorgu parametreleri
v1.x'te, hem sorgu dizesinde hem de hash dizesinde rotalar için sorgu parametreleri belirtebilirsiniz, bu nedenle m.route.set("/route?foo=1&bar=2")
, m.route.set("/route?foo=1#bar=2")
ve m.route.set("/route#foo=1&bar=2")
hepsi eşdeğerdi ve bunlardan çıkarılan özellikler {foo: "1", bar: "2"}
olurdu.
v2.x'te, hash dizelerinin içeriği yok sayılır, ancak korunur. Bu nedenle, her birinden çıkarılan özellikler şunlar olurdu:
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")
→{}
https://example.com/#!/route#key
gibi URL'ler, URL standardına göre geçersizdir. Bu durum, HTML standardındaki bir ayrıntıdan kaynaklanmaktadır. (HTML spesifikasyonu, spesifikasyonu takip etmek istiyorsa, en başından itibaren kimliklerin ve konum parçalarının geçerli URL parçaları olmasını gerektirmeliydi.)
Ya da kısacası, geçersiz URL'ler kullanmayı bırakın!
Anahtarlar (Keys)
v1.x'te, anahtarlı ve anahtarsız vnode'ları serbestçe karıştırmak mümkündü. Eğer listedeki ilk öğe bir anahtara sahipse, her öğenin anahtarlı olduğu varsayılır ve anahtarsız öğeler yok sayılır. Aksi takdirde, yinelemeli bir fark gerçekleştirilir ve bir düğümün bir anahtarı varsa, etiketlerin ve benzerlerinin aynı anda değişmediği kontrol edilir.
v2.x'te, hem parçaların hem de öğelerin çocuk listeleri ya tamamen anahtarlı ya da tamamen anahtarsız olmalıdır. Boşluklar da bu kontrolün amaçları doğrultusunda anahtarsız olarak kabul edilir - artık onları yok saymaz.
Bu sorunu çözmek için, tek bir vnode içeren bir parça deyimini kullanın, örneğin [m("div", {key: whatever})]
.
m.version
kaldırıldı
Genel olarak çok az işe yaradı ve her zaman kendiniz geri ekleyebilirsiniz. Hangi özelliklerin mevcut olduğunu bilmek için özellik algılamayı tercih etmelisiniz ve v2.x API'si bunu daha iyi sağlamak için tasarlanmıştır.