Material-ui: [MenuItem] Enlaces dentro de los elementos del menú

Creado en 6 ene. 2015  ·  43Comentarios  ·  Fuente: mui-org/material-ui

Hola, estaba mirando la implementación actual de los elementos del menú y noté que no hay un enlace real (es decir, etiqueta html <a> ). Como resultado, por ejemplo, incluso en la barra de navegación no hay un enlace real, y las transiciones a otras páginas se gestionan mediante eventos onclick.

Creo que tener enlaces sería una mejora, especialmente considerando las páginas renderizadas del lado del servidor.

¿Crees que esto tiene sentido o tienes razones específicas para no ir en esta dirección?

v0.x

Comentario más útil

¡Usa el accesorio containerElement !

ver:
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 comentarios

Me pregunto sobre esto también. Estoy usando la representación del lado del servidor en mi aplicación, esto es algo que se debe analizar.

El uso de elementos de anclaje con atributos href también mejoraría la accesibilidad y permitiría a las personas usar el comportamiento del navegador al que están acostumbrados (por ejemplo, ⌘-Hacer clic para abrir en una nueva pestaña).

+1

+1

+1

+1

+1

+1

+1

@ecesena , ¿crees que esto seguiría siendo un problema con el nuevo componente MenuItem ? Ver aquí Los MenuItem pueden estar rodeados por <a>..</a> , ¿no?

esto es posible con lo que sugirió @shaurya947 .

Estoy intentando usar MenuItems en mi LeftNav así:

        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 un <a> alrededor de una etiqueta <MenuItem> arroja una advertencia validateDOMNesting(...): <a> cannot appear as a descendant of <a>. See MainLayout > a > ... > MenuItem > ListItem > EnhancedButton > a"

Si realiza una inspección React de la salida, obtendrá lo siguiente.

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

que tener elementos <a> anidados es ofensivo.

<MenuItems> genera <a> elementos dentro de la declaración del Botón. ¿Qué accesorio se usa de MenuItem para completar el atributo href dentro de los <EnhancedButton> generados?

El uso de un objeto MenuItem como accesorio para LeftNav hace que la vinculación funcione, pero no he podido descifrar cómo agregar íconos izquierdo/derecho de esta manera.

es decir:

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 es un problema aparte, abra uno, para que podamos etiquetarlo y agregarlo a los hitos, tnx :grin:

¡Usa el accesorio containerElement !

ver:
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>
  } />

Ahora el accesorio linkButton de EnhancedButton está en desuso. LinkButton ya no es necesario cuando se proporciona la propiedad href . Se eliminará con v0.16.0.

Por ejemplo:

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

href recarga la página. ¿Qué tal si quiero usar el enrutador de reacción?

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

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

la documentación menciona que debe ingresar también linkButton . si elimina esto, funciona sin errores.

@DaxChen Vi su respuesta actualizada de stackoverflow para diciembre de 2016 (extremadamente reciente, jaja) y me preguntaba si sabía si esto funcionaba para un elemento de menú dentro de un cajón. Estoy intentando lo siguiente a continuación y no he podido hacer que Link funcione con MenuItem ya que containerElement parece no hacer 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 pero no está documentado, así que supongo que este hilo tendrá que servir como documentación oficial por ahora. ¡Gracias!

¡Hola @Faolain !

Realmente lo siento por la respuesta tardía...
Probé tu código en una aplicación limpia con create-react-app , ¡¿pero todo parecía funcionar bien?!
¿Tal vez configuró react-router diferente, o la versión es diferente?

De todos modos, aquí hay un repositorio de ejemplo y la demostración en vivo aquí .

Si aún no puede encontrar la causa de su problema, ¿puede proporcionar un repositorio de muestra para reproducirlo?

Ninguna de las soluciones anteriores funcionó en Safari e iOS. Así que esto es lo que hice como solución alternativa por react-router

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

@janzenz, ¿ este ejemplo no funciona en su navegador?

Lo probé en Safari en macOS y Safari en iOS y todos funcionan. ¿Esto no te funciona?

Aunque su solución alternativa funciona, puede causar un mal SEO y perderá algunos comportamientos nativos, como la vista previa del enlace y la opción-clic para abrir en una nueva pestaña.

