Проблемы с макетом Office UI Fabric

[РЕДАКТИРОВАТЬ: обновлено, чтобы сосредоточить внимание на проблеме наложения; также были внесены изменения в CodePens] [EDIT2: обновлено, чтобы включить детали о методе, предложенном Мохамедом Мансуром]

У меня возникают трудности при разработке макета для Office UI Fabric React UI. Это макет, который у меня сейчас есть:

введите описание изображения здесь

Цель состоит в том, чтобы верхний CommandBar и заголовки (текстовые метки и поле поиска) были привязаны к верху, а DetailsList и кнопка хранения прикреплены к нижней части и занимали как можно больше места после области заголовка.

Я успешно использовал ScrollablePane и два Sticky-компонента, чтобы закрепить CommandBar и кнопку в нужных местах. Тем не менее, DetailsList прокручивает верхний стик, содержащий CommandBar и заголовок, и кнопка слегка накладывается поверх сетки DetailsList:

введите описание изображения здесь

Я попытался использовать компонент Fabric Grid для разметки всех разделов, но это не имеет значения (если это вообще поможет). Лучший макет имеет раздел проектов между двумя Sticky элементами; макет ужасен, если раздел проекта добавлен к элементам "Заголовок" или "Нижний колонтитул". Как я могу убедиться, что DetailsList не прокручивается под верхним и нижним компонентами?

Вот две ручки кода, которые иллюстрируют проблему:

Без сетки: https://codepen.io/elegault/pen/aQayvY?editors=0010 (fileHeader использует сетку для своих элементов, но все остальные элементы не находятся в сетке)

const columns = [{
  key: 'projectNameColumn',
  name: 'Project',
  fieldName: 'name',
  minWidth: 100,
  maxWidth: 200,
  isResizable: true,
  ariaLabel: 'Operations for Project'
}];
const items = [{
    id: '0',
    name: 'ABC Construction'
  },
  {
    id: '1',
    name: 'Air Bee and Bee'
  },
  {
    id: '2',
    name: 'Architectural Salvage'
  },
  {
    id: '3',
    name: 'Arkham Airport'
  },
  {
    id: '4',
    name: 'Arkham Assembly Hall'
  },
  {
    id: '5',
    name: 'Arkham Library'
  },
  {
    id: '6',
    name: 'zArkham Renovation'
  },
  {
    id: '7',
    name: 'Foo'
  },
  {
    id: '8',
    name: 'Foo1'
  },
  {
    id: '9',
    name: 'Foo2'
  },
  {
    id: '10',
    name: 'Foo3'
  },
  {
    id: '11',
    name: 'Foo4'
  },
  {
    id: '12',
    name: 'Foo5'
  },
  {
    id: '13',
    name: 'Foo6'
  },
  {
    id: '14',
    name: 'Foo7'
  },
  {
    id: '15',
    name: 'Foo8'
  },
  {
    id: '16',
    name: 'Foo9'
  },
  {
    id: '17',
    name: 'Foo10'
  },
];
class Content extends React.Component {
  public render() {
    const fileHeader = <
      div className = 'ms-Grid' >
      <
      div className = 'ms-Grid-row' >
      <
      div className = 'ms-Grid-col ms-sm2 ms-md2 ms-lg2' >
      <
      img width = '32'
    height = '32'
    alt = 'logo'
    title = 'logo' / >
      <
      /div> <
      div className = 'ms-Grid-col ms-sm10 ms-md10 ms-lg10' >
      <
      Fabric.Label className = 'ms-font-l ms-fontWeight-bold ms-fontColor-blue' > [TITLE] < /Fabric.Label> <
      /div> <
      /div> <
      div className = 'ms-Grid-row' >
      <
      div className = 'ms-Grid-col ms-sm2 ms-md2 ms-lg2' >
      <
      /div> <
      div className = 'ms-Grid-col ms-sm10 ms-md10 ms-lg10' >
      <
      Fabric.Label
    className = 'ms-font-m ms-fontWeight-bold ms-fontColor-neutralPrimary' > SELECTED PROJECT: < /Fabric.Label> <
      /div> <
      /div> <
      /div>;

    const commandBar = < div >
      <
      Fabric.CommandBar
    isSearchBoxVisible = {
      false
    }
    items = {
      [{
        key: 'openWebApp',
        name: 'Open Web App',
        icon: 'OpenInNewWindow', // Or Link
        ['data-automation-id']: 'openWebAppButton',
        title: 'Open web app',
        href: 'http://www.codepen.io',
        target: '_blank',
      }]
    }
    farItems = {
      [{
        key: 'menuOptions',
        name: 'Options',
        icon: 'Settings',
        iconOnly: 'true',
        ['data-automation-id']: 'settingsButton',
        subMenuProps: {
          items: [{
              key: 'privacyPolicy',
              name: 'Privacy Policy',
              icon: 'PageLock',
              href: 'http://www.codepen.io',
              target: '_blank',

            },
            {
              key: 'termsOfUse',
              name: 'Terms & Conditions',
              icon: 'TextDocument',
              href: 'http://www.codepen.io',
              target: '_blank'
            }
          ]
        }
      }]
    }
    /> <
    /div>;

    const projects = < Fabric.MarqueeSelection selection = {
      null
    }
    data - is - scrollable = {
        false
      } >
      <
      Fabric.DetailsList
    items = {
      items
    }
    columns = {
      columns
    }
    /> <
    /Fabric.MarqueeSelection>;
    const selection = < div > [project name] < /div>;
    const search = < Fabric.TextField label = 'Search projects:' / > ;
    const fileButton = <
      div >
      <
      Fabric.DefaultButton primary = {
        true
      } > File To Project < /Fabric.DefaultButton> <
      /div>;

    return ( <
      Fabric.Fabric >
      <
      div style = {
        {
          height: '500px',
          position: 'relative',
          maxHeight: 'inherit'
        }
      } >
      <
      Fabric.ScrollablePane scrollbarVisibility = {
        Fabric.ScrollbarVisibility.auto
      } >
      <
      Fabric.Sticky stickyPosition = {
        Fabric.StickyPositionType.Header
      } > {
        commandBar
      } {
        fileHeader
      } {
        selection
      } {
        search
      } <
      /Fabric.Sticky>     {
        projects
      } <
      Fabric.Sticky stickyPosition = {
        Fabric.StickyPositionType.Footer
      } > {
        fileButton
      } <
      /Fabric.Sticky>       <
      /Fabric.ScrollablePane> <
      /div> <
      /Fabric.Fabric>
    );
  }
}

