【问题标题】:How can I access DOM elements in Polymer elements from a global namespace?如何从全局命名空间访问 Polymer 元素中的 DOM 元素?
【发布时间】:2014-08-25 01:42:43
【问题描述】:

我想从我的 app.dart 全局访问 my-app-as-an-element.html 中的 DOM 元素(因为它是我想从多个地方调用的方法,例如它更改页面标题),但由于它被阴影所包裹,我似乎无法理解它。有一个技巧可以做,例如

HtmlElement el;
el = document.querySelector('body /deep/ #page-title');

但 /deep/ 在 Safari 中不受尊重,因此不在讨论范围内。想法?

【问题讨论】:

    标签: dart polymer dart-polymer


    【解决方案1】:

    您正在尝试做的事情直接违背了 Polymer 的理念:所有封装、使用 Shadow DOM 等的重点是让可重用的组件管理自己的状态,包括 DOM。

    如果拥有您尝试访问的 DOM 元素的元素是 custom 元素(即您或您公司的某个人已经编写了它),最好的解决方案是公开功能您需要作为该元素的公共方法。

    比如说,你的元素有一个<h1>,你想改变它的内容。您可以按如下方式实现:

    Polymer("my-custom-element", {
        changeTitle: function(newTitle) {
            // this operates on the element's Shadow DOM *only*,
            // NOT the entire page
            document.querySelector('h1').htmlContent = newTitle;
        }
    })
    

    然后您可以从您的全局代码中进行此调用:

    document.querySelector("my-custom-element").changeTitle("My New Title");
    

    如果您尝试更改的元素属于 public 元素(例如来自 core-elementspaper-elements),或者您从某个存储库下载的任何内容,请阅读文档并看看它是否以某种方式公开了您需要的功能。如果没有,您可以尝试编写自己的自定义元素 extends 该元素。在您的扩展元素中,您可以使用 <shadow></shadow> 标记插入被扩展对象的 Shadow DOM,并通过您元素的 JavaScript 以与上述相同的方式对其进行操作。

    编辑:实际上,有一种方法可以直接做你想做的事,尽管我只推荐这作为最后的手段。如果您阅读Shadow DOM 201,您会注意到您可以通过.shadowRoot 属性访问元素的Shadow DOM。这会为您提供另一个 Document 对象,您可以在其上再次使用 .querySelector,如下所示:

    document.querySelector('my-custom-element').shadowRoot.querySelector('h1');
    

    甚至

    document.querySelector('my-custom-element::shadow h1');
    

    这为您提供了元素的句柄,然后您可以根据需要对其进行修改。但同样,我不建议您使用它,除非您需要快速访问此元素以进行调试。

    【讨论】:

    • 伟大的见解!如果我有 my-app 并且其中有子元素并且我想从那里调用 my-app.changeTitle() 怎么办?我应该将 my-app 类导入子元素以便调用它的方法,还是使用您的第一个解决方案?好奇,你为什么不推荐第二种和第三种解决方案?更新的答案会动摇。
    • 为了扩展这一点,如果我将 my-app 类导入子元素以便我可以调用它的方法,IDE 将自动完成并识别该方法,而使用 document.querySelector ('my-app').myMethod(),“没有为类 Element 定义方法”。但是将父元素导入子元素有缺点吗?无论如何,看起来很奇怪。
    • 事实上,对我来说最干净的方法似乎是将changeTitle()方法放入App全局,然后使用document.querySelector('my-app-as-an-element::shadow #page-title');与元素交互,然后我可以调用app.changeTitle( ) 从任何地方导入 App,但为什么说不推荐呢?
    • @DavidNotik 我不确定您所说的“将 my-app 类导入子元素”是什么意思,您能澄清一下吗?
    • @DavidNotik 我建议将 changeTitle() 方法放在包含您要更改的标题的元素上。这将使其成为其公共界面的一部分,因此您可以执行document.querySelector('my-element').changeTitle("whatever") 之类的操作。如果可能的话,你永远不应该从外部访问另一个元素的 Shadow DOM 的原因是封装:Shadow DOM 应该是“私有”内容,由拥有它的元素管理。
    【解决方案2】:

    querySelector 中的 /deep/ 的 Polyfill 正在进行中,很快将在不支持本机 Shadow DOM 的浏览器上使用。

    【讨论】:

    • 确实,在此对所有人都非常重要。我的问题是关于如何在没有它的情况下解决这个问题(特别是考虑到它目前缺乏支持),而另一个答案表明我应该以不同的方式思考它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-06
    • 2012-10-03
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    相关资源
    最近更新 更多