【问题标题】:Recommended method to locate the current script?定位当前脚本的推荐方法?
【发布时间】:2020-03-12 01:17:34
【问题描述】:

我正在编写一个脚本,需要在脚本所在的位置向页面添加 DOM 元素(类似小部件的方法)。 最好的方法是什么?

以下是我正在考虑的技术:

  1. 在脚本正上方包含一个 id="Locator" 的元素。问题:
    • 我不喜欢多余的标记
    • 如果我在页面中重复使用小部件,几个元素将具有相同的“定位器”ID。我正在考虑在脚本中添加一行以删除曾经使用过的 id,但仍然...
  2. 为脚本添加一个 ID。问题:
    • 尽管它似乎可以工作,但 id 属性对脚本元素无效
    • 同样的问题,如果我在页面中重用脚本,几个元素将具有相同的 id。
  3. 使用 getElementsByTagName("script") 并选择最后一个元素。到目前为止,这对我有用,只是看起来有点重,我不确定它是否可靠(考虑延迟脚本)
  4. document.write:不优雅,但似乎可以胜任。

  5. [编辑]根据idealmachine的回复,我正在考虑另一种选择:

    • 在脚本标签中包含一个属性,例如goal="tabify"。
    • 使用 getElementsByTagName("script") 获取所有脚本。
    • 遍历脚本并检查goal="tabify" 属性以找到我的脚本。
    • 如果页面中有另一个小部件,请删除目标属性。
  6. [编辑] 另一个想法,也受到迄今为止回复的启发:

    • 使用 getElementsByTagName("script") 获取所有脚本。
    • 遍历脚本并检查 innerHTML 以找到我的脚本。
    • 在脚本结束时,删除脚本标签,以防页面中有另一个小部件。

