Material-ui: [MenuItem] Links dentro dos itens do Menu

Criado em 6 jan. 2015  ·  43Comentários  ·  Fonte: mui-org/material-ui

Oi, eu estava olhando para a implementação atual de itens de menu e notei que não há link real (ou seja, html <a> tag). Como resultado, por exemplo, mesmo na barra de navegação não há um link real, e as transições para outras páginas são gerenciadas por meio de eventos onclick.

Acho que ter links seria uma melhoria, especialmente considerando as páginas renderizadas do lado do servidor.

Você acha que isso faz sentido, ou você tem razões específicas para não ir nessa direção?

v0.x

Comentários muito úteis

Use o adereço containerElement !

Vejo:
http://stackoverflow.com/questions/32106513/material-ui-menu-using-routes/34507786#34507786

<MenuItem
  containerElement={<Link to="/profile" />}
  primaryText="Profile"
  leftIcon={
    <FontIcon className="material-icons">people</FontIcon>
  } />

Todos 43 comentários

Estou me perguntando sobre isso também. Estou usando renderização do lado do servidor em meu aplicativo, isso é algo a ser analisado.

O uso de elementos âncora com atributos href também melhoraria a acessibilidade e permitiria que as pessoas usassem o comportamento do navegador com o qual estão acostumadas (por exemplo, ⌘-Clique para abrir em uma nova guia).

+1

+1

+1

+1

+1

+1

+1

@ecesena você acha que isso ainda seria um problema com o novo componente MenuItem ? Veja aqui . Os MenuItem s podem ser cercados por <a>..</a> , não?

isso é possível com o que @shaurya947 sugeriu.

Estou tentando usar MenuItems no meu LeftNav assim:

        let menuItems = (
            <div>
                <MenuItem primaryText="Doors"           leftIcon={<FontIcon className="material-icons" color={GlobalStyles.default.activeColor}>home</FontIcon>} /></a>
                <MenuItem primaryText="Load"           leftIcon={<FontIcon className="material-icons" color={GlobalStyles.default.activeColor}>home</FontIcon>} />
                <MenuItem primaryText="Notes"           leftIcon={<FontIcon className="material-icons" color={GlobalStyles.default.activeColor}>home</FontIcon>} />
                <MenuItem primaryText="Alerts"          leftIcon={<FontIcon className="material-icons" color={GlobalStyles.default.activeColor}>home</FontIcon>} />
                <MenuItem primaryText="Admin"           leftIcon={<FontIcon className="material-icons" color={GlobalStyles.default.activeColor}>home</FontIcon>} />
            </div>
        );

        return (
            <LeftNav
                ref="leftNav"
                docked={false}
                onChange={this._onLeftNavChange}
            >
                {menuItems}
            </LeftNav>
        )

Envolver um <a> torno de uma tag <MenuItem> lança um aviso validateDOMNesting(...): <a> cannot appear as a descendant of <a>. See MainLayout > a > ... > MenuItem > ListItem > EnhancedButton > a"

Se você fizer uma inspeção React da saída, obterá o seguinte.

<a href="/">
    <MenuItem..>
        <ListItem..>
            <div>
                <EnhancedButton..>
                    <a>
                        <TouchRipple ..>
                    </a>
                </EnhancedButton>
            </div>
        </ListItem>
    </MenuItem>
</a>

que ter elementos <a> aninhados é ofensivo.

<MenuItems> gera elementos <a> dentro da declaração Button. Qual prop é usado de MenuItem para preencher o atributo href dentro do <EnhancedButton> gerado?

Usar um objeto MenuItem como um suporte para LeftNav faz com que a vinculação funcione, mas não consegui descobrir como adicionar ícones esquerdo/direito dessa maneira.

ou seja:

let menuItems = [
         { route: '/load_areas/'+ this.state.area + '/doors', text: 'Doors' },
         { route: '/load_areas/'+ this.state.area + '/trailer_loads', text: 'Load' },
         { route: 'notes', text: 'Notes' },
         { route: 'alerts', text: 'Alerts' },
         { route: 'admin', text: 'Admin' }
         ];

