Skip to content
Mithril.js 2
Main Navigation PrzewodnikAPI

Polski

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Türkçe
čeština
magyar

Polski

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Türkçe
čeština
magyar

Wygląd

Sidebar Navigation

Pierwsze kroki

Instalacja

Prosta aplikacja

Zasoby

JSX

ES6+ na starszych przeglądarkach

Animacje

Testowanie

Przykłady

Integracja z zewnętrznymi bibliotekami

Obsługa ścieżek

Kluczowe koncepcje

Węzły Virtual DOM

Komponenty

Metody cyklu życia

Klucze

System automatycznego odświeżania

Różne

Porównanie frameworków

Migracja z v1.x

Migracja z wersji 0.2.x

API

Na tej stronie

Migracja z v1.x ​

Wersja 2.x jest w dużej mierze kompatybilna z API wersji 1.x, ale wprowadza pewne zmiany powodujące niezgodność wsteczną (breaking changes).

Przypisywanie do vnode.state ​

W wersji 1.x można było manipulować vnode.state i przypisywać do niego dowolne wartości. W wersji 2.x próba modyfikacji spowoduje błąd. Migracja zależy od konkretnego przypadku użycia, ale w większości sytuacji wystarczy zmienić odwołania z vnode.state na vnode.state.foo, wybierając odpowiednią nazwę dla foo (np. count, jeśli reprezentuje aktualną wartość licznika).

v1.x ​

javascript
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 ​

javascript
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++;
          },
        },
        '+'
      ),
    ]);
  },
};

W początkowych wersjach v1.0 komponenty klasowe i oparte na domknięciach nie istniały, więc dane pobierano z vnode.tag. Ten szczegół implementacyjny to umożliwiał i był sugerowany w dokumentacji. Obecnie sytuacja jest inna, co ułatwia zarządzanie, ponieważ istnieje tylko jedno odniesienie do stanu, a nie dwa.

Zmiany w kotwicach routingu ​

W wersji 1.x używano oncreate: m.route.link i, opcjonalnie, onupdate: m.route.link jako hooków cyklu życia dla routowalnych vnode. W wersji 2.x używany jest komponent m.route.Link. Selektor można określić za pomocą atrybutu selector:, jeśli używano selektora innego niż m("a", ...). Opcje można określić za pomocą options:, można go wyłączyć za pomocą disabled:, a inne atrybuty można określić inline, w tym href: (wymagane). Sam selector: może zawierać dowolny selektor akceptowalny jako pierwszy argument dla m, a atrybuty [href=...] i [disabled] można określić zarówno w selektorze, jak i w opcjach.

v1.x ​

javascript
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 ​

javascript
m(m.route.Link, {
  href: '/path',
});

m(m.route.Link, {
  selector: 'button',
  href: '/path',
});

m(m.route.Link, {
  selector: 'button.btn[href=/path]',
});

Zmiany w obsłudze błędów m.request ​

W wersji 1.x, m.request parsował błędy z odpowiedzi JSON i przypisywał właściwości sparsowanego obiektu do obiektu błędu. Na przykład, jeśli otrzymano odpowiedź ze statusem 403 i treścią {"code": "backoff", "timeout": 1000}, obiekt błędu miałby dwie właściwości: err.code = "backoff" i err.timeout = 1000.

W wersji 2.x odpowiedź jest przypisywana do właściwości response w obiekcie błędu, a właściwość code zawiera kod statusu HTTP. Tak więc, jeśli otrzymano odpowiedź ze statusem 403 i treścią {"code": "backoff", "timeout": 1000}, obiekt błędu miałby dwie właściwości: err.response = {code: "backoff", timeout: 1000} i err.code = 403.

Usunięcie m.withAttr ​

W wersji 1.x, event listenery mogły używać oninput: m.withAttr("value", func) i podobnych konstrukcji. W wersji 2.x, wartości należy odczytywać bezpośrednio z targetu zdarzenia. Współpracowało to dobrze ze strumieniami danych, ale ponieważ idiom m.withAttr("value", stream) nie był tak powszechny jak m.withAttr("value", prop), m.withAttr straciło na użyteczności i zostało usunięte.

v1.x ​

javascript
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 ​

javascript
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);
  },
});

Zmiana m.route.prefix ​

W wersji 1.x, m.route.prefix było funkcją wywoływaną za pomocą m.route.prefix(prefix). Teraz jest to właściwość, którą ustawia się za pomocą m.route.prefix = prefix.