ReactDOM.render( <
  Content / > ,
  document.getElementById('content')
);

С полной сеткой: https://codepen.io/elegault/pen/wQxoRR

const columns = [
    {
        key: 'projectNameColumn',
        name: 'Project',
        fieldName: 'name',
        minWidth: 100,
        maxWidth: 200,
        isResizable: true,
        ariaLabel: 'Operations for Project'
    }
];
const items = [
    {id: '0', name: 'ABC Construction'},
    {id: '1', name: 'Air Bee and Bee'},
    {id: '2', name: 'Architectural Salvage'},
    {id: '3', name: 'Arkham Airport'},
    {id: '4', name: 'Arkham Assembly Hall'},
    {id: '5', name: 'Arkham Library'},
    {id: '6', name: 'zArkham Renovation'},
    {id: '7', name: 'Foo'},
    {id: '8', name: 'Foo1'},
    {id: '9', name: 'Foo2'},
    {id: '10', name: 'Foo3'},
    {id: '11', name: 'Foo4'},
    {id: '12', name: 'Foo5'},
    {id: '13', name: 'Foo6'},
    {id: '14', name: 'Foo7'},
    {id: '15', name: 'Foo8'},
    {id: '16', name: 'Foo9'},
    {id: '17', name: 'Foo10'},
];
class Content extends React.Component {
    public render() {        
        
  const commandBar = <div>
            <Fabric.CommandBar
                isSearchBoxVisible={false}
                items={[
                    {
                        key: 'openWebApp',
                        name: 'Open Web App',
                        icon: 'OpenInNewWindow', // Or Link                        
                        title: 'Open web app',
                        href: 'http://www.codepen.io',
                        target: '_blank',
                    }
                ]}
                farItems={[
                    {
                        key: 'menuOptions',
                        name: 'Options',
                        icon: 'Settings',
                        iconOnly: 'true',
                        ['data-automation-id']: 'settingsButton',
                        subMenuProps: {
                            items: [
                                {
                                    key: 'privacyPolicy',
                                    name: 'Privacy Policy',
                                    icon: 'PageLock',
                                    href: 'http://www.codepen.io',
                                    target: '_blank',

                                },
                                {
                                    key: 'termsOfUse',
                                    name: 'Terms & Conditions',
                                    icon: 'TextDocument',
                                    href: 'http://www.codepen.io',
                                    target: '_blank'
                                }
                            ]
                        }
                    }
                ]}
            />
        </div>;
      
        const projects = <Fabric.MarqueeSelection selection={null} data-is-scrollable={false}>
            <Fabric.DetailsList
                items={items}
                columns={columns}              
            />
        </Fabric.MarqueeSelection>;
        const selection = <div>[project name]</div>;
        const search = <Fabric.TextField label='Search projects:'/>;
        const fileButton = 
              <div>
                <Fabric.DefaultButton primary={true}>File To Project</Fabric.DefaultButton>
              </div>;
  
      const fileHeader =             
            <div className='ms-Grid'>
                <div className='ms-Grid-row'>
                    <div className='ms-Grid-col ms-sm2 ms-md2 ms-lg2'>
                        <img width='32' height='32' alt='logo' title='logo'/>
                    </div>
                    <div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
                        <Fabric.Label className='ms-font-l ms-fontWeight-bold ms-fontColor-blue'>[TITLE]</Fabric.Label>
                    </div>
                </div>
                <div className='ms-Grid-row'>
                    <div className='ms-Grid-col ms-sm2 ms-md2 ms-lg2'>
                    </div>
                    <div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
                        <Fabric.Label
                            className='ms-font-m ms-fontWeight-bold ms-fontColor-neutralPrimary'>SELECTED PROJECT:</Fabric.Label>
                    </div>
                </div>
            </div>;
   
        return (
   <Fabric.Fabric>                
    <div style={{height:'500px', position:'relative', maxHeight:'inherit'}}>          
          <Fabric.ScrollablePane scrollbarVisibility={Fabric.ScrollbarVisibility.auto}>
      <div className='ms-Grid'>
       <Fabric.Sticky stickyPosition={Fabric.StickyPositionType.Header}>
        <div className='ms-Grid-row'>
         <div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
          {commandBar}
         </div>
        </div>        
        <div className='ms-Grid-row'>
         <div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
          {fileHeader}
         </div>
        </div>         
        <div className='ms-Grid-row'>
         <div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
          {selection}
         </div>
        </div>       
        <div className='ms-Grid-row'>
         <div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
          {search}            
         </div>
        </div>                  
       </Fabric.Sticky>    
       <div className='ms-Grid-row'>
        <div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
         {projects}            
        </div>
       </div>                              
       <Fabric.Sticky stickyPosition={Fabric.StickyPositionType.Footer}>      
        <div className='ms-Grid-row'>
         <div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
          {fileButton}            
         </div>
        </div>        
       </Fabric.Sticky>      
      </div>
          </Fabric.ScrollablePane>
    </div>
      </Fabric.Fabric>
        );   
  
    }
}