@DaxChen gracias por las ideas. No estoy seguro si mi problema está relacionado con su primer enlace. Ya probé el segundo, pero una vez que agrego un accesorio onTouchTap , el <Link /> ya no funciona.

@janzenz Agregué onTouchTap prop en mi ejemplo anterior y todavía funciona.
No sé si tu configuración es diferente en algún lugar o algo... 😢
¿Puede consultar el código actualizado y ver si funciona para usted?

@DaxChen Veo que está usando material-ui en la versión ~0.16.0 . ¿Has probado los últimos ~0.17.0 y has visto si sigue sin ser un problema?

@janzenz ¡Estaba usando una versión anterior, recién actualizada a la última 0.17.4 y todavía funciona!

¡Touché! Probablemente mi configuración entonces. Gracias por confirmar que @DaxChen. Volveré a este hilo si encuentro el problema real.

@DaxChen , probé el ejemplo que me diste, pero falla

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

Mi código está disponible en https://github.com/hhimanshu/spicyveggie/tree/cards (sucursal cards )

No estoy seguro de qué es diferente, pero simplemente no funciona.

@janzenz
También probé browserHistory.push('/howItWorks') e importé import browserHistory from 'react-router-dom' , pero obtuve undefuned .

@Oduig ,
Probé #/your/link , pero no me lleva a ningún lado
Probé /your/link , pero recarga la página y pierdo Drawer de Material-UI

Ninguna de estas cosas funcionó para mí. Mi código está disponible en https://github.com/hhimanshu/spicyveggie/tree/cards (rama cards ), la confirmación específica es https://github.com/hhimanshu/spicyveggie/commit/844b7b7cddf9102995cd2680a783df3b6ef48537 , podría alguien por favor ayuda?

@hhimanshu cambia esta línea a

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

más información en MDN

@DaxChen , gracias. Eso fue todo. Sin embargo, no cuando mi página se carga con {<Link to="/menu"/>} , carga toda la página y mi Drawer desaparece.

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

@hhimanshu eso se debe a que utilizó sólo el Menu componente de su \menu ruta , por lo que App no se brindará.

Anide sus Menu y Summary dentro de App o algunos componentes de diseño, y pase los hijos respectivos.

¡Puede usar react-devtools para verificar la jerarquía de componentes renderizados y sus estados!

Esto no está relacionado con material-ui, lea más en los tutoriales/documentos de react-router.

+1

Soluciones alternativas para enlaces MANEJADOS Y NO MANEJADOS por React Router.


Si el enlace de destino es manejado por 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 muestra:

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

Si el enlace de destino NO es manejado por React Router, es decir: la solicitud se reenvía a un servidor API o lo que sea

Función al hacer clic:

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

Código de muestra:

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

Voy a agregar a esto, en caso de que alguien más lo haya encontrado también.

En v3.4, puede lograr esto así:

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

...

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

La única solución que funcionó para mí sin romper el diseño del menú fue:
```javascript


Notificaciones



Perfil


La única solución que funcionó para mí sin romper el diseño del menú fue:

<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 Esto terminaría en un HTML de mala semántica.

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

Dejo esto aquí en caso de que ayude a alguien (ejecutando v3.9.0). Necesitaba un <Select> para actuar como un menú de react-router-dom <Link> s. Cada enlace correspondía a una configuración de idioma, por lo que el menú desplegable mostraría el valor del idioma actual del 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>

Esta fue la solución más limpia que pude encontrar que requirió una conversión mínima de TypeScript y mantuvo imágenes consistentes con Material UI.

@goyney tiene la solución, gracias

Voy a agregar a esto, en caso de que alguien más lo haya encontrado también.

En v3.4, puede lograr esto así:

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

...

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

Solución funcional y limpia, gracias ❤️

Para enlaces externos querrás usar component="a" , pero también rodear el MenuItem en <li> :

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

Esto genera el siguiente 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>

Supongamos que tengo un menú emergente y uso

importar {Enlace} desde 'react-router-dom';
importar MenuItem desde '@material-ui/core/MenuItem';

\\

El enlace abrirá la página /your-path, ¿cómo se cerraría el menú emergente?

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

FranBran picture FranBran  ·  3Comentarios

ghost picture ghost  ·  3Comentarios

chris-hinds picture chris-hinds  ·  3Comentarios

pola88 picture pola88  ·  3Comentarios

revskill10 picture revskill10  ·  3Comentarios