日志

  • 直播写代码

    晚上直播写代码啦!如果有人看的话,大概10点半到11点半。

    以 Web 相关技术为主,写的多半是各种 side project。

    地址:http://www.douyutv.com/meathill

    欢迎光临,可以点播。

  • Surface Pro 移动办公

    Surface Pro 移动办公

    图文终于相关一回

    晒出住院照之后,各路亲朋好友基本都送来早日康复的祝福,这里一并感谢。不过有几位似乎很关注 Surface 的使用情况。经过这几天密集使用,尤其是在医院病房这种本身不是为办公设计的环境中使用(之前即使用多半也是在办公室里),我自觉积累了一些经验,在此分享给大家。

    整体环境

    整体环境请看照片。基本上,就是一张床,一个床头柜,一把椅子。床头柜有可以拉出来的小餐桌,旁边有足够多的插座。Surface 可以放在床头柜上,高低比较合适;小餐桌拉出来放键盘轨迹球;手机可以卡在键盘后面。病房里空间还算富裕,所以我可以放心霸占自己这条过道。

    底座

    我觉得底座还是很有必要的。首先 Surface 为了放便携带重量较轻,很容易移动,或者说,被线扯动。有了底座之后,稳定很多。其次,像我随身携带好多设备,充电也是个大问题,底座自带5个USB,基本可以不需要别的插头了。

    而且我还要使用键盘鼠标,Surface 本身只有一个USB,即使扩展也很难满足。想象一下,没有底座的 Surface,为了连上这些设备,拖一个巨大的 USB Hub,还能稳定使用么?

    有了底座,还可以更好的规制其它线缆,比如耳机。

    键盘鼠标

    键盘盖是个好东西,不过可能只在咖啡厅好用,这个时候我还是喜欢分离的键鼠。首先,机械键盘的手感自不消说。其次,带着键盘盖实际上对平面的要求更高,反而不如分解后适应性强。这点普通笔记本也一样。最后,键盘盖上的触摸板使用面积太小,实在不方便。

    最后说到应用优化。由于大部分 Windows 设备都是标准分辨率,跟苹果刚好相反,所以绝大多数 Windows 应用都没有针对高分屏做过优化,导致的结果就是可视面积可操作面积很小,虽然Surface是触屏,但真正能用指头点的机会并不多——Windows平板应用也太少太差。笔就更不用提了,手臂悬空点来点去想想就累。所以鼠标仍然是最重要的操作媒介。而狭小空间里,轨迹球就是最佳选择,操作精准,反应迅速。

    应用

    应用软件仍然是 Windows 系统下最大的优势,虽然 iOS 和 Android 也有一些类似产品,但使用体验实在不可同日而语,比如完全不支持快捷键,输入定位很糟糕,大量功能缺失等等。这也没办法,面对纯触摸设备设计的产品,它们的交互要求必然是简单直接,传统桌面软件借助键盘鼠标实现精准操作的体验很难达到。

    新的交互方式出现之前,平板类产品只能作为消费产品,很难成为生产工具。

    总结

    Surface 是个很棒的产品,便携性一流,配置完善,散热也很好。Windows 10也不错,新版界面和触摸屏相得映彰。只是其它应用要么未经优化,要么压根就没有,整体使用体验并不好,无法离开键盘鼠标,自然对环境的要求也比较高。不过软件本身的性能效果都很棒,远非平板类能及。

  • “作作作,作ju作够你就知道了”

    语出我妈。

    小时候我经常被我妈用这句教训。长大了之后教训少了,于是便作了起来。来到广州之后,一来天热,二来也没人管束,一时间忘乎所以,把饮料当水喝,终于喝出糖尿病。

    于是这辈子第一次住院,而且一住就是半个月。感谢我司领导允许我在医院半工半休,感谢家人的支持。

    奉劝各位不要不信邪,大家都是普通人,有问题赶紧看,平时要自律。

    我好饿。

    PS:好的方面是许了3年的105KG即将达成……

  • PHP匿名函数使用父作用域的变量

    PHP匿名函数使用父作用域的变量

    (自古图文不相关)

    同事问为什么要用 array_maparray_filter之类的函数,用 foreach 不就好了?

    答:这样写出来的代码语义更清晰,阅读更容易。

    那么如何使用其它变量呢?global 么?

    答:global 肯定不合适,不过怎么写我也不知道。待我查查。

    在PHP中,不能像JS那样直接使用闭包里的其它变量,必须通过声明继承的语法,写出来是这样的:

        <?php
    
        $arr = [1, 2, 3];
        $split = 2; // 分界
        $arr = array_map(function ($value) use ($split) {
          return $value < $split ? 0 : $value;
        }, $arr);
        var_dump($arr);
    
        // 输出
        // 0, 2, 3
    

    重点是那个 use ($split)


    参考:

  • npm start, npm stop

    npm start, npm stop

    使用 npm 可以直接调用 package.json 里面 scripts 标签里定义的脚本。比如,Astinus 项目中,index.js 是入口JS,并且需要 ES6 支持,就可以这样:

        // package.json
        {
          "scripts": {
            “start": "node index --harmony"
          }
        }
    

    然后直接运行

        npm start
    

    即可。

    那么怎么终止进程呢?

    首先要在 index.js 里增加一句

        process.title = 'astinus';
    

    声明该应用的标题是“astinus”,然后增加脚本:

        {
          "scripts": {
            "start": "node index --harmony",
            "stop": "killall SIGINT astinus"
          }
        }
    

    之后就可以

        npm stop
    

    参考:

  • Compass + cleancss 导致的灵异小问题

    Compass + cleancss 导致的灵异小问题

    问题不大,不过很诡异。代码如下:

    SASS:

    .some-class
      display: none
    
    .other-class:blank
      display: none
    

    HTML:

    <div class="some-class">...</div>
    

    理论上说,这样这个div应该不显示。在本项目中,它的确没显示;但是在另外一个将本项目作为依赖的项目中,它却显示出来了。

    经检查,本地开发和部署时,直接使用 compass compile 生成CSS,compass 配置中,设置输出模式(output_style)为 compressed,结果是这样的:

    .some-class{display:none}.other-class:blank{display:none}
    

    而在作为依赖时,用到的则是 grunt-contrib-cssmin 处理过的CSS,刚才那句就被压缩成

    .some-class,.other-class:blank{display:none}
    

    :blank伪类尚未被Chrome中支持,于是整条规则都被忽略,导致div显示出来。

  • 啊,前端的轮子啊

    啊,前端的轮子啊

    时势造英雄。

    IT科技几十年来诞生过不少概念,但直接拿来就能作为宣传材料的不多,HTML5算一个。借助智能手机、微信微博快速普及带来的平台优势,HTML5快速成长,接连攻陷投资界、创业界、广告界,现在说起H5,在我的圈子里几乎无人不知无人不晓。

    资金充裕,整个行业自然地位上升,财务上升;继而自然从业者增加;继而就会出产大量的产品。而作为前端从业人员,最大的感觉就是:轮子真TM多啊……这不,我前几天计划学习一下近来出现的各种新技术,今天正好看到Bable最新入门The Complete Guide to ES6 with Babel 6,正好我写xgame-api的时候饱受node不能完全支持ES6之苦,马上坐正准备好好看。

    然后就看到:

    Keeping up to date

    Here’s a little story: while writing these guides, I learned that the require hook in babel-core used by Gulp and Mocha is already set to be deprecated.

    跟上变化

    讲个段子:就在我写这套入门的时候,babel-core里的require钩子,就是Gulp和Mocha使用的那个,被标记为“弃用”

    Babel6是24天之前发布的,这套文章是上周写的,核心API已经发生变化了。这让我不禁去想,紧跟业界潮流的成本会不会太高了?ES6的确提供了不少语法糖,以及终于像样的模块管理。如果现在就开始使用ES6,不仅可以提前享受到这一切,到标准真正到来的时候,可以省去升级的时间。

    不过这里面之考虑了标准变化,没有考虑需求变化和产品变化。如果是抽象性很强的代码,比如某种算法库,或者某个功能组件,那么从开发之日起,遇到的变化可能不会太多太大。但如果是业务代码,就不得不遭遇各种各样的修改和变化,于是功能稳定便于维护就更加重要。紧跟潮流,意味着必须付出多余的精力去应对各种不稳定导致的节外生枝,一不小心,业务逻辑就要延期交付鸟。

    又有个切身例子。Tiger Prawn(后面简称TP)立项的时候,模块管理无论是AMD还是CMD还是sea.js都难以让人满意,所以我就用了最简单的直接引用和命名空间。前几日用Browserify感觉不错,赶上TP遇到个问题,就寻思着重构下。结果努力一天之后,架构变化还是太复杂,遂放弃。次日修正实际问题只花了半天。生产中,还是优秀的架构设计更重要,毕竟开发和维护效率至上;追新追潮流几乎都可以算是作死的行为。

    那么什么时候学习新技术呢?程序员都应该做业余项目,不是私活,而是根据一些平日里瞎想出来的需求,用一些新技术去实现,即使实现不了,也能够实地演练各种新技术。这样,有朝一日新技术成熟了,就可以很快应用到新产品中。

  • 给WebStorm添加FileWatcher支持Browserify

    给WebStorm添加FileWatcher支持Browserify

    按惯例先介绍本文角色:

    Browserify 是一款让我们在浏览器端使用require('modules')来管理模块的工具。它会分析代码中的依赖关系,然后进行编译,打包成一个文件,我们只需要在HTML中引用生成的文件即可。

    WebStorm 则是JetBrains出品的开发利器,集成了各种开发工具和环境,价格不贵,速度很快,样式好看,我非常喜欢。

    Browserify 也提供了个工具,叫 watchify ,可以监控文件变化,即时编译。不过我更喜欢让WebStorm帮我处理这些事情,所以小小研究了一下,配置成功。

    具体步骤

    1. 通过 NPM 安装 Browserify
      npm install browserify -g
      
    2. [Preferences] -> [Tools] -> [File Watchers]

    3. 点击“+”按钮,没有内建方案,所以选择“<custom>”

      WebStorm Preferences

    4. 名字(Name)随便写,描述(Description)可以留空,重点是下面几项

    5. FileType 选择 JavaScript

    6. Scope 监控范围,内建的都不合适,所以点“…”按钮,弹出自定义的监控范围

    7. 新建一个域,名字和项目一样,好认。展开项目目录,选择存放JS文件的目录,点右侧的“Include”和“Include Recursively”将该目录下所有文件和文件夹都包含进来。OK保存。

      WebStorm Scope

    8. Program 是要执行的程序,这里自然是 Browserify,Mac下通常在/usr/local/bin/browserify

    9. Arguments 参数,参考 Browserify 的文档介绍,常规命令是

      browserify index.js -o bundle.js --debug
      

      其中 index.js 是我的入口JS,那么直接去掉 browserify 就好了。

    10. Working Directory 工作目录,点击右侧的“Insert Macros”按钮,选择 “$ProjectFileDir$”。后面接上目录“/js/”。

    11. 完成!

      WebStorm Browserify File Watcher

    小优化

    1. 前面我们设置监控范围的时候比较粗放,这样生成 bundle.js 之后会再跑一遍,有点不爽,所以图中我把 bundle.js 过滤掉了

    2. 确保这个File Watcher正常工作后,可以去把 Show console 设置成Never,这样在编辑到一半的时候就不会有错误提示了。

  • bower小技巧一则

    bower小技巧一则

    早先看到过一个用socket服务在线调试PHP的工具,后来怎么也找不到,于是决定自己造轮子。socket.io提供WebSocket服务,nodejs(今天竟然发布了5.0stable,简直丧心病狂) + express.js做服务器端。以前没有正经用过express.js,不过感觉上把Web所需的内容和nodejs所需的内容混在一起应该不是什么最佳实践,还是分开比较好。

    使用express.static('public')可以把public目录映射为web根目录。但是用bower管理依赖的话,默认安装目录在项目的根目录,虽然也可以映射出去,不过实际路径和项目路径有异,Webstorm里的黄色波浪线看起来也很不舒服。

    Google一下果然bower可以解决这个问题。在项目根目录下创建.bowerrc文件,按照JSON的写法,写入:

        {
          "directory": "public/components"
        }
    

    就可以指定别的目录作为安装依赖的位置。然后可以移动原来的依赖文件夹,也可以重新执行bower install

  • Chrome表单验证和keyup导致的灵异问题

    Chrome表单验证和keyup导致的灵异问题

    先说下环境,Mac OS El Capitan + Chrome 46,框架是Backbone + Boostrap。

    我做了一个自动搜索组件,独立测试时一切正常,放到产品中,别的都没问题,只有回车会出问题。代码在这里

    不用说,这个问题很诡异,调试了半天没有头绪,只能通过观察现象去推测:

    1. 没有报错
    2. 除了回车,其它功能正常
    3. 除了回车,keyUpHandler都能被正确触发
    4. 回车后,光标跳到其它元素

    看来看去,第4条最可疑——我按的是回车,它会什么会跳到别的单元格呢?

    这次运气比较好,表单中的接下来的几个元素刚好是日期,用到Bootstrap Datetimepicker这个插件,focus之后会自动填充日期。于是我发现,每次跳到的“其它元素”,都是原先空白的,而且是required的;不会跳到固定的,或者紧挨着的那个文本框。

    于是我便想,会不会是:

    1. 表单submitkeydown之后触发
    2. 触发之后进行表单验证,发现有未填的required元素,于是跳到该元素并提示
    3. Bootstrap Datetimepicker响应focus时间,填入日期,提示消失
    4. 我的Typeahead响应blur事件,隐藏列表
    5. keyup事件触发,但是输入框已没有焦点,就没有触发

    这个推测看起来有点道理,于是我把侦听的事件改成keydown,问题果然解决。