zoukankan      html  css  js  c++  java
  • 模仿igoogle【定制化、拖动排序,最大化、分屏】

    【jquery仿dataList】应用之——模仿igoogle【定制化、拖动排序,最大化、分屏】

    接上一次日志哈,这一次用原来写的datalist实现了简单应用,模拟igoogle。

    做的过程中发现代码很多问题,主要是流程上的问题。

    主要是自己层次不够,明明已经感到这样那样的问题,都能说出来就是不知道怎么改。主要问题:

    1 初始化时候参照其他jquery框架,应该达到配置最小化,却怎么都做不好

    2 现在控件必须提供数据源datalist与模板template,数据源还好说,但是模板的写法真的太坑爹,现在是放在数据库里面了

    以后怎么做还说不清哦

    3 与.net中datalist一致,不论datalist还是item都会生成多余的标签,这里是生成的div,看上去很是别扭

    4 最大问题还是,混乱!!!就像这篇文章一样,js控制力不同于服务器语言,所有整个做起来,不论事件绑定

    还是其他什么定义都感觉有点混乱,流程不清,这是我主要应该改进的地方。


    主要流程:

    1 加载小工具模板:现在先一次性加载,以后用到一个保存一个作为全局参数
    2 加载该用户的所有小工具:现在先一次性加载,以后先加载第一页,
    根据页索引判断加载
    3 根据用户小工具数据,初始化所有小工具外框
    由于数据以及模板已经取出,此时加载速度应该非常快,左中右一次加载
    **此处注意,虽说小工具外框一样,但是新增的小工具可能会在外框加载结束后再修饰外框
    比如,weibo、top.....,此数据存于小工具定制列(CustomData)
    4 此时进行数据异步加载,
    ***数据可以统一加载,但是此处先加载所有小工具每列前两名数据
    在根据后台用户干预加载那些大数据小工具,加载结束后,当用户滑动鼠标便进行以下
    控件加载,每次控件加载数量可配置化
    5 所有控件加载结束,已加载结束控件,可能会根据后台配置要求动态刷新数据
    此处需要做轮询
    6 控件加载结束后,开始做控件事件绑定
    ***注意粒度尽量小,不要和其他模块相互影响


    首页效果图:

    此处点击都会触发事件,一个是异步加载选项卡数据,一个是展开摘要:

    也可以延后加载,比如:开始只加载前三个模块,鼠标滑动后,再加载后面的模块:

    一下是,初始化后鼠标滑动前与鼠标滑动后的效果:


    分屏、分页效果

    点击上面1,2,3肯定会指向不同也了,其实现在用户是我,若是用户换了也会有所不同

    下面是第二页和第三页


    拖动排序也实现了,之前想自己写一个拖动插件,拖动时实现了却发现插件非常困难,

    局限于自己的层次,就直接用的jquery ui的拖动

    下面是拖动排序的展示,保存到数据库的,最后一张是刷新后重新排序的图:


    点击最大化,并实现鼠标滚动到最下边重新加载数据(滚动分页嘛):


    数据库简要设计,因为我没有安装数据库,所有优点不好弄:

    设计缘由:由于今后可能不止五页,做到页数动态化

    NO.

    字段名称

    说明

    1

    uuid

    页面唯一标识

    2

    pageSort

    页面排序

    3

    pageName

    页面标题,默认1,2,3,4,5

    4

    pageDes

    页面描述,鼠标划上显示

    5

    小工具模板表 templates(基本字段)

    NO.

    字段名称

    说明

    1

    uuid

    页面唯一标识

    2

    templateKey

    标识

    3

    templateValue

    模板内容

    4

    des

    描述

    5

    小工具表 modules(基本字段)

    小工具参数化,可变参数,具有验证性

    NO.

    字段名称

    说明

    1

    uuid

    小模块唯一标识

     

    author

    小工具作者

    2

    alias

    模块前台标识名,对应category

    3

    title

    小模块名称

    4

    dataSourceUrl

    数据源链接地址

    5

    pageId

    当前小工具属于第几屏,对应pages 的 uuid

    6

    colId

    当前小工具属于第几列(暂分为1,2,3列)

    7

    sort

    当前小工具顺序

    8

    templateId

    当前小工具对应模板,对应templates表

    9

    type

    当前小工具类型,frame或者json

     

     

    参数化后

    NO.

    字段名称

    说明

    1

    uuid

    小模块唯一标识

    2

    alias

    模块前台标识名,对应category

    3

    title

    小模块名称

    5

    pageId

    当前小工具属于第几屏,对应pages 的 uuid

    6

    colId

    当前小工具属于第几列(暂分为1,2,3列)

    7

    sort

    当前小工具顺序

    8

    moduleParameter

    当前小工具具有的参数对象,现在采用json对象

    采用键值对,加一个描述字段

    {dataSourceUrl:XXXXX ,templateId:XXXX , type:XXX }

    以上是基本属性,应该是字段吧…..

    灰色部分可以不用,直接默认在第一页第一排,默认最大

    其默认值在用户小工具表中体现出来

    小工具参数moduleParameter

    NO.

    字段名称

    说明

    1

    uuid

    小模块唯一标识

    2

    moduleKey

    3

    moduleValue

    4

    des

    5

    isTransfer

    是否形成json传向前台

     

    用户小工具设置表(用户参数设置)

    userModules

    NO.

    字段名称

    说明

    1

    uuid

    小模块唯一标识

    2

    userId

    用户id

    3

    moduleId

    小工具Id

     

    userPrefers

    用户偏好设置

     

    用户小工具参数偏好userModulePre

    NO.

    字段名称

    说明

    1

    uuid

    小模块唯一标识

    2

    preKey

    3

    preValue

    4

    des

    5

    isTransfer

    是否形成json传向前台

     

    最终表设计


    核心实现代码如下:原来的datalist的代码我就不发了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    /// <reference path="../scripts/jquery-1.4.1.js" />
    /// <reference path="dataList.js" />
    /// <reference path="itemTemplate.js" />
    //全局变量设置
    var templateWarehouse = {};
    var userModuleData = {};
    var leftColModule, centerColModule, rightColModule;
    //首页模块加载参数
    var moduleLoadPara = {};
    moduleLoadPara.index = 1; //初始化加载索引
    moduleLoadPara.num = 1; //每次索引加载个数
    moduleLoadPara.isLoad = false; //当前是否在加载
    //---------------------------------------------------------------------------
    //第一步,加载模板
    function loadTemplate() {
        $.ajax({
            type: "post",
            url: "../Ajax.aspx?sql=select * from templates ",
            type: "json",
            async: false,
            success: function (data) {
                $.each(data, function (i, item) {
                    templateWarehouse[item.templateKey] = item.templateValue;
                });
            }
        });
    }
    //加载所有模板数据
    function loadModuleData(isAsync) {
        var _isAsync = false;
        if (isAsync)
            _isAsync = isAsync;
        var userId = "wl";
        $.ajax({
            type: "post",
            url: "../Ajax.aspx?sql=select * from modules m ,userModules um where 1=1 and m.uuid=um.moduleId and um.userId='" + userId + "'",
            type: "json",
            async: _isAsync,
            success: function (data) {
                userModuleData["1"] = [];
                userModuleData["2"] = [];
                userModuleData["3"] = [];
                userModuleData["4"] = [];
                userModuleData["5"] = [];
                $.each(data, function (i, item) {
                    var userPrefs = item.userPrefers;
                    if (typeof (userPrefs) == "string") {
                        userPrefs = eval("(" + userPrefs + ")"); ;
                    }
                    item.userPrefers = userPrefs;
                    userModuleData[userPrefs.pageId].push(item);
                });
            }
        });
    }
    //---------------------------------------------------------------------------
    //根据用户id,按要求加载其模板
    function initModuleFrame(_pageId) {
        var pageId = 1;
        if (_pageId)
            pageId = _pageId;
        var $div = $("#main");
        $div.html("");
        loadColModule(pageId, "left_conter");
        loadColModule(pageId, "cell_conter");
        loadColModule(pageId, "right_conter");
    }
    function loadColModule(pageId, colId) {
        var $div = $("#main");
        var colData = getColData(pageId, colId);
        var colModule = new dataList(colId, "commonFrame");
        colModule.itemElementEvent = {
            _sortItems: {
                elementKey: ".content",
                eventType: "ready",
                funcName: itemSort
            },
            _itemMaxClick: {
                elementKey: ".btn_close",
                eventType: "click",
                funcName: itemMaxClick
            },
            _itemMenuClick: {
                elementKey: ".btn_more",
                eventType: "click",
                funcName: itemMenuClick
            }
        };
        colModule.className = "column";
        colModule.dataSource = colData;
        colModule.dataBind($div);
        if (colId == "left_conter") {
            leftColModule = colModule;
        } else if (colId == "cell_conter") {
            centerColModule = colModule;
        } else if (colId == "right_conter") {
            rightColModule = colModule;
        }
    }
    function getColData(pageId, colId) {
        var tempData = [];
        var data = userModuleData[pageId];
        $.each(data, function (i, item) {
            var userPrefs = item.userPrefers;
            if (userPrefs.pageId == pageId && userPrefs.colId == colId) {
                tempData.push(item);
            }
        });
        tempData = tempData.sort(function (a, b) {
            if (a.userPrefers.sort < b.userPrefers.sort) {
                return -1;
            }
            if (a.userPrefers.sort > b.userPrefers.sort) {
                return 1;
            }
            return 0;
        });
        return tempData;
    }
    //---------------------------------------------------------------------------
    function loadItemMax(sender, param, e, isClick) {
        var dataSourceUrl = param.dataSourceUrl;
        var templateId = param.templateId + "-max";
        var title = param.title;
        var type = param.type;
        var id = sender.id;
        var $max = $("#list-max");
        var $main = $("#main");
        var $content = $("#list-max #list-max-content");
        if (isClick)
            $content.html("");
        var $title = $("#list-max #list-max-title");
        var $itemList = $("#list-max .list");
        var $listMore = $("#list-max #list-max-more");
        var isLoad = $listMore.val();
        $listMore.val("-1");
        var len = $itemList.length;
        var _index = len + 1;
        var itemStr = '<fieldset  class="list"><legend><span class="index">page' + _index.toString() + '</span></legend><div id="itemContent' + _index.toString() + '" >数据加载中......</div></fieldset>';
        $main.hide();
        $max.show();
        $title.html(title);
        if (type && type == "s-html") {
            var html = '<iframe scrolling="no" frameborder="0" src="' + dataSourceUrl + '"></iframe>';
            $content.html(html);
        } else {
            $content.append(itemStr);
            $.ajax({
                type: "post",
                url: dataSourceUrl,
                type: "json",
                async: true,
                success: function (data) {
                    var $itemContent = $("#list-max #itemContent" + _index.toString() + "");
                    $itemContent.html("");
                    var dataNews = data;
                    if (typeof (dataNews) == "string") {
                        dataNews = eval("(" + data + ")");
                    }
                    var listMax = new dataList(id + "_max", templateId);
                    listMax.dataSource = dataNews;
                    listMax.dataBind($itemContent);
                    $listMore.val("1");
                }
            });
        }
    }
    //小工具事件定义,小工具事件处理函数
    function itemMaxClick() {
        var sender = this;
        var param = arguments[0];
        var e = arguments[1];
        loadItemMax(sender, param, e, true);
        $(document).unbind("scroll");
        $(document).bind("scroll", function (e) {
            var windowHeight = $(window).height();
            var windowScrollTop = $(window).scrollTop();
            var documentHeight = $(document).height();
            var $listMore = $("#list-max #list-max-more");
            var isLoad = $listMore.val();
            if ((windowHeight + windowScrollTop + 100) > documentHeight && isLoad == "1") {
                loadItemMax(sender, param, e);
            }
        });
    }
    //小工具事件定义,点击出现菜单栏
    function itemMenuClick() {
        var sender = this;
        var param = arguments[0];
        var e = arguments[1];
        //    alert("弹出菜单" + "--" + param.uuid1 + "--" + sender.id)
        var uuid = param.uuid1;
        var popupMenu = $("#popupMenu");
     
    }
    //定义小工具会用到的工具类
    var moduleInitTool = {};
    //适用于不同模板,若是有新模板,只需根据规范添加函数即可,工厂方法
    moduleInitTool.jsonModule = function (sender, param, e) {
        var templateId = param.templateId;
        var id = param.uuid;
        var dataSourceUrl = param.dataSourceUrl;
        var $itemContent = sender.getItemElement(".content");
        if (dataSourceUrl) {
            moduleLoadPara.isLoad = false;
            $.ajax({
                type: "post",
                url: dataSourceUrl,
                type: "json",
                async: true,
                success: function (data) {
                    $itemContent.html("");
                    var dataNews = data;
                    if (typeof (dataNews) == "string") {
                        dataNews = eval("(" + data + ")"); ;
                    }
                    var listItemNews = new dataList(id + "_news", templateId);
                    listItemNews.itemElementEvent = {
                        clickTitle: {
                            elementKey: ".span2",
                            eventType: "click",
                            funcName: titleClick
                        }
                    }
                    listItemNews.dataSource = dataNews;
                    listItemNews.dataBind($itemContent);
                    //                if (sender.id == "right_conter_id_1")
                    //                    setInterval(function () {
                    //                        alert("重新加载" + sender.id);
                    //                    }, 5000);
                    moduleLoadPara.isLoad = true;
                }
            });
        }
    }
    moduleInitTool.htmlModule = function (sender, param, e) {
        var id = param.uuid;
        var dataSourceUrl = param.dataSourceUrl;
        var $itemContent = sender.getItemElement(".content");
        if (dataSourceUrl) {
            var html = '<iframe scrolling="no" frameborder="0" src="' + dataSourceUrl + '"></iframe>';
            $itemContent.html(html);
        }
    }
    moduleInitTool.weiboModule = function (sender, param, e) {
     
    }
    moduleInitTool.labelModule = function (sender, param, e) {
        var templateId = param.templateId;
        var id = param.uuid;
        var dataSourceUrl = param.dataSourceUrl;
        var customData = param.customData;
        var modulePara = param.moduleParameter;
        if (typeof (modulePara) == "string") {
            modulePara = eval("(" + modulePara + ")"); ;
        }
        templateWarehouse["labelHeadTemplate"] = modulePara.labelHeadTemplate;
        var $itemContent = sender.getItemElement(".content");
        $itemContent.html(customData);
        var lableHead = sender.getItemElement("#labelHead");
        moduleLoadPara.isLoad = false;
        $.getJSON("../Ajax.aspx?sql=select * from bigType", function (data) {
            var labelHeadList = new dataList(id + "_head", "labelHeadTemplate");
            labelHeadList.dataSource = data;
            labelHeadList.className = "labelHead";
            labelHeadList.itemEvent = {
                _labelHeadClick: {
                    eventType: "click",
                    funcName: function () {
                        var _sender = this;
                        var _param = arguments[0];
                        var _e = arguments[1];
                        var labelBody = sender.getItemElement("#labelBody");
                        var bigTypeId = _param.id;
                        var url = "../Ajax.aspx?sql=select * from smallType where bigTypeId=" + bigTypeId + "";
                        $.getJSON(url, function (_data) {
                            labelBody.html("");
                            var labelBodyList = new dataList(bigTypeId + "_head", templateId);
                            labelBodyList.dataSource = _data;
                            labelBodyList.dataBind(labelBody);
                        });
                    }
                }
            };
            labelHeadList.dataBind(lableHead);
            moduleLoadPara.isLoad = true;
        });
    }
     
    function elementDatabind(s) {
        var sender = this;
        var param = arguments[0];
        var e = arguments[1];
        var type = param.type;
        if (type && type.length > 2) {
            var _funcName = type.substring(2) + "Module";
            //        eval(_funcName);//此方法不能异步调用
            var funcName = moduleInitTool[_funcName];
            if (funcName && typeof (funcName) == "function") {
                funcName(sender, param, e);
            }
        }
    }
     
    function titleClick() {
        var sender = this;
        var param = arguments[0];
        var e = arguments[1];
        var summary = sender.getItemElement(".summary");
        var isShow = summary.css("display");
        if (isShow == "none") {
            summary.show();
        } else {
            summary.hide();
        }
    }
    //用于小工具排序
    function itemSort() {
        var sender = this;
        var html = sender.htmlElement;
    //    alert(html.offset().top);
        $(".column").sortable({
            connectWith: ".column",
            cursor: 'move',
            opacity: 0.7,
            handle: " .title",
            stop: sortItemsAjax
        });
    }
    //向后台发送数据
    function sortItemsAjax() {
        submitSortData("left_conter");
        submitSortData("cell_conter");
        submitSortData("right_conter");
     
    }
    function submitSortData(colId) {
        var parent = $("#" + colId);
        var $children = parent.children();
        $children.each(function (i, item) {
            var id = item.id;
            var itemId = "#" + id + " #itemId";
            var $uuid = $(itemId);
            var uuid = $uuid.html();
            var userPrefers = item.userPrefers;
            $.ajax({
                type: "post",
                url: "../Ajax.aspx?sort=" + i + "&colId=" + colId + "&id=" + uuid + "&no=no",
                type: "json",
                async: true,
                success: function (data) {
                }
            });
     
        });
    }
    //---------------------------------------------------------------------------
    //总体外部流程,外部方法
    function mainProcess() {
        var $max = $("#list-max");
        var $main = $("#main");
        var $btn_Narrow = $("#list-max .btn_Narrow");
        $btn_Narrow.unbind("click");
        $btn_Narrow.bind("click", function () {
            if ($max.css("display") == "none") {
                $main.hide();
                $max.show();
            } else {
                $(document).unbind("scroll");
                var $listMore = $("#list-max #list-max-more");
                $listMore.val("-1");
                $main.show();
                $max.hide();
            }
        });
    }
     
     
    function LaterEvent() {
        var commomEvent = {
            _loadItems: {
                elementKey: ".content",
                eventType: "ready",
                funcName: elementDatabind
            }
        };
        var num = (moduleLoadPara.index) * (moduleLoadPara.num);
        for (var i = 0; i < num; i++) {
            if (leftColModule.items[i])
                leftColModule.items[i].eventAdd(commomEvent);
            if (centerColModule.items[i])
                centerColModule.items[i].eventAdd(commomEvent);
            if (rightColModule.items[i])
                rightColModule.items[i].eventAdd(commomEvent);
        }
        moduleLoadPara.index++;
         
        //    leftColModule.eventAdd(commomEvent);
        //    centerColModule.eventAdd(commomEvent);
        //    rightColModule.eventAdd(commomEvent);
    }
    function delayLoad() {
        var commomEvent = {
            _loadItems: {
                elementKey: ".content",
                eventType: "ready",
                funcName: elementDatabind
            }
        };
        $(document).unbind("scroll");
        $(document).bind("scroll", function (e) {
            if (moduleLoadPara.isLoad) {
                var num = (moduleLoadPara.index) * (moduleLoadPara.num);
                var oldNum = (moduleLoadPara.index-1) * (moduleLoadPara.num);
                for (var i = oldNum; i < num; i++) {
                    if (leftColModule.items[i])
                        leftColModule.items[i].eventAdd(commomEvent);
                    if (centerColModule.items[i])
                        centerColModule.items[i].eventAdd(commomEvent);
                    if (rightColModule.items[i])
                        rightColModule.items[i].eventAdd(commomEvent);
                }
                moduleLoadPara.index++;
            }
        });
    }
    function pageClick() {
        for (var i = 1; i <= 5; i++) {
            var page = $("#pageIndex" + i.toString());
            page.unbind("click");
            page.bind("click", function (e) {
                var _p = $(this);
                initModuleFrame(_p.text());
                LaterEvent();
                var $max = $("#list-max");
                var $main = $("#main");
                $main.show();
                $max.hide();
                $(document).unbind("scroll");
                var $listMore = $("#list-max #list-max-more");
                $listMore.val("-1");
                //置顶
                $('html,body').animate({ scrollTop: '0px' }, 800);
                //            A:return false --->In event handler ,prevents default behavior and event bubbing 。
                //return false 在事件的处理中,可以阻止默认事件和冒泡事件。
                //B:event.preventDefault()---> In event handler ,prevent default event (allows bubbling) 。
                //event.preventDefault()在事件的处理中,可以阻止默认事件但是允许冒泡事件的发生。
                //C:event.stopPropagation()---> In event handler ,prevent bubbling (allows default behavior).
                //event.stopPropagation()在事件的处理中,可以阻止冒泡但是允许默认事件的发生。
                e.stopPropagation();
                return false;
            });
        }
    }
    function pageLoad() {
        mainProcess();
        loadTemplate();
        loadModuleData();
        initModuleFrame();
          
        LaterEvent();
        pageClick();
        //置顶
        $('html,body').animate({ scrollTop: '0px' }, 800);
        delayLoad();
     
        //5分钟更新一次模块数据
        var updateModuleData = setInterval("loadModuleData(true)", 50000);
     
    }
    //---------------------------------------------------------------------------

      


    代码太多不做说明了,以后肯定会封装,

    就现在看来整个应用感觉问题不少,实际用处不大吧。

    后面点代码整理后再一并发出吧,如果有需要的话。

    Web前端
     
     
     
     
     
     
  • 相关阅读:
    【转】SQL时间函数
    C#操作Word完全方法
    出水芙蓉,风华绝代记民国才女林徽因
    梅超风:我就是那个多年以前的女子
    厉胜男
    南海恶神
    挪窝
    吴若权——洛可可动画电影馆
    美的慢箭
    机械公敌(I, Robot) 场景设定
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2399769.html
Copyright © 2011-2022 走看看