route(root, defaultRoute, routes)
Açıklama
Bir uygulama içinde sayfalar arasında gezinmeyi sağlar.
var Home = {
view: function () {
return 'Hoş Geldiniz';
},
};
m.route(document.body, '/home', {
'/home': Home, // `https://localhost/#!/home` adresini tanımlar
});
Her uygulama için yalnızca bir m.route
çağrısı yapabilirsiniz.
İmza
m.route(root, defaultRoute, routes)
Argüman | Tür | Gerekli | Açıklama |
---|---|---|---|
root | Element | Evet | Alt ağacın ana düğümü olacak bir DOM öğesi |
defaultRoute | String | Evet | Geçerli URL bir rotayla eşleşmezse yönlendirilecek rota. Bu, başlangıç rotası değildir. Başlangıç rotası, adres çubuğundaki URL'dir. |
routes | Object<String,Component|RouteResolver> | Evet | Anahtarları rota dizeleri, değerleri ise bileşenler veya bir RouteResolver olan bir nesne |
döner | undefined döndürür |
Statik üyeler
m.route.set
Eşleşen bir rotaya veya eşleşen rota bulunamazsa varsayılan rotaya yönlendirir. Tüm bağlama noktalarını eşzamansız olarak yeniden çizer.
m.route.set(path, params, options)
Argüman | Tür | Gerekli | Açıklama |
---|---|---|---|
path | String | Evet | Ön ek olmadan gidilecek yol adı. Yol, params değerleriyle doldurulmuş parametreler içerebilir. |
params | Object | Hayır | Yönlendirme parametreleri. Eğer path içinde yönlendirme parametreleri için yer tutucular varsa, bu nesnenin özellikleri yol dizesine yerleştirilir. |
options.replace | Boolean | Hayır | Yeni bir geçmiş girdisi oluşturulup oluşturulmayacağı veya geçerli olanın değiştirilip değiştirilmeyeceği. Varsayılan olarak false değeridir. |
options.state | Object | Hayır | Temel alınan history.pushState / history.replaceState çağrısına aktarılacak state nesnesi. Bu durum nesnesi, history.state özelliğinde kullanılabilir hale gelir ve yönlendirme parametreleri nesnesi ile birleştirilir. |
options.title | String | Hayır | Temel alınan history.pushState / history.replaceState çağrısına geçirilecek title dizesi. |
döner | undefined döndürür |
.set
'i params
ile kullanırken rotayı da tanımlamanız gerektiğini unutmayın:
var Article = {
view: function (vnode) {
return 'Bu makale ' + vnode.attrs.articleid;
},
};
m.route(document.body, {
'/article/:articleid': Article,
});
m.route.set('/article/:articleid', { articleid: 1 });
m.route.get
Ön ek olmadan, en son tam olarak çözümlenmiş yönlendirme yolunu döndürür. Eşzamansız bir rota çözüm beklerken konum çubuğunda görüntülenen yoldan farklı olabilir.
path = m.route.get()
Argüman | Tür | Gerekli | Açıklama |
---|---|---|---|
döner | String | Son tam olarak çözümlenmiş yolu döndürür |
m.route.prefix
Bir yönlendirici ön eki tanımlar. Yönlendirici ön eki, yönlendirici tarafından kullanılan temel stratejiyi belirleyen URL'nin bir parçasıdır.
m.route.prefix = prefix
Argüman | Tür | Gerekli | Açıklama |
---|---|---|---|
prefix | String | Evet | Mithril tarafından kullanılan temel yönlendirme stratejisini kontrol eden ön ek. |
Bu basit bir özelliktir; bu nedenle hem okunabilir hem de yazılabilir.
m.route.Link
Bu bileşen, dinamik bir yönlendirilmiş bağlantı oluşturur. Temel işlevi, yerel href
değerlerini rota ön ekini hesaba katarak dönüştürülmüş a
bağlantıları oluşturmaktır.
m(m.route.Link, { href: '/foo' }, 'foo');
// m.route.prefix varsayılan stratejiden değişmediği sürece, şuna dönüştürülür:
// <a href="#!/foo">foo</a>
Bağlantılar bir dizi özel özniteliği kabul eder:
selector
,m
fonksiyonuna ilk argüman olarak neyin aktarılacağını belirtir:a
olmayan öğeler de dahil olmak üzere herhangi bir seçici kullanılabilir.params
&options
,m.route.set
içinde tanımlananlarla aynı adlara sahip argümanlardır.disabled
,true
ise, yönlendirme davranışını ve herhangi bir bağlıonclick
işleyicisini devre dışı bırakır ve erişilebilirlik ipuçları için birdata-disabled="true"
özniteliği ekler; öğe bira
ise,href
kaldırılır.
Yönlendirme davranışı, olay dinleme API'si ile engellenemez; bunun yerine disabled
özelliğini kullanmalısınız.
m(
m.route.Link,
{
href: '/foo',
selector: 'button.large',
disabled: true,
params: { key: 'value' },
options: { replace: true },
},
'bağlantı adı'
);
// Şuna dönüştürülür:
// <button disabled aria-disabled="true" class="large">bağlantı adı</button>
vnode = m(m.route.Link, attributes, children)
Argüman | Tür | Gerekli | Açıklama |
---|---|---|---|
attributes.href | Object | Evet | Gidilecek hedef rota. |
attributes.disabled | Boolean | Hayır | Öğeyi erişilebilirlik standartlarına uygun şekilde devre dışı bırakır. |
attributes.selector | String|Object|Function | Hayır | m için bir seçici, varsayılan olarak "a" olur. |
attributes.options | Object | Hayır | m.route.set öğesine geçirilen options 'ı ayarlar. |
attributes.params | Object | Hayır | m.route.set öğesine geçirilen params 'ı ayarlar. |
attributes | Object | Hayır | m 'ye iletilecek diğer öznitelikler. |
children | Array<Vnode>|String|Number|Boolean | Hayır | Bu bağlantı için kullanılacak alt vnode'lar. |
döner | Vnode | Bir vnode. |
m.route.param
Son tam olarak çözümlenmiş rotadan bir rota parametresi alır. Rota parametresi, bir anahtar-değer çiftidir. Rota parametreleri birkaç farklı yerden gelebilir:
- rota enterpolasyonları (örneğin, bir rota
/users/:id
ise ve/users/1
olarak çözümlenirse, rota parametresinin birid
anahtarı ve"1"
değeri vardır) - yönlendirici sorgu dizeleri (örneğin, yol
/users?page=1
ise, rota parametresinin birpage
anahtarı ve"1"
değeri vardır) history.state
(örneğin,history.state
{foo: "bar"}
ise, rota parametresinin birfoo
anahtarı ve"bar"
değeri vardır)
value = m.route.param(key)
Argüman | Tür | Gerekli | Açıklama |
---|---|---|---|
key | String | Hayır | Bir rota parametre adı (örneğin, /users/:id rotasında id veya /users/1?page=3 yolunda page veya history.state içinde bir anahtar) |
döner | String|Object | Belirtilen anahtar için bir değer döndürür. Bir anahtar belirtilmezse, tüm enterpolasyon anahtarlarını içeren bir nesne döndürür |
Bir RouteResolver
'ın onmatch
fonksiyonunda, yeni rota henüz tam olarak çözümlenmediğinden m.route.param()
fonksiyonunun, eğer varsa, önceki rotanın parametrelerini döndüreceğini unutmayın. onmatch
, yeni rotanın parametrelerini bir argüman olarak alır.
m.route.SKIP
Bir rota çözümleyicisinin onmatch
öğesinden bir sonraki rotaya atlamak için döndürülebilen özel bir değer.
RouteResolver
RouteResolver
, bir onmatch
yöntemi ve/veya bir render
yöntemi içeren bileşen olmayan bir nesnedir. Her iki yöntem de isteğe bağlıdır, ancak en az biri mevcut olmalıdır.
Bir nesne bir bileşen olarak algılanabiliyorsa (view
yönteminin varlığıyla veya bir function
/class
olmasıyla), onmatch
veya render
yöntemleri olsa bile bu şekilde ele alınacaktır. Bir RouteResolver
bir bileşen olmadığından, yaşam döngüsü yöntemleri yoktur.
Genel bir kural olarak, RouteResolver
'lar m.route
çağrısının yapıldığı dosya ile aynı dosyada bulunmalıdır; bileşen tanımları ise kendi modüllerinde yer almalıdır.
routeResolver = {onmatch, render}
Eğer Home
adında bir bileşeniniz varsa, bileşenleri kullanırken bu rota çözümleyicisini Home
bileşeni için özel bir kolaylık (syntactic sugar) olarak düşünebilirsiniz:
var routeResolver = {
onmatch: function () {
return Home;
},
render: function (vnode) {
return [vnode];
},
};
routeResolver.onmatch
onmatch
fonksiyonu, yönlendiricinin oluşturması gereken bir bileşeni bulması gerektiğinde çağrılır. Yönlendirici yolundaki değişiklikler için yalnızca bir kez çağrılır, aynı yolda kalındığı sürece sonraki yeniden çizimlerde çağrılmaz. Bir bileşen başlatılmadan önce mantık yürütmek için kullanılabilir (örneğin, kimlik doğrulama mantığı, veri ön yükleme, yönlendirme analizi izleme vb.)
Bu yöntem ayrıca hangi bileşenin oluşturulacağını eşzamansız olarak tanımlamanıza olanak tanır, bu da onu kod bölme ve eşzamansız modül yükleme için uygun hale getirir. Bir bileşeni eşzamansız olarak yüklemek için, o bileşene çözümlenen bir promise
döndürün.
onmatch
hakkında daha fazla bilgi için gelişmiş bileşen çözümü bölümüne bakın.
routeResolver.onmatch(args, requestedPath, route)
Argüman | Tür | Açıklama |
---|---|---|
args | Object | Yönlendirme parametreleri |
requestedPath | String | Son yönlendirme eylemi tarafından istenen, yerleştirilmiş yönlendirme parametre değerleri de dahil olmak üzere, ancak ön ek olmadan yönlendirici yolu. onmatch çağrıldığında, bu yol için çözümleme tamamlanmamıştır ve m.route.get() hala önceki yolu döndürür. |
route | String | Son yönlendirme eylemi tarafından istenen, yerleştirilmiş yönlendirme parametre değerleri hariç yönlendirici yolu |
döner | Component|\Promise<Component>|undefined | Bir bileşen veya bir bileşene çözümlenen bir promise döndürür |
onmatch
bir bileşen veya bir bileşene çözümlenen bir promise
döndürürse, bu bileşen RouteResolver
'ın render
yöntemindeki ilk argüman için vnode.tag
olarak kullanılır. Aksi takdirde, vnode.tag
"div"
olarak ayarlanır. Benzer şekilde, onmatch
yöntemi atlanırsa, vnode.tag
da "div"
olur.
Eğer onmatch
fonksiyonu reddedilen bir promise
döndürürse, yönlendirici defaultRoute
olarak belirlenen yola geri yönlendirir. Döndürmeden önce promise
zincirinde .catch
çağırarak bu davranışı geçersiz kılabilirsiniz.
routeResolver.render
render
fonksiyonu, eşleşen bir rota için her yeniden çizim işleminde çağrılır. Bileşenlerdeki view
fonksiyonuna benzer ve bileşen kompozisyonunu kolaylaştırmak amacıyla kullanılır. Ayrıca, Mithril.js'nin tüm alt ağacı değiştirme normal davranışından kaçınmanızı sağlar.
vnode = routeResolver.render(vnode)
Argüman | Tür | Açıklama |
---|---|---|
vnode | Object | Öznitelikler nesnesi yönlendirme parametreleri içeren bir vnode. onmatch bir bileşen veya bir bileşene çözümlenen bir promise döndürmezse, vnode 'un tag alanı varsayılan olarak "div" olur |
vnode.attrs | Object | URL parametre değerlerini içeren bir harita (map) |
döner | Array<Vnode>|Vnode | Oluşturulacak vnode'lar |
vnode
parametresi sadece m(Component, m.route.param())
'dir, burada Component
rotanın çözümlenmiş bileşenidir (routeResolver.onmatch
'tan sonra) ve m.route.param()
burada belgelendiği gibidir. Bu fonksiyonu atladığınızda, varsayılan dönüş değeri [vnode]
olur ve bu değer bir bölüm içine sarılır, böylece anahtar parametrelerini kullanabilirsiniz. Bir :key
parametresiyle birleştirildiğinde, tek elemanlı anahtarlı bir bölüm haline gelir, çünkü sonunda [m(Component, {key: m.route.param("key"), ...})]
gibi bir şeye dönüştürülür.
Nasıl çalışır
Yönlendirme, Tek Sayfa Uygulaması (SPA) geliştirmeye olanak sağlayan bir sistemdir; yani, tarayıcıda tam bir sayfa yenilemesi yapmadan bir "sayfadan" diğerine geçebilen uygulamalar.
Her bir sayfayı ayrı ayrı yer imlerine ekleme ve uygulamanın tarayıcı geçmişi aracılığıyla gezinme olanağını koruyarak kesintisiz bir gezinme deneyimi sunar.
Sayfa yenilemesi gerektirmeyen yönlendirme, kısmen history.pushState
API'si sayesinde mümkün olmaktadır.
Bu API sayesinde, bir sayfa yüklendikten sonra tarayıcıda görünen URL'yi programatik olarak değiştirmek mümkündür; ancak, uygulamanın soğuk bir başlangıçtan (örneğin, yeni bir sekme açıldığında) herhangi bir URL'ye gidildiğinde doğru içeriği göstereceğinden emin olmak geliştiricinin sorumluluğundadır.
Yönlendirme stratejileri
Yönlendirme stratejisi, bir kütüphanenin yönlendirme işlemini nasıl gerçekleştireceğini tanımlar. Bir SPA yönlendirme sistemini uygulamak için kullanılabilecek üç genel strateji vardır ve her birinin farklı uyarıları vardır:
m.route.prefix = '#!'
(varsayılan) – URL'nin parça tanımlayıcısı (diğer adıyla hash) bölümünü kullanma. Bu stratejiyi kullanan bir URL tipik olarakhttps://localhost/#!/page1
gibi görünür.m.route.prefix = '?'
– Sorgu dizisi (query string) kullanma. Bu stratejiyi kullanan bir URL tipik olarakhttps://localhost/?/page1
gibi görünür.m.route.prefix = ''
– Yol adını (pathname) kullanma. Bu stratejiyi kullanan bir URL tipik olarakhttps://localhost/page1
gibi görünür.
Karma (hash) stratejisini kullanmak, history.pushState
özelliğini desteklemeyen tarayıcılarda bile çalışmayı garanti eder, çünkü bu durumda onhashchange
olayını kullanmaya geri dönebilir. Hash'leri tamamen yerel tutmak istiyorsanız bu stratejiyi kullanın.
Sorgu dizisi (query string) stratejisi, sunucu tarafında algılama yapılmasına olanak tanır, ancak URL'de normal bir yol gibi görünmez. Sunucu tarafında sabitlenmiş bağlantıları desteklemek ve potansiyel olarak algılamak istiyorsanız ve yol adı stratejisini desteklemek için gerekli değişiklikleri yapamıyorsanız (Apache kullanıyorsanız ve .htaccess
dosyanızı değiştiremiyorsanız gibi) bu stratejiyi kullanın.
Yol adı (pathname) stratejisi, en temiz görünümlü URL'leri oluşturur; ancak, sunucunun uygulamanın yönlendirme yapabileceği her bir URL için tek sayfa uygulaması (SPA) kodunu sunacak şekilde yapılandırılmasını gerektirir. Daha temiz görünen URL'ler istiyorsanız bu stratejiyi kullanın.
Karma (hash) stratejisini kullanan tek sayfa uygulamaları (SPA), karmayı bir yönlendirme mekanizması olarak kullandıklarını ve sayfa içi bağlantılara (anchor links) gitmek için kullanmadıklarını belirtmek amacıyla genellikle karmadan sonra bir ünlem işareti (!) kullanma alışkanlığına sahiptir. #!
dizesi bir hashbang olarak bilinir.
Varsayılan strateji hashbang'i kullanır.
Tipik kullanım
Genellikle, rotaları belirli bileşenlere bağlamak için birkaç bileşen oluşturmanız gerekir:
var Home = {
view: function () {
return [m(Menu), m('h1', 'Ana Sayfa')];
},
};
var Page1 = {
view: function () {
return [m(Menu), m('h1', 'Sayfa 1')];
},
};
Yukarıdaki örnekte, iki bileşen vardır: Home
ve Page1
. Her biri bir menü ve biraz metin içerir. Menü, tekrarı önlemek için bir bileşen olarak tanımlanır:
var Menu = {
view: function () {
return m('nav', [
m(m.route.Link, { href: '/' }, 'Ana Sayfa'),
m(m.route.Link, { href: '/page1' }, 'Sayfa 1'),
]);
},
};
Şimdi rotaları tanımlayabilir ve bileşenlerimizi onlara eşleyebiliriz:
m.route(document.body, '/', {
'/': Home,
'/page1': Page1,
});
Burada iki rota belirtiyoruz: /
ve /page1
. Kullanıcı her URL'ye gittiğinde ilgili bileşenlerini oluşturur.
Farklı rotalara gitme
Yukarıdaki örnekte, Menu
bileşeni içinde iki adet m.route.Link
bulunmaktadır. Bu, varsayılan olarak bir <a>
etiketi oluşturur ve kullanıcının bu etikete tıkladığında uygulamanın başka bir rotasına gitmesini sağlar. Sunucuya istek göndermez, sadece uygulama içinde (yerel olarak) yönlendirme yapar.
Ayrıca, m.route.set(route)
aracılığıyla programlı olarak da gidebilirsiniz. Örneğin, m.route.set("/page1")
.
Rotalar arasında gezinme yaparken, yönlendirici ön eki otomatik olarak yönetilir.
Yani, Mithril.js rotalarını tanımlarken, hem m.route.set
fonksiyonunda hem de m.route.Link
bileşeninde hashbang #!
'i (veya m.route.prefix
ile ayarladığınız herhangi bir ön eki) kullanmayın.
Sadece belirli bir bölümü güncellemek istiyorsanız, render fonksiyonunu kullanan bir rota çözümleyici kullanın.
Yönlendirme parametreleri
Bazen bir rotada değişken bir kimliğe veya benzer verilere sahip olmak isteriz, ancak mümkün olan her kimlik için ayrı bir rota belirtmek istemeyiz. Bu amaca ulaşmak için Mithril.js, parametrik rotaları destekler:
var Edit = {
view: function (vnode) {
return [m(Menu), m('h1', vnode.attrs.id + " düzenleniyor")];
},
};
m.route(document.body, '/edit/1', {
'/edit/:id': Edit,
});
Yukarıdaki örnekte, bir /edit/:id
rotası tanımladık. Bu, /edit/
ile başlayan ve ardından bazı verilerle (örneğin, /edit/1
, edit/234
vb.) takip edilen herhangi bir URL ile eşleşen dinamik bir rota oluşturur. id
değeri, daha sonra bileşenin vnode
nesnesinin bir özelliği olarak atanır (vnode.attrs.id
).
Bir rotada birden fazla argümana sahip olmak mümkündür, örneğin /edit/:projectID/:userID
, bileşenin vnode
öznitelikleri nesnesinde projectID
ve userID
özelliklerini verir.
Anahtar parametresi
Bir kullanıcı parametreli bir rotadan farklı bir parametreye sahip aynı rotaya gittiğinde (örneğin, bir /page/:id
rotası verildiğinde /page/1
'den /page/2
'ye gitmek), her iki rota da aynı bileşene çözümlendiğinden bileşen sıfırdan yeniden oluşturulmaz ve bu da sanal DOM yerinde farklılığına neden olur. Bunun, oninit
/oncreate
yerine onupdate
kancasını tetikleme gibi bir yan etkisi vardır. Ancak, bir geliştiricinin bileşenin yeniden oluşturulmasını rota değişikliği olayıyla senkronize etmek istemesi nispeten yaygındır.
Bunu başarmak için, rota parametreleştirmesini anahtarlarla çok uygun bir desen için birleştirmek mümkündür:
m.route(document.body, '/edit/1', {
'/edit/:key': Edit,
});
Bu, rotanın kök bileşeni için oluşturulan vnode
nesnesinin key
adında bir rota parametresine sahip olduğu anlamına gelir. Rota parametreleri, vnode
nesnesinin attrs
özelliği içinde saklanır. Bu nedenle, bir sayfadan diğerine geçiş yapıldığında key
değeri değişir ve bu da bileşenin sıfırdan yeniden oluşturulmasına yol açar (çünkü anahtar, sanal DOM motoruna eski ve yeni bileşenlerin farklı olduğunu belirtir).
Yeniden yüklendiklerinde kendilerini tekrar oluşturan bileşenler oluşturmak için bu fikri daha da ileri götürebilirsiniz:
m.route.set(m.route.get(), {key: Date.now()})
Hatta URL'yi değiştirmeden yeniden yüklenebilir bileşenler oluşturmak için geçmiş durumu özelliğini kullanabilirsiniz:
m.route.set(m.route.get(), null, {state: {key: Date.now()}})
Anahtar parametresinin yalnızca bileşen rotaları için çalıştığını unutmayın. Eğer bir rota çözümleyici kullanıyorsanız, aynı sonucu elde etmek için key: m.route.param("key")
ifadesini kullanarak tek elemanlı anahtarlı bir bölüm oluşturmanız gerekir.
Değişken rotalar
Değişken rotalara, yani slash karakterleri içeren URL yol adları içeren bir argümana sahip bir rotaya sahip olmak da mümkündür:
m.route(document.body, '/edit/pictures/image.jpg', {
'/edit/:file...': Edit,
});
404'leri işleme
İzomorfik (isomorphic) / evrensel (universal) JavaScript uygulamalarında, bir URL parametresi ve değişken bir rota bir araya getirilerek özel bir 404 hata sayfası göstermek oldukça kullanışlıdır.
404 Bulunamadı (Not Found) hatası oluştuğunda, sunucu özel bir hata sayfasını istemciye gönderir. Mithril.js yüklendiğinde, istemciyi varsayılan rotaya yönlendirecektir çünkü sunucu bu rotayı tanımayacaktır.
m.route(document.body, '/', {
'/': homeComponent,
// [...]
'/:404...': errorPageComponent,
});
Geçmiş durumu
Kullanıcıların gezinme deneyimini geliştirmek amacıyla, altta yatan history.pushState
API'sinden en iyi şekilde yararlanmak mümkündür.
Örneğin, bir uygulama, kullanıcı bir sayfadan ayrılırken büyük bir formun durumunu "hatırlayabilir"; böylece kullanıcı tarayıcıda geri düğmesine bastığında, boş bir form yerine daha önce doldurulmuş bir formla karşılaşır.
Örneğin, şöyle bir form oluşturabilirsiniz:
var state = {
term: '',
search: function () {
// bu rota için durumu kaydet
// bu, `history.replaceState({term: state.term}, null, location.href)` ile eşdeğerdir
m.route.set(m.route.get(), null, {
replace: true,
state: { term: state.term },
});
// sayfadan ayrıl
location.href = 'https://google.com/?q=' + state.term;
},
};
var Form = {
oninit: function (vnode) {
state.term = vnode.attrs.term||''; // kullanıcı tarayıcının geri tuşuna basarsa `history.state` özelliğinden doldurulur
},
view: function () {
return m('form', [
m("input[placeholder='Ara']", {
oninput: function (e) {
state.term = e.target.value;
},
value: state.term,
}),
m('button', { onclick: state.search }, 'Ara'),
]);
},
};
m.route(document.body, '/', {
'/': Form,
});
Bu sayede, kullanıcı bir arama yaptıktan sonra uygulamaya geri dönmek için geri düğmesine basarsa, arama kutusu hala arama terimiyle dolu olacaktır. Bu yöntem, büyük formlar ve kullanıcıların kalıcı olmayan verileri tekrar tekrar girmesini gerektiren diğer uygulamalarda kullanıcı deneyimini önemli ölçüde iyileştirebilir.
Yönlendirici ön ekini değiştirme
Yönlendirici ön eki, yönlendiricinin kullandığı temel stratejiyi belirleyen URL'nin bir bölümüdür.
// yol adı stratejisine ayarla
m.route.prefix = '';
// sorgu dizesi stratejisine ayarla
m.route.prefix = '?';
// ünlem işareti olmadan hash olarak ayarla
m.route.prefix = '#';
// kök dizin olmayan bir URL'de yol adı stratejisine ayarla
// örneğin, uygulama `https://localhost/my-app` altında yaşıyorsa ve başka bir şey
// `https://localhost` altında yaşıyor
m.route.prefix = '/my-app';
Gelişmiş Bileşen Çözümleme
Bir bileşeni bir rotaya eşlemek yerine, bir RouteResolver
nesnesi belirtebilirsiniz. Bir RouteResolver
nesnesi, bir onmatch()
ve/veya bir render()
metodu içerir. Her iki metot da isteğe bağlıdır, ancak en az birinin bulunması gerekir.
m.route(document.body, '/', {
'/': {
onmatch: function (args, requestedPath, route) {
return Home;
},
render: function (vnode) {
return vnode; // (m(Home)'a eşdeğer)
},
},
});
RouteResolver
lar, çeşitli gelişmiş yönlendirme senaryolarında kullanışlıdır.
Bir Düzen Bileşenini Sarmalama
Genellikle, yönlendirilen bileşenlerin tamamını veya çoğunu yeniden kullanılabilir bir şablon içinde sarmalamak istenir. Bunu yapmak için, öncelikle farklı bileşenleri saracak ortak işaretlemeyi içeren bir bileşen oluşturmanız gerekir:
var Layout = {
view: function (vnode) {
return m('.layout', vnode.children);
},
};
Yukarıdaki örnekte, düzen yalnızca bileşene iletilen çocukları içeren bir <div class="layout">
'tan oluşur, ancak gerçek bir senaryoda gerektiği kadar karmaşık olabilir.
Düzeni sarmalamanın bir yolu, rotalar haritasında anonim bir bileşen tanımlamaktır:
// örnek 1
m.route(document.body, '/', {
'/': {
view: function () {
return m(Layout, m(Home));
},
},
'/form': {
view: function () {
return m(Layout, m(Form));
},
},
});
Ancak, en üst düzey bileşen anonim bir bileşen olduğundan, /
rotasından /form
rotasına (veya tam tersi) geçmek, anonim bileşeni yok edecek ve DOM yapısını sıfırdan yeniden oluşturacaktır. Layout
bileşeninde yaşam döngüsü metotları tanımlanmışsa, oninit
ve oncreate
kancaları her rota değişikliğinde tetiklenir. Uygulamaya bağlı olarak, bu istenebilir veya istenmeyebilir.
Layout
bileşeninin sıfırdan yeniden oluşturulmak yerine karşılaştırılmasını ve korunmasını tercih ederseniz, bunun yerine kök nesne olarak bir RouteResolver
kullanmalısınız:
// örnek 2
m.route(document.body, '/', {
'/': {
render: function () {
return m(Layout, m(Home));
},
},
'/form': {
render: function () {
return m(Layout, m(Form));
},
},
});
Bu durumda, Layout
bileşeninde oninit
ve oncreate
yaşam döngüsü metotları varsa, yalnızca ilk rota değişikliğinde tetikleneceklerini unutmayın (tüm rotaların aynı düzeni kullandığı varsayılarak).
İki örnek arasındaki farkı netleştirmek için, örnek 1 bu kod ile eşdeğerdir:
// işlevsel olarak örnek 1'e eşdeğer
var Anon1 = {
view: function () {
return m(Layout, m(Home));
},
};
var Anon2 = {
view: function () {
return m(Layout, m(Form));
},
};
m.route(document.body, '/', {
'/': {
render: function () {
return m(Anon1);
},
},
'/form': {
render: function () {
return m(Anon2);
},
},
});
Anon1
ve Anon2
farklı bileşenler olduğundan, alt ağaçları (Layout
dahil) sıfırdan yeniden oluşturulur. Bileşenler doğrudan bir RouteResolver
olmadan kullanıldığında da bu durum geçerlidir.
Örnek 2'de, Layout
her iki rotada da en üst düzey bileşen olduğundan, Layout
bileşeninin DOM yapısı karşılaştırılır (yani, herhangi bir değişiklik yoksa sağlam bırakılır) ve yalnızca Home
'dan Form
'a geçiş, DOM'un o bölümünün yeniden oluşturulmasını tetikler.
Yönlendirme (Redirection)
RouteResolver
'ın onmatch
kancası, bir rotadaki en üst düzey bileşen başlatılmadan önce işlem yapmak için kullanılabilir. Mithril'in m.route.set()
veya tarayıcının history
API'sini kullanabilirsiniz. history
API ile yönlendirirken, onmatch
kancası, eşleşen rotanın çözümlenmesini önlemek için asla çözümlenmeyen bir Promise
döndürmelidir. m.route.set()
, eşleşen rotanın çözümlenmesini dahili olarak iptal eder, bu nedenle bununla gerekli değildir.
Örnek: Kimlik Doğrulama
Aşağıdaki örnek, kullanıcıların oturum açmadıkları sürece /secret
sayfasını görmelerini engelleyen bir oturum açma duvarının nasıl oluşturulacağını gösterir.
var isLoggedIn = false;
var Login = {
view: function () {
return m('form', [
m(
'button[type=button]',
{
onclick: function () {
isLoggedIn = true;
m.route.set('/secret');
},
},
'Login'
),
]);
},
};
m.route(document.body, '/secret', {
'/secret': {
onmatch: function () {
if (!isLoggedIn) m.route.set('/login');
else return Home;
},
},
'/login': Login,
});
Uygulama yüklendiğinde, onmatch
çağrılır ve isLoggedIn
false
olduğundan, uygulama /login
'e yönlendirilir. Kullanıcı oturum açma düğmesine bastıktan sonra, isLoggedIn
true
olarak ayarlanır ve uygulama /secret
'e yönlendirilir. onmatch
kancası bir kez daha çalışır ve isLoggedIn
bu sefer true
olduğundan, uygulama Home
bileşenini oluşturur.
Basitlik adına, yukarıdaki örnekte, kullanıcının oturum açmış durumu genel bir değişkende tutulur ve bu durum yalnızca kullanıcı oturum açma düğmesini tıkladığında değiştirilir. Gerçek bir uygulamada, bir kullanıcının uygun oturum açma kimlik bilgilerini sağlaması gerekir ve oturum açma düğmesini tıklamak, kullanıcıyı doğrulamak için bir sunucuya bir istek gönderir:
var Auth = {
username: '',
password: '',
setUsername: function (value) {
Auth.username = value;
},
setPassword: function (value) {
Auth.password = value;
},
login: function () {
m.request({
url: '/api/v1/auth',
params: { username: Auth.username, password: Auth.password },
}).then(function (data) {
localStorage.setItem('auth-token', data.token);
m.route.set('/secret');
});
},
};
var Login = {
view: function () {
return m('form', [
m('input[type=text]', {
oninput: function (e) {
Auth.setUsername(e.target.value);
},
value: Auth.username,
}),
m('input[type=password]', {
oninput: function (e) {
Auth.setPassword(e.target.value);
},
value: Auth.password,
}),
m('button[type=button]', { onclick: Auth.login }, 'Login'),
]);
},
};
m.route(document.body, '/secret', {
'/secret': {
onmatch: function () {
if (!localStorage.getItem('auth-token')) m.route.set('/login');
else return Home;
},
},
'/login': Login,
});
Verileri Önceden Yükleme
Tipik olarak, bir bileşen başlatıldığında veri yükleyebilir. Bu şekilde veri yüklemek, bileşeni iki kez çizer. İlk oluşturma geçişi yönlendirme sırasında gerçekleşir ve ikincisi istek tamamlandıktan sonra tetiklenir. loadUsers()
'ın bir Promise
döndürdüğünü, ancak oninit
tarafından döndürülen herhangi bir Promise
'in şu anda yoksayıldığını unutmayın. İkinci oluşturma geçişi, m.request
için background
seçeneğinden gelir.
var state = {
users: [],
loadUsers: function () {
return m.request('/api/v1/users').then(function (users) {
state.users = users;
});
},
};
m.route(document.body, '/user/list', {
'/user/list': {
oninit: state.loadUsers,
view: function () {
return state.users.length > 0
? state.users.map(function (user) {
return m('div', user.id);
})
: 'loading';
},
},
});
Yukarıdaki örnekte, ilk oluşturmada, istek tamamlanmadan önce state.users
boş bir dizi olduğundan, kullanıcı arayüzü "loading"
görüntüler. Ardından, veriler kullanılabilir olduğunda, kullanıcı arayüzü yeniden çizilir ve bir kullanıcı ID'lerinin listesi gösterilir.
RouteResolver
lar, arayüzdeki titreşimi engellemek ve böylece bir yükleme göstergesine ihtiyaç duymadan geçmek için bir bileşeni oluşturmadan önce verileri önceden yüklemek için bir mekanizma olarak kullanılabilir:
var state = {
users: [],
loadUsers: function () {
return m.request('/api/v1/users').then(function (users) {
state.users = users;
});
},
};
m.route(document.body, '/user/list', {
'/user/list': {
onmatch: state.loadUsers,
render: function () {
return state.users.map(function (user) {
return m('div', user.id);
});
},
},
});
Yukarıda, render
yalnızca istek tamamlandıktan sonra çalışır ve üçlü koşul operatörünü gereksiz kılar.
Kod Bölme (Code Splitting)
Büyük bir uygulamada, her rota için kodu önceden değil, talep üzerine indirmek istenebilir. Kod tabanını bu şekilde bölmek, kod parçalama veya tembel yükleme olarak bilinir. Mithril.js'de, bu onmatch
kancasından bir Promise
döndürülerek gerçekleştirilebilir:
En temel biçiminde, aşağıdakiler yapılabilir:
// Home.js
module.export = {
view: function () {
return [m(Menu), m('h1', 'Home')];
},
};
// index.js
function load(file) {
return m.request({
method: 'GET',
url: file,
extract: function (xhr) {
return new Function(
'var module = {};' + xhr.responseText + ';return module.exports;'
);
},
});
}
m.route(document.body, '/', {
'/': {
onmatch: function () {
return load('Home.js');
},
},
});
Ancak, gerçekçi olarak, bunun bir üretim ölçeğinde çalışması için, Home.js
modülünün tüm bağımlılıklarını nihayetinde sunucu tarafından sunulan dosyaya paketlemeniz gerekir.
Neyse ki, modülleri tembel yükleme için paketleme işini kolaylaştıran bir dizi araç vardır. İşte birçok paketleyici tarafından desteklenen yerel dinamik import(...)
kullanan bir örnek:
m.route(document.body, '/', {
'/': {
onmatch: function () {
return import('./Home.js');
},
},
});
Tipli Rotalar
Bazı gelişmiş yönlendirme senaryolarında, bir değeri sadece yol ile değil, örneğin sayısal bir ID ile de kısıtlamak isteyebilirsiniz. Bir rotadan m.route.SKIP
döndürerek bunu oldukça kolay bir şekilde yapabilirsiniz.
m.route(document.body, '/', {
'/view/:id': {
onmatch: function (args) {
if (!/^\d+$/.test(args.id)) return m.route.SKIP;
return ItemView;
},
},
'/view/:name': UserView,
});
Gizli Rotalar
Nadir durumlarda, bazı kullanıcılar için belirli rotaları gizlemek isteyebilirsiniz, ancak hepsi için değil. Örneğin, bir kullanıcının belirli bir kullanıcıyı görüntülemesi yasaklanabilir ve bir izin hatası göstermek yerine, bunun var olmadığını varsaymak ve bunun yerine bir 404 görünümüne yönlendirmek istersiniz. Bu durumda, rotanın var olmadığını varsaymak için m.route.SKIP
kullanabilirsiniz.
m.route(document.body, '/', {
'/user/:id': {
onmatch: function (args) {
return Model.checkViewable(args.id).then(function (viewable) {
return viewable ? UserView : m.route.SKIP;
});
},
},
'/:404...': PageNotFound,
});
Rota İptali / Engelleme
RouteResolver
onmatch
, asla çözümlenmeyen bir Promise
döndürerek rota çözümlemesini engelleyebilir. Bu, tekrarlanan rota çözümleme denemelerini tespit etmek ve bunları iptal etmek için kullanılabilir.
m.route(document.body, '/', {
'/': {
onmatch: function (args, requestedPath) {
if (m.route.get() === requestedPath) return new Promise(function () {});
},
},
});
Harici Entegrasyon
Belirli durumlarda, React gibi başka bir çerçeveyle birlikte çalışmanız gerekebilir. İşte bunu nasıl yapacağınız:
- Tüm rotalarınızı normalde
m.route
kullanarak tanımlayın, ancak yalnızca bir kez kullandığınızdan emin olun. Birden çok rota noktası desteklenmez. - Yönlendirme aboneliklerini kaldırmak için,
m.route(root, ...)
fonksiyonunda kullandığınız aynı kökü kullanarakm.mount(root, null)
fonksiyonunu kullanın.m.route
fonksiyonu, her şeyi bağlamak için dahili olarakm.mount
fonksiyonunu kullandığından, bu sihirli bir işlem değildir.
İşte React ile bir örnek:
class Child extends React.Component {
constructor(props) {
super(props);
this.root = React.createRef();
}
componentDidMount() {
m.route(this.root, '/', {
// ...
});
}
componentDidUnmount() {
m.mount(this.root, null);
}
render() {
return <div ref={this.root} />;
}
}
Ve işte Vue ile kabaca eşdeğeri:
<div ref="root"></div>
Vue.component('my-child', {
template: `<div ref="root"></div>`,
mounted: function () {
m.route(this.$refs.root, '/', {
// ...
});
},
destroyed: function () {
m.mount(this.$refs.root, null);
},
});