JM Javascript Mobile Framework

新一代轻量级高性能移动web框架,由腾讯前端团队AlloyTeam经项目实践积累沉淀而成。为拥抱移动互联网全新设计,专注为移动web项目,整个框架压缩后只有36K

新的移动平台,给web带来更多的机会,同时也带来更多的挑战。原PC端的各种浏览器兼容,已经升级为多平台多终端多版本多浏览器的复杂问题。为了解决这个问题,各种移动框架应运而生,但是为了解决问题而使整个库的体积庞大,最终在兼容和性能的权衡上没有取得平衡。JM在设计上更看重性能,所以代码量上力求精简,同时能够处理大部分的移动web兼容问题。或许你发现JM并没有过多地为帮你做什么事情,但我们却为你避开了很多移动上的坑。

特性

  • 体积小
  • 源用JX的编码方式
  • 模块按需加载,可定制
  • 可与JMUI结合使用,提供一整套移动方案

第一个用JM写的程序

下面我们尝试使用JM来写一个HelloWorld程序,通过这个小Demo,你可以对JM有个概括的了解。

点击我查看Demo

主要html

<button id="myButton" class="btn btn-primary btn-block" >
    <span class="btn_text">Hello World</span>
</button>

<div class="word">
    <div id="word1">Hello World !</div>
    <h2 id="word2" >by Tencent AlloyTeam</h2>
</div>

主要js

var $E = JM.event;
var $D = JM.dom;

var btn = $D.id('myButton');
var word1 = $D.id('word1');
var word2 = $D.id('word2');

$E.on(btn,'click',function(){
    //设置动画基本参数,并且每个动画间隔为1.5秒
    J.Animation({
        selector:'#word1',
        duration:1500,
        use3d:true
    }).setStyle({       //向右运动了40%,并且color变成蓝色
        'top':'60px',
        'opacity':'1'
    }).transit(function(){
        this.setDuration(600);
        this.scale(2).setStyle({
            'top': '40px',
            'opacity':'0'
        }).transit(function(){
            word1.style.cssText = "";  //清空dom的style,让动画回归起初状态
        });
    });

    J.Animation({
        selector:'#word2',
        duration: 1500,
        use3d : true
    }).setStyle({
        'top':'140px',
        'opacity':'1'
    }).transit(function(){
        this.setDuration(800);
        this.scale(2).setStyle({
            'top': '150px',
            'opacity':'0'
        }).transit(function(){
            word2.style.cssText = "";
        });
    });
});

代码解析 示例程序的button样式额外地使用了JMUI的button样式,不使用也没有影响,样式可以你写你喜欢的。我们来看看js代码部分,$D$E是引用jm的模块名,这样再代码使用中更加简洁而已,你完全也可以var btn = JM.dom.id('#word1');。代码中展示了JM三个模块的使用:Dom节点选择器,事实处理机制,动画模块。

JM除了提供常规的选择器外JM.dom.$(selectorText),还提供专门的选择id选择器JM.dom.$(id),我们也建议尽量使用id选择器,因为在效率上id选择器是最快的。在事件处理上JM.event.on(obj, evtType, handler),obj为绑定的dom节点,evtType为事件类型,hadler的事件处理函数,obj和handler都可以输入数组,我们支持多对象多事件同时处理处理。还有些常规的off,one,fire等方法外,还对swip,hold,toch等移动专属事件方法,详细情况可以参考event模块

事件处理的代码里面是JM.Animation内容。有两个段动画代码,我们看第一段就可以了。传给Animation的是一些基本参数,其中use3d来开启这段动画是否使用GPU的3D动画加速(注意这不是银弹,不是所有动画都必须加上),setStyle方法顾名思义设置要修改的样式,transit方法就是把我们setStyle修改的样式使用css3的transiton的动画形式展示,transit方法只接受一个FinshFunc参数,动画执行后就会执行FinshFunc。通过在FinshFunc函数里在写动画函数,就形成动画回调了。在最后的transit方法回调中,我们把dom的style属性取消掉,这样进行动画就会回归源点。

Animation

动画模块,JM的动画实现全部由CSS3实现,有以下几个特征

依赖dom,event,type三个模块。

核心代码

runBtn.onclick = function(){
    $D.setStyle(runBtn,"display","none");
    rect.style.cssText = "";

    //设置动画基本参数,并且每个动画间隔为1秒
    J.Animation({
        selector:"#demo1_rect",  //要操作的dom的selector
        duration:1000,
        use3d:true
    }).setStyle({       //向右运动了60%,并且color变成蓝色
        "left":"60%",
        "background":"blue"
    }).transit(function(){
        this.scale(.5).setStyle({
            'background':"red"
        }).transit(function(){
            this.rotate(180).setStyle({
                opacity:0
            }).transit(function(){
                this.toOrigin().setStyle({
                    "opacity":1,
                    "background":"green"
                }).transit(function(){
                    $D.setStyle(runBtn,"display","block");
                });
            });
        });
    });
}

J.Animation是这个模块的命名模块,传入一个options的obj来设置动画的基本参数。然后在函数尾部使用setStyle进行回调,setStyle是用于设置动画改变的状态。再在函数尾部调用transit方法表示以CSS3的transition方式进行启动动画。我们依旧在transit里面传入匿名函数,表示一段动画结束后,进行回调函数callback,这样我们就不断进行链式调用和callback回调来完成一段动画。

Animation 传入参数说明

Animation 动画函数说明

大体上动画函数都很好理解,不做过多解析,我们使用链式js的方式来编辑CSS3动画,CSS3的动画参数都可以自个设置,并且动画结束后可自行销毁,不会冗余页面代码样式。

audio(按需加载)

在web上播放声音一直体验都不是很好,包括下载声源需要加载时间,而且各种的声音播放方式兼容性差等等。JM的额外模块audio是就是处理web上声音的模块。因为不是所有的web页面都需要声音,所以我们建议需要播放声音的时候才加载这个模块。在HTML5诞生到来,让web在多媒体领域上不区于flash,原生的控件,让我们的页面播放页面更加简单。但是并不是真正的简单,问题依旧是浏览器间的问题,或者是各种终端版本的问题,兼容性依旧是个核心问题。我们audio模块就是为了解决播放声音的兼容性及操作的一致性而生,让我们的声音在web上,在真正意义上的简单起来

依赖dom,event,browser三个模块。

base 核心模块

JM的一些核心方法,为所有模块所共用。例如JM的命名方式namespace,类封装Class,继承extend,操作Listfilter``map``some等一系列继承函数。

示例代码

JM.$package("MUI",function(J){
    // JM的命名空间
});

//JM的类继承方式
var AnimateTab = J.Class({extend:MUI.Tab},{
    init:function(options){
        //do something
    },
    _handleEvent:function(e){
        //do something
    },
    bindHandlers:function(){
        //do something
    }
});

base 公开对外基础函数

browser 浏览器检测模块

本可简单简单地划分到utils模块,但是在移动web上我们检测的不单单是浏览器及其版本后,后继拓展还有,终端平台及其版本,所以我们单独地划分出一个模块出来(其实最终还是会合到一个js里面)。

//对应的值是版本号,如果不是这个浏览器则版本号为0

if(J.browser.plugins.flash>=9){

}
if(J.browser.ie){

}
if(J.browser.chrome >= 30){

}
if(J.adobeAir){

}

非常简单的cookie种植和移除,直接粘贴源码吧

J.$package(function(J){
    var domainPrefix = window.location.host;
    var cookie = {
        set : function(name, value, domain, path, hour) {
            if (hour) {
                var today = new Date();
                var expire = new Date();
                expire.setTime(today.getTime() + 3600000 * hour);
            }
            window.document.cookie = name + "=" + value + "; " + (hour ? ("expires=" + expire.toGMTString() + "; ") : "") + (path ? ("path=" + path + "; ") : "path=/; ") + (domain ? ("domain=" + domain + ";") : ("domain=" + domainPrefix + ";"));
            return true;
        },
        get : function(name) {
            var r = new RegExp("(?:^|;+|\\s+)" + name + "=([^;]*)");
            var m = window.document.cookie.match(r);
            return (!m ? "" : m[1]);
        },
        remove : function(name, domain, path) {
            window.document.cookie = name + "=; expires=Mon, 26 Jul 1997 05:00:00 GMT; " + (path ? ("path=" + path + "; ") : "path=/; ") + (domain ? ("domain=" + domain + ";") : ("domain=" + domainPrefix + ";"));
        }
    };
    J.cookie = cookie;

});

dom

HTML的dom操作模块。包括选择器,选取样式,修改样式切换Class等方法。虽然跟著名的jquery对比会逊色一筹,但是基本的功能都能满足,最重要的是jquery有100多K,我们才30多K,我们把最实际常用的Dom操作抽离处理,减少库的代码量,在移动Web上带来更少的流量。

示例代码

var $D = J.dom;
var runBtn = $D.id('runBtn'),
    runObj = $D.$('#demo_block .rect'),
    stopBtn = $D.className('demaxiya');

runBtn.onclick = function(){
    $D.toggleClass(runBtn,'active');
}

if($D.getStyle(runBtn,'background') == '#000'){
    $D.remove(stopBtn);
}

除了比较常用的J.dom.$()的选择器方式,我们还提供了J.dom.id()J.dom.tagName()等的选择器方式,我们建议,可以的话尽量是用id选择器,因为这是效率最高的。我们没有像Jquery那样吧选择到的Dom元素包装成一个Jquery对象,我们选择到的是原生的Dom元素,方式也是传入Dom和参数。It's simple,but it do well。

dom 函数列表

event

除了平常的支持IE等浏览器兼容外,最重要的是支持移动端的touch,swip等手势事件及transform等移动专有事件.PC端和移动端最大一个不同除了屏幕分辨率外,还有一个非常重要的就是事件不同。我们不但支持了这些事件,还自定义了手势事和提供了很多辅助方法,帮助开发者的实际开发应用,例如:getTouchPos``getDist等。在移动web上坑最多的就是event处理的这一块,至少JM会让你少走很多弯路。

示例代码

var $E = J.event;
//动画事件结束后
$E.on(this.contentWrap,"webkitTransitionEnd",function(e){
    // 自身销毁changed事件
    $E.fire(self ,"changed" ,{
        type:"changed",
        currentIndex:self.currentIndex
    });
});

var startEvt = isTouchDevice ? "touchstart" : "mousedown";
var moveEvt = isTouchDevice ? "touchmove" : "mousemove";
var endEvt = isTouchDevice ? "touchend" : "mouseup";

//touch事件的绑定
$E.on(document.body ,moveEvt ,_handleEvent);
$E.on(document.body ,endEvt ,_handleEvent);

注意,这里关于touch或swip事件的例子可以查看JMUI的控件,这样会更加清楚.

event 方法事件列表

event 自定义事件

format

不多说,直接上源码

var date = function(date, formatString){
    /*
     * eg:formatString="YYYY-MM-DD hh:mm:ss";
     */
    var o = {
        "M+" : date.getMonth()+1,    //month
        "D+" : date.getDate(),    //day
        "h+" : date.getHours(),    //hour
        "m+" : date.getMinutes(),    //minute
        "s+" : date.getSeconds(),    //second
        "q+" : Math.floor((date.getMonth()+3)/3),    //quarter
        "S" : date.getMilliseconds()    //millisecond
    }

    if(/(Y+)/.test(formatString)){
        formatString = formatString.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length));
    }

    for(var k in o){
        if(new RegExp("("+ k +")").test(formatString)){
            formatString = formatString.replace(RegExp.$1, RegExp.$1.length==1 ? o[k] : ("00"+ o[k]).substr((""+ o[k]).length));
        }
    }
    return formatString;
};

http

http处理模块,一些处理urlparam方法和ajax方法。

示例代码

J.http.ajax({
    url: 'http:www.xxx.com/getSomething'
    method : 'post',
    timeout : 50000,
    withCredentials : true, //是否跨域
    async : true, //是否异步

    onError : function(data){
        alert(' ajax error : ' + data.msg);
    },

    onSuccess : function(data){
        //do something ...
    },
    onTimeout : function(data){
        //do something ...
    }

});

http 方法列表

platform 平台检查模块

平台检查模块跟browser模块一样,是检测模块,后继优化会把两者这合并。为兼容多终端多版本,平台检查是少不了。

示例代码

if(J.platform.android && J.platform.ieVersion > 4){
    //....
}
if(platform.android){

}
//其他平台检查
//platform.android
//platform.iPhone
//platform.iPad
//platform.iPod
//platform.winPhone 
//platform.IOS
//.touchDevice

prefix 前缀辅助模块

提供了集中使用prefixe的场景,dom节点,css,js等。

J.prefix.dom == 'WebKit'
J.prefix.lowercase == 'moz'
J.prefix.css == '-ms'
J.prefix.js == 'webkit'

string

提供tmpl 轻量的模板函数。encodeHTMLdecodeHTML常用字符编码解析函数和一些URL操作的辅助函数。

support 特性检测模块

目前特效检测内容只用audio,fixed,flash和transition。

J.support = {
    audio : {
        m4a : 'maybe',
        mp3 : 'maybe',
        ogg : 'probably',
        wav : 'probably'
    }
    fixed : true,
    flash : ture,
    transitionend : 'transititonend'
}

type 类型检查辅助模块

util 辅助模块

提供常用的辅助函数,还有提供一些移动上特色需要的辅助函数,例如hideUrlBar隐藏url栏,preventScrolling禁止滚动等。