Material-ui: [MenuItem] Ссылки в пунктах меню

Созданный на 6 янв. 2015  ·  43Комментарии  ·  Источник: mui-org/material-ui

Привет, я просматривал текущую реализацию пунктов меню и заметил, что на самом деле нет ссылки (имеется в виду тег html <a> ). В результате, например, даже в панели навигации нет фактической ссылки, а переходы на другие страницы управляются через события onclick.

Я думаю, что наличие ссылок было бы улучшением, особенно учитывая страницы, отображаемые на стороне сервера.

Как вы думаете, есть ли в этом смысл, или у вас есть конкретные причины не идти в этом направлении?

Самый полезный комментарий

Используйте реквизит containerElement !

видеть:
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>
  } />

Все 43 Комментарий

Я тоже думаю об этом. Я использую рендеринг на стороне сервера в своем приложении, это то, на что стоит обратить внимание.

Использование элементов привязки с атрибутами href также улучшит доступность и позволит людям использовать поведение браузера, к которому они привыкли (например, ⌘-Щелкните, чтобы открыть в новой вкладке).

+1

+1

+1

+1

+1

+1

+1

@ecesena Как вы думаете, это все еще будет проблемой с новым компонентом MenuItem ? Смотрите здесь . MenuItem могут быть окружены <a>..</a> , не так ли?

это возможно с тем, что предложил @shaurya947 .

Я пытаюсь использовать MenuItems в моем LeftNav следующим образом:

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

Оборачивая <a> вокруг тега <MenuItem> выдается предупреждение validateDOMNesting(...): <a> cannot appear as a descendant of <a>. See MainLayout > a > ... > MenuItem > ListItem > EnhancedButton > a"

Если вы сделаете проверку вывода React, вы получите следующее.

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

который с вложенными элементами <a> является оскорбительным.

<MenuItems> генерирует элементы <a> в объявлении Button. Какая опора используется из MenuItem для заполнения атрибута href в сгенерированном <EnhancedButton> ?

Использование объекта MenuItem в качестве опоры для LeftNav позволяет связать работу, но я не смог понять, как таким образом добавлять левые/правые значки.

то есть:

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

это отдельная проблема, пожалуйста, откройте ее, чтобы мы могли пометить ее и добавить к вехам, tnx :grin:

Используйте реквизит containerElement !

видеть:
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>
  } />

Теперь реквизит linkButton EnhancedButton устарел. LinkButton больше не требуется, если указано свойство href . Он будет удален с v0.16.0.

Например:

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

href перезагружает страницу. как насчет того, если я хочу использовать реагирующий маршрутизатор

@cezarneaga попробуй href="#/your/link"

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

в документации упоминается, что вам также необходимо ввести linkButton . если это убрать, то работает без ошибок.

@DaxChen Я видел ваш обновленный ответ stackoverflow за декабрь 2016 года (крайне недавний, ха-ха), и мне было интересно, знаете ли вы, работает ли это для элемента меню в ящике? Я пытаюсь сделать следующее ниже, и мне совершенно не удалось заставить Link работать с MenuItem, поскольку containerElement, похоже, ничего не делает.

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

containerElement работает, но не задокументирован, поэтому я думаю, что эта тема пока должна служить официальной документацией. Спасибо!

Привет @Faolain !

Искренне извиняюсь за поздний ответ...
Я попробовал ваш код в чистом приложении с помощью create-react-app , но все вроде работало нормально?!
Может вы по другому настроили react-router или версия другая?

В любом случае, вот пример репозитория и живая демонстрация здесь .

Если вы все еще не можете найти причину своей проблемы, можете ли вы предоставить образец репозитория для воспроизведения?

Ни одно из приведенных выше решений не работало в Safari и iOS. Итак, вот что я сделал в качестве обходного пути для react-router

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

@janzenz этот пример не работает в вашем браузере?

Я попробовал это в Safari на macOS и Safari на iOS, и все они работают. Это не работает для вас?

Хотя ваш обходной путь работает, он может привести к ухудшению SEO, и вы потеряете некоторые собственные функции, такие как предварительный просмотр ссылки и нажатие опции, чтобы открыть в новой вкладке.

@DaxChen спасибо за понимание. Я не уверен, что моя проблема связана с вашей первой ссылкой. Я уже пробовал второй, но как только я добавляю реквизит onTouchTap <Link /> больше не работает.