ReactDOM.render( 
  <Content />,
  document.getElementById('content')
);

Кроме того, при попытке использовать классы Flex или определенные высоты в родительских элементах div (согласно предложению Мохамеда Мансура) в проекте за пределами codepens, в котором используются вложенные пользовательские компоненты React, весь DetailsList не отображается. Например, этот DOM-проводник показывает, как даже установка заданной высоты и использование flex в нескольких "основных" div ах по-прежнему не могут отобразить DetailsList:

введите описание изображения здесь

1 ответ

Решение

Давайте проясним некоторые термины, они из документов:

  • ScrollablePane: использует абсолютное позиционирование, родительский элемент должен иметь относительное значение и высоту (от flex или static). Поэтому, если вы хотите, чтобы он растягивался по-своему, вам необходимо удовлетворить эти ограничения.
  • Важно: они идеально подходят для верхних и нижних колонтитулов, но все равно будут находиться в области полосы прокрутки. Обычно используется для нескольких разделов.
  • Перекрывающееся содержимое: это совершенно нормально, верхний и нижний колонтитулы не имеют сплошного фона, установите его на белый, и он будет работать как положено.

Чтобы добиться того, что вы хотели, чтобы полоса прокрутки просто появлялась между верхним и нижним колонтитулами, вы можете добавить обычный CSS. Запустите фрагмент ниже, чтобы увидеть его. В основном просто гибкий макет.

Я также обновил ваш пример: https://codepen.io/mohamedhmansour/pen/rQqqvP

let { DetailsList, Fabric, ScrollablePane, ScrollbarVisibility } = window.Fabric;

function Content() {
  const items = [...Array(500).keys()].map(i => ({key: i, text: `Item ${i}`}));
  
  return (
    <ScrollablePane  scrollbarVisibility={ScrollbarVisibility.auto}> 
      <DetailsList items={items} />
    </ScrollablePane>
  );
}

ReactDOM.render( 
  <Fabric className='wrapper'>
    <div className='header'>Header</div>
    <div className='main'>
      <Content />
    </div>
    <div className='footer'>Footer</div>
  </Fabric>,
  document.getElementById('content')
);
.wrapper {
  display: flex;
  flex-direction: column;
  width: 100%;
  position: absolute;
  top: 0;
  bottom: 0;
}

.main {
  flex: 1;
  position: relative;
}


.header, .footer {
  background: black;
  color: white;
  padding: 10px;
}
<script src="//unpkg.com/react@16/umd/react.development.js"></script>
<script src="//unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<!-- could point to local version -->
<script src="//unpkg.com/office-ui-fabric-react/dist/office-ui-fabric-react.min.js"></script>

<div id='content'></div>

Другие вопросы по тегам