【问题讨论】:

    标签: javascript dom document.write getelementsbytagname


    【解决方案1】:

    开箱即用:document.currentScript(IE 不支持)

    【讨论】:

    • 谢谢!很遗憾,并非所有主流浏览器都支持。
    • @Christophe 您可以对其进行 polyfill 或使用预先存在的 polyfill,但您是对的。
    • 我进行了快速搜索,但找不到适用于 IE11 的 polyfill。
    • 有些类似github.com/samyk/jiagragithub.com/JamesMGreene/document.currentScript。但我从未测试过它们,因为我根本不关心 IE,所以我不能说它们是否工作/是否安全
    • 以防万一有人使用 Nuxt 出现这样的消息,只需将 pollyfill.io 中的 pollyfill 与 document.currentScript 捆绑在一起,它就会解决问题。这个答案帮助我识别了 pollyfill 名称。
    【解决方案2】:

    我曾为 OnlyWire 工作过,该公司提供的主要服务是一个小部件,可以放在您的网站上。

    我们使用var scripts = document.getElementsByTagName("script"); var thisScript = scripts[scripts.length - 1]; 技巧,它似乎工作得很好。然后我们使用 thisScript.parentNode.insertBefore(ga, thisScript); 在 DOM 树中插入我们想要的任何内容。

    我不确定我是否理解您为什么认为这是一个“繁重”的解决方案......它不涉及迭代,它是一个完美集成的纯跨浏览器解决方案。

    【讨论】:

    • 好吧,与直接 getElementById 相比,“重”。但我明白你的意思,没什么大不了的。
    • 如果src 加载的<script> 中没有使用async,则可以跨浏览器工作。此代码也可以隐藏在小部件或脚本本身中。并且<script>可以在插入HTML组件后删除。
    【解决方案3】:

    这适用于页面上相同代码的多个副本以及动态插入的代码:

    <script type="text/javascript" class="to-run">
    (function(self){
        if (self == window) {
            var script = document.querySelector('script.to-run');
            script.className = '';
            Function(script.innerHTML).call(script);
        } else {
            // Do real stuff here. self refers to current script element.
            console.log(1, self);
        }
    })(this);
    </script>
    

    【讨论】:

    • 我关心浏览器支持(querySelector),但除此之外它看起来很有趣!给我一些时间来完全理解它;-)。我担心的另一个问题是 querySelector 可能会在同一页面上返回另一个脚本,而当前脚本将永远不会被执行。
    • querySelector 存在于所有现代浏览器和 IE10 中 caniuse.com/#search=query
    • 缺少说明。 Function(script.innerHTML) 如何不评估为 null?没有return
    【解决方案4】:

    document.write 或选择最后一个脚本元素将适用于大多数网页中同步加载的脚本。但是,我可以想到一些您没有考虑允许异步加载的选项:

    • 在脚本前添加 divclass="Locator"。 HTML 类的优点是重复项不是无效。当然,要处理多个小部件的情况,您需要在添加完 HTML 元素后更改元素的类名,这样就不会添加两次。 (请注意,一个元素也可以是多个类的成员;它是一个以空格分隔的列表。)

    • 检查每个脚本元素的 src 可以确保在页面最后加载的跟踪代码(例如 Google Analytics(分析)旧跟踪代码)和其他脚本不会阻止您使用异步加载时脚本无法正常工作。同样,要处理多个小部件的情况,您可能需要在完成后删除脚本元素(当所需的代码已添加到页面时)。


    我要说的最后一条评论(尽管您可能已经意识到这一点)是,在编写小部件时,您需要使用var 声明所有变量并将所有代码包含在其中:(JSLint 可以帮助检查)

    (function(){
        ...
    })();
    

    这被称为“自执行函数”,将确保脚本中使用的变量不会干扰网页的其余部分。

    【讨论】:

    • 我使用自执行函数。删除脚本不是一个选项,因为小部件包括交互。我考虑过使用类,但随后抓取元素并不像使用 id 那样简单。我喜欢检查 src 或脚本标签的其他属性的想法,这可以帮助识别正确的。
    • @Christophe:我并不是说实际上删除脚本本身。一旦脚本已经加载并执行完毕,就可以安全地移除加载它的脚本元素(当然,在添加包含动态生成代码的 div 之后)。
    • 我写了“脚本标签的另一个属性”,但后来意识到可供选择的并不多……好吧,也许我可以编一个类型,就像微软为 jQuery 模板插件所做的那样(文本/x-jquery-tmpl)。
    • @Christophe:你可以在 JavaScript 中获取和设置你想要的任何属性名称,它不会影响 HTML 的有效性。
    • 感谢 cmets。不确定我是否理解所有内容,但我在最初的帖子中添加了另外两个选项(5 和 6)。
    【解决方案5】:

    无论您将&lt;script&gt; 标记或&lt;div class="mywidget"&gt; 放入,您都在向标记添加一些内容。就个人而言,我更喜欢后者,因为脚本本身只添加一次。页面正文中的脚本过多会减慢页面加载时间。

    但是如果您需要在小部件所在的位置添加脚本标记,我看不出使用 document.write() 放置 div 有什么问题。

    【讨论】:

    • 问题是 document.write() 仅在页面仍在加载时“工作”。如果您在 onload 后附加到页面的脚本中执行document.write()(...或其他东西,不确定确切的拐点),效果就好像当前页面在写入之前被吹走了,结果是一个包含刚刚写入文档的代码的页面。
    • 嗯,我更喜欢另一种方式。我没有遇到你描述的情况。在大多数浏览器中,在我看到的情况下,它会停止加载其他内容,直到加载您的 javascript - 这就是它减慢加载时间的原因。
    • 我对 document.write 的另一个担忧:以这种方式包含的元素是否可以像标准元素一样被 DOM 方法操作?还是有什么限制?
    • @Christophe 添加元素后,假设它们的格式正确,就可以像从一开始就存在的元素一样访问它们。但是,要记住的一件事是,如果您使用的是 jQuery 之类的库,例如,如果您将操作绑定到特定的 css 类,然后添加该类的元素,它将没有绑定。跨度>
    【解决方案6】:

    我刚刚找到了另一种似乎可以回答我的问题的方法:

    How to access parent Iframe from javascript

    将脚本嵌入 iframe 允许随时定位它,因为脚本始终保持对自己窗口的引用。

    我认为这是最好的方法,因为无论您将脚本添加到页面多少次(想想小部件),它都将始终有效。欢迎您发表评论。

    促使我首先考虑 iframe 的是我为构建 Google 小工具所做的一项实验。

    【讨论】:

      【解决方案7】:

      在许多情况下这很好用(hud.js 是 scipt 的名称):

      var jsscript = document.getElementsByTagName("script"); 
      for (var i = 0; i < jsscript.length; i++) { 
            var pattern = /hud.js/i; 
            if ( pattern.test( jsscript[i].getAttribute("src") ) )
            {
               var parser = document.createElement('a');
               parser.href = jsscript[i].getAttribute("src");
               host = parser.host; 
            }
      
       }
      

      【讨论】:

        【解决方案8】:

        您还可以在其中添加单个脚本的名称。

        • 在一些 js-script

           dataset['my_prefix_name'] = 'someScriptName'
          
        • 或在 HTML 内 - 在

           data-my_prefix_name='someScriptName'
          

        然后通过遍历 document.scripts 数组来搜索合适的下一个:

         ... function(){
            for (var i = 0, n = document.scripts.length; i < n; i++) {
                var prefix = document.scripts[i].dataset['my_prefix_name']
                if (prefix == 'whatYouNeed') 
                   return prefix
            }
         }
        

        【讨论】:

          【解决方案9】:

          我永远无法访问 Internet Explorer,但这应该几乎在任何地方都可以使用:

          <script src="script.js"
              data-count="30"
              data-headline="My headline"
              onload="uniqueFunctionName(this)"
              defer
              ></script>
          

          在 script.js 中:

          window.uniqueFunctionName = function (currentScript) {
             var dataset = currentScript.dataset
             console.log(dataset['count'])
             console.log(dataset['headline'])
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-07-24
            • 2011-12-02
            • 2011-02-06
            • 2011-05-05
            • 2015-04-01
            • 1970-01-01
            相关资源
            最近更新 更多