<LeftNav
                ref="leftNav"
                docked={false}
                menuItems={menuItems}
                onChange={this._onLeftNavChange}
            />

este é um problema separado, abra um, para que possamos rotulá-lo e adicioná-lo aos marcos, tnx :grin:

Use o adereço containerElement !

Vejo:
http://stackoverflow.com/questions/32106513/material-ui-menu-using-routes/34507786#34507786

<MenuItem
  containerElement={<Link to="/profile" />}
  primaryText="Profile"
  leftIcon={
    <FontIcon className="material-icons">people</FontIcon>
  } />

Agora a prop linkButton de EnhancedButton está obsoleta. LinkButton não é mais necessário quando a propriedade href é fornecida. Ele será removido com v0.16.0.

Por exemplo:

<MenuItem primaryText="Primary Text" href="/your/link" />

href recarrega a página. que tal se eu quiser usar o roteador react

@cezarneaga tente href="#/your/link"

<MenuItem
  containerElement={<Link to="/profile" />}
.../>

documentação menciona que você precisa inserir também linkButton . se você remover isso, ele funciona sem erros.

@DaxChen Eu vi sua resposta atualizada do stackoverflow para dezembro de 2016 (extremamente recente haha) e eu queria saber se você sabia se isso funcionava para um MenuItem dentro de uma gaveta? Estou tentando o seguinte abaixo e não consegui fazer o Link funcionar com o MenuItem, pois containerElement parece não fazer nada.

<Drawer
  docked={false}
  width={300}
  onRequestChange={this.closeDrawer}
  open={this.state.open}>
  <AppBar title="Title"
 />
  <MenuItem primaryText="home" containerElement={<Link to="/home" />} />
</Drawer>

containerElement funciona, mas não está documentado, então acho que este tópico terá que servir como documentação oficial por enquanto. Obrigado!

Olá @Faolain !

Realmente desculpe a demora na resposta...
Eu tentei você codificar em um aplicativo limpo com create-react-app , mas tudo parecia funcionar bem?!
Talvez você tenha configurado react-router diferente, ou a versão é diferente?

De qualquer forma, aqui está um exemplo de repositório e a demonstração ao vivo aqui .

Se você ainda não conseguir encontrar a causa do seu problema, você pode fornecer um repositório de amostra para reproduzir?

Nenhuma das soluções acima funcionou no Safari e no iOS. Então aqui está o que eu fiz como uma solução para react-router

          <MenuItem
            onTouchTap={() => {
              this._yourMethod()
              browserHistory.push('/howItWorks')
            }}
            primaryText="Menu Link"
          />

@janzenz este exemplo aqui não está funcionando no seu navegador?

Eu tentei no Safari no macOS e no Safari no iOS e todos funcionam. Isso não está funcionando para você?

Embora sua solução funcione, ela pode causar SEO ruim e você perderá alguns comportamentos nativos, como visualização de link e clique com a opção para abrir em uma nova guia.

@DaxChen obrigado pelos insights. Não tenho certeza se meu problema está relacionado ao seu primeiro link. Eu já tentei o 2º, mas uma vez que eu adiciono um prop onTouchTap o <Link /> não funciona mais.

@janzenz Eu adicionei onTouchTap prop no meu exemplo anterior e ainda funciona.
Não sei se sua configuração é diferente em algum lugar ou algo assim... 😢
Você pode verificar o código atualizado e ver se funciona para você?

@DaxChen Vejo que você está usando material-ui na versão ~0.16.0 . Você já tentou o mais recente ~0.17.0 e viu se isso ainda não é um problema?

@janzenz Eu estava usando uma versão mais antiga, acabei de atualizar para o mais recente 0.17.4 e ainda funciona!

Touché! Provavelmente minha configuração então. Obrigado por confirmar que @DaxChen voltarei a este tópico se encontrar o problema real.

