专栏首页菩提树下的杨过ExtJs学习笔记(23)-ScriptTagProxy+XTemplate+WCF跨域取数据

ExtJs学习笔记(23)-ScriptTagProxy+XTemplate+WCF跨域取数据

ajax应用中跨域一直是一个非常麻烦的问题,目前也有一些解决办法,但要么比较麻烦,要么就不具备通用性,幸好ExtJs里的ScriptTagProxy提供了跨域读取数据的功能,而且在几大浏览器上都可以正常运行,但在使用过程中要注意几点:

1.服务端返回时,必须按以下格式返回:

stcCallback1001({...})

其中stcCallback1001中的1001是自动生成的,如果是分页提交的话,每再请求一次1001会变成1002,1003...类推

2.ExtJs官方的示例中虽然ScriptTagProxy的例子并不少,但是就是没有XTemplate+ScriptTagProxy跨域读取的单一功能示例,下面给一个XTemplate跨域读取数据的示例

a.服务端WCF的处理

Code
[OperationContract]
    [WebInvoke(ResponseFormat = WebMessageFormat.Json, UriTemplate = "GetData3?start={start}&limit={limit}&callback={callback}", Method = "*")]
    public Stream GetData3(int start, int limit,string CallBack)
    {
        System.Threading.Thread.Sleep(1000);//为演示Ajax加载效果,停1秒

        List<T_GuestBook> _List = new List<T_GuestBook>();
        _List.Add(new T_GuestBook() { F_ID = 1, F_IP = "192.23.37.41", F_Date = DateTime.Now, F_Content = "这是第一条留言", F_Reply = "" });
        _List.Add(new T_GuestBook() { F_ID = 2, F_IP = "192.168.0.1", F_Date = DateTime.Now, F_Content = "这是第二条留言", F_Reply = "" });
        _List.Add(new T_GuestBook() { F_ID = 3, F_IP = "192.168.0.2", F_Date = DateTime.Now, F_Content = "这是第三条留言", F_Reply = "" });
        _List.Add(new T_GuestBook() { F_ID = 4, F_IP = "172.168.235.1", F_Date = DateTime.Now, F_Content = "这是第四条留言", F_Reply = "" });
        _List.Add(new T_GuestBook() { F_ID = 5, F_IP = "10.200.30.4", F_Date = DateTime.Now, F_Content = "这是第五条留言", F_Reply = "" });
        _List.Add(new T_GuestBook() { F_ID = 6, F_IP = "10.200.30.5", F_Date = DateTime.Now, F_Content = "这是第六条留言", F_Reply = "" });
        //以上操作也可以改为利用Linq直接从数据库读取                   


        PageData<List<T_GuestBook>> _PageData = new PageData<List<T_GuestBook>>();

        _PageData.RecordCount = _List.Count;

        int PageSize = limit;

        if (PageSize <= 0) { PageSize = 1; }
        if (PageSize > _PageData.RecordCount) { PageSize = _PageData.RecordCount; }
        _PageData.PageSize = PageSize;

        //计算总页数
        if (_PageData.RecordCount % _PageData.PageSize == 0)
        {
            _PageData.PageCount = (_PageData.RecordCount / _PageData.PageSize);
        }
        else
        {
            _PageData.PageCount = (_PageData.RecordCount / _PageData.PageSize) + 1;
        }

        int PageIndex = (start/limit) + 1;

        if (PageIndex <= 0) { PageIndex = 1; }
        if (PageIndex > _PageData.PageCount) { PageIndex = _PageData.PageCount; }

        _PageData.CurrentPageIndex = PageIndex;

        List<T_GuestBook> _List2 = _List.Skip(start).Take(limit).ToList();//取得当前页数据

        _PageData.Data = _List2;


        string returnStr = CallBack + "(" + JavaScriptConvert.SerializeObject(_PageData) +")";
        MemoryStream ms = new MemoryStream();
        StreamWriter sw = new StreamWriter(ms);
        sw.AutoFlush = true;
        sw.Write(returnStr);
        ms.Position = 0;
        WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";

        return ms;
    }

这里与上一篇http://www.cnblogs.com/yjmyzz/archive/2008/09/10/1288399.html (ExtJs学习笔记(22)-XTemplate + WCF 打造无刷新数据分页)相比,多了一个参数callBack,同时返回类型改为Stream,返回方法的处理参考了老张的(再说ExtJs与WCF之间的跨域访问)一文

b.ExtJs的前端处理

Code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link type="text/css" rel="Stylesheet"  href="../resources/css/ext-all.css" />
    <script type="text/javascript" src="../adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="../ext-all-debug.js"></script>
    <style type="text/css">        *{font-size: 9pt;line-height: 120%;}        .red{color: Red;}        h1{font-size:16px;}    </style>    
</head>
<body>

<script type="text/javascript">
    Ext.onReady(function() {
        var proxy = new Ext.data.ScriptTagProxy({
        url: 'http://ext.cneds.net/WCF/MyService.svc/GetData3'

        //服务端的返回值类似:
        //stcCallback1001({"RecordCount":6,"PageSize":2,"PageCount":3,"CurrentPageIndex":2,"Data":[{"F_ID":3,"F_IP":"192.168.0.2","F_Date":new Date(1221399073843),"F_Content":"这是第三条留言","F_Reply":""},{"F_ID":4,"F_IP":"172.168.235.1","F_Date":new Date(1221399073843),"F_Content":"这是第四条留言","F_Reply":""}]})
        //其中stcCallback1001中的1001是自动生成的,如果是分页提交的话,每再请求一次1001会变成1002,1003类推
        
        });
        var reader = new Ext.data.JsonReader(
         { root: 'Data', totalProperty: 'RecordCount' },
         [
           { name: 'F_ID' },
           { name: 'F_IP' },
           { name: 'F_Date' },
           { name: 'F_Content' }
         ]
       );

        var tpl = new Ext.XTemplate(
        '<table width="100%">',
        '<tpl for="data">', //表明这里开始循环
       '<tr><td style="font-weight:bold;color:#666">网友[{F_IP}] {F_Date} 说:</td></tr>', '<tr><td>  {F_Content}</td></tr>', '<tr><td><hr style="height:1px"/></td></tr>',
        '</tpl>', //循环结束
        '</table>'
        );

        var oGrid = Ext.get("page-grid");

        //回调函数
        function callback(data, arg, success) {
            if (success) {
                var _returnStr = Ext.util.JSON.encode(data);
                //{"success":true,"records":[{"id":1001,"data":{"F_ID":3,"F_IP":"192.168.0.2","F_Date":"2008-09-14T21:28:28","F_Content":"这是第三条留言"},"json":{"F_ID":3,"F_IP":"192.168.0.2","F_Date":"2008-09-14T21:28:28","F_Content":"这是第三条留言","F_Reply":""}},{"id":1002,"data":{"F_ID":4,"F_IP":"172.168.235.1","F_Date":"2008-09-14T21:28:28","F_Content":"这是第四条留言"},"json":{"F_ID":4,"F_IP":"172.168.235.1","F_Date":"2008-09-14T21:28:28","F_Content":"这是第四条留言","F_Reply":""}}],"totalRecords":6}
                //服务端将返回类似上面的字符串,无法直接跟xTemplate绑定,需要转换一下
                
                var oReg = /\"json\":({.*?})/gi;
                var oResult = _returnStr.match(oReg);
                var s = "";
                for (var i = 0; i < oResult.length; i++) {
                    oResult[i].match(oReg);
                    s += RegExp.$1 + ",";
                }
                if (s.length != 0) { s = s.substr(0, s.length - 1); }
                s = "{data:[" + s + "]}";
                //最终将转换成
                //{data:[{"F_ID":3,"F_IP":"192.168.0.2","F_Date":"2008-09-14T21:29:55","F_Content":"这是第三条留言","F_Reply":""},{"F_ID":4,"F_IP":"172.168.235.1","F_Date":"2008-09-14T21:29:55","F_Content":"这是第四条留言","F_Reply":""}]}
                var data = eval("(" + s + ")");
                tpl.overwrite("page-grid", data);
            }
        }

        oGrid.dom.innerHTML = "加载中";
        
        proxy.load({ start: 2, limit: 2 }, reader, callback, this);
    });
</script>

<div id="page-grid"></div>
</body>
</html>

这里要注意的是:

尝试了多次,发现XTemplate不支持多层节点的绑定,即服务端返回的值类似:

stcCallback1001({"RecordCount":6,"PageSize":2,"PageCount":3,"CurrentPageIndex":2,"Data":[{"F_ID":3,"F_IP":"192.168.0.2","F_Date":new Date(1221399073843),"F_Content":"这是第三条留言","F_Reply":""},{"F_ID":4,"F_IP":"172.168.235.1","F_Date":new Date(1221399073843),"F_Content":"这是第四条留言","F_Reply":""}]})

在回调函数里经过Ext.util.JSON.encode(data)处理后,变成了

{"success":true,"records":[{"id":1001,"data":{"F_ID":3,"F_IP":"192.168.0.2","F_Date":"2008-09-14T21:28:28","F_Content":"这是第三条留言"},"json":

{"F_ID":3,"F_IP":"192.168.0.2","F_Date":"2008-09-14T21:28:28","F_Content":"这是第三条留言","F_Reply":""}},{"id":1002,"data":{"F_ID":4,"F_IP":"172.168.235.1","F_Date":"2008

-09-14T21:28:28","F_Content":"这是第四条留言"},"json":{"F_ID":4,"F_IP":"172.168.235.1","F_Date":"2008-09-14T21:28:28","F_Content":"这是第四条留

言","F_Reply":""}}],"totalRecords":6}

虽然也是标准的JSON字符串,但是数据节点是多层次的,XTemplate无法直接读取。所以只能在客户端用JS的正则表达式处理,手动重新组织成XTemplate所需的JSON对象,最终转换成:

{data:[{"F_ID":3,"F_IP":"192.168.0.2","F_Date":"2008-09-14T21:29:55","F_Content":"这是第三条留言","F_Reply":""},{"F_ID":4,"F_IP":"172.168.235.1","F_Date":"2008-09-14T21:29:55","F_Content":"这是第四条留言","F_Reply":""}]}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • python:爬虫入门

    直接上代码吧: 一、爬取某外卖平台的指定商家菜品信息 from urllib import request import json import random ...

    菩提树下的杨过
  • mybatis 使用经验小结

    一、多数据源问题 主要思路是把dataSource、sqlSesstionFactory、MapperScannerConfigurer在配置中区分开,各Map...

    菩提树下的杨过
  • 几种常见复合sql查询语句的linq写法[继续补充中]

    1.IN 语句 尝试了很多次,好象linq死活不生成in语句,无奈只能做了下变换 例,要找出"手机大类"以及"手机下属所有子类"的产品 (手机大类的ID为D0...

    菩提树下的杨过
  • 再谈分布式ID生成方案

    昨天沉思君分享了一篇关于分布式ID生成方案的文章《分布式ID常见解决方案》,文中介绍了几种常见的分布式ID生成方案,并讨论了其优缺点。刚好最近沉思君在看李艳鹏老...

    黄泽杰
  • 澳大利亚航空公司容量优化服务商Volantio获260万美元B轮融资

    【数据猿导读】 Volantio是澳大利亚的一家全球领先的基于机器学习的航空公司容量优化服务商,近日宣布已获得来自Ingleside Investors领投的2...

    数据猿
  • 浅谈JSON劫持

    单从字面上就可以理解的出来,JSON是一种轻量级的数据交换格式,而劫持就是对数据进行窃取(或者应该称为打劫、拦截比较合适。恶意攻击者通过某些特定的手段,将本应该...

    天钧
  • 不在 sudoers 文件中。此事将被报告。

    使用Linux,初学使用root不要太方便,工作中却不会给你这样的,必须要用自己的账号。新账号需要添加sudo的权限。 su 使用root登陆 visudo 在...

    Ryan-Miao
  • 需求评审会怎么做?

    无论什么职位都需要一个归属感,而不是一个接收任务和完成任务的工具,让团队中每个人都了解一件事情的来龙去脉更有利于这件事上的落实和达成共识。

    靠谱先生
  • 在ASP.NET MVC中使用Unity进行依赖注入的三种方式第一种方法第二种方法第三种方法

         在ASP.NET MVC4中,为了在解开Controller和Model的耦合,我们通常需要在Controller激活系统中引入IoC,用于处理用户请...

    小白哥哥
  • 求两个有序数组合并后的中位数,最透讲解| 腾讯面试编程50题(三)

    本文是腾讯50道常考编程题之一:求解两个有序数组合并后的中位数,属于 "Hard" 难度,在校招中难倒一大波校招生。本文提供一种基本解法:基于归并排序。并对归并...

    double

扫码关注云+社区

领取腾讯云代金券