同步两个 MDC 抽屉

Synchronizing two MDC drawers

在我的页面中,我有两个 Material 设计组件抽屉,其中包含相同的项目。一个是 desktop/tablet 永久显示,另一个是 hidden/modal 移动显示。

<aside class="mdc-drawer mdc-drawer--permanent">
    <div class="mdc-drawer__header">
        <h3 class="mdc-drawer__title">App</h3>
        <h6 class="mdc-drawer__subtitle">@username</h6>
    </div>
    <div class="mdc-drawer__content">
        <nav class="mdc-list--permanent">@menu_drawer_content</nav>
    </div>
</aside>

<aside class="mdc-drawer mdc-drawer--modal">
    <div class="mdc-drawer__header">
        <h3 class="mdc-drawer__title">App</h3>
        <h6 class="mdc-drawer__subtitle">@username</h6>
    </div>
    <div class="mdc-drawer__content">
        <nav class="mdc-list">@menu_drawer_content</nav>
    </div>
</aside>

两者都已初始化:

modalDrawer = mdc.drawer.MDCDrawer.attachTo(document.querySelector('.mdc-drawer--modal'));
let list = mdc.list.MDCList.attachTo(document.querySelector('.mdc-list--permanent'));
list.wrapFocus = true;

我有 javascript 可以将一个切换到另一个:

let smallForm = window.matchMedia("(max-width: 767px)").matches;

function resized() {
    let smallForm_ = window.matchMedia("(max-width: 767px)").matches;
    if (smallForm !== smallForm_) {
        smallForm = smallForm_;
        changedMedia();
    }
}

function changedMedia() {
    let drawerButton = $('.mdc-top-app-bar__row > section > button');
    if (smallForm) {
        $('.mdc-drawer--permanent').hide();
        drawerButton.show();
    } else {
        $('.mdc-drawer--permanent').show();
        drawerButton.hide();
        modalDrawer.open = false;
    }
}

仍然存在的一个错误是 select 将一个抽屉中的项目 select 放入另一个抽屉中的相同项目。如果我从一种尺寸转换为另一种尺寸,selected 项目将与内容不匹配。

我可以 link 两个抽屉,这样一个抽屉上的 selection 会改变另一个抽屉的状态吗(特别是不触发 "other" 抽屉上的事件或进入递归循环交叉通知循环)?

编辑:添加赏金。 Full source.

弄清楚如何“撤消”MDC 组件实例化,以便您可以使用单个抽屉并在模式和永久之间切换,同时保留对抽屉列表项的选择。下面代码片段的重要部分是在切换媒体时调用destroy(),以便您可以修改抽屉class并重新实例化成功。

let timeout;
let activeBar;
let activeDrawer;
let activeList;
const actualResizeHandler = () => {
  const fixedStyles = () => {
    document.body.style = 'display: flex; height: 100vh;';
    document.querySelector('.mdc-drawer-app-content').style = 'flex: auto; overflow: auto;';
    document.querySelector('.main-content').style = 'height: 100%; overflow: auto;';
    document.querySelector('.mdc-top-app-bar').style = 'position: absolute;';
  };

  const modalStyles = () => {
    document.body.removeAttribute('style');
    document.querySelector('.mdc-drawer-app-content').removeAttribute('style');
    document.querySelector('.main-content').removeAttribute('style');
    document.querySelector('.mdc-top-app-bar').removeAttribute('style');
  };
  
  const bar = document.querySelector('.mdc-top-app-bar');
  const drawer = document.querySelector('.mdc-drawer');
  const list = document.querySelector('.mdc-list');
  if (typeof activeBar !== 'undefined') {
    activeBar.destroy();
  }
    
  if (window.matchMedia('(max-width: 767px)').matches) {
    if (typeof activeList !== 'undefined') {
      activeList.destroy();
    }
    
    drawer.classList.add('mdc-drawer--modal');
    drawer.insertAdjacentHTML('afterend', '<div class="mdc-drawer-scrim"></div>');
    modalStyles();
    activeBar = mdc.topAppBar.MDCTopAppBar.attachTo(bar);
    activeBar.listen('MDCTopAppBar:nav', () => {
      if (typeof activeDrawer !== 'undefined') {
        activeDrawer.open = !activeDrawer.open;
      }
      
    });
    
    activeDrawer = mdc.drawer.MDCDrawer.attachTo(drawer);
  } else {
    const scrim = document.querySelector('.mdc-drawer-scrim');
    if (scrim) {
      scrim.remove();
    }
    
    if (typeof activeDrawer !== 'undefined') {
      activeDrawer.destroy();
    }
    
    drawer.classList.remove('mdc-drawer--modal');
    fixedStyles();
    activeList = mdc.list.MDCList.attachTo(list);
    activeList.wrapFocus = true;
  }
};

const resizeThrottler = () => {
  if (!timeout) {
    timeout = setTimeout(() => {
      timeout = null;
      actualResizeHandler();
     }, 66);
  }
};
  
window.addEventListener('resize', resizeThrottler, false);
actualResizeHandler();
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Material Modal / Dismissible Drawer Example</title>
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700">
    <link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css" rel="stylesheet">
    <script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
  </head>
  <body>
    <aside class="mdc-drawer">
      <div class="mdc-drawer__content">
        <nav class="mdc-list">
          <a class="mdc-list-item mdc-list-item--activated" href="#" tabindex="0" aria-current="page">
            <span class="mdc-list-item__text">Item 1</span>
          </a>
          <a class="mdc-list-item" href="#" tabindex="-1">
            <span class="mdc-list-item__text">Item 2</span>
          </a>
          <a class="mdc-list-item" href="#" tabindex="-1">
            <span class="mdc-list-item__text">Item 3</span>
          </a>
        </nav>
      </div>
    </aside>
    <div class="mdc-drawer-app-content">
      <header class="mdc-top-app-bar">
        <div class="mdc-top-app-bar__row">
          <section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-start">
            <button class="material-icons mdc-top-app-bar__navigation-icon mdc-icon-button">menu</button>
            <span class="mdc-top-app-bar__title">Title</span>
          </section>
        </div>
      </header>
      <main class="main-content">
        <div class="mdc-top-app-bar--fixed-adjust">
          App Content
        </div>
      </main>
    </div>
  </body>
</html>