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

时间:2012-03-19 19:38:14

标签: javascript jquery google-maps

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

<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);引起的,如果我发表评论,则错误消失,但当然,网页无法正确加载。

3 个答案:

答案 0 :(得分:1)

您应该将每个脚本添加为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对大多数问题都不是一个好的解决方案(但我不会说从不正确的解决方案 - 每个规则都有例外)

答案 1 :(得分:0)

上述解决方案适用于现代浏览器,但对于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);
}

答案 2 :(得分:0)

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

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

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>