在我的插件中有条件地加载外部javascript库

conditionally loading external javascript libraries in my plugin

本文关键字:加载 外部 javascript 有条件 我的 插件      更新时间:2023-09-26

我已经编写了一个插件,它依赖于我想要有条件地包含的外部库,也就是说,如果用户的网站已经有这些库,用户可以选择不自动包含这些库。下面是一些伪代码来说明的问题

<script type="text/javascript" src="path/to/plugin.js"></script>
<script type="text/javascript">
PLUGIN.init({
    "param1": "foo",
    "parma2": 33, 
    "include": {"jquery": 0, "googlemaps": 0}
});
</script>

在我的插件脚本中

var PLUGIN = {
    "init": function(obj) {
        if (obj.include.googlemaps !== 0) {
            document.write('<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true&v=3.6">'x3C/script>');
        }
        if (obj.include.jquery !== 0) {
            document.write('<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js">'x3C/script>');
        }
        .. do more things ..
}

问题是,当我准备"做更多的事情"时,库似乎还没有加载。我得到一个错误,jquery找不到,或者谷歌地图找不到。我可以通过将代码更改为来解决这个问题

document.write('<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true&v=3.6">'x3C/script>');
document.write('<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js">'x3C/script>');
var PLUGIN = {
    "init": function(obj) {         
        .. do more things ..
}

但是现在用户无法控制是否加载库。建议?解决方法?

更新:谢谢大家的建议,但到目前为止没有任何乐趣。以下是我正在做的事情和正在发生的事情。由于我可能正在加载0个或更多的脚本(用户可以选择决定哪些脚本不需要加载),我已经将我的代码设置为

"importLib": function(libPath, callback) {
    var newLib = document.createElement("script");
    if (callback !== null) {
        newLib.onload = callback;
    }
    newLib.src = libPath;
    document.head.appendChild(newLib);
},
"init": function(obj) {
    var scripts = [];
    if (obj.include.googlemaps !== 0) {
        scripts.push("http://maps.google.com/maps/api/js?sensor=true&v=3.6");
    }
    if (obj.include.jquery !== 0) {
        scripts.push("http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js");
    }
    if (obj.include.anotherlib !== 0) {
        scripts.push("http://path/to/another/lib.js");
    }
    var len_scripts = scripts.length,
        callback = null;
    if (len_scripts > 0) {
        for (var i = 0; i < len_scripts; i++) {
            // add callback only on the last lib to be loaded
            if (i == len_scripts - 1) {
                callback = function() { startApp(obj) };
            }
            importLib(scripts[i], callback);
        }
    }
    // Start the app rightaway if no scripts need to be loaded
    else {
        startApp(obj);
    }
},
"startApp": function(obj) {
}

发生的情况是,Firefox发出一个attempt to run compile-and-go script on a cleared scope错误,Safari没有收到这个错误,但没有加载任何内容。有趣的是,Safari错误控制台显示没有任何错误。Firefox错误似乎是由document.head.appendChild(newLib);行引起的,如果我对此发表评论,错误就会消失,但当然,网页加载不正确。

您应该将每个脚本添加为DOM节点,并在完成加载后使用onload属性执行操作。

function importLib(libPath, callback) {
    var newLib = document.createElement("script");
    newLib.onload = callback;
    newLib.src = libPath;
    document.head.appendChild(newLib);
}

上面,libPath参数是库的URL,callback参数是加载完成时要调用的函数。您可以按如下方式使用它:

importLib("http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js", function() {
   alert("jquery loaded!");
   nowDoSomething(aboutIt); 
});

顺便说一句:一般来说,document.write不是大多数问题的好解决方案(但我不会说永远是正确的解决方案——每个规则都有例外)。

上述解决方案可以在现代浏览器中使用,但对于IE 7/8,您可能需要添加一些额外的代码,比如:

function importLib(libPath, callback) {
    var newLib = document.createElement("script");
    if (navigator.userAgent.indexOf('MSIE') !== -1) {
        newLib.onreadystatechange = function () {// this piece is for IE 7 and 8
           if (this.readyState == 'complete') {
              callback();
           }
        };
    } else {
        newLib.onload = callback;
    }
    newLib.src = libPath;
    document.head.appendChild(newLib);
}

我遇到了同样的问题。如果您在.NET中编写网站,一种解决方法是在从代码隐藏加载页面之前有条件地编写脚本引用。我的问题是,当远程用户通过VPN访问我的应用程序时,它会阻止访问互联网,因此无法引用谷歌地图。这会阻止页面的其余部分在合理的时间范围内加载。我尝试通过jQuery的getScript()命令控制谷歌地图库的脚本引用,但正如您所发现的,后续的谷歌地图配置代码在引用外部库之前运行。

我的解决方案是有条件地从代码背后引用谷歌地图:

VB(代码隐藏):

'if VPN mode is not enable, add the external google maps script reference (this speeds up the interface when using VPN significantly)
    If Session("VPNMode") = False Then
        Dim sb As System.Text.StringBuilder = New System.Text.StringBuilder()
        sb.AppendLine("")
        sb.AppendLine("<script type='text/javascript'")
        sb.Append(" src='http://maps.google.com/maps/api/js?v=3&sensor=false'>")
        sb.Append("</script>")
        Dim header As LiteralControl = New LiteralControl
        header.Text = sb.ToString()
        Me.Page.Header.Controls.Add(header)
    End If

客户端脚本(javascript):

<script type='text/javascript'>
    $(function () {
        if ($("input[name*='VPN']").is(":checked"))
        { }
        else {
            loadGoogleMap()
        }
    });
    function loadGoogleMap() {
        hazsite = new google.maps.LatLng(hazLat, hazLong);
        map = new google.maps.Map(document.getElementById('map_canvas'), { zoom: 18, center: hazsite, mapTypeId: google.maps.MapTypeId.SATELLITE });
        var marker = new google.maps.Marker({
            position: hazsite,
            map: map,
            title: "Site Location"
        });
    }
</script>