简体   繁体   English

如何修改多级菜单以与* ngFor和querySelectorAll一起使用?

[英]How to modify a multi-level menu to work with *ngFor & querySelectorAll?

I've been stuck on this forever, and I cannot figure out the issue. 我一直坚持下去,无法解决问题。 I think I may just be out of luck as querySelectorAll isn't very ... angular. 我认为我可能只是运气不好,因为querySelectorAll不是很...棱角分明。

I have implemented the multi-level-menu into an application from this codrops: tympanus.net/codrops/2015/11/17/multi-level-menu/ 我已经通过以下codrops将多级菜单实现到应用程序中:tympanus.net/codrops/2015/11/17/multi-level-menu/

It works great. 效果很好。 Perfectly. 完美。

EXCEPT, when I use *ngFor to create the menus and sub menus. 除此以外,当我使用* ngFor创建菜单和子菜单时。

  <section class="list">
          <nav id="ml-menu" class="menu">
            <button class="action action--close" aria-label="Close Menu"><span class="icon icon--cross"></span></button>
            <div class="menu__wrap">

              <ul data-menu="main" class="menu__level">
                <li class="menu__item" *ngFor='let a of data'><a class="menu__link" attr.data-submenu="{{a.name}}">{{a.name}}</a></li>
              </ul>

              <ul attr.data-menu="{{a.name}}" *ngFor='let a of data' class="menu__level">
                <li class="menu__item" *ngFor="let b of a.subdata"><a class="menu__link">{{b.name}}</a></li>
              </ul>
            </div>
          </nav>
        </section>        

The point of contention is this line of javascript, using queryselectorall to get the menu levels: 争论点是这行javascript,使用queryselectorall获取菜单级别:

 this.menus = [].slice.call(this.el.querySelectorAll('.menu__level'));

When I hand code the html menus, I get this as the result: 当我手动编写html菜单时,得到的结果是:

https://imgur.com/Uledknr https://imgur.com/Uledknr

When I use *ngFor I get this: 当我使用* ngFor我得到这个:

https://imgur.com/KBNZUhm https://imgur.com/KBNZUhm

Can anyone help me figure out why? 谁能帮我找出原因? I'm running the build menu command in ngAfterViewInit as well. 我也在ngAfterViewInit中运行构建菜单命令。

Data is in the following format (it gets mapped in the component service): 数据采用以下格式(在组件服务中被映射):

0 : name: "Name1"
    subdata: Array(3)
    0:{name: "Apple", score: true, id: "pi-cc"}
    1:{name: "Banana", score: true, id: "pi-01"}
    2:{name: "Orange", score: true, id: "pi-02"}
1 : name: "Name2"
    subdata: Array(3)
    0:{name: "Red", score: true, id: "pj-cc"}
    1:{name: "Blue", score: true, id: "pj-01"}
    2:{name: "Green", score: true, id: "pj-02"}

etc. 等等

This happens because you're accessing the DOM before that Angular can inject the elements. 发生这种情况是因为您在Angular可以注入元素之前访问DOM。

If you want an advice, avoid direct access to the DOM as much as possible, it's not only wrong for portability but it also dangerous and it brings a lot of troubles. 如果您需要建议,请尽可能避免直接访问DOM,这不仅对可移植性有问题,而且很危险,并且会带来很多麻烦。

A better (more efficient, more elegant, more Angular ) way to accomplish it, is using the ViewChildren decorator. 使用ViewChildren装饰器是一种更好(更有效,更优雅,更Angular )的实现方法。 Firstly, you have to reference your template elements with a variable: 首先,您必须使用变量引用模板元素:

 <ul 
    #level 
    attr.data-menu="{{a.name}}" 
    *ngFor='let a of data' 
    class="menu__level">
      <li 
         class="menu__item" 
         *ngFor="let b of a.subdata"><a class="menu__link">
            {{b.name}}
       </li>
 </ul>

Then you have to require the reference in the component: 然后,您必须在组件中需要引用:

@ViewChildren('level', {read: ElementRef}) levels: QueryList<ElementRef>;

Then you can use the variable to get the template of any level: 然后,您可以使用该变量获取任何级别的模板:

ngAfterViewInit(){
  let firstLevel = this.levels._results[0].nativeElement;
}

Or convert your QueryList into an Array (how you tried in your question): 或将您的QueryList转换为数组 (您在问题中的尝试方式):

ngAfterViewInit(){
  this.menus = this.levels
                 .toArray()
                 .map(el => el.nativeElement);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM