标签归档:web develop

knockout在不同ViewModel之间的通讯

构建复杂应用,view-model之间的通讯是非常重要的一个环节,此过程的方便与否,组件之间的严格隔离与否,直接影响健壮性和开发禅道心情。

本文会:

  1. 介绍knockout.js自带的事件收发;
  2. 一个简单扩展实现 ViewModel之间 数据同步(或者叫数据捆绑);

 一:Knockout的事件收发

抽象的理解:建立一个公开的无线电塔,任何viewmodel可以在某个频道广播信息,其他正在收听的viewmodel,只要频道对的上,那么就能收听到对应信息

var radioTower = new ko.subscribable(); //创建一个无线电塔

收听者用法:

 //三个参数依次为收到的信息callback、目标viewModel(可选)、频道名称(可选)
radioTower.subscribe(callback, target, channel);
//收听者的俩个例子
radioTower.subscribe(function(newValue) { this.latestTopic(newValue);}, vm, "mytopic");
radioTower.subscribe(function(newData) {
    console.log("收到新数据:",newData);
}, null, "changeLength");

发送者的用法:

//两个参数依次为想发送的数据、频道名称
radioTower.notifySubscribers(data, channel);
//真实的例子
//接收者
radioTower.subscribe(function(newValue) {
    this.latestTopic(newValue);
}, vm, "mytopic");
//发送者
radioTower.notifySubscribers("MayDay MayDay!", "changeLength");

二:一个小扩展来更方便的实现数据同步

扩展代码:

;(function(ko){
    var radioTower = new ko.subscribable();

    ko.subscribable.fn.pub = function(topic) {
        this.subscribe(function(newValue) {
            radioTower.notifySubscribers(newValue, topic);
        });
        return this; //support chaining
    };
    ko.subscribable.fn.sub = function(topic,call,vm) {
        var target = vm || null;
        var cb = call || this; //如果没有call,那么直接捆绑原始数据
        radioTower.subscribe(cb, target, topic);

        return this;  //support chaining
    };
})(ko);

用法:

viewModel-A中:
//监听数组,当数组变化时在“ulist”频道里发送list这个数据
this.list = ko.observableArray([]).pub("ulist");
viewModel-B中:
this.list2 = ko.observableArray([]);
this.list2.sub("ulist"); //收听"ulist",当viewModel-A中的list改变时,它也会跟着变

//如果不想直接绑定,比如这里实现viewModel-A中的ulist的长度 和 viewModel-B中的length同步:
self.length = ko.observable(0);
self.length.sub("ulist",function(val){
    self.length(val.length);
});//第二个可选参数为回调

源代码例子

WebStorm里配置Browserify自动编译

Browserify Logo
Browserify

Browserify是个好东西,相比requireJS seaJS 他配合Script的async属性去实现“模块化、异步、非阻塞”可以说是“Drop Dead Simple”,简单高效又直接。自从他添加了sourcemap功能后,chrome里调试起来简直如鱼得水,越发喜欢了。

但是它本身是一个Compiler,不是一个JS框架。每次修改模块都需要重新执行一次browserify命令,相当麻烦。

我这里来介绍下WebStorm里的配置,以让Browserify自动化。
继续阅读WebStorm里配置Browserify自动编译

就是现在,用Promise取代callback吧!

Callback-Hell
什么是callback hell?
答:(如上图)过多的,过深的callbacks导致代码丑陋,难以阅读和维护。

window.Promise兼容不好吧?
答:这篇文章就是教你如何想Promise就Promise想callback就callback,还有去兼容浏览器的Promise的polyfill

ES6里的Promise让JS变得更加优雅。那么现在我们怎么把原有的代码转变成Promise Style呢?

原有代码(Callback Style):

    var waitCon = function(time,callback){
        //这里可以做很多工作的代码,先用延迟来代替
        var result=1+1;
        setTimeout(function(){
            if(callback){
                callback(result);
            }
        },time);
    };

原有代码(Callback Style)-调用方法:

    waitCon(2000,function(res){
        console.log(res); //两秒后得出2这个结果
    });

改写成Promise Style:

    var waitCon = function(time){
        return new Promise(function(resolve,reject){
            var result=1+1;
            setTimeout(function(){
                resolve(result);
                //成功完成,传出结果。如果用reject则是完成失败,传出错误内容
            },time);
        });
    };

Promise Style的调用方法:

    waitCon(2000).then(function(result){
       //原本callback里的内容
       console.log(result);
    });//可读性很高:先执行XXX,然后XXX

还可以Promise链、多重Promise具体查看 http://www.html5rocks.com/zh/tutorials/es6/promises/
这里只谈最简单的异步callback升级换代。

这里送出一个callback+Promise的整合版,想用什么用什么,妈妈再也不用担心其他小朋友不会用婆迷丝了。

    var waitCon=function(time,callback){
        return new Promise(function(resolve,reject){
            var result=1+1;
            setTimeout(function(){
                if(typeof callback === "function"){callback(result);}//执行callback
                resolve(result);//成功完成,传出结果
            },time);
        });
    };

My Angular Mobile App Boilerplate: AngularNavPlusHammer

我建立的这个GitHub项目为一个整合包,意在快速带你进入Angular Mobile App的生产开发中

    功能:

  1. 暂且采用BootStrap3.0 UI(其实这个项目核心和UI无关);
  2. 可追溯的后退按钮;
  3. 支持20种触摸手势,并可以以“ng-click”类似的HTML directive进行使用;
  4. 在route里、在控制器里均可自由控制页面过度动画(Page Transition Effects)

    这个项目由三大件组合而成:

  1. https://github.com/regou/angular-mobile-nav (由ajoslin版Fork出来,修改了几个我无法忍受的bug)
  2. https://github.com/randallb/angular-hammer (各种触摸手势都靠他了)
  3. 我的一些御用Module

Demo:

http://tools.regou.me/angular-nav-plus-hammer/

项目地址:

https://github.com/regou/angular-nav-plus-hammer

AngularJS+ JqueryMobile+ PhoneGap 打造APP

转载必须附带本文地址http://blog.regou.me/?p=790,谢谢

最近在做一个项目,一个B2B的移动APP。
我是这样选择的
前端UI框架:jQueryMobile
前端MVC和页面导航:AngularJS
封包器:PhoneGap Build
AngularJS和jQueryMobile的桥接器:jQueryMobile-Angular-Adapter(以下简称Adapter)
AngularJS JqueryMobile PhoneGap worktogether

两个著名框架融合在一起,还要让他们被封包了后还要运行OK可不容易,期间遇到了各种各样的问题,国内文档较少,于是Github、GoogleGroup、StakOverflow这些网站四处奔波提问+查资料
下面说下我遇到的问题和解决方法 继续阅读AngularJS+ JqueryMobile+ PhoneGap 打造APP

AngularJS兼容IE的处理(官方文档不全面)

AngularJS
最近在学些AngularJS,感觉挺强大的。
但是如果想投入到生产环境中,还需要考虑到IE6,7的兼容问题。

官方文档提到如何兼容IE了,但是即使全部按照文档里说的做,其实还是不能做到在IE6,7下运行。

经过各种实践,在这里给出一个补充:
需要在html标签上添加id=”ng-app”和class=”ng-app:APPNAME”,于是一个标准的ng-app的标签应该是:(app名为myapp为例)

##注意下面的“HTMLTAG”必须是合法的html标签,永远不要使用自定义标签(ng-view改成<div ng-view>),否则依然不兼容IE
<html xmlns:ng="http://angularjs.org">
......
<HTMLTAG ng-app="myapp" class="ng-app:myapp" id="ng-app">
   ....
</HTMLTAG>
.....
</html>

这样就行了,以上是唯一的和官网说明不同的地方.

另附官网文档所说的让IE兼容JSON2和HTML5标签的JS在这,直接引用进head标签里就行了里就行了(这两个JS也是必要的)

<script src="http://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.6.2pre/html5shiv.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/json2/20121008/json2.js"></script>

随便做了一个demo,兼容IE67:
http://tools.regou.me/angularJS.html

2013.6.22更新
目前我在正式的生产环境中,用AngularJS+jQueryMobile+PhoneGap在做一个B2B商城APP
分享了点AngularJS用户手机APP开发的心得:
blog.regou.me/?p=790

2013.12.16更新
我看了下,官方文档已经做好了补充,现在可以完全以官网文档为准了。
AngularJS 1.3.0开始,将不再支持IE8和IE8以下的浏览器,所以,别再挣扎了

JS/PHP添加Do Not Track(DNT),保护访客隐私

大多数的网络浏览器的设置中有一个“Do Not Track”(DNT 即“不追踪”)设定,让用户能够控制自己的隐私信息被追踪的情况。
但是网站到底是否真的不追踪,还要看网站本身是否响应它
那么,做一个善良的网站,如果用户设置了Do Not Track,那么就保护一下他的隐私吧!

下面这个为JavaScript的代码,如果 navigator.doNotTrack 等于1,那么用户就开启了DNT,不要去运行那些搜集用户信息的脚本了!

if(!navigator.doNotTrack){
  //这里面写搜集信息的脚本,如果开启DNT则不执行
}

这个为PHP的,通过判断HTTP Header “HTTP_DNT”的值是否为”1″来判定是否开启了DNT:

function get_dnt() {
  // returns TRUE if DNT is on and is equal to 1
  return (isset($_SERVER['HTTP_DNT']) && $_SERVER['HTTP_DNT'] == 1);
  $DoNotTrackHeader = "DNT";
  $DoNotTrackValue = "1";

  $phpHeader = "HTTP_" . strtoupper(str_replace("-", "_", $DoNotTrackHeader));
  return (array_key_exists($phpHeader, $_SERVER)) and ($_SERVER[$phpHeader] == $DoNotTrackValue)
}

同理,nodejs的:

var dnt=function(){
  return (headers['HTTP_DNT']==1)
}

HTML5视频的多平台兼容方案 JW Player

JW Player通过配置可以在不支持HTML5浏览器的情况下,自动的将HTML5视频转化为Flash视频
同时也支持m3m8、flv等流媒体播放。具体参见 http://www.longtailvideo.com/players/

DEMO预览点这里

配置起来很简单,先在引JS

<script src='jwplayer.js'></script>

再在想放视频的地方放下如下代码就行了,上面面那个demo是我希望优先用html5播放,再其次用Flash播放

<video id='mediaplayer' ></video>
<script type="text/javascript">
    jwplayer('mediaplayer').setup({
        'id': 'playerID',
        'width':1280,
        'height':720,
        levels: [
            {file: 'Using2-stepverification.mp4',type: 'video/mp4' },//mp4文件提供给Flash
            {file: 'Using2-stepverification.webm', type: 'video/webm' },//webm文件提供给HTML5
        ],
        'modes': [
            {type: 'html5'},//优先级1,以下类推
            {type: 'flash', src: 'player.swf'},
            {type: 'download'}
        ]
    });
</script>