2017.11.23 接口传参编码问题、AppCan前端速度优化、简单三层、显示日期段中去掉的日子、C#(Winform的几个小知识点)

第一组:杨昊 接口传参编码问题

在新框架使用时遇到这样一个问题:


image.png

如上图所示,管理页面有一个富文本编辑器,现在要把编辑器里的内容通过接口传到后台,实际上,编辑器里的内容是含有HTML标签的字符串,像这样:


image.png

这样的话会有一个问题,在将含有标签的字符串转化成Json的过程中,由于标签中特殊字符的存在(,/?:@&=+$# 等),会将Json的结构完全破坏,因此接口传输的东西便会错误。

解决方案:

使用JS中的encodeuricomponent()函数,该函数可以将传入的字符串中的中文以及特殊字符转换为UTF-8的编码格式,像这样:

我们将使用 encodeURIComponent() 对 URI 进行编码:

<script type="text/javascript">
document.write(encodeURIComponent("http://www.loongair.cn"))
document.write("<br />")
document.write(encodeURIComponent(",/?:@&=+$#"))
</script>

输出:
http%3A%2F%2Fwww.loongair.cn
%2C%2F%3F%3A%40%26%3D%2B%24%23

不过这样会出现新的问题:

新框架中后台会将URL中的UTF-8字符自动解码,这就造成即使前端将特殊字符转换成UTF-8,但是在保存进数据库之前,后台已经自动解码,于是又会出现结构被破坏的问题(相当于没有编码,只是保证了传输过程中的结构不被破坏)。

新的解决方案:

先使用Base64进行编码,Base64编码的具体方式不再赘述,可参考该链接JS实现Base64编码解码(转载)。这样一来,存入数据库的是转码的字符串,需要前台显示的时候再进行解码,并不会破坏结构。


第二组:赵彩凤 AppCan前端速度优化方案

1. 开启硬件加速
  • 开启硬件加速会极大提升页面切换速度

开启方法是在config.xml文件中配置 <hardware>true</hardware>

  • 某些场景下硬件加速会与业务逻辑冲突

决方案为:全局开启硬件加速保证速度,在特定场景关闭硬件加速,保证业务逻辑正常;

 var extras = {
     extraInfo: {//网页配置
         hardware: 0//是否开启硬件加速,0:否,1:开启(仅Android)
     }
 };
uexWindow.open('singlePage_normal', '0', 'singlePage_normal.html', 10, '', '', 0, 500, JSON.stringify(extras));
2. 单页面(webview)改造

单webview改造会明显提升运行速度,且只有单webview时,才能实现打开新页面时input自动弹出键盘的功能

  • 依赖

须引入

ui-base.css
appcan.js
appcan.control.js
**
需要页面弹动时引入,可实现下拉刷新和下载加载功能
appcan.scrollbox.js
需要tab选项卡时引入,常用于主界面,可免去预加载处理
template.import.js
appcan.tab.js
  • 普通单页面

模板代码如下,根据注释,将对应内容填入对应区域即可:

<!DOCTYPE html>
<html class="um landscape min-width-240px min-width-320px min-width-480px min-width-768px min-width-1024px">
<head>
    <title>普通单页面</title>
    <meta charset="utf-8">
    <meta name="viewport"
          content="target-densitydpi=device-dpi, width=device-width, initial-scale=1, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <link rel="stylesheet" href="css/fonts/font-awesome.min.css">
    <link rel="stylesheet" href="css/ui-box.css">
    <link rel="stylesheet" href="css/ui-base.css">
    <link rel="stylesheet" href="css/ui-color.css">
    <link rel="stylesheet" href="css/appcan.icon.css">
    <link rel="stylesheet" href="css/appcan.control.css">
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="page_0" class="bc-bg" data-control="PAGE">
    <!--header开始-->
    <div id="header" class="uh bc-head ub ubb bc-border bc-text-head" data-control="HEADER">
        <!--左边-->
        <div class="nav-btn" id="nav-left">
            <!--返回按钮图标-->
            <div class="ub ub-img tagimg tagwh"></div>
        </div>
        <!--中间-->
        <h1 id="title" class="ut ub-f1 ulev-3 ut-s tx-c">普通单页面</h1>
        <!--右边-->
        <div class="nav-btn" id="nav-right">右边</div>
    </div>
    <!--header结束-->
    <!--content开始-->
    <div id="content" data-control="CONTENT">
        <div id="scrollBox" class="" data-control="ScrollBOX" data-bounce="1">
            <div data-control="BounceBox">
                <!--下拉刷新控件-->
                <div class="box_bounce ub ub-ver ub-pc">
                    <div class="ub-f1"></div>
                    <!--正在下拉-->
                    <div id="draging" class="bounce_status"></div>
                    <!--触发下拉刷新的界限-->
                    <div id="dragToReload" class="bounce_status"></div>
                    <!--下拉刷新回调触发后-->
                    <div id="releaseToReload" class="bounce_status"></div>
                </div>
                <!--内容区域,在这里放界面的HTML代码-->
                <!--内容区域结束-->
            </div>
        </div>
    </div>
    <!--content结束-->
</div>
<script src="js/appcan.js"></script>
<script src="js/appcan.control.js"></script>
<script src="js/appcan.scrollbox.js"></script>
</body>
<script>
    /**
     * 下拉刷新和上拉加载
     * Scroll BOX function DEMO START
     */
    (function ($) {
        //初始化下拉刷新
        initPullDownRefresh(
                //下拉刷新的回调
                function () {
                    console.log("下拉刷新");
                    endPullDownRefreshLately(500);
                }
                //上拉到底部的回调
                , function () {
                    console.log("上拉加载");
                }
                //是否显示提示语
                , true
        );
    })($);
    //插件加载完成的回调
    appcan.ready(function () {
        console.log("appcan.ready");
        //手动调用下拉刷新
        pullDownRefresh();
    });
    //导航栏点击事件
    appcan.button(".nav-btn", "btn-act", function () {
        //左侧
        this.id == "nav-left" && appcan.window.close(-1);
        //右侧
        //this.id == "nav-right" &&;
    });
</script>
</html>
  • 带有tab栏的单页面

需要注意的地方:

  • 每个tab.html的css和js都要在主页面被引入
  • 如果不需要导航栏header,先删除header的部分,还需要将data-control="CONTENT"修改为data-control="CONTENT_NO_HEADER",原理很简单,即为去掉CONTENT的padding-top = 2.75em属性
<!DOCTYPE html>
<html class="um landscape min-width-240px min-width-320px min-width-480px min-width-768px min-width-1024px">
<head>
    <title>带有tab栏的单页面</title>
    <meta charset="utf-8">
    <meta name="viewport"
          content="target-densitydpi=device-dpi, width=device-width, initial-scale=1, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <link rel="stylesheet" href="css/fonts/font-awesome.min.css">
    <link rel="stylesheet" href="css/ui-box.css">
    <link rel="stylesheet" href="css/ui-base.css">
    <link rel="stylesheet" href="css/ui-color.css">
    <link rel="stylesheet" href="css/appcan.icon.css">
    <link rel="stylesheet" href="css/appcan.control.css">
    <link rel="stylesheet" href="css/style.css">
    <link rel="stylesheet" href="css/main.css">
</head>
<body>
<div id="page_0" class="bc-bg" tabindex="0" data-control="PAGE">
    <!--header开始-->
    <div id="header" class="uh bc-head ub ubb bc-border bc-text-head" data-control="HEADER">
        <!--左边-->
        <div class="nav-btn" id="nav-left">
            <!--返回按钮图标-->
            <div class="ub ub-img tagimg tagwh"></div>
        </div>
        <!--中间-->
        <h1 id="title" class="ut ub-f1 ulev-3 ut-s tx-c">带有tab栏的单页面</h1>
        <!--右边-->
        <div class="nav-btn" id="nav-right">右边</div>
    </div>
    <!--header结束-->
    <!--header结束--><!--content开始-->
    <div id="content" class="" data-control="CONTENT">
        <div class="" data-control="ScrollBOX" data-bounce="1">
            <div data-control="BounceBox">
                <div class="box_bounce ub ub-ver ub-pc">
                    <div class="ub-f1"></div>
                    <div class="bounce_status">
                        下拉更新......
                    </div>
                    <div class="bounce_status">
                        松手更新......
                    </div>
                    <div class="bounce_status">
                        更新中......
                    </div>
                </div>
                <!--内容区域,在这里放界面的HTML代码-->
                <div class="tab_pane active" data-import="tab1.html">
                </div>
                <div class="tab_pane" data-import="tab2.html">
                </div>
                <div class="tab_pane" data-import="tab3.html">
                </div>
                <!--内容区域结束-->
            </div>
        </div>
    </div>
    <!--content结束-->
    <div id="tabview" class="uf sc-bg ubt sc-border-tab" data-control="FOOTER"></div>
</div>
<script src="js/appcan.js"></script>
<script src="js/appcan.control.js"></script>
<script src="js/appcan.listview.js"></script>
<script src="js/appcan.scrollbox.js"></script>
<script src="js/template.import.js"></script>
<script src="js/appcan.tab.js"></script>
</body>
<script>
    //插件加载完成的回调
    appcan.ready(function () {

    });
    //导航栏点击事件
    appcan.button(".nav-btn", "btn-act", function () {
        //左侧
        this.id == "nav-left" && appcan.window.close(-1);
        //右侧
        //this.id == "nav-right" &&;
    });
    //按钮点击事件
    appcan.button(".btn", "btn-act", function () {
    });
    /**
     * 下拉刷新和上拉加载
     * Scroll BOX function DEMO START
     */
    (function ($) {
        //初始化下拉刷新
        initPullDownRefresh(
                //下拉刷新的回调
                function () {
                    console.log("下拉刷新");
                    endPullDownRefreshLately(500);
                }
                //上拉到底部的回调
                , function () {
                    console.log("上拉加载");
                    //添加数据
                    addData();
                }
                //是否显示提示语
                , true
        );
    })($);
    /**
     * 底部tab栏点击事件
     * Scroll BOX function DEMO END
     */
    var tabview = appcan.tab({
        selector: "#tabview",
        hasIcon: true,
        hasAnim: true,//控制是否有下方滑块和动画
        hasLabel: false,
        hasBadge: false,
        data: [{
            label: "QQ",
            "icon": "fa-qq"
        }, {
            label: "微软",
            "icon": "fa-windows"
        }, {
            label: "微信",
            "icon": "fa-weixin"
        }]
    });
    tabview.on("click", function (obj, index) {
        $(".tab_pane").removeClass("active");
        $($(".tab_pane")[index]).addClass("active");
    });
</script>
</html>

第三组:蔡永坚 简单三层

敲了这么久的代码,回到最基本的开始:我们是否知道如何去搭建一个项目,项目中每个目录到底什么用的?该如何去创建它们。要想知道这些,必须得了解简单三层结构。

三层构架,说到底就是一个简单的分层概念,一个数据访问层,业务逻辑层,和UI层。

1. 三层体系架构
  • 表示层(UI):主要表示WEB方式,也可以表示成WINFORM方式。如果逻辑层相当强大和完善,无论表现层如何定义和更改,逻辑层都能完善地提供服务。

  • 业务逻辑层(BLL):主要是针对具体的问题的操作,也可以理解成对数据层的操作,对数据业务逻辑处理。如果说数据层是积木,那逻辑层就是对这些积木的搭建。

  • 数据访问层(DAL):主要是对原始数据(数据库或者文本文件等存放数据的形式)的操作层,而不是指原始数据,也就是说,是对数据的操作,而不是数据库,具体为业务逻辑层或表示层

2. 具体区分
  • 表示层:主要对用户的请求接受,以及数据的返回,为客户端提供应用程序的访问。

  • 业务逻辑层:主要负责对数据层的操作,也就是说把一些数据层的操作进行组合。

  • 数据访问层:主要看你的数据层里面有没有包含逻辑处理,实际上他的各个函数主要完成各个对数据文件的操作,而不必管其他操作。

3. 总结

三层结构是一种严格分层方法,即数据访问层(DAL)只能被业务逻辑层(BLL)访问,业务逻辑层只能被表示层(UI)访问,用户通过表示层将请求传送给业务逻辑层,业务逻辑层完成相关业务规则和逻辑,并通过数据访问层访问数据库获得数据,然后按照相反的顺序依次返回将数据显示在表示层。有的三层结构还加了Factory、Model等其他层,实际都是在这三层基础上的一种扩展和应用.

一个简单的三层结构程序一般包括DAL BLL WEB Model几个项目,它们的相互引用关系如下

1) WEB引用 BLL,Model
2)BLL引用 DAL,Model
3)DAL引用Model
4)Model无引用

而common放的则是公共类,如用于计算的Math类就放在Common下。
目前系统是将DAL和BLL层合在了一起建的类库DB。


第四组:傅云 显示日期段中去掉的日子

我们经常会进行日期查询,但是如果要显示日期段中去掉的日子该如何操作?如我们有10月8日,10月9日,在10月中去除这两天。便可进行如下操作:

image.png
List < DateTime > cannotUseList = new List < DateTime > (); //定义一个时间数组
int count = int.Parse((timeTo.AddDays(1) - timeFrom).TotalDays.ToString()); //获取需要的时间段中天数
for (int i = 0; i < count; i++) {
    DateTime dateParam = timeFrom;
    dateParam = dateParam.AddDays(i);
    bool ifMatch = false;
    foreach(var item in flightInfoArr) {
        if (item.VF_FlightDate == dateParam) {
            ifMatch = true; //判断是否在时间段内
            break;
        }
    }
    if (!ifMatch) {
        cannotUseList.Add(dateParam);
    }
}
foreach(var adddate in cannotUseList) {
    cannotUseDates = adddate + ";" + cannotUseDates; //获取去除之后的日期
}

第五组:王炳钧 C#(Winform的几个小知识点)

  • 在WinForm中使多个控件共享一个事件的实现:

方法:按住Ctrl键,一次选中多个控件,选择它们共有事件,双击即可。

例如:选择多个Button,在事件中找到Button的单击事件,双击进去,在Click事件中编写代码,这样就实现了多个控件共享一个事件。

  • 在WinForm中使用DataGridView与数据库绑定数据

在WinForm中使用DataGridView与数据库绑定数据时,会出现中英文列名同时显示的麻烦,这时只需一行代码将英文列明显示屏蔽掉既可以只显示中文列名;

示例代码:
this.DataGridView1.AutoGenerateColumns=false;

在Winform中清空窗体的简单方法可以这样写:

public void Clear()
{
    foreach(Control c in this.Controls)
    {
       if(c is TextBox)
       {
          c.Text=string.Empty;
       }
       if(c is CheckBox)
       {
          CheckBox chb=c as CheckBox;
          chb.Checked=false;
       }
    }
}

但是这样的话,如果我们想清空某个容器中的控件而不是所有的控件的话。我们只需要将foreach里面的this.Controls改为this.Panel1.Controls就可以了。

  • 在Winform窗体中添加滚动字幕:

我们需要三个控件:一个Label控件,两个个Button控件,一个Timer控件,Timer控件来控制文字滚动的速度。编写Timer控件的tick事件。

示例代码如下:

private void Timer1_Tick(object sender,EventArgs e)
{
     Label1.Left-=2;    //Label向左减2
     if(this.Label1.Right<0)
     {
          this.Label1.Left=this.Width;
     }
}

下面编写Button1和Button2的单击事件,用来控制字幕滚动的开始和停止.

示例代码如下:

//控制字幕滚动的开始
private void Button1_Click(object sender,EventArgs e)
{
   this.Timer1.Enabled=true;
}
//控制字幕滚动的结束
private void Button2_Click(object sender,EventArgs e)
{
    this.Timer2.Enabled=false;
}

启动调试,预览效果。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容