Понимание Angular 4 Framework и веб-компонента MDC: Drawer

Главный вопрос

Основная проблема, с которой я столкнулся, заключается в понимании того, как используется определенная строка кода, а именно объект mdc (ниже в приведенном примере кода) в документации MDC Webcomponent Drawer. По-видимому, я не могу размещать более 2 ссылок, потому что у меня недостаточно очков «репутации» bs. Поэтому я не могу связать все исследования, которые я действительно провел, чтобы найти ответ для себя... Таким образом, пример Drawer является рабочим примером и исходным кодом из него. Я прочитал эти конкретные ресурсы:

Пример кода

Ниже приведен код целиком. Если бы я вставил это непосредственно в файл "index.html" в каталоге src/ проекта angular4, он работал бы правильно, поэтому я явно не понимаю, как получить доступ к mdc объект, который, по-видимому, исходит из файла material-web-components.js. Я думаю, что каким-то образом мне нужно сделать объект mdc в этом файле .js доступным для моего проекта angular4, и я довольно много исследовал это, но, вероятно, я не задаю правильный вопрос. Во всех примерах просто говорится: используйте сеть доставки контента (CDN) или ссылайтесь на нее локально в своем проекте через каталог ./assets/ или через папку node_modules/. Я могу получить доступ к файлу .js либо через CDN, либо через локальные ресурсы/ссылку, но он доступен только в этом файле index.html верхнего уровня. Если я попытаюсь использовать его в любой другой части проекта angular4, например, в корневом компоненте приложения, он не будет подключен или не работает. Нужно ли мне сделать это доступным где-то, например, в файле конфигурации, app.module.ts, импорте и т. д.?

<!DOCTYPE html>
<!--
  Copyright 2016 Google Inc. All rights reserved.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      https://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License
-->
<html>
  <head>
    <meta charset="utf-8">
    <title>Drawer (Persistent) - Material Components Catalog</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" type="image/png" href="/images/logo_components_color_2x_web_48dp.png" />
    <script src="../assets/material-components-web.css.js" charset="utf-8"></script>
    <script src="../assets/demo-styles.css.js" charset="utf-8"></script>
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
    <style>
    /* Ensure layout covers the entire screen. */
    html {
      height: 100%;
    }

    /* Place drawer and content side by side. */
    .demo-body {
      display: flex;
      flex-direction: row;
      padding: 0;
      margin: 0;
      box-sizing: border-box;
      height: 100%;
      width: 100%;
    }

    /* Stack toolbar and main on top of each other. */
    .demo-content {
      display: inline-flex;
      flex-direction: column;
      flex-grow: 1;
      height: 100%;
      box-sizing: border-box;
    }

    .demo-main {
      padding-left: 16px;
    }
    </style>
  </head>
  <body class="demo-body mdc-typography">
    <aside class="mdc-persistent-drawer">
      <nav class="mdc-persistent-drawer__drawer">
        <div class="mdc-persistent-drawer__toolbar-spacer"></div>
        <div class="mdc-list-group">
          <nav class="mdc-list">
            <a class="mdc-list-item mdc-persistent-drawer--selected" href="#">
              <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">inbox</i>Inbox
            </a>
            <a class="mdc-list-item" href="#">
              <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">star</i>Star
            </a>
            <a class="mdc-list-item" href="#">
              <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">send</i>Sent Mail
            </a>
            <a class="mdc-list-item" href="#">
              <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">drafts</i>Drafts
            </a>
          </nav>

          <hr class="mdc-list-divider">

          <nav class="mdc-list">
              <a class="mdc-list-item" href="#">
                <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">email</i>All Mail
              </a>
              <a class="mdc-list-item" href="#">
                <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">delete</i>Trash
              </a>
              <a class="mdc-list-item" href="#">
                <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">report</i>Spam
              </a>
            </nav>
          </div>
      </nav>
    </aside>
    <div class="demo-content">
      <header class="mdc-toolbar mdc-elevation--z4">
        <div class="mdc-toolbar__row">
          <section class="mdc-toolbar__section mdc-toolbar__section--align-start">
            <button class="demo-menu material-icons mdc-toolbar__icon--menu">menu</button>
            <span class="mdc-toolbar__title catalog-title">Persistent Drawer</span>
          </section>
        </div>
      </header>

      <main class="demo-main">
        <h1 class="mdc-typography--display1">Persistent Drawer</h1>
        <p class="mdc-typography--body1">Click the menu icon above to open and close the drawer.</p>
      </main>

      <script src="../assets/material-components-web.js" charset="utf-8"></script>
      <script>
        var drawerEl = document.querySelector('.mdc-persistent-drawer');
        var MDCPersistentDrawer = mdc.drawer.MDCPersistentDrawer;
        var drawer = new MDCPersistentDrawer(drawerEl);
        document.querySelector('.demo-menu').addEventListener('click', function() {
          drawer.open = !drawer.open;
        });
        drawerEl.addEventListener('MDCPersistentDrawer:open', function() {
          console.log('Received MDCPersistentDrawer:open');
        });
        drawerEl.addEventListener('MDCPersistentDrawer:close', function() {
          console.log('Received MDCPersistentDrawer:close');
        });
      </script>
    </div>
  </body>