@DaxChen , tentei o exemplo que você me deu, mas falha

Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in. Check the render method of `EnhancedButton`.
    at invariant (invariant.js:44)
    at ReactCompositeComponentWrapper.instantiateReactComponent [as _instantiateReactComponent] (instantiateReactComponent.js:74)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:367)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactDOMComponent.mountChildren (ReactMultiChild.js:238)
    at ReactDOMComponent._createInitialChildren (ReactDOMComponent.js:697)
    at ReactDOMComponent.mountComponent (ReactDOMComponent.js:516)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactDOMComponent.mountChildren (ReactMultiChild.js:238)
    at ReactDOMComponent._createInitialChildren (ReactDOMComponent.js:697)
    at ReactDOMComponent.mountComponent (ReactDOMComponent.js:516)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactDOMComponent.mountChildren (ReactMultiChild.js:238)
    at ReactDOMComponent._createInitialChildren (ReactDOMComponent.js:697)
    at ReactDOMComponent.mountComponent (ReactDOMComponent.js:516)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactDOMComponent.mountChildren (ReactMultiChild.js:238)
    at ReactDOMComponent._createInitialChildren (ReactDOMComponent.js:697)
    at ReactDOMComponent.mountComponent (ReactDOMComponent.js:516)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at mountComponentIntoNode (ReactMount.js:104)
    at ReactReconcileTransaction.perform (Transaction.js:140)
    at batchedMountComponentIntoNode (ReactMount.js:126)
    at ReactDefaultBatchingStrategyTransaction.perform (Transaction.js:140)
    at Object.batchedUpdates (ReactDefaultBatchingStrategy.js:62)
    at Object.batchedUpdates (ReactUpdates.js:97)
    at Object._renderNewRootComponent (ReactMount.js:320)
    at Object._renderSubtreeIntoContainer (ReactMount.js:401)
    at Object.render (ReactMount.js:422)
    at Object.<anonymous> (index.js:36)
    at __webpack_require__ (bootstrap e3e2367…:555)
    at fn (bootstrap e3e2367…:86)
    at Object.<anonymous> (bootstrap e3e2367…:578)
    at __webpack_require__ (bootstrap e3e2367…:555)
    at bootstrap e3e2367…:578
    at bootstrap e3e2367…:578

Meu código está disponível em https://github.com/hhimanshu/spicyveggie/tree/cards ( cards branch)

Não tenho certeza do que é diferente, mas simplesmente não funciona

@janzenz
Eu também tentei browserHistory.push('/howItWorks') e importei import browserHistory from 'react-router-dom' , mas consegui undefuned .

@Oduig ,
Eu tentei #/your/link , mas não me leva a lugar nenhum
Eu tentei /your/link , mas ele recarrega a página e eu perco Drawer de Material-UI

Nenhuma dessas coisas funcionou para mim. Meu código está disponível em https://github.com/hhimanshu/spicyveggie/tree/cards ( cards branch), commit específico é https://github.com/hhimanshu/spicyveggie/commit/844b7b7cddf9102995cd2680a783df3b6ef48537 , Poderia alguém por favor ajuda?

@hhimanshu mude esta linha para

import { Link } from 'react-router-dom'

mais informações sobre MDN

@DaxChen , obrigado. Foi isso. No entanto, não quando minha página carrega com {<Link to="/menu"/>} , ela carrega a página inteira e meu Drawer desaparece.

screen shot 2017-04-24 at 1 54 23 pm

@hhimanshu é porque você usou apenas o componente Menu em sua rota \menu , então App não será renderizado.

Aninhe seus Menu e Summary dentro de App ou alguns componentes de layout e passe os respectivos filhos.

Você pode usar react-devtools para verificar a hierarquia de componentes renderizados e seus estados!

Isso não está relacionado ao material-ui, por favor leia mais nos tutoriais/docs do react-router.

+1

Soluções alternativas para links HANDLED & NOT HANDLED pelo React Router.


Se o link de destino for tratado pelo React Router

MenuItemLink.js

import React from 'react';
import { MenuItem } from 'material-ui/Menu';
import { Route } from 'react-router-dom';

