Material-ui: [MenuItem] Liens dans les éléments de menu

Créé le 6 janv. 2015  ·  43Commentaires  ·  Source: mui-org/material-ui

Salut, je regardais l'implémentation actuelle des éléments de menu et j'ai remarqué qu'il n'y avait pas de lien réel (ce qui signifie, balise html <a> ). En conséquence, par exemple, même dans la barre de navigation, il n'y a pas de lien réel et les transitions vers d'autres pages sont gérées via des événements onclick.

Je pense qu'avoir des liens serait une amélioration, surtout si l'on considère les pages rendues côté serveur.

Pensez-vous que cela a du sens, ou avez-vous des raisons précises de ne pas aller dans cette direction ?

v0.x

Commentaire le plus utile

Utilisez l'accessoire containerElement !

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

Tous les 43 commentaires

Je m'interroge aussi à ce sujet. J'utilise le rendu côté serveur dans mon application, c'est quelque chose à examiner.

L'utilisation d'éléments d'ancrage avec des attributs href améliorerait également l'accessibilité et permettrait aux utilisateurs d'utiliser le comportement de navigateur auquel ils sont habitués (par exemple, ⌘-Cliquez pour ouvrir dans un nouvel onglet).

+1

+1

+1

+1

+1

+1

+1

@ecesena pensez -vous que ce serait toujours un problème avec le nouveau composant MenuItem ? Voir ici . Les MenuItem s peuvent être entourés de <a>..</a> , non ?

c'est possible avec ce que @shaurya947 a suggéré.

J'essaie d'utiliser MenuItems dans mon LeftNav comme ceci :

        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>
        )

Envelopper un <a> autour d'une balise <MenuItem> lance un avertissement validateDOMNesting(...): <a> cannot appear as a descendant of <a>. See MainLayout > a > ... > MenuItem > ListItem > EnhancedButton > a"

Si vous effectuez une inspection React de la sortie, vous obtenez ce qui suit.

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

qui a imbriqué des éléments <a> est offensant.

<MenuItems> génère des éléments <a> dans la déclaration Button. Quel accessoire est utilisé à partir de MenuItem pour remplir l'attribut href dans le <EnhancedButton> généré ?

L'utilisation d'un objet MenuItem comme accessoire pour LeftNav fait fonctionner la liaison, mais je n'ai pas réussi à comprendre comment ajouter des icônes gauche/droite de cette façon.

c'est à dire:

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

il s'agit d'un problème distinct, veuillez en ouvrir un, afin que nous puissions l'étiqueter et l'ajouter aux jalons, tnx :grin:

Utilisez l'accessoire containerElement !

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

Maintenant, la prop linkButton de EnhancedButton est obsolète. LinkButton n'est plus requis lorsque la propriété href est fournie. Il sera supprimé avec la v0.16.0.

Par example:

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

href recharge la page. que diriez-vous si je veux utiliser le routeur de réaction

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

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

la documentation mentionne que vous devez également saisir linkButton . si vous supprimez cela, cela fonctionne sans erreur.

@DaxChen J'ai vu votre réponse mise à jour de stackoverflow pour décembre 2016 (extrêmement récente haha) et je me demandais si vous saviez si cela fonctionnait pour un élément de menu dans un tiroir? J'essaie ce qui suit ci-dessous et j'ai été totalement incapable de faire fonctionner Link avec le MenuItem car containerElement semble ne rien faire.

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

containerElement fonctionne mais n'est pas documenté, donc je suppose que ce fil devra servir de documentation officielle pour le moment. Merci!

Salut @Faolain !

Vraiment désolé pour la réponse tardive...
J'ai essayé votre code sur une application propre avec create-react-app , mais tout semblait bien fonctionner ?!
Peut-être avez-vous configuré react-router différemment, ou la version est-elle différente ?

Quoi qu'il en soit, voici un exemple de dépôt et la démo en direct ici .

Si vous ne trouvez toujours pas la cause de votre problème, pouvez-vous fournir un exemple de référentiel à reproduire ?

Aucune des solutions ci-dessus n'a fonctionné sur Safari et iOS. Alors voici ce que j'ai fait comme contournement pour react-router

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

@janzenz est- ce que cet exemple ici ne fonctionne pas dans votre navigateur ?

Je l'ai essayé dans Safari sur macOS et Safari sur iOS et ils fonctionnent tous. Cela ne fonctionne pas pour vous ?

Bien que votre solution de contournement fonctionne, elle peut entraîner un mauvais référencement et vous perdrez certains comportements natifs tels que l'aperçu du lien et l'option-clic pour ouvrir dans un nouvel onglet.