</html>

Соответствующий код

Соответствующая строка: var MDCPersistentDrawer = mdc.drawer.MDCPersistentDrawer; и объект mdc не распознан.

Ниже приведен конкретный код:

      <script src="../assets/material-components-web.js" charset="utf-8"></script>
      <script>
        var drawerEl = document.querySelector('.mdc-persistent-drawer');
        var MDCPersistentDrawer = mdc.drawer.MDCPersistentDrawer;
        var drawer = new MDCPersistentDrawer(drawerEl);
        document.querySelector('.demo-menu').addEventListener('click', function() {
          drawer.open = !drawer.open;
        });
        drawerEl.addEventListener('MDCPersistentDrawer:open', function() {
          console.log('Received MDCPersistentDrawer:open');
        });
        drawerEl.addEventListener('MDCPersistentDrawer:close', function() {
          console.log('Received MDCPersistentDrawer:close');
        });
      </script>

Отсутствие понимания

Я новичок в JavaScript, среде MVC, Angular2/4/Angular-cli и интеграции набора инструментов Material Design. Я учу себя этому в течение нескольких месяцев и пытаюсь сформулировать фундаментальное понимание всего этого вместе. Я уже прошел и построил весь пример проекта Angular «Heroes» и прочитал с ним поверхностную документацию, поэтому я попытался подготовиться к концепциям и тому, как работать с этой конкретной структурой. Я чувствую, что мне не хватает чего-то простого (может быть, сложного) здесь с этим объектом mdc. В документации проекта Github они реализуют JavaScript немного иначе, чем в примере Drawer, как вы можете видеть:

HTML

<aside class="mdc-persistent-drawer mdc-typography">
  <nav class="mdc-persistent-drawer__drawer">
    <header class="mdc-persistent-drawer__header">
      <div class="mdc-persistent-drawer__header-content">
        Header here
      </div>
    </header>
    <nav id="icon-with-text-demo" class="mdc-persistent-drawer__content mdc-list">
      <a class="mdc-list-item mdc-persistent-drawer--selected" href="#">
        <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">inbox</i>Inbox
      </a>
      <a class="mdc-list-item" href="#">
        <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">star</i>Star
      </a>
    </nav>
  </nav>
</aside>

JS:

let drawer = new mdc.drawer.MDCPersistentDrawer(document.querySelector('.mdc-persistent-drawer'));
document.querySelector('.menu').addEventListener('click', () => drawer.open = true);

Но они по-прежнему ссылаются на этот объект mdc и каким-то образом имеют к нему доступ. Я уже установил все веб-компоненты через npm следующим образом: npm install --save material-components-web и следовал инструкциям здесь (material.io/components/web/), как начать работу.

Так что я упускаю или не понимаю?

Спасибо за любую помощь.


person Brandon Authier    schedule 12.07.2017    source источник
comment
Почему вы не используете Angular Material? Все еще в бета-версии и есть некоторые ошибки, но это очень приятно.   -  person André Roggeri Campos    schedule 14.07.2017
comment
Я пробовал Angular Material, Material Design Lite и Material Design (веб-компоненты, также известные как MDC). Я обнаружил, что с Angular Material он обычно не отображается должным образом с такими вещами, как панель инструментов, ящик, карточки или компонент *insert. Теперь это может быть связано с моим уровнем знаний в настоящее время, поэтому, возможно, стоит создать еще один каркасный проект. У меня довольно короткий срок, который я хотел бы сохранить, поэтому я пытался выбрать набор инструментов, который даст мне наилучшие результаты. Кроме того, мой вопрос оказался не связанным с набором инструментов, а с фреймворком.   -  person Brandon Authier    schedule 15.07.2017


Ответы (1)


Вот что я сделал, чтобы заставить базовый пример работать.

npm install --save material-components-web

После того, как это будет установлено, вам необходимо обновить файл .angular-cli.json. Добавьте "../node_modules/material-components-web/dist/material-components-web.min.css" под строкой "styles.css" в массиве стилей и "../node_modules/material-components-web/dist/material-components-web.min.js" в качестве записи в массиве скриптов.

Я не знаком с этой веб-библиотекой material-components, но чтобы пример соответствовал вашему, я обновил src/index.html до

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>TestMcw</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body class="demo-body mdc-typography">
  <app-root></app-root>
</body>
</html>

А затем src/app/app.component.html в

<aside class="mdc-persistent-drawer" #drawer>
      <nav class="mdc-persistent-drawer__drawer">
        <div class="mdc-persistent-drawer__toolbar-spacer"></div>
        <div class="mdc-list-group">
          <nav class="mdc-list">
            <a class="mdc-list-item mdc-persistent-drawer--selected" href="#">
              <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">inbox</i>Inbox
            </a>
            <a class="mdc-list-item" href="#">
              <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">star</i>Star
            </a>
            <a class="mdc-list-item" href="#">
              <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">send</i>Sent Mail
            </a>
            <a class="mdc-list-item" href="#">
              <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">drafts</i>Drafts
            </a>
          </nav>

          <hr class="mdc-list-divider">

          <nav class="mdc-list">
              <a class="mdc-list-item" href="#">
                <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">email</i>All Mail
              </a>
              <a class="mdc-list-item" href="#">
                <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">delete</i>Trash
              </a>
              <a class="mdc-list-item" href="#">
                <i class="material-icons mdc-list-item__start-detail" aria-hidden="true">report</i>Spam
              </a>
            </nav>
          </div>
      </nav>
    </aside>
    <div class="demo-content">
      <header class="mdc-toolbar mdc-elevation--z4">
        <div class="mdc-toolbar__row">
          <section class="mdc-toolbar__section mdc-toolbar__section--align-start">
            <button class="demo-menu material-icons mdc-toolbar__icon--menu" (click)="toggle()">menu</button>
            <span class="mdc-toolbar__title catalog-title">Persistent Drawer</span>
          </section>
        </div>
      </header>

      <main class="demo-main">
        <h1 class="mdc-typography--display1">Persistent Drawer</h1>
        <p class="mdc-typography--body1">Click the menu icon above to open and close the drawer.</p>
      </main>
</div>

И, наконец, файл src/app/app.component.ts для

import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';

declare var mdc: any;

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {
  @ViewChild('drawer') drawerEl: ElementRef;

  drawer: any;
  ngAfterViewInit(): void {
        const MDCPersistentDrawer = mdc.drawer.MDCPersistentDrawer;
        this.drawer = new MDCPersistentDrawer(this.drawerEl.nativeElement);
        this.drawerEl.nativeElement.addEventListener('MDCPersistentDrawer:open', function() {
          console.log('Received MDCPersistentDrawer:open');
        });
        this.drawerEl.nativeElement.addEventListener('MDCPersistentDrawer:close', function() {
          console.log('Received MDCPersistentDrawer:close');
        });
  }

  toggle() {
    this.drawer.open = !this.drawer.open;
  }
}

Здесь есть ряд вещей, на которые стоит обратить внимание. #drawer в html в сочетании с @ViewChild('drawer') drawerEl: ElementRef; в файле ts дает вам нужный элемент без селектора документов.

declare var mdc: any; в файле ts поможет вам с Typescript. Многие пакеты npm имеют соответствующий файл объявлений машинописного текста, который можно установить следующим образом: npm install --save @types/material-components-web, но в этой библиотеке, похоже, его нет. Оператор declare сообщает компилятору, что существует переменная с именем mdc, и она имеет тип «любой», что означает, что вывод типа невозможен, поэтому он позволит вам получить доступ к любым свойствам этого объекта без жалоб.

Вы можете использовать фреймворк для доступа к событиям dom (см. (щелчок) в html выше), но я не знаю, как сделать то же самое с фреймворком для пользовательских библиотечных событий, таких как «MDCPersistentDrawer: open», поэтому эти все еще необходимо настроить в файле ts, как показано выше.

Надеюсь это поможет!


ОБНОВЛЕНИЕ

Ответ на ваши вопросы:

  1. Разница между операторами импорта и объявления. import использует новую функцию модуля JavaScript. В идеале следует использовать этот. Если вы используете этот подход, вы можете удалить "../node_modules/material-components-web/dist/material-components-web.min.js" из вашего файла .angular-cli.json. Если все настроено правильно, это позволит Angular cli делать некоторые приятные вещи во время AOT при сборке в режиме prod (ng build --prod).

ОДНАКО, с этой конкретной библиотекой на данный момент, похоже, есть ошибка, потому что, если вы используете этот подход, cli выдаст вам ошибку сборки: Unexpected token: name (MDCTabBarFoundation). Наличие этого js-файла в разделе script вашего файла angular-cli.json помещает переменную mdc в глобальную область и удаляет возможность Angular выполнять AOT для нее, но в этом случае это позволит AOT продолжать работать в течение остальная часть вашего приложения. Затем оператор declare сообщает Typescript об этой глобальной переменной, поэтому он не будет жаловаться во время транспиляции.

  1. В их официальной документации используется ElementRef. Я вижу, что вы говорите об их предупреждении, но я не вижу никаких других "официальных ' способ достижения такого типа результата.
person peinearydevelopment    schedule 13.07.2017
comment
Спасибо за ответ. Вчера, после того как я опубликовал этот вопрос, я продолжал искать и пробовать разные вещи. Я нашел несколько ключевых вещей, и одна из них заключалась в том, как получить ссылку на элементы, которую вы хорошо показали здесь, и на этом я остановился. Я дошел до того, что нашел @VeiwChild, но не понял, что вы обозначаете элемент с помощью #. Я также обнаружил, что вы можете import * as mdc from 'material-components-web'; импортировать объектную переменную (?). Я не уверен, что предпочтительнее декларировать или импортировать, может быть, это просто выбор стиля? - person Brandon Authier; 14.07.2017
comment
Кроме того, в этом примере панель инструментов размещается под скрытым ящиком, а над ним рисуются слайды, чего никто не хочет. Мне придется поиграть с другими примерами теперь, когда я правильно подключил их благодаря вам. Что касается AfterViewInit, я просмотрел документацию Angular, и это только для любого компонента, который необходимо просмотреть после того, как начальное представление было отрисовано? Angular также предостерегает от прямого доступа к DOM с помощью ElementRef, это проблема? Должен ли я в какой-то момент задуматься об этом и попытаться придумать что-то еще, например, использовать Renderer2? - person Brandon Authier; 14.07.2017
comment
@BrandonAuthier Я обновил свой ответ, чтобы ответить на ваши вопросы. - person peinearydevelopment; 14.07.2017
comment
Спасибо. Я ценю обновленный ответ и информацию. Попытка понять, как все взаимодействует и работает, оказалась намного сложнее, чем я изначально предполагал. Это вознаграждало борьбу и обучение, но немного замедлило разработку :) Я буду продолжать заниматься этим и пытаться понять, как работает Angular Framework. - person Brandon Authier; 15.07.2017
comment
@BrandonAuthier Я только что наткнулся на эта статья. # 9 обсуждает использование Renderer2. У меня еще не было времени попробовать это, но я хотел, чтобы вы знали об этом из-за вашего вопроса и моего менее чем удовлетворительного ответа ранее. - person peinearydevelopment; 24.07.2017
comment
ах большое спасибо. Эта статья вообще отличная. - person Brandon Authier; 26.07.2017