@janzenz Я добавил реквизит onTouchTap в свой предыдущий пример, и он все еще работает.
Не знаю, отличается ли где-то ваша настройка или что-то в этом роде... 😢
Вы можете проверить обновленный код и посмотреть, работает ли он для вас?

@DaxChen Я вижу, вы используете material-ui в версии ~0.16.0 . Пробовали ли вы последнюю версию ~0.17.0 и посмотрите, не проблема ли это?

@janzenz Я использовал более старую версию, только что обновил ее до последней 0.17.4 и она все еще работает!

Туше! Тогда, наверное, моя установка. Спасибо, что подтвердили, что @DaxChen я вернусь к этой теме, если

@DaxChen , я попробовал пример, который вы мне дали, но он не работает

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

Мой код доступен по адресу https://github.com/hhimanshu/spicyveggie/tree/cards (ветка cards )

Я не уверен, что отличается, но это просто не работает

@janzenz
Я также пробовал browserHistory.push('/howItWorks') и импортировал import browserHistory from 'react-router-dom' , но получил undefuned .

@Oduig ,
Я пробовал #/your/link , но это никуда не ведет
Я пробовал /your/link , но страница перезагружается, и я теряю Drawer из Material-UI

Ни одна из этих вещей не работала для меня. Мой код доступен по адресу https://github.com/hhimanshu/spicyveggie/tree/cards (ветвь cards ), конкретная фиксация https://github.com/hhimanshu/spicyveggie/commit/844b7b7cddf9102995cd2680a783df3b6ef48537 , может кто-нибудь, пожалуйста, помогите?

@hhimanshu измените эту строку на

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

больше информации на MDN

@DaxChen , спасибо. Вот и все. Однако не тогда, когда моя страница загружается с {<Link to="/menu"/>} , она загружает всю страницу, а мой Drawer исчезает.

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

@hhimanshu это потому , что вы использовали только Menu компонента в вашем \menu маршрута , так что App не будут оказаны.

Вложите свои Menu и Summary внутрь App или некоторых компонентов макета и передайте соответствующие дочерние элементы.

Вы можете использовать react-devtools для проверки иерархии отображаемых компонентов и их состояний!

Это не связано с material-ui, пожалуйста, читайте больше в учебниках/документах по реакции-маршрутизатору.

Спасибо @DaxChen , я решил это как https://github.com/hhimanshu/spicyveggie/blob/master/src/index.js#L20.

+1

Обходные пути для ссылок, ОБРАБАТЫВАЕМЫХ И НЕ ОБРАБАТЫВАЕМЫХ React Router.


Если целевая ссылка обрабатывается 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;

Образец кода:

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

Если целевая ссылка НЕ ​​обрабатывается React Router, то есть: запрос перенаправляется на сервер API или что-то еще

Функция onClick:

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

Образец кода:

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

Я собираюсь добавить к этому, на случай, если кто-то еще наткнулся на это.

В v3.4 вы можете добиться этого следующим образом:

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

...

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

Единственное решение, которое сработало для меня без нарушения макета меню, было:
```javascript


Уведомления



Профиль


Единственное решение, которое сработало для меня без нарушения макета меню, было:

<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 Это приведет к плохой семантике HTML.

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

Оставьте это здесь на случай, если это кому-нибудь поможет (под управлением версии 3.9.0). Мне нужно <Select> чтобы действовать как меню из react-router-dom <Link> s. Каждая ссылка соответствовала настройке языка, поэтому в раскрывающемся списке отображалось значение текущего языка из параметра запроса.

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

Это было самое чистое решение, которое я мог найти, которое требовало минимального приведения TypeScript и поддерживало визуальные эффекты, соответствующие пользовательскому интерфейсу материалов.

У @goyney есть решение, спасибо

Я собираюсь добавить к этому, на случай, если кто-то еще наткнулся на это.

В v3.4 вы можете добиться этого следующим образом:

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

...

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

Рабочее и чистое решение, спасибо ❤️

Для внешних ссылок вы захотите использовать component="a" , но также окружите MenuItem <li> :

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

Это генерирует следующий 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>

Предположим, у меня есть всплывающее меню и я использую

импортировать {Link} из 'react-router-dom';
импортировать MenuItem из '@material-ui/core/MenuItem';

\\

Ссылка откроет страницу /your-path, как закрыть всплывающее меню?

Была ли эта страница полезной?
0 / 5 - 0 рейтинги