v1.x ​

javascript
m.route.prefix('/root');

v2.x ​

javascript
m.route.prefix = '/root';

Parametry i ciało żądania m.request/m.jsonp ​

data i useBody zostały zastąpione przez params (parametry zapytania interpolowane do URL i dołączane do żądania) oraz body (ciało do wysłania w bazowym XHR). Daje to znacznie lepszą kontrolę nad wysyłanym żądaniem i pozwala zarówno na interpolację parametrów zapytania w żądaniach POST, jak i tworzenie żądań GET z ciałami.

m.jsonp, nie mając sensownego "ciała", po prostu używa params, więc zmiana nazwy data na params jest wystarczająca dla tej metody.

v1.x ​

javascript
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 ​

javascript
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,
});

Szablony ścieżek (Path templates) ​

W wersji 1.x istniały trzy oddzielne składnie szablonów ścieżek, które, choć podobne, miały 2 oddzielnie zaprojektowane składnie i 3 różne implementacje. Definicja była dość ad-hocowa, a parametry na ogół nie były escape'owane. Teraz, jeśli używasz :key, wszystko jest kodowane, a jeśli :key..., wszystko jest surowe. Jeśli coś jest nieoczekiwanie kodowane, użyj :path.... To proste.

Konkretnie, oto jak wpływa to na każdą metodę:

Adresy URL m.request i m.jsonp, ścieżki m.route.set ​

W wersji 2.x składniki ścieżki są automatycznie escape'owane podczas interpolacji. Załóżmy, że wywołujesz m.route.set("/user/:name/photos/:id", {name: user.name, id: user.id}). Wcześniej, jeśli user był {name: "a/b", id: "c/d"}, ustawiłoby to trasę na /user/a%2Fb/photos/c/d, ale teraz ustawi ją na /user/a%2Fb/photos/c%2Fd. Jeśli chcesz celowo interpolować klucz bez escape'owania, użyj :key....

Klucze w wersji 2.x nie mogą zawierać żadnych wystąpień . ani -. W wersji 1.x mogły zawierać wszystko oprócz /.

Interpolacje w inline query strings (ciągach zapytań w linii), jak w /api/search?q=:query, nie są wykonywane w wersji 2.x. Przekazuj je zamiast tego za pomocą params z odpowiednimi nazwami kluczy, bez określania ich w ciągu zapytania.

Wzorce tras m.route ​

Klucze ścieżki w formie :key... zwracały swój URL zdekodowany w wersji 1.x, ale zwracają surowy URL w wersji 2.x.

Wcześniej, rzeczy takie jak :key.md były błędnie akceptowane, a wartość wynikowego parametru była ustawiana na keymd: "...". To już nie ma miejsca - .md jest teraz częścią wzorca, a nie nazwą.

Kolejność wywołań cyklu życia (Lifecycle call order) ​

W wersji 1.x hooki cyklu życia atrybutów na vnode komponentu były wywoływane przed hookami cyklu życia samego komponentu. W wersji 2.x, ma to miejsce tylko dla onbeforeupdate. Może być konieczne odpowiednie dostosowanie kodu.

v1.x ​

javascript
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 ​

javascript
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

Synchroniczność m.redraw ​

m.redraw() w wersji 2.x jest zawsze asynchroniczne. Możesz konkretnie zażądać synchronicznego przerysowania za pomocą m.redraw.sync(), pod warunkiem że aktualnie nie trwa przerysowywanie.

Kolejność atrybutów selektora ​

W wersji 1.x, atrybuty selektora miały pierwszeństwo przed atrybutami określonymi w obiekcie atrybutów. Na przykład, m("[a=b]", {a: "c"}).attrs zwracało {a: "b"}.

W wersji 2.x, atrybuty określone w obiekcie atrybutów mają pierwszeństwo przed atrybutami selektora. Na przykład, m("[a=b]", {a: "c"}).attrs zwraca {a: "c"}.

Zauważ, że technicznie jest to powrót do zachowania z wersji 0.2.x.

Normalizacja dzieci ​

W wersji 1.x, dzieci vnode komponentu były normalizowane jak inne vnode. W wersji 2.x, to już nie ma miejsca i należy to uwzględnić w kodzie. Nie wpływa to na normalizację wykonywaną podczas renderowania.

