【问题标题】:How to get/set/remove element attribute in Angular 2 using "the angular way"?如何使用“角度方式”在 Angular 2 中获取/设置/删除元素属性?
【发布时间】:2019-03-16 02:39:08
【问题描述】:

我一直在阅读一些关于 Angular 2 陷阱以及要避免什么的文章,其中之一是关于不直接访问 DOM。

我注意到Renderer 非常有用,因为它包含一些有助于避免 DOM 陷阱的方法。但是,我注意到它不包含任何get 函数,只有set 函数,例如setElementAttributesetElementClass 等。

所以我的问题很简单,除了getremove 版本,您如何使用上述功能?他们是否生活在另一个类中,或者您如何使用检索属性或类?

【问题讨论】:

    标签: angular


    【解决方案1】:

    要从 DOM 中删除属性,请提供 null 值。

    设置属性(属性值可以是空字符串):

    myrenderer.setElementAttribute(elementRef.nativeElement, 'attributename', 'attributevalue');
    

    要删除一个属性:

    myrenderer.setElementAttribute(elementRef.nativeElement, 'attributename', null);
    

    要获取元素属性值,您需要将 nativeElement 传递给 setElementAttribute,因此您可以使用它通过标准 Javascript 获取属性值:

    elementRef.nativeElement.getAttribute('attributename');
    

    【讨论】:

      【解决方案2】:

      Angular2 不支持从 DOM 获取任何内容,除了 ElementRef 和事件。
      Angular2 的方式是维护模型中的状态并更新 DOM 以反映该状态。

      如果您需要从 DOM 中读取,您可以使用直接 DOM 访问或提供自定义 Renderer,以提供您在默认 Renderer 中缺少的功能。

      自定义渲染器示例

      【讨论】:

      • 有没有办法扩展渲染器?那会是个好主意吗?还是创建一个完全自定义的更好?
      • 我还没有仔细研究Renderer,但我很确定扩展是个好主意。
      • 好的,我去看看。但是,在这种情况下,我想知道正确的方法是什么,假设我有一个接收$event 作为参数的函数。然后我使用$event.target.getAttribute('some-attr') 从目标元素中获取一个属性。当无法访问目标的nativeElement 时,这是正确的方法吗?值得注意的是,我首先使用Renderer 绑定了事件侦听器本身,这是事件的来源。
      • 我不确定。恕我直言,这也是直接的 DOM 访问,这通常是不鼓励的,但也许对事件没问题。
      • 如果您有兴趣使用新的获取/删除属性类创建示例,我可以奖励您。
      【解决方案3】:

      如果有人还在寻找这个(就像我一样),我会在 Angular 原生渲染器上的 David's answer 上加一点。

      您在最新的Angular Renderer2 中拥有所有这些要求的功能

      特别是如果您想从元素中完全删除属性(例如,社区组件中的无效 aria 标签未通过可访问性测试)并且不将其值设置为 null,则有

      renderer2.removeAttribute(elementRef.nativeElement, 'AttributeName');
      

      编辑:您应该使用 AfterViewInit() 生命周期,如其他答案中所述,因为必须在进行任何自定义 DOM 更改之前呈现初始视图。

      【讨论】:

      • 那么 Renderer2 的什么方法获取 DOM 元素属性的值呢?
      【解决方案4】:

      我不喜欢在 Angular 中访问 dom,但是您可能需要这个用例。禁用烦人的自动完成的唯一方法似乎是添加属性“只读”并在表单加载后将其删除。

      ngAfterViewInit() {
            window.setTimeout(function () {
      
               var arr: HTMLCollection = document.getElementsByClassName('form-control');
               for (var i = 0; i < arr.length; i++) {
                 if (arr[i].hasAttribute("readonly")) {
                   arr[i].removeAttribute('readonly');
                 }
               }
      
         }, 500);
      }
      

      【讨论】:

      • 你为什么要使用 ngOnInit 设置超时?您可以使用另一个 Angular Lyfecycle Hook,例如 ngDoCheck。
      • judasane:谢谢! AfterViewInit 或 AfterContentInit 不使用超时就可以解决问题。 DoCheck 被多次调用,因此这是使用 AfterViewInit 的原因,因为这似乎是被调用一次的生命周期的最后一个或接近最后一个事件。 Angular 5 新手,仍在学习中。
      • judasane:我评论得太早了。我确实认为 chrome 和可能的其他浏览器在 dom 写入角度执行后 1/2 秒后实现了它们的自动完成。它与角度无关,而只是浏览器功能的性质,即插入自动完成文本的时间。似乎唯一可以解决这个问题的机制是使用超时。
      • 还有`var arr: HTMLCollection`应该是`const arr: HTMLCollection`和for (var i = 0; i &lt; arr.length; i++) {应该是for (let i = 0; i &lt; arr.length; i++) {。我还添加了一个disable-autocomplete CSS 类并对其进行了迭代,删除了readonly 属性,以加快速度。还将字段的背景颜色设为白色,以免在只读属性被删除时闪烁。
      • @RandallTo - 2020 年仍然有效。绝对棒极了!必须从图像中删除硬编码的宽度和高度以使其具有响应性。
      【解决方案5】:

      由于getAttribute只是一个方法,你可以使用invokeElementMethod

      var attr = renderer.invokeElementMethod(elementRef.nativeElement, 'getAttribute', []);
      

      如果您切换到服务器端渲染,这种方法将不起作用(鼠标点击等事件回调除外)。

      扩展DOMRenderer 实际上意味着与浏览器实现紧密耦合,这与直接nativeElement 操作相同。


      看来您根本不应该调用 getter。那么问题来了,为什么需要知道属性值或者类名呢?

      您可以创建特定指令或模板变量并将其与ViewChild/ViewChildren 一起使用,或者创建适当的数据模型并与[class.name]="nameEnabled" 绑定

      【讨论】:

      • 嗯,我很感兴趣。明天我会试试这个,看看它是否能完成这项工作。它将解决我与 Gunter 讨论的事件目标操作问题。
      • classList 和其他类似属性怎么样?
      • classList 可以使用class 属性进行模拟。
      • 是的,我不知道你为什么要这么做。如果您的 DOM 元素需要使用 DOM attr/data 设置/获取的特殊状态,那么可能这是一种极端情况,您想为其创建自定义指令。
      • 我也想过这个,但是invokeElementMethod 没有返回任何东西github.com/angular/angular/issues/8386(自从问题产生以来没有检查过自己)。
      【解决方案6】:

      基于上述@RandallTo 的answer 的解决方案。

      角度

      ngAfterViewInit() {
            window.setTimeout(function () {
      
               const arr: HTMLCollection = document.getElementsByClassName('disable-autocomplete');
               for (let i = 0; i < arr.length; i++) {
                   arr[i].removeAttribute('readonly');
               }
      
         }, 500);
      }
      

      HTML

      <input type="text" name="username" readonly="" class="form-control disable-autocomplete"/>
      

      CSS

      .disable-autocomplete {
        background-color: #fff;
      }
      

      添加白色背景色意味着当表单加载只读字段(默认为灰色)时,您不会得到闪光,然后在删除只读属性时变为白色。

      在我的版本中您不需要 if 语句,因为您只在要禁用自动完成功能的字段上设置了 readonly.disable-autocomplete

      例如,您可能希望在电子邮件字段中允许自动完成,但在用户名字段中不允许。

      【讨论】:

        【解决方案7】:

        要删除一个类,你仍然可以使用setElementClassisBool 应该设置为false。有关更多信息,请参阅此链接https://github.com/angular/angular/blob/9de76ebfa545ad0a786c63f166b2b966b996e64c/modules/%40angular/platform-browser/src/dom/dom_renderer.ts#L237

        【讨论】:

          猜你喜欢
          • 2017-11-10
          • 1970-01-01
          • 2017-02-28
          • 1970-01-01
          • 2019-05-21
          • 2019-06-23
          • 2018-11-25
          • 1970-01-01
          • 2017-10-02
          相关资源
          最近更新 更多