class MenuItemLink extends React.Component {
  render() {
    const {
      to, also,
      ...rest
    } = this.props;

    return (
      <Route
        render={({ history, location }) => (
          <MenuItem
            onClick={() => {
              history.push(to);
              if (typeof also === 'function') {
                also();
              }
            }}
            {...rest}
          />
        )}
      />
    );
  }
}
MenuItemLink.muiName = 'MenuItem';
export default MenuItemLink;

Código de amostra:

import MenuItemLink from './MenuItemLink';
<Menu ... >
        <MenuItemLink to="/users"
          also={this.handleRequestClose}>Users</MenuItemLink>
</Menu>

Se o link de destino NÃO for tratado pelo React Router, ou seja: a solicitação é encaminhada para um servidor de API ou qualquer outro

função onClick:

    function facebookLoginRedirect () {
      if (window) window.location.href = "/api/auth/facebook"
      return true;
    }

Código de amostra:

<MenuItem onClick={ facebookLoginRedirect }>Login with Facebook</MenuItem>

Estou vindo para adicionar a isso, no caso de alguém tropeçar nisso também.

Na v3.4, você pode conseguir isso assim:

import { Link } from 'react-router-dom';
import MenuItem from '@material-ui/core/MenuItem';

...

<MenuItem component={Link} to="/your-path">...</MenuItem>

A única solução que funcionou para mim sem quebrar o layout do menu foi:
```javascript


Notificações



Perfil


A única solução que funcionou para mim sem quebrar o layout do menu foi:

<MenuList>
  <Link to='/your-path' style={{ textDecoration: 'none' }}>
    <MenuItem>
      Notifications
     </MenuItem>
  </Link>
  <Link to='/your-path' style={{ textDecoration: 'none' }}>
    <MenuItem>
      Profile
     </MenuItem>
  </Link>
</MenuList>

@eladlevy Isso acabaria em um HTML de semântica ruim.

<ul>
  <a><li/></a>
  <a><li/></a>
</ul>

Deixando isso aqui caso ajude alguém (executando a v3.9.0). Eu precisava de um <Select> para funcionar como um menu de react-router-dom <Link> s. Cada link correspondia a uma configuração de idioma, portanto, a lista suspensa exibiria o valor do idioma atual do parâmetro de consulta.

<Select value={currentLanguage}>
  {languages.map(language => (
    <ListItem
      button
      component={btnProps => (
        <Link
          to={ `/things?lang=${ language }` }
          {...btnProps as any}
        />
      )}
      value={language}
      key={language}
    >
      {language}
    </ListItem>
  ))}
</Select>

Essa foi a solução mais limpa que encontrei que exigia uma conversão mínima do TypeScript e mantinha visuais consistentes com a interface do usuário do material.

@goyney tem a solução, obrigado

Estou vindo para adicionar a isso, no caso de alguém tropeçar nisso também.

Na v3.4, você pode conseguir isso assim:

import { Link } from 'react-router-dom';
import MenuItem from '@material-ui/core/MenuItem';

...

<MenuItem component={Link} to="/your-path">...</MenuItem>

Solução funcional e limpa, obrigado ❤️

Para links externos, você deve usar component="a" , mas também colocar MenuItem em <li> :

<MenuList>
    <li>
        <MenuItem
            component="a"
            href="https://google.com"
            target="_blank"
        >Google</MenuItem>
    </li>
</MenuList>

Isso gera o seguinte HTML:

<ul class="MuiList-root MuiList-padding" role="menu" tabindex="-1">
    <li>
        <a class="[...]" tabindex="-1" aria-disabled="false" role="menuitem" href="https://google.com" target="_blank">Google</a>
    </li>
</ul>

Suponha que eu tenha um menu pop-up e use

import { Link } de 'react-router-dom';
importar MenuItem de '@material-ui/core/MenuItem';

\\

O Link abrirá a página /seu-caminho, como fechar o menu pop-up?

Esta página foi útil?
0 / 5 - 0 avaliações