Nagłówki m.request ​

W wersji 1.x, Mithril.js ustawiał te dwa nagłówki dla wszystkich żądań innych niż GET, ale tylko wtedy, gdy useBody było ustawione na true (domyślnie) i spełnione były pozostałe wymienione warunki:

  • Content-Type: application/json; charset=utf-8 dla żądań z ciałami JSON
  • Accept: application/json, text/* dla żądań oczekujących odpowiedzi JSON

W wersji 2.x, Mithril.js ustawia nagłówek Content-Type: application/json; charset=utf-8 dla wszystkich żądań z ciałami JSON, które nie są null i pomija go w przeciwnym razie. Dzieje się to niezależnie od wybranej metody, w tym w żądaniach GET.

Ustawienie nagłówka Content-Type może wywołać preflight CORS, ponieważ nie jest to nagłówek żądania bezpieczny dla CORS ze względu na określony typ zawartości, a to może wprowadzić nowe błędy w zależności od konfiguracji CORS na serwerze. Jeśli napotkasz problemy z tym związane, może być konieczne zastąpienie tego nagłówka, przekazując headers: {"Content-Type": "text/plain"}. (Nagłówek Accept nie wywołuje preflight, więc nie trzeba go zastępować.)

Specyfikacja Fetch pozwala uniknąć sprawdzania preflight CORS tylko dla typów zawartości application/x-www-form-urlencoded, multipart/form-data i text/plain. Nie pozwala na nic innego i celowo zabrania JSON.

Parametry zapytania w ciągach hash w trasach ​

W wersji 1.x można było określić parametry zapytania dla tras zarówno w ciągu zapytania, jak i w ciągu hash, więc m.route.set("/route?foo=1&bar=2"), m.route.set("/route?foo=1#bar=2") i m.route.set("/route#foo=1&bar=2") były równoważne, a atrybuty z nich wyodrębnione byłyby {foo: "1", bar: "2"}.

W wersji 2.x, zawartość ciągów hash jest ignorowana, ale pozostaje zachowana. Tak więc atrybuty wyodrębnione z każdego z nich byłyby następujące:

  • 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") → {}

Powodem tego jest to, że adresy URL takie jak https://example.com/#!/route#key są technicznie nieprawidłowe zgodnie ze specyfikacją URL i były nawet nieprawidłowe zgodnie z RFC, które ją poprzedzało, i to tylko dziwactwo specyfikacji HTML, że są dozwolone. (Specyfikacja HTML powinna była wymagać, aby identyfikatory i fragmenty lokalizacji były od początku prawidłowymi fragmentami URL, jeśli chciała postępować zgodnie ze specyfikacją.)

Lub krótko mówiąc, przestań używać nieprawidłowych adresów URL!

Klucze ​

W wersji 1.x można było swobodnie mieszać vnode z kluczami i bez kluczy. Jeśli pierwszy węzeł ma klucz, wykonywane jest różnicowanie z kluczami, zakładając, że każdy element ma klucz i po prostu ignorując puste miejsca po drodze. W przeciwnym razie wykonywane jest różnicowanie iteracyjne, a jeśli węzeł ma klucz, sprawdzane jest, czy nie zmienił się w tym samym czasie, w którym sprawdzane są tagi i tym podobne.

W wersji 2.x, listy dzieci zarówno fragmentów, jak i elementów muszą być albo wszystkie z kluczami, albo wszystkie bez kluczy. Puste węzły są również uważane za nieposiadające kluczy na potrzeby tego sprawdzenia - nie są już ignorowane.

Jeśli musisz to obejść, użyj idiomu fragmentu zawierającego pojedynczy vnode, takiego jak [m("div", {key: whatever})].

Usunięcie m.version ​

Ogólnie rzecz biorąc, służyło to niewielu celom i zawsze możesz dodać to z powrotem samodzielnie. Powinieneś preferować wykrywanie możliwości, aby wiedzieć, jakie funkcje są dostępne, a API wersji 2.x zostało zaprojektowane tak, aby lepiej to umożliwić.

Pager
Poprzednia stronaPorównanie frameworków
Następna stronaMigracja z wersji 0.2.x

Opublikowano na licencji MIT.

Copyright (c) 2024 Mithril Contributors

https://mithril.js.org/migration-v1x.html

Opublikowano na licencji MIT.

Copyright (c) 2024 Mithril Contributors