Skip to content
Mithril.js 2
Main Navigation GuiaAPI

Português – Brasil

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

Português – Brasil

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

Aparência

Sidebar Navigation

API

API principal

m(selector, attributes, children)

render(element, vnodes)

mount(root, component)

route(root, defaultRoute, routes)

request(options)

parseQueryString(string)

buildQueryString(object)

buildPathname(object)

parsePathname(string)

trust(html)

fragment(attrs, children)

redraw()

censor(object, extra)

API Opcional

stream()

Guia

Nesta página

route(root, defaultRoute, routes) ​

Descrição ​

Permite a navegação entre "páginas" dentro de um aplicativo, sem recarregar a página.

javascript
var Home = {
  view: function () {
    return 'Welcome';
  },
};

m.route(document.body, '/home', {
  '/home': Home, // define `https://localhost/#!/home`
});

Você pode ter apenas uma chamada m.route por aplicativo.

Assinatura ​

m.route(root, defaultRoute, routes)

ParâmetroTipoObrigatórioDescrição
rootElementSimUm elemento DOM que será o nó pai da árvore de elementos renderizados pelo Mithril.
defaultRouteStringSimA rota para a qual redirecionar se a URL atual não corresponder a nenhuma rota definida. Note que esta não é a rota inicial; a rota inicial é determinada pela URL na barra de endereço do navegador.
routesObject<String,Component|RouteResolver>SimUm objeto onde as chaves (keys) são strings de rota e os valores são componentes ou um RouteResolver.
retornaRetorna undefined.

Como ler assinaturas

Membros estáticos ​

m.route.set ​

Redireciona para uma rota correspondente ou para a rota padrão se nenhuma rota correspondente for encontrada. Dispara uma atualização assíncrona de todos os pontos de montagem.

m.route.set(path, params, options)

ParâmetroTipoObrigatórioDescrição
pathStringSimO nome do caminho para o qual rotear, sem o prefixo. O caminho pode incluir parâmetros que são interpolados com valores de params.
paramsObjectNãoParâmetros de roteamento. Se path contiver espaços reservados para parâmetros de roteamento, as propriedades deste objeto serão interpoladas na string do caminho.
options.replaceBooleanNãoIndica se uma nova entrada deve ser criada no histórico do navegador ou se a entrada atual deve ser substituída. O padrão é false.
options.stateObjectNãoO objeto state a ser passado para a chamada subjacente history.pushState / history.replaceState. Este objeto de estado se torna disponível na propriedade history.state e é mesclado no objeto de parâmetros de roteamento. Observe que esta opção só funciona quando se usa a API pushState e é ignorada se o roteador utilizar o modo hashchange (ou seja, se a API pushState não estiver disponível).
options.titleStringNãoA string title a ser passada para a chamada subjacente history.pushState / history.replaceState.
retornaRetorna undefined.

Lembre-se de que, ao usar .set com params, você também precisa definir a rota correspondente:

javascript
var Article = {
  view: function (vnode) {
    return 'This is article ' + vnode.attrs.articleid;
  },
};

m.route(document.body, {
  '/article/:articleid': Article,
});
m.route.set('/article/:articleid', { articleid: 1 });

m.route.get ​

Retorna o último caminho de roteamento totalmente resolvido, sem o prefixo. Pode ser diferente do caminho exibido na barra de endereço enquanto uma rota assíncrona está aguardando resolução.

path = m.route.get()

ParâmetroTipoObrigatórioDescrição
retornaStringRetorna o último caminho totalmente resolvido.

m.route.prefix ​

Define o prefixo do roteador. O prefixo do roteador é um fragmento da URL que define a estratégia subjacente utilizada pelo Mithril.

m.route.prefix = prefix

ParâmetroTipoObrigatórioDescrição
prefixStringSimO prefixo que controla a estratégia de roteamento subjacente usada pelo Mithril.

Esta é uma propriedade simples, então você pode lê-la e escrever nela.

m.route.Link ​

Este componente cria um link roteado dinâmico. Sua principal função é gerar links <a> com atributos href que são adaptados de acordo com o prefixo de rota.

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

// A menos que m.route.prefix tenha mudado da estratégia padrão, renderiza para:
// <a href="#!/foo">foo</a>

