你能用 JavaScript 加载 jQuery contextMenu 吗?

Can you load jQuery contextMenu with JavaScript?

我想用 JavaScript 加载一个 jQuery 插件 jQuery contextMenu

我尝试在 Chrome 开发人员工具控制台上执行 JavaScript 脚本并收到错误 VM4631:1 Uncaught TypeError: $.contextMenu is not a function

// setting up jQuery contextMenu Plugin 

function dynamicallyLoadScript(url) {
    var script = document.createElement("script");
    script.src = url;
    document.head.appendChild(script);
}

dynamicallyLoadScript('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js')

var link = document.createElement( "link" );
link.href = "https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.7.0/jquery.contextMenu.min.css" ;
link.type = "text/css";
link.rel = "stylesheet";
link.media = "screen,print";
document.getElementsByTagName( "head" )[0].appendChild( link );

dynamicallyLoadScript('https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.7.0/jquery.contextMenu.min.js')
dynamicallyLoadScript('https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.7.0/jquery.ui.position.js')

// testing 

$.contextMenu({
    selector: '#post-868 > div > header > h2 > a',
    items: {
        copy: {
            name: "Copy",
            callback: function(key, opt){
                alert("Clicked on " + key);
            }
        }
    }
});

简答

问题是<script>的加载是一个异步操作。
并且因为您正在动态插入这些脚本,所以当您的 $.contextMenu 指令被执行时,还没有加载必要的脚本。

说明

当您静态在页面<script>标签中定义多个脚本时<head>,浏览器将并行获取它们并尽快执行它们可能,维持它们的顺序(并阻止进一步解析页面)。

但在你的情况下,你是动态地<script>标签一个接一个地插入页面<head>,这意味着:

  • 这些脚本的执行顺序未知(一获取就执行)
  • 在您的 <script> 加载时继续执行,因此 $.contextMenu 在您的 <script> 确实加载之前执行。

为了说明这一点,我在 $.contextMenu 指令之前添加了一个 console.log,并在 dynamicallyLoadScript 函数中添加了一个 console.time/timeEnd

function dynamicallyLoadScript(url) {
    var script = document.createElement("script");
    script.src = url;
    // Print log on script loaded
 script.onload = () => { console.timeEnd(url); };
    console.time(url);
    document.head.appendChild(script);
}

dynamicallyLoadScript('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js')

var link = document.createElement( "link" );
link.href = "https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.7.0/jquery.contextMenu.min.css" ;
link.type = "text/css";
link.rel = "stylesheet";
link.media = "screen,print";
document.getElementsByTagName( "head" )[0].appendChild( link );

dynamicallyLoadScript('https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.7.0/jquery.contextMenu.min.js')
dynamicallyLoadScript('https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.7.0/jquery.ui.position.js')

console.log('Calling $.contextMenu');

$.contextMenu({
    selector: '#post-868 > div > header > h2 > a',
    items: {
        copy: {
            name: "Copy",
            callback: function(key, opt){
                alert("Clicked on " + key);
            }
        }
    }
});

我不知道你为什么要这样加载脚本。
如果您添加 script.async = false;,您的脚本将以正确的顺序加载,但这不会阻止 $.contextMenu 首先执行。
我建议您看看 this great HTML5 Rocks article 处理脚本加载。