0

我有一个用户控件,其中包含来自 Google 图表 api 的一些图表。

当用户控件被服务器加载和呈现时,一切都按预期工作。但是,当我使用 ajax webservice 渲染控件异步并使用 ajax 返回 html 并将其添加到页面时,我在 firebug 中遇到一些脚本错误(chrome 将其称为 ReferenceError):

“谷歌未定义”

图片

我的项目是带有一些 javascript 的 ASP.Net MVP Webforms。
我制作了一个示例项目,在其中重新创建了问题。在这里下载

控制渲染器代码:

public virtual string RenderControlToString(string path, bool htmlEncode)
{
    StringWriter stringWriter = new StringWriter();
    this.RenderControl(path, (TextWriter)stringWriter);
    string s = stringWriter.ToString();
    if (!htmlEncode)
        return s;
    else
        return HttpContext.Current.Server.HtmlEncode(s);
}

public virtual void RenderControl(string path, TextWriter writer)
{
    var page = new PageForRendering();
    page.Controls.Add(page.LoadControl(path));
    HttpContext.Current.Server.Execute((IHttpHandler)page, writer, true);
}

(省略“需要在表单中”错误 - 控件添加到的页面上有一个表单)

public class PageForRendering : Page
{
    public override void VerifyRenderingInServerForm(Control control)
    {}
}

用户控件上的脚本:

<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
    console.log("Loading Google Charts...");
    google.load('visualization', '1.0', { 'packages': ['corechart'] });
    console.log("Google Charts loaded!");

    google.setOnLoadCallback(function () {
        ...some code...
    });
</script>

使用 firebug,我发现https://www.google.com/jsapi加载正常,但只打印了我的第一个控制台日志。

我认为这可能是某种范围问题... google 变量将在此脚本中定义:

<script type="text/javascript" src="https://www.google.com/jsapi"></script>

但在这种情况下,它在下一个脚本块中是不可访问的。通过正常渲染,它可以正常工作。要么脚本在 google.load 调用之前没有完成加载,要么 google 变量现在以某种方式定义在另一个范围内,因为呈现方法不同。

如果我查看 firebug DOM,google 变量的定义如下所示。但是我发现如果我在 line: 处放置一个断点google.load('visualization', '1.0', { 'packages': ['corechart'] });,我发现此时 google 变量没有在 DOM 中定义。所以它也可能是关于加载脚本的一些想法。但是该行在<script type="text/javascript" src="https://www.google.com/jsapi"></script>它之前,应该同步执行,对吗?当我在 firebug 中检查网络时,我还发现文件已正确下载。

我可能还需要提到加载 ajax 代码的用户控件如下所示:

<div id="statisticsContent">&nbsp;</div>

<script type="text/javascript">
    $(document).ready(function () {
        function getStatisticsView() {
            var id = $(".chooseStatisticsToShow input:radio:checked").val();
            var statisticsType = (id == $(".choosePlayingGroupDropDownList option:selected").val() ? 1 : 0);

            $.ajax({
                cache: false,
                global: false,
                type: "POST",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                url: '/Services/StatisticsService.svc/GetStatisticsView',
                data: JSON.stringify({
                    statisticsType: statisticsType,
                    id: id
                }),
                success: function (data) {
                        $("#statisticsContent").html(data.d.ViewHtml);
                }
            });
        }
        getStatisticsView();

        $(".chooseStatisticsToShow").change(function () {
            getStatisticsView();
        });
    });
</script>



我制作了一个示例项目,在其中重新创建了问题。在这里下载

4

1 回答 1

1

在您的服务发送响应并使用$("#statisticsContent").html(data.d.ViewHtml);浏览器添加响应后,它会解释 html 并开始并行加载和执行脚本。我怎么知道?只是经验-在我的项目中,每次我尝试注入<script src='...'>浏览器时都不会等待脚本加载,并且script带有自定义代码的下一个标签会立即执行。

这是您的情况,您需要等待jsapi加载,然后才执行将加载包并执行图表渲染的代码。这是代码:

<div id="chart_div"></div>

<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
    waitForGoogleApiAndLoadPackages();
    function waitForGoogleApiAndLoadPackages() {
        if (typeof (google) === 'undefined')
            setTimeout(waitForGoogleApiAndLoadPackages, 100);
        else {
            google.load('visualization', '1.0', { 'callback': 'renderChart', 'packages': ['corechart'] });
        }
    }

    function renderChart() {
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Topping');
        data.addColumn('number', 'Slices');
        data.addRows([['Mushrooms', 3], ['Onions', 1], ['Olives', 1], ['Zucchini', 1], ['Pepperoni', 2]]);

        var options = { 'title': 'How Much Pizza I Ate Last Night', 'width': 400, 'height': 300 };

        var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
        chart.draw(data, options);
    }
</script>

另一个有趣的部分是功能elsewaitForGoogleApiAndLoadPackages。这是为什么 google.load 会导致我的页面变为空白?问题。


引用为什么 google.load 会导致我的页面变为空白?

看起来 google.load 正在使用 document.write() 将脚本添加到页面,如果在页面加载后使用,则会清除 html。

于 2013-04-25T09:43:29.623 回答