@DaxChen merci pour les informations. Je ne sais pas si mon problème est lié à votre premier lien. J'ai déjà essayé le 2ème mais une fois que j'ai ajouté un accessoire onTouchTap le <Link /> ne fonctionne plus.

@janzenz J'ai ajouté onTouchTap prop dans mon exemple précédent et cela fonctionne toujours.
Je ne sais pas si votre réglage est différent quelque part ou quelque chose...
Vous pouvez consulter le code mis à jour et voir si cela fonctionne pour vous ?

@DaxChen Je vois que vous utilisez material-ui à la version ~0.16.0 . Avez-vous essayé la dernière version de ~0.17.0 et voyez si ce n'est toujours pas un problème ?

@janzenz J'utilisais une ancienne version, juste mise à jour vers la dernière version 0.17.4 et cela fonctionne toujours !

Touché ! Probablement ma configuration alors. Merci d'avoir confirmé que @DaxChen je reviendrai sur ce fil si j'ai trouvé le vrai problème.

@DaxChen , j'ai essayé l'exemple que vous m'avez donné, mais il échoue

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

Mon code est disponible sur https://github.com/hhimanshu/spicyveggie/tree/cards (branche cards )

Je ne sais pas ce qui est différent, mais cela ne fonctionne tout simplement pas

@janzenz
J'ai également essayé browserHistory.push('/howItWorks') et importé import browserHistory from 'react-router-dom' , mais j'ai obtenu undefuned .

@Oduig ,
J'ai essayé #/your/link , mais ça ne m'amène nulle part
J'ai essayé /your/link , mais il recharge la page et je perds Drawer de Material-UI

Aucune de ces choses n'a fonctionné pour moi. Mon code est disponible sur https://github.com/hhimanshu/spicyveggie/tree/cards (branche cards ), le commit spécifique est https://github.com/hhimanshu/spicyveggie/commit/844b7b7cddf9102995cd2680a783df3b6ef48537 , Pourrait quelqu'un s'il vous plaît aider?

@hhimanshu change cette ligne en

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

plus d'infos sur MDN

@DaxChen , merci. C'était ça. Cependant, pas lorsque ma page se charge avec {<Link to="/menu"/>} , elle charge la page entière et mon Drawer est parti.

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

@hhimanshu c'est parce que vous n'avez utilisé que le composant Menu dans votre \menu route , donc App ne sera pas rendu.

Imbriquer vos Menu et Summary intérieur de App ou de certains composants de mise en page, et transmettre les enfants respectifs.

Vous pouvez utiliser react-devtools pour vérifier la hiérarchie des composants rendus et ses états !

Ceci n'est pas lié à material-ui, veuillez en savoir plus dans les didacticiels/docs de react-router.

+1

Solutions de contournement pour les liens GÉRÉS ET NON GÉRÉS par React Router.


Si le lien cible est géré par 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;

Exemple de code :

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

Si le lien cible n'est PAS géré par React Router, c'est-à-dire que la demande est transmise à un serveur API ou autre

Fonction onClick :

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

Exemple de code :

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

Je viens ajouter à cela, au cas où quelqu'un d'autre tomberait dessus également.

Sur la v3.4, vous pouvez y parvenir comme ceci :

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

...

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

La seule solution qui a fonctionné pour moi sans casser la disposition du menu était :
```javascript


Notifications



Profil


La seule solution qui a fonctionné pour moi sans casser la disposition du menu était :

<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 Cela aboutirait à un HTML sémantique médiocre.

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

Laissez ceci ici au cas où cela aiderait quelqu'un (exécutant v3.9.0). J'avais besoin d'un <Select> pour servir de menu de react-router-dom <Link> s. Chaque lien correspondait à un paramètre de langue, la liste déroulante afficherait donc la valeur de la langue actuelle à partir du paramètre de requête.

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

C'était la solution la plus propre que j'ai pu trouver qui nécessitait un casting TypeScript minimal et des visuels maintenus cohérents avec Material UI.

@goyney a la solution, merci

Je viens ajouter à cela, au cas où quelqu'un d'autre tomberait dessus également.

Sur la v3.4, vous pouvez y parvenir comme ceci :

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

...

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

Solution fonctionnelle et propre, merci ️

Pour les liens externes, vous voudrez utiliser component="a" , mais aussi entourer le MenuItem de <li> :

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

Cela génère le code HTML suivant :

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

Supposons que j'ai un menu contextuel et que j'utilise

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

\\

Le lien fera apparaître la page /your-path, comment fermer le menu contextuel ?

Cette page vous a été utile?
0 / 5 - 0 notes