Os links aceitam uma seleção de atributos especiais:

  • selector é o que seria passado como o primeiro argumento para m: qualquer seletor é válido, incluindo elementos que não são <a>.
  • params & options são os argumentos com os mesmos nomes definidos em m.route.set.
  • disabled, se verdadeiro, desativa o comportamento de roteamento e qualquer manipulador onclick vinculado, e anexa um atributo data-disabled="true" para dicas de acessibilidade. Se o elemento for um <a>, o atributo href é removido.

O comportamento de roteamento não pode ser impedido pela API de eventos: use disabled em vez disso.

javascript
m(
  m.route.Link,
  {
    href: '/foo',
    selector: 'button.large',
    disabled: true,
    params: { key: 'value' },
    options: { replace: true },
  },
  'link name'
);

// Renderiza para:
// <button disabled aria-disabled="true" class="large">link name</button>

vnode = m(m.route.Link, attributes, children)

ParâmetroTipoObrigatórioDescrição
attributes.hrefObjectSimA rota de destino para a qual navegar.
attributes.disabledBooleanNãoDesativa o elemento de forma acessível.
attributes.selectorString|Object|FunctionNãoUm seletor para m; o padrão é "a".
attributes.optionsObjectNãoDefine as options passadas para m.route.set.
attributes.paramsObjectNãoDefine os params passados para m.route.set.
attributesObjectNãoQuaisquer outros atributos a serem encaminhados para m.
childrenArray<Vnode>|String|Number|BooleanNãovnodes filhos para este link.
retornaVnodeUm vnode.

m.route.param ​

Obtém um parâmetro da última rota que foi completamente resolvida. Um parâmetro de rota é um par chave-valor. Os parâmetros de rota podem vir de diferentes fontes:

  • Interpolações de rota (por exemplo, se uma rota for /users/:id e ela for resolvida para /users/1, o parâmetro de rota tem uma chave id e o valor "1").
  • Querystrings da URL (por exemplo, se o caminho for /users?page=1, o parâmetro de rota tem uma chave page e o valor "1").
  • history.state (por exemplo, se history.state for {foo: "bar"}, o parâmetro de rota tem a chave foo e o valor "bar").

value = m.route.param(key)

ParâmetroTipoObrigatórioDescrição
keyStringNãoO nome de um parâmetro de rota (por exemplo, id na rota /users/:id ou page no caminho /users/1?page=3 ou uma chave em history.state).
retornaString|ObjectRetorna o valor para a chave especificada. Se nenhuma chave for especificada, retorna um objeto contendo todas as chaves utilizadas na interpolação.

Observe que, na função onmatch de um RouteResolver, a nova rota ainda não foi totalmente resolvida e m.route.param() retornará os parâmetros da rota anterior, se houver. onmatch recebe os parâmetros da nova rota como um argumento.

m.route.SKIP ​

Um valor especial que pode ser retornado pela função onmatch de um resolvedor de rotas para que a próxima rota seja considerada.

RouteResolver ​

Um RouteResolver é um objeto que não é um componente e contém um método onmatch e/ou um método render. Ambos os métodos são opcionais, mas pelo menos um deve estar presente.

Se um objeto puder ser detectado como um componente (pela presença de um método view ou por ser uma function/class), ele será tratado como tal, mesmo que tenha métodos onmatch ou render. Por não ser um componente, um RouteResolver não possui métodos de ciclo de vida.

Como regra geral, os RouteResolvers devem estar no mesmo arquivo que a chamada m.route, enquanto as definições de componente devem estar em seus próprios módulos.

routeResolver = {onmatch, render}

Ao usar componentes, você pode pensar neles como um atalho para este resolvedor de rota, assumindo que seu componente seja Home:

javascript
var routeResolver = {
  onmatch: function () {
    return Home;
  },
  render: function (vnode) {
    return [vnode];
  },
};

routeResolver.onmatch ​

A função onmatch é executada quando o roteador precisa determinar qual componente deve ser renderizado. É executada uma vez por cada mudança de caminho do roteador, mas não em redesenhos subsequentes enquanto estiver no mesmo caminho. Pode ser utilizada para executar lógica antes que um componente seja inicializado (por exemplo, autenticação, carregamento prévio de dados, rastreamento de analytics para redirecionamento, etc.).

