【问题标题】:loading script only once on click event在单击事件上仅加载一次脚本
【发布时间】:2016-06-18 21:52:59
【问题描述】:

我已经一起破解了 vanilla javascript 以在点击事件时加载外部脚本。

var searchLabel = document.getElementById('search-toggle-label');
searchLabel.onclick = function(){
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = "wp-content/themes/2016/js/cse.js."; 
    document.getElementsByTagName("head")[0].appendChild(script);
    return false;
}

但每次点击事件时它都会加载相同的脚本。

所以我加入了一个 if 语句来检查值和类型。 "==="

var searchLabel = document.getElementById('search-toggle-label');
if (typeof searchLabel === 'undefined') {
    searchLabel.onclick = function() {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = "wp-content/themes/2016/js/cse.js."; 
        document.getElementsByTagName("head")[0].appendChild(script);
        return false;
    }
}
else {
    alert('loaded already');
}

显然,这是错误的,因为我在页面加载和点击事件时收到警报,脚本未加载。

我被难住了。我知道使用 jQuery 有一个简单的解决方案,但我正在尝试真正学习编写 javascript。

任何帮助将不胜感激。

【问题讨论】:

  • 你想让它做什么?只在第一次点击时加载脚本?
  • 是的。仅在第一次点击时加载脚本,而不是在后续点击时加载。

标签: javascript onclick getelementbyid typeof getelementsbytagname


【解决方案1】:

在事件监听器触发后移除它:

var searchLabel = document.getElementById('search-toggle-label');
searchLabel.addEventListener('click', loadScript('wp-content/themes/2016/js/cse.js'), false);

function loadScript(src){
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = src; 
    document.head.append(script);
    return searchLabel.removeEventListener('click', loadScript, false);
}

【讨论】:

  • 对不起大卫沃尔什。您的包装器工作得很好,但上面的脚本对我来说更简洁。所以我要和马尔克一起去。谢谢!!我实际上曾尝试添加 .removeEventLister & 我明白为什么它不起作用;因为我试图在它触发之前将其移除。
  • 非常实用且紧凑!我进行了一些更改以使一切变得更加精简,希望您能欣赏!
【解决方案2】:

也许尝试在函数定义之前设置一个标志。这样,您可以在函数开始时检查标志并省略其余部分。你还有一个我在互联网上找到的很好的例子。查找此solution

【讨论】:

  • 谢谢。确实使用了 David Walsh 的包装函数并且它确实有效。但是,Malk 删除 EventlListner 的方法对我来说似乎更合适?
  • 你是对的,这种方法更好。所以就用那个吧。
【解决方案3】:

如果脚本存在于 DOM 中,则添加一个函数以返回 true/false。这是一个:

function isScriptLoaded(src) {
  return !!Array.prototype.filter.call(document.getElementsByTagName('script'), function(node) {
    return node.src === src;
  });
}

然后用它来测试脚本是否已经插入到 DOM 中。

【讨论】:

  • 不。不太确定“匹配脚本 src 的后缀/结尾”是什么意思,但是您的正则表达式? “srcSuffix$”(不确定这是什么)无法阻止脚本的后续加载。
  • @HackYa 是的,我在那里犯了一个错误——我会改正的。
  • @HackYa 我已经修正了这个错误
  • 我的意思是如果你设置一个相对的src,浏览器可能会扩展它以包含协议、主机等。所以如果你只想匹配你设置的,您将测试节点 src 的结尾与整个 src 不匹配(要匹配整个源,必须传入更多)。
  • 但好消息是它不适用于 Chrome —— src 是相对的。我更新以保持简单和干净。
【解决方案4】:

使用它来同步加载脚本(并且只加载一次):

const isScriptLoaded = (src)=>{
  const scripts = Array.from(document.getElementsByTagName('script')) || []
  return scripts.filter((node) => node.src && node.src.indexOf(src)>-1).length>0
}

const loadScript = (src, once=true)=>{
  if (once && isScriptLoaded(src)) return

  return new Promise((resolve)=>{
    const node = document.createElement('script')
    node.setAttribute('src', src)
    node.onload = ()=>{ 
      setTimeout(()=>{ resolve() }, 0)
    }
    document.getElementsByTagName('head')[0].appendChild(node)
  })
}

然后,在你的 vue 组件中:

  ...

  async mounted () {
    await loadScript('/js/globe.min.js') // wait for the script to be loaded
    // this.scriptIsReadyLetsDoSomethingWithIt()
    
    // Will do nothing if you call loadScript multiple times (as the script is already loaded)
    // await loadScript('/js/globe.min.js')
    
  },
  ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-27
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    相关资源
    最近更新 更多