分类: 技术

各种开发心得,包括语言、软件工程、开发工具等

  • 纯CSS实现toggle按钮

    将来要用到,提前准备一个。

  • 新项目:诺兹多姆,时间的守护者

    其实也不算新项目。加入点乐之后,我的主要任务之一就是做后台。我是个自视甚高的人,所以要做就做最好用的后台,经过不懈努力,现在的点乐后台V3.3版,无论从开发的角度还是使用者的角度来看,(应该说)都已经非常好用了。

    不过问题仍然有很多,主要分为两方面:性能和弹性。

    性能

    先说性能,最初的版本是完全PHP的,用户操作都基于表单。我将其改成加载局部HTML片段,用户操作主要用ajax实现。显然,后台不可能停工,所以我边改边上线,架构上基本继承前人的设计,比如,大多数页面没有分页功能(很多同事用习惯了,也要求不要加分页)。

    于是,大多数页面都要读取符合条件的全部数据,然后由Javascript实现排序、筛选、搜索等功能。当初我这么做的时候,公司业务量小,没什么问题;如今公司发展起来了,业务量越来越大,每次都加载全部数据,页面性能越来越差。尤其是手机端,很多页面一开就死。无奈之下,我只好先用Javascript分页顶着。

    弹性

    曾经懵懂少年的我动手时还不太会用Backbone,没有理解其精髓,只是觉得Backbone.View的事件代理比较好,写起来蛮舒服;更没想到借助Robotlegs的优秀设计开发Nervenet,所以前端架构上也有问题。比较严重的是数据同步(所谓数据双向绑定),即操作人员修改了某数据,保存到服务器后再回来,页面应该更新被修改的数据。那时候Knockout刚出来,Angular和Ember都还不堪大用,数据双向绑定对我来说只是个梦想。还好我码功扎实,也能解决的七七八八,比如主功能区共用一个Model作为中介(Mediator Pattern,中介者模式),数据交互都从它那儿走,其它组件监听change事件来更新视图。

    不过这样终究不是办法,因为随着功能的增加,代码里各种写死的属性和方法越来越多,代码日益臃肿,弹性也是个大问题。

    诺兹多姆诞生

    恰在此时,新项目来了。新项目也需要后台,我当然不会直接把点乐后台拿来重用,而是花了一些时间剥离其中的前端框架,准备将其独立出来,成为一个新项目:诺兹多姆。

    诺兹多姆,青铜龙之王,时间守护者。在炉石传说里,诺兹多姆将强制把每回合的事件降到15秒,这也是我的目的,无论用户要干什么,都能在很短的时间内——不妨假定是15秒——完成。

    这是个专门针对后台的前端框架,能够覆盖各种后台的需求,也能提供漂亮的界面和良好的交互。等各种希望这个项目完成后,能够达到这些目的:

    1. 大大提高后台类应用的开发效率
    2. 前后端分离,独立开发,分开部署
    3. 丰富的组件,覆盖后台常用功能
    4. 灵活的插件机制,扩展能力强大
    5. 漂亮的界面,可以自由更换主题
    6. 全平台覆盖,甚至支持打包成移动应用

    开源

    此项目是在公司做的,当然要以公司的名义开源。当然,开源的结果基本上还是只有我们公司在用……

    现在还在开发中,离最终目标还很远。

    [github repo=”Dianjoy/nozdormu”]

    致谢

    此项目中用到了大量开源代码,感谢他们的创作者,是他们让世界变得更加美好。

    感谢公司给我这个机会。感谢同事们让公司不断成长,给我留下尝试的机会。

  • mustache.php在生产环境下一定要开cache

    mustache.php在生产环境下一定要开cache。

    实测开与不开有3倍左右的性能差距,当然我们的模板并不复杂,理论上应该越复杂越能拉开差距。

     

  • Android Hybrid App四大坑

    Android Hybrid App四大坑

    首先解释下题目,Hybrid App,混合应用,代表平台Phonegap,一般指使用原生包装Web页面开发的应用。与原生应用相比,主要用户界面和业务逻辑都是用Web技术也就是HTML+CSS+Javascript实现的;与Web应用相比,Web部分打包在应用内部,使用时不需要网络。

    顺便说一句,很多解决方案其实不算Hybrid,比如Adobe AIRTitaniumMono,这些都是使用某一特定技术开发跨平台应用的工具,最终产品都是编译成原生来跑的。

    我们没有选择phoengap为技术基础(我对此并不满意,我认为以phonegap为基础可以少走一些弯路,少花一些精力,还能产出很多有价值的副产品),而是自行开发原生框架,主要目标平台是Android——嗯,就是那个从系统版本到模块组合都巨分散的Android,可以这么说,坎坷从立项的那一刻起就已经注定了……接下来,便请听我一一讲述:Android Hybrid App四大坑。(此文主要针对Android 4.3-的webview,部分浏览器比如Chrome已经改善了具体实现,所以Web App其实环境不错。)

    游戏泡泡v0.2首页截图
    游戏泡泡v0.2首页截图

    前端代码开源就好,https://github.com/Dianjoy/gamepop,要跑起来需要修改config.js,把if (debug) {}的内容删掉。

    (更多…)

  • 文章预告:移动 Web 开发四大坑

    虽然明知道没什么人看,不过也先放个预告吧,其实是怕自己到时候忘记了。

    《移动开发四大坑》,分享这次移动泡泡开发过程中踩到的坑和解决方案:

    1. 缺少标准 flexbox,没法自动换行,导致列表排版出问题
    2. tapclick 之间的 300ms 引来的各种问题
    3. position:relative 也可能是罪魁祸首
    4. 很多 JS API 都不是默认开启的,得用原生实现
  • 的pathname在不同浏览器中表现不同

    <a href="download://gamename/游戏名称">Download</a>

    在桌面版Chrome 32里,这样的<a>,其pathname会被解析成“//gamename/游戏名称”。

    在Android 4.2的WebView里,会被解析成“/游戏名称”。

  • 破pure

    pure是我用过的最差的前端框架:1. 布局不兼容老版flex-box,大量Android手机用不了;2. 外层框架字间距缩小,还得单独恢复;3. .pure-button里一堆莫名其妙的属性,用Android手机自带的WebKit无法正常tap。小是小,没带来啥价值,毛病又多,所以我一直不喜欢雅虎系的东西。

  • boostrap3的不良部分

    Bootstrap 3的脑残部分略多啊……比如.hidden-xs,明显应该是在超小设备上隐藏,结果里面赫然写着:display: block !important,important个毛啊……

  • [教程]纯CSS实现多选组件

    [教程]纯CSS实现多选组件

    产品篇

    在我们的后台中,需要设置广告精准投放的区域,也就是要在全国31个省、自治区、直辖市中选择。那么,出现下面这幅景象也就理所应当了:
    1

    这样做有几个问题:

    1. 选项很多,没有规律,找起来很累
    2. 如果是一个已经选择了部分选项的广告,修改时仍然需要用肉眼寻找,无法一眼看出来投放到哪些省份
    3. 选完一个,再选下一个,还要从头找,甚至会被已经选过的影响

    于是我想,首先应该把所有选项分为“已选中”和“未选中”两批,解决第2个问题,减轻第3个问题;其次复选框本身的价值不大,可以被替换为其它样式;唯一可能引入的问题,就是点选时,用户的预期是看到复选框里出现一个小对勾,表示选中,如果我把它移开放到“已选中”组里,用户可能会迷惑,需要一些时间学习。

    于是我跟某产品经理朋友聊了聊这个想法,他表示确实可能造成用户迷惑,不过如果能加入动画效果,那么基本没问题。嗯,开始动手。

    技术实现篇

    近日flexbox规范定案,浏览器相继支持display:flex;,同时传来一条好消息,新实现比老实现display:box;快很多。这次我打算用flexbox来解决问题,因为里面有一个很重要的属性:order(之前叫box-ordinal-group),它可以改变布局中元素的排列顺序,配合CSS3新增的选择器,应该可以满足需要。

    第一步 分拆选中/未选中

    (关于flexbox的知识,可以通过Google了解,虽然搜到的多是上一个版本,不过和最终版差别不大,只是叫法不同。本文不再过多讲解,我就当大家都会了)

    <input type="checkbox">本身的样式不能修改,所以我们必须借助<label>的帮助;实现选中/未选中区分,那自然就要用到伪类:checked;选择器一定是从外到内、从前到后的,没法选择父级元素,所以不能用<label>去包<input>,那么最终布局就只能是:

    <div>
        <input type="checkbox" name="q[]" id="q1" />
        <label for="q1">小宝3225</label>
        <input type="checkbox" name="q[]" id="q2" />
        <label for="q2">王老白白白</label>
        <input type="checkbox" name="q[]" id="q3" />
        <label for="q3">空夫31</label>
        <input type="checkbox" name="q[]" id="q4" />
        <label for="q4">谷大白话</label>
        <input type="checkbox" name="q[]" id="q5" />
        <label for="q5">Meathill</label>
        <input type="checkbox" name="q[]" id="q6" />
        <label for="q6">一毛不拔大师</label>
    </div>

    很简单哈,不解释了。CSS3新增了“下一节点”选择器 +,用来选择某节点的下一个节点,结合:checked伪类就可以将选中的<input>和它临近的<label>通过改变order属性移到前面去:

    #container {
      display:flex;
      flex-direction:row;
      flex-wrap:wrap;
    }
    #container input,
    #container label {
      order: 2; //所有选项、label顺序为2
    }
    input[type=checkbox]:checked,
    input[type=checkbox]:checked + label {
      order: 0; // 越小越靠前
    }

    不过这样只是把选中的内容提前,视觉上没有真正的分割。所以我决定再加入一根分割线,上面是选中的,下面是未选的。这个时候我们需要用到 ~ 这个选择器,选择某节点后面的节点:

    hr {
      display:none; // 默认情况下,没选任何选项,分割线隐藏
      order: 1; // 分割线顺序为1
      width:100%; // 保证独霸一行
    }
    input[type=checkbox]:checked ~ hr {
      display:block; // 有选项被选中后才会显示分割线
    }

    Demo如下:

    这样基础功能实现了。不过视觉上,排版仍然不整齐,选中的选项和未选中的选项区分不算太明显,所以下一步我准备美化下checkbox。

    第二步,美化checkbox

    做法与前面类似,也要用到CSS3新增的选择器。前面为了实现<label>提前,没有用它包裹<input>,所以在选项很多很长导致换行的时候,可能出现复选框和标签脱离的尴尬状况。好在复选框的价值可以用别的样式取代,所以先把小方框隐藏起来,转而将<label>作为操作目标,再来点边框底色圆角(参考自Bootstrap 3),就可以了:

    input[type=checkbox] {
      display: none;
    }
    label {
      min-width: 120px;
      border: 1px solid #CCC;
      padding: 2px 8px;
      text-align: center;
      margin: 0 5px 5px 0;
      background: #FFF;
      color: #333;
      border-radius: 3px;
      box-sizing: border-box;
    }
    label:hover {
      border-color: #ADADAD;
      background: #EBEBEB;
      cursor: pointer;
    }
    input[type=checkbox]:checked + label {
      order: 0;
      background-color: #5cb85c;
      border-color: #4cae4c;
      color: #FFF;
    }
    input[type=checkbox]:checked + label:hover {
      background-color: #47a447;
      border-color: #398439;
    }

    这样看起来还有上升空间,如果加上几个图标响应用户操作,那么学习成本会更低,对操作后的预期也会更准确。于是引用CDN上的font-awesome,使用:before伪类加上小图标,就得到了最终效果:

    我无意中发现,这样批量添加删除时,鼠标可以常点不动,应该也是个意外的收获吧。

    第三步,加入动画教育用户(失败)

    至此功能基本做好了,不过由于修改了行为,可能导致用户迷惑,所以准备加个动画帮助用户理解这个交互。

    可惜作为一个新功能,浏览器的支持尚不完善,虽然规范中规定“animatable: yes”,但是实测在Chrome v.30也无法工作:http://jsfiddle.net/meathill/Ka66W/1/

    看来只有等新版浏览器发布后再去完善了。

    兼容性

    使用纯CSS做组件,几乎不用担心兼容性问题,因为浏览器本身就做了很好的向下兼容,代码最多不生效,一般不会错。

    具体到这个组件,因为只针对视觉效果,没有增删改任何浏览器行为,所以兼容性也没有任何问题。不过最终效果呢,只有支持flexbox和CSS3选择符的浏览器才能正常渲染。

    我的环境是Window 8 + Chrome v.30,以及小米2 + Chrome v.30,测试通过。

    后记

    如今CSS很强,纯CSS可以实现很多功能,希望今后能做出更多有价值的东西。分享这个组件的实现,希望对大家有用。

  • 推荐好用的JS CDN

    上周GFW又抽风,导致取自CDN的jQuery和Bootstrap经常404,后台各种罢工。

    开始想说干脆放弃CDN得了,结果自家服务器也不是很给力……本地路径的静态文件也经常加载失败,挠了半天头,再去找找国内的CDN吧。

    后来想起来前几天看到七牛搞了个免费的开源仓库CDN,通过Google找到,叫http://www.staticfile.org/。打开一看,首页只列出不多的几个库,版本也不是最新的。我以为又是个没人维护的烂尾工程,读了介绍才知道他们倡导大家都来提交库信息,共同建立全面的CDN资源。我本想把这次要到的库和可以更新的库提交上去,后来发现原来他们已经引入了cdnjs.com里所有的库,只不过没有写在首页……果然大家都喜欢写代码不喜欢写文档啊,差点就错过了。

    BTW,cdnjs.com居然还提供了animate.css,真好。

    好在他们做了命令行工具,可以装上查引用地址。比如我想知道能不能用underscore,就可以这样:

    // 安装
    npm install -g sfile
    
    // 查找underscore
    sfile search underscore
    
    // 得到链接,这里要用全名
    sfile get underscore.js

    最后看https://github.com/staticfile/static/issues里的内容才知道,他们会把国外成熟的库直接从cdnjs复制过来,提交新库应以国内的为主。嗯,将来把Nervenet弄完也提交进去。

    重复一下网站地址:http://www.staticfile.org/。最后感谢下这些好人,以及服务提供商七牛云存储