Este método também permite que você defina assincronamente qual componente será renderizado, tornando-o adequado para divisão de código e carregamento de módulo assíncrono. Para renderizar um componente de forma assíncrona, retorne uma promise que seja resolvida para um componente.

Para obter mais informações sobre onmatch, consulte a seção resolução avançada de componente.

routeResolver.onmatch(args, requestedPath, route)

ParâmetroTipoDescrição
argsObjectOs parâmetros de roteamento.
requestedPathStringO caminho do roteador solicitado pela última ação de roteamento, incluindo valores de parâmetro de roteamento interpolados, mas sem o prefixo. Quando onmatch é chamado, a resolução para este caminho não está completa e m.route.get() ainda retorna o caminho anterior.
routeStringO caminho do roteador solicitado pela última ação de roteamento, excluindo valores de parâmetro de roteamento interpolados.
retornaComponent|\Promise<Component>|undefinedRetorna um componente ou uma promise que é resolvida para um componente.

Se onmatch retornar um componente ou uma promise que é resolvida para um componente, este componente é usado como o vnode.tag para o primeiro argumento no método render do RouteResolver. Caso contrário, vnode.tag é definido como "div". Da mesma forma, se o método onmatch for omitido, vnode.tag também é "div".

Se onmatch retornar uma Promise que for rejeitada, o roteador redirecionará para a rota definida em defaultRoute. Você pode substituir este comportamento chamando .catch na cadeia de promise antes de retorná-la.

routeResolver.render ​

O método render é chamado em cada redesenho para uma rota correspondente. É similar ao método view dos componentes e tem como objetivo simplificar a composição de componentes. Ele também permite que você escape do comportamento normal do Mithril.js de substituir toda a subárvore.

vnode = routeResolver.render(vnode)

ParâmetroTipoDescrição
vnodeObjectUm vnode cujo objeto de atributos contém parâmetros de roteamento. Se onmatch não retornar um componente ou uma promise que é resolvida para um componente, o campo tag do vnode assume o padrão "div".
vnode.attrsObjectUm mapa de valores de parâmetro de URL.
retornaArray<Vnode>|VnodeOs vnodes a serem renderizados.

O parâmetro vnode é equivalente a m(Component, m.route.param()), onde Component é o componente resolvido para a rota (após routeResolver.onmatch) e m.route.param() é como documentado aqui. Se você omitir este método, o valor de retorno padrão é [vnode], embrulhado em um fragmento para que você possa usar parâmetros de chave. Combinado com um parâmetro :key, ele se torna um fragmento chaveado de elemento único, já que acaba renderizando para algo como [m(Component, {key: m.route.param("key"), ...})].

Como funciona ​

O sistema de roteamento permite a criação de Single Page Applications (SPAs), que são aplicações capazes de navegar entre "páginas" sem a necessidade de recarregar o navegador.

Ele permite a navegabilidade perfeita, preservando a capacidade de marcar cada página individualmente e a capacidade de navegar no aplicativo por meio do mecanismo de histórico do navegador.

O roteamento sem atualizações de página é parcialmente possível pela API history.pushState. Usando esta API, é possível alterar programaticamente o URL exibido pelo navegador após o carregamento de uma página, mas é responsabilidade do desenvolvedor do aplicativo garantir que a navegação para qualquer URL fornecido a partir de um estado inativo (por exemplo, uma nova aba) renderize a marcação apropriada.

Estratégias de roteamento ​

A estratégia de roteamento define como uma biblioteca implementa o roteamento. Existem três estratégias gerais que podem ser usadas para implementar um sistema de roteamento SPA, e cada uma tem diferentes ressalvas:

  • m.route.prefix = '#!' (padrão) – Usando a porção identificador de fragmento (também conhecido como hash) da URL. Uma URL usando esta estratégia normalmente se parece com https://localhost/#!/page1.
  • m.route.prefix = '?' – Usando a querystring. Uma URL usando esta estratégia normalmente se parece com https://localhost/?/page1.
  • m.route.prefix = '' – Usando o nome do caminho. Uma URL usando esta estratégia normalmente se parece com https://localhost/page1.

A estratégia de hash tem garantia de funcionar em navegadores que não oferecem suporte à API history.pushState, pois utiliza o evento onhashchange como alternativa. Use esta estratégia se você quiser manter os hashes puramente locais.

A estratégia de querystring permite a detecção do lado do servidor, mas não aparece como um caminho normal. Use esta estratégia se você quiser suportar e potencialmente detectar links ancorados no lado do servidor, e você não for capaz de fazer as alterações necessárias para suportar a estratégia de nome do caminho (como se você estiver usando o Apache e não puder modificar seu .htaccess).

A estratégia de nome do caminho produz URLs mais limpas, mas requer configuração do servidor para servir o código do aplicativo de página única em cada URL que o aplicativo pode rotear. Use esta estratégia se você quiser URLs de aparência mais limpa.

Aplicativos de página única que usam a estratégia de hash geralmente usam a convenção de ter um ponto de exclamação após o hash para indicar que eles estão usando o hash como um mecanismo de roteamento e não para fins de vinculação a âncoras. A string #! é conhecida como hashbang.

A estratégia padrão usa o hashbang.

Uso típico ​

Geralmente, é necessário criar alguns componentes para associar às rotas:

javascript
var Home = {
  view: function () {
    return [m(Menu), m('h1', 'Home')];
  },
};

var Page1 = {
  view: function () {
    return [m(Menu), m('h1', 'Page 1')];
  },
};

No exemplo acima, há dois componentes: Home e Page1. Cada um contém um menu e algum texto. O menu em si está sendo definido como um componente para evitar repetição:

javascript
var Menu = {
  view: function () {
    return m('nav', [
      m(m.route.Link, { href: '/' }, 'Home'),
      m(m.route.Link, { href: '/page1' }, 'Page 1'),
    ]);
  },
};

Agora podemos definir rotas e mapear nossos componentes para elas:

javascript
m.route(document.body, '/', {
  '/': Home,
  '/page1': Page1,
});

Aqui especificamos duas rotas: / e /page1, que renderizam seus respectivos componentes quando o usuário navega para cada URL.

Navegando para diferentes rotas ​

No exemplo acima, o componente Menu tem dois m.route.Links. Isso cria um elemento, que por padrão é um <a>, e o configura para que, ao ser clicado, o usuário navegue para outra rota. A navegação ocorre apenas localmente, não remotamente.

Você também pode navegar programaticamente, via m.route.set(route). Por exemplo, m.route.set("/page1").

Ao navegar entre rotas, o prefixo do roteador é tratado automaticamente. Em outras palavras, omita o hashbang #! (ou qualquer prefixo que você definir para m.route.prefix) ao vincular rotas Mithril.js, incluindo em m.route.set e em m.route.Link.

Note que, ao navegar entre componentes, toda a subárvore é substituída. Use um resolvedor de rota com um método render se você quiser apenas atualizar uma parte da subárvore.

Parâmetros de roteamento ​

Às vezes, queremos ter um ID variável em uma rota, mas não queremos especificar uma rota separada para cada ID possível. Para isso, o Mithril.js oferece suporte a rotas parametrizadas.

javascript
var Edit = {
  view: function (vnode) {
    return [m(Menu), m('h1', 'Editing ' + vnode.attrs.id)];
  },
};
m.route(document.body, '/edit/1', {
  '/edit/:id': Edit,
});

No exemplo acima, definimos uma rota /edit/:id. Isso cria uma rota dinâmica que corresponde a qualquer URL começando com /edit/ seguido por dados. O valor id é então mapeado como um atributo do vnode do componente (vnode.attrs.id).

É possível ter vários argumentos em uma rota, por exemplo, /edit/:projectID/:userID renderizaria as propriedades projectID e userID no objeto de atributos vnode do componente.

Parâmetro chave ​

Quando um usuário navega de uma rota parametrizada para a mesma rota com um parâmetro diferente (por exemplo, indo de /page/1 para /page/2 dada uma rota /page/:id), o componente não seria recriado do zero, pois ambas as rotas são resolvidas para o mesmo componente e, portanto, resultam em um diff virtual DOM no local. Isso tem como efeito colateral disparar a função onupdate, em vez de oninit/oncreate. No entanto, é relativamente comum que um desenvolvedor queira sincronizar a recriação do componente com o evento de mudança de rota.

Para conseguir isso, é possível combinar a parametrização de rota com keys para um padrão muito conveniente:

javascript
m.route(document.body, '/edit/1', {
  '/edit/:key': Edit,
});

Isso significa que o vnode que é criado para o componente raiz da rota tem um objeto de parâmetro de rota key. Os parâmetros de rota se tornam attrs no vnode. Assim, ao pular de uma página para outra, a key muda e faz com que o componente seja recriado do zero (já que a chave (key) informa ao mecanismo de DOM virtual que os componentes antigo e novo são entidades distintas).

Você pode levar essa ideia adiante para criar componentes que se recriam quando recarregados:

m.route.set(m.route.get(), {key: Date.now()})

Ou até mesmo usar o recurso history state para conseguir componentes recarregáveis sem poluir a URL:

m.route.set(m.route.get(), null, {state: {key: Date.now()}})

Observe que o parâmetro chave funciona apenas para rotas de componente. Se você estiver usando um resolvedor de rota, você precisará usar um fragmento chaveado de filho único, passando key: m.route.param("key"), para realizar o mesmo.

Rotas variádicas ​

Também é possível ter rotas variádicas, ou seja, uma rota com um argumento que contém nomes de caminho de URL que contêm barras:

javascript
m.route(document.body, '/edit/pictures/image.jpg', {
  '/edit/:file...': Edit,
});

Tratamento de 404s ​

Para aplicativos JavaScript isomórficos / universais, um parâmetro de URL e uma rota variádica combinados são muito úteis para exibir uma página de erro 404 personalizada.

Em um caso de erro 404 Não Encontrado, o servidor envia de volta a página personalizada para o cliente. Quando o Mithril.js é carregado, ele redirecionará o cliente para a rota padrão porque não pode saber dessa rota.

javascript
m.route(document.body, '/', {
  '/': homeComponent,
  // [...]
  '/:404...': errorPageComponent,
});

History state ​

É possível aproveitar a API history.pushState para melhorar a experiência de navegação do usuário. Por exemplo, um aplicativo pode "lembrar" o estado de um formulário grande quando o usuário sai de uma página navegando para fora, de modo que, se o usuário pressionar o botão Voltar no navegador, ele terá o formulário preenchido em vez de um formulário em branco.

Por exemplo, você pode criar um formulário como este:

javascript
var state = {
  term: '',
  search: function () {
    // save the state for this route
    // isso equivale a `history.replaceState({term: state.term}, '', location.href)`
    m.route.set(m.route.get(), null, {
      replace: true,
      state: { term: state.term },
    });

    // navigate away
    location.href = 'https://google.com/?q=' + state.term;
  },
};

var Form = {
  oninit: function (vnode) {
    state.term = vnode.attrs.term || ''; // populated from the `history.state` property if the user presses the back button
  },
  view: function () {
    return m('form', [
      m("input[placeholder='Search']", {
        oninput: function (e) {
          state.term = e.target.value;
        },
        value: state.term,
      }),
      m('button', { onclick: state.search }, 'Search'),
    ]);
  },
};

m.route(document.body, '/', {
  '/': Form,
});

Assim, se o usuário pesquisar e pressionar o botão Voltar, o campo de entrada ainda estará preenchido com o termo de pesquisa. Esta técnica pode melhorar a experiência do usuário de formulários grandes e outros aplicativos onde o estado não persistido é trabalhoso para um usuário produzir.

Alterando o prefixo do roteador ​

O prefixo do roteador é um fragmento da URL que determina a estratégia subjacente usada pelo roteador.

javascript
// set to pathname strategy
m.route.prefix = '';

// set to querystring strategy
m.route.prefix = '?';

// set to hash without bang
m.route.prefix = '#';

// set to pathname strategy on a non-root URL
// e.g. if the app lives under `https://localhost/my-app` and something else
// lives under `https://localhost`
m.route.prefix = '/my-app';

Resolução Avançada de Componentes ​

Em vez de associar um componente diretamente a uma rota, você pode especificar um objeto RouteResolver. Um objeto RouteResolver contém um método onmatch() e um método render(). Ambos os métodos são opcionais, mas pelo menos um deles deve estar presente.

javascript
m.route(document.body, '/', {
  '/': {
    onmatch: function (args, requestedPath, route) {
      return Home;
    },
    render: function (vnode) {
      return vnode; // equivalente a m(Home)
    },
  },
});

RouteResolvers são úteis para implementar diversos casos de uso avançados de roteamento.

Envolvendo um Componente de Layout ​

Frequentemente, é desejável envolver todos ou a maioria dos componentes roteados em uma estrutura reutilizável (geralmente chamada de "layout"). Para isso, você precisa primeiro criar um componente que contenha a marcação comum que envolverá os diferentes componentes:

javascript
var Layout = {
  view: function (vnode) {
    return m('.layout', vnode.children);
  },
};

No exemplo acima, o layout consiste apenas em uma <div class="layout"> que contém os filhos passados para o componente, mas em um cenário real, poderia ser tão complexo quanto necessário.

Uma maneira de envolver o layout é definir um componente anônimo no mapa de rotas:

javascript
// example 1
m.route(document.body, '/', {
  '/': {
    view: function () {
      return m(Layout, m(Home));
    },
  },
  '/form': {
    view: function () {
      return m(Layout, m(Form));
    },
  },
});

No entanto, observe que, como o componente de nível superior é anônimo, navegar da rota / para a rota /form (ou vice-versa) irá desmontar o componente anônimo e recriar o DOM do zero. Se o componente Layout tivesse métodos de ciclo de vida definidos, os hooks oninit e oncreate seriam disparados a cada mudança de rota. Dependendo da aplicação, isso pode ou não ser desejável.

Se você preferir que o componente Layout seja atualizado e mantido intacto, em vez de ser recriado do zero, você deve usar um RouteResolver como o objeto raiz:

javascript
// example 2
m.route(document.body, '/', {
  '/': {
    render: function () {
      return m(Layout, m(Home));
    },
  },
  '/form': {
    render: function () {
      return m(Layout, m(Form));
    },
  },
});

Observe que, neste caso, se o componente Layout tiver métodos de ciclo de vida oninit e oncreate, eles só serão disparados na primeira mudança de rota (assumindo que todas as rotas usem o mesmo layout).

Para ilustrar a diferença entre os dois exemplos, o exemplo 1 equivale a este código:

javascript
// functionally equivalent to example 1
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);
    },
  },
});

Como Anon1 e Anon2 são componentes diferentes, suas subárvores (incluindo Layout) são recriadas do zero. Isso também é o que acontece quando os componentes são usados diretamente sem um RouteResolver.

No exemplo 2, como Layout é o componente de nível superior em ambas as rotas, o DOM para o componente Layout é atualizado (ou seja, deixado intacto se não houver alterações), e apenas a mudança de Home para Form aciona uma recriação dessa subseção do DOM.

Redirecionamento ​

O hook onmatch do RouteResolver pode ser usado para executar lógica antes que o componente de nível superior de uma rota seja inicializado. Você pode usar m.route.set() do Mithril ou a API history nativa do HTML5. Ao redirecionar com a API history, o hook onmatch deve retornar uma Promise que nunca se resolve, para evitar a resolução da rota correspondente. m.route.set() cancela a resolução da rota correspondente internamente, portanto, isso não é necessário com ele.

Exemplo: Autenticação ​

O exemplo abaixo demonstra como implementar um mecanismo de login que impede que os usuários vejam a página /secret, a menos que estejam logados.

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

Quando a aplicação carrega, onmatch é chamado e, como isLoggedIn é falso, a aplicação redireciona para /login. Depois que o usuário clicar no botão de login, isLoggedIn será definido como verdadeiro e a aplicação redirecionará para /secret. O hook onmatch será executado novamente e, como isLoggedIn está definido como verdadeiro, a aplicação renderizará o componente Home.

Para simplificar, no exemplo acima, o status de login do usuário é armazenado em uma variável global, e esse sinalizador é simplesmente alternado quando o usuário clica no botão de login. Em uma aplicação real, um usuário obviamente precisaria fornecer credenciais de login válidas, e clicar no botão de login acionaria uma requisição a um servidor para autenticar o usuário:

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

Pré-carregamento de Dados ​

Normalmente, um componente pode carregar dados durante a inicialização. Carregar dados dessa forma faz com que o componente seja renderizado duas vezes. A primeira renderização ocorre durante o roteamento, e a segunda é disparada após a conclusão da requisição. Tome cuidado para observar que loadUsers() retorna uma Promise, mas qualquer Promise retornada por oninit é atualmente ignorada. A segunda passagem de renderização vem da opção background para m.request.

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

No exemplo acima, na primeira renderização, a UI exibe "loading" já que state.users é um array vazio antes que a solicitação seja concluída. Então, uma vez que os dados estão disponíveis, a UI redesenha e uma lista de IDs de usuário é mostrada.

RouteResolvers podem ser usados como um mecanismo para pré-carregar dados antes de renderizar um componente, a fim de evitar oscilações na interface do usuário (UI) e, assim, evitar a necessidade de um indicador de carregamento:

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

Acima, render só é executado após a conclusão da solicitação, tornando o operador ternário redundante.

Divisão de Código (Code Splitting) ​

Em uma aplicação grande, pode ser desejável baixar o código para cada rota sob demanda, em vez de tudo de uma vez. Dividir a base de código dessa forma é conhecido como divisão de código (code splitting) ou carregamento lento (lazy loading). Em Mithril.js, isso pode ser realizado retornando uma Promise do hook onmatch:

Na sua forma mais básica, pode-se fazer o seguinte:

javascript
// Home.js
module.export = {
  view: function () {
    return [m(Menu), m('h1', 'Home')];
  },
};
javascript
// 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');
    },
  },
});

No entanto, para que isso funcione em um ambiente de produção, seria necessário empacotar todas as dependências do módulo Home.js em um único arquivo, que seria servido pelo servidor.

Felizmente, existem várias ferramentas que facilitam a tarefa de agrupar módulos para carregamento lento. Aqui está um exemplo usando import(...) dinâmico nativo, suportado por muitos bundlers:

javascript
m.route(document.body, '/', {
  '/': {
    onmatch: function () {
      return import('./Home.js');
    },
  },
});

Rotas Tipadas (Typed Routes) ​

Em certos casos avançados de roteamento, você pode querer restringir um valor além do próprio caminho, permitindo apenas valores como um ID numérico. Você pode fazer isso facilmente retornando m.route.SKIP de uma rota.

javascript
m.route(document.body, '/', {
  '/view/:id': {
    onmatch: function (args) {
      if (!/^\d+$/.test(args.id)) return m.route.SKIP;
      return ItemView;
    },
  },
  '/view/:name': UserView,
});

Rotas Ocultas (Hidden Routes) ​

Em raras circunstâncias, você pode querer ocultar certas rotas de alguns usuários. Por exemplo, um usuário pode não ter permissão para visualizar um determinado perfil e, em vez de mostrar um erro de permissão, você preferiria simular que a rota não existe e redirecionar para uma página 404. Nesse caso, você pode usar m.route.SKIP para simular que a rota não existe.

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

Cancelamento / Bloqueio de Rota ​

O RouteResolver onmatch pode impedir a resolução da rota retornando uma Promise que nunca se resolve. Isso pode ser usado para detectar tentativas de resolução de rotas redundantes e cancelá-las:

javascript
m.route(document.body, '/', {
  '/': {
    onmatch: function (args, requestedPath) {
      if (m.route.get() === requestedPath) return new Promise(function () {});
    },
  },
});

Integração de Terceiros ​

Em certas situações, você pode precisar integrar o Mithril.js com outro framework, como o React. Veja como fazer isso:

  • Defina todas as suas rotas usando m.route normalmente, mas certifique-se de usá-lo apenas uma vez por aplicação. Não é possível definir múltiplos pontos de roteamento.
  • Quando você precisar remover as subscrições de roteamento, use m.mount(root, null), utilizando a mesma raiz que você utilizou em m.route(root, ...) . m.route utiliza m.mount internamente para realizar a configuração, portanto, não há mágica envolvida.

Aqui está um exemplo com React:

jsx
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} />;
  }
}

E aqui está a versão equivalente com Vue:

html
<div ref="root"></div>
javascript
Vue.component('my-child', {
  template: `<div ref="root"></div>`,
  mounted: function () {
    m.route(this.$refs.root, '/', {
      // ...
    });
  },
  destroyed: function () {
    m.mount(this.$refs.root, null);
  },
});
Pager
Anteriormount(root, component)
Próximorequest(options)

Distribuído sob a Licença MIT.

Copyright (c) 2024 Mithril Contributors

https://mithril.js.org/route.html

Distribuído sob a Licença MIT.

Copyright (c) 2024 Mithril Contributors