当前位置: 首页
前端开发
Angular获取ngIf条件渲染DOM元素示例

Angular获取ngIf条件渲染DOM元素示例

热心网友 时间:2026-06-17
转载

Angular获取普通Dom元素的方法

在Angular开发中,获取DOM元素是高频操作,但一个容易被忽略的细节就能卡住开发者很长时间。通常我们通过模板变量名(#greet)配合@ViewChild获取元素,这种方式在绝大多数场景下都很顺手。然而一旦遇上由*ngIf控制显示的元素,问题立刻暴露——获取到的往往是undefined。下面查看一段经典代码:

import { Component, ViewChild, AfterViewInit } from '@angular/core';
@Component({
  selector: 'my-app',
  template: `
    

Welcome to Angular World

Hello {{ name }}

`, }) export class AppComponent { name: string = 'Semlinker'; @ViewChild('greet') greetDiv: ElementRef; ngAfterViewInit() { console.log(this.greetDiv.nativeElement); } }

这段代码在普通元素上运行良好,但一旦换成*ngIf包裹的结构,就会扑空。具体场景如下:

Angular获取ngIf渲染的Dom元素示例

将static改成false 获取

解决方法其实很简单:在@ViewChild的配置选项中,将static显式设置为false。Angular默认的static值就是false,但当你向@ViewChild传递第二个参数时,某些版本下该值可能会被误配置为true。明确指定static: false能让查询行为符合预期——等到结构渲染完成后再去查找。改造后的代码如下:

@ViewChild('dropList', { read: CdkDropList, static: false }) dropList: CdkDropList;
ngAfterViewInit(): void {
    if (this.dropList) {
      console.log(this.dropList)
    }
  }

使用这一方案,就能顺利获取到*ngIf渲染后的cdkDropList实例。顺便提一下,上面这段代码源自一个实际功能:buttonGroup内的按钮与某个列表里的按钮可以互相拖拽,底层正是利用Angular自带的cdk/drag-drop实现。

import { CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';

自己实现的思路

官方文档中的demo比较简单,并未涉及跨组件的拖拽整合。这里分享实现时的核心思路。

首先,将所有需要拖拽的元素都加入cdkDropList。在A组件和B组件各自初始化时,获取各自的DOM元素,并注册到一个全局store中,每个元素附带一个唯一的componentId

A、B组件通过cdkDropListConnectedTo属性控制跨组件拖拽的目标范围,该属性绑定到一个动态数组_connectableDropLists。在页面初始化时,利用RxJS订阅特定componentId的变化,一旦store中有新的拖拽列表注册进来,就更新_connectableDropLists。关键代码片段如下:

const parentId = this.storeService.getProperty(this.pageId, this.componentId, 'parentId');
this.dragDropService.getDragListsAsync(this.pageId, parentId.value)
      .pipe(takeUntil(this.destroy))
      .subscribe(dropLists => {
        this._connectableDropLists = dropLists || [];
      });
this.storeService.getPropertyAsync(this.pageId, this.componentId, 'children')
      .pipe(takeUntil(this.destroy)).subscribe(result => {
        if (!result || result.length === 0) {
          this._children = [];
          this._dragData = [];
          this.changeRef.markForCheck();
        } else {
          const dropbuttonArray = result.filter((item) => {
            const itemType = this.storeService.getProperty(this.pageId, item, 'componentType');
            if (itemType === AdmComponentType.DropdownButton) return item;
          });
          if (dropbuttonArray.length > 0) {
            this._connectableDropLists = [];
            dropbuttonArray.forEach(comId => {
              this.dragDropService.getDragListsAsync(this.pageId, comId)
                .pipe(takeUntil(this.destroy))
                .subscribe(dropLists => {
                  this._connectableDropLists.push(...dropLists);
                });
            });
          }
        }
      });

由于A组件是B组件的父级,因此需要通过当前组件id获取父级id,再进一步获取可拖拽的元素列表。

通过cdkDragData 把拖拽的元素的value,id等值带上

在模板中通过(cdkDropListDropped)="drop($event)"注册拖拽结束的回调。回调里需要处理数据更新——本质上是删除旧父级下的子节点,再将当前组件添加到新父级下面,同时更新parentId。另外,buttonGroup内部的按钮之间也允许互相拖拽,所以需要加一层判断做特殊处理。

drop(event: CdkDragDrop) {
    if (event.previousContainer != event.container) {
      const { eventData } = event.item.data;
      const componentId = eventData[event.previousIndex];
      const oldParentId = this.storeService.getProperty(this.pageId, componentId, 'parentId', false)?.value;
      // delete oldParent children
      const oldParent = this.storeService.getProperties(this.pageId, oldParentId);
      const index = oldParent.children.indexOf(componentId);
      oldParent.children.splice(index, 1);
      // add newParent children
      const oldChildren = this.itemDatas.map(x => x.id.value);
      oldChildren.splice(event.currentIndex, 0, componentId);
      this.storeService.setProperty(this.pageId, componentId, 'parentId', { value: this.componentId }, [[this.pageId, componentId]]);
      this.storeService.setProperty(this.pageId, oldParentId, 'children', oldParent.children, [[this.pageId, oldParentId]]);
      this.storeService.setProperty(this.pageId, this.componentId, 'children', oldChildren);
      this.changeDetector.markForCheck();
      return;
    }
    moveItemInArray(this.itemDatas, event.previousIndex, event.currentIndex);
    const children = this.itemDatas.map(x => x.id.value);
    this.storeService.setProperty(this.pageId, this.componentId, 'children', children);
  }

这样一来,子组件和父组件内部的元素就能互相拖拽,整个交互流程也就顺畅起来。

来源:https://www.jb51.net/article/284189.htm

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
如何用拖放在Flask看板应用中更新数据库状态

如何用拖放在Flask看板应用中更新数据库状态

在Flask看板应用中,通过HTML5拖放API结合前端fetch异步POST请求,将拖拽任务的task_id和target_state发送至后端路由;后端接收JSON后更新数据库并提交事务,实现跨列拖拽时实时更新状态。需注意将事件绑定到容器而非子元素,并在ondragover中阻止默认行为以确保drop触发。

时间:2026-07-09 07:01
如何用CSS :has()选择器快速实现悬停span显示相邻div

如何用CSS :has()选择器快速实现悬停span显示相邻div

利用CSS的:has()伪类选择器,通过` bar:has(> baz:hover)+ qux`实现悬停内联元素时显示相邻块级容器,解决了传统相邻兄弟选择器无法跨层级匹配的局限,可用于悬停图标显示详情框等交互场景。需注意浏览器兼容性和性能优化,避免过度使用影响渲染效率。

时间:2026-07-09 07:01
display:block居中段落文本的响应式实现方法

display:block居中段落文本的响应式实现方法

通过`display:block`与`max-width`限制宽度,配合`margin:auto`使段落块水平居中并实现响应式布局;同时用CSS统一控制段落间距,避免脱离文档流,提升可读性与维护性。

时间:2026-07-09 07:01
JavaScript代码去重:高效避免重复编写的技巧

JavaScript代码去重:高效避免重复编写的技巧

将重复代码中的变化点提取为参数,利用ES6模板字符串动态生成选择器,可消除重复、保持一致性。注意参数安全性,必要时进行白名单校验;批量化场景可扩展为数组形式;现代框架中更推荐数据驱动或组件化封装替代手动选择器。

时间:2026-07-09 07:00
使用容器查询单位cqw实现表单输入框相对于祖父容器百分比宽度

使用容器查询单位cqw实现表单输入框相对于祖父容器百分比宽度

利用CSS容器查询单位cqw,表单输入框宽度可直接基于祖父容器计算,绕过中间包装器尺寸干扰,实现简洁响应式布局,无需硬编码或JavaScript,显著降低维护成本,提升嵌套结构下的布局灵活性。

时间:2026-07-09 07:00
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