Javascript Mobile Framework - 轻量级高性能移动web框架


MIT
Android
JavaScript

软件简介

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实现,有以下几个特征

  • 动画底层由CSS3实现

  • 动画参数采用链式调用动画,非传统的class操作css3动画。

  • 可自由开启GPU的3D动画加速

依赖 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 传入参数说明

  • selector 动画操作的dom的selector(id)

  • duration 一段动画执行时间

  • use3d 是否启用硬件加速

  • runType 动画类型(ease-in, ease-in-out)

  • delay 动画延迟时间

Animation 动画函数说明

  • scale:function(scale){}

  • scaleX:function(scaleX){}

  • scaleY:function(scaleY){}

  • rotate:function(rotate){}

  • rotateX:function(rotateX){}

  • rotateY:function(rotateY){}

  • rotateZ:function(rotateZ){}

  • translate:function(translateX,translateY,translateZ){}

  • translateX:function(translateX){}

  • translateY:function(translateY){}

  • skew:function(x,y){}

  • skewX:function(x){}

  • skewY:function(y){}

  • setStyle:function(styleName,styleValue){}

  • toOrigin:function(){} 动画参数清空

  • transit:function(onFinished){} 启动动画 onFinished为动画回调函数

大体上动画函数都很好理解,不做过多解析,我们使用链式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 公开对外基础函数

  • $namespace: function(name) {}为$package函数内部使用

  • $package:function(ns,func) {}命名空间

  • extend:function(destination,source) {} 继承

  • bind:function(func, context, var_args) {}

  • Class:function(){} 定义类函数

  • toArray: function(pseudoArrayObj){}

  • indexOf:function(arr,elem){}

  • every:function(arr,callback){}

  • some:function(arr,callback){}

  • each:function(arr,callback){}

  • map:function(arr,callback){}

  • filter:function(arr,callback){} 过滤List

  • isEmptyObject:function(obj){}

  • random : function(min, max){}

browser 浏览器检测模块

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

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

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

}
if(J.browser.ie){

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

}
if(J.adobeAir){

}

cookie

非常简单的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 函数列表

  • $:function(selector,context){} 会优先选用原生的

  • id:function(id){}

  • tagName:function(tagName,context){}

  • className:function(className,context){}

  • remove:function(node){}

  • setSelectorEngine:function(func){}

  • toDomStyle:function(cssStyle){}

  • toCssStyle:function(domStyle){}

  • setStyle:function(elem ,styleName,styleValue){}

  • getStyle: function(el, styleName){}

  • getVendorPropertyName : function(prop) {}

  • isSupprot3d : function(){}

  • filterSelector:function(arr,selector){}

  • addClass function(elem,className){}

  • removeClass function(elem,className){}

  • hasClass function(elem,className){}

  • toggleClass:function(ele,className){}

  • insertAfter: function(parentElement, newElement, refernceElement){} 类似源生方法 insertBefore

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 方法事件列表

  • isDomEvent function(obj,evtType){} 如果是DOM事件,返回正确的事件名;否则返回布尔值 false

  • bindDomEvent function(obj, evtType, handler){} 封装绑定DOM事件的方法,以兼容低版本IE

  • unbindDomEvent function(obj, evtType, handler){} 解除绑定DOM事件的方法

  • on:function(obj, evtType, handler){}

  • once:function(obj,evtType,handler){}

  • off:function(obj,evtType,handler){}

  • fire:function(obj,evtType){}

  • getActionTarget : function(event, level, property, parent){}

获取点击的事件源, 该事件源是有 cmd 属性的 默认从 event.target 往上找三层,找不到就返回null @param {Event}
event

@param {Int}level 指定寻找的层次

@param {String} property 查找具有特定属性的target,默认为cmd

@param {HTMLElement} parent 指定查找结束点, 默认为document.body

@return {HTMLElement} | null

  • bindCommands : function(targetElement, eventName, commends, commendName){}

@example

bindCommands(cmds);

bindCommands(el, cmds);

bindCommands(el, ‘click’, cmds);

  • getTouchPos = function(e){} 辅助函数

  • getDist = function(p1 , p2){} 计算两点之间距离

  • getAngle = function(p1 , p2){} 计算两点之间所成角度

event 自定义事件

  • _fire

  • _off

  • tap 按下松开之间的移动距离小于20,认为发生了tap

  • hold 按下松开之间的移动距离小于20,认为点击生效swipe按下之后移动30px之后就认为swipe开始,swipe最大经历时间500

  • transform

  • scrollstart

  • scrollend

  • scrolltobottom

  • ortchange 兼容性更好的orientationchange事件,这里使用resize实现。不覆盖原生orientation change 和 resize事件

format

不多说,直接上源码

var date = function(date, formatString){
    /*
     * eg:formatString="YYYY-MM-DD hh🇲🇲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 方法列表

  • serializeParam : function ( param ) {}

  • getUrlParam : function ( name ,href ,noDecode ) {}

  • ajax : function ( option ) {}

  • offlineSend:function(options) {}

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操作的辅助函数。

  • template function(str, data){}

  • encodeHtml function(sStr){}

  • isURL function(str) {}

  • parseURL function(str) {}

  • buildURL function(obj) {}

support 特性检测模块

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

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

type 类型检查辅助模块

  • isArray : function(o){}

  • isObject : function(o) {}

  • isBoolean : function(o) {}

  • isNumber : function(o) {}

  • isUndefined : function(o) {}

  • isNull : function(o) {}

  • isFunction : function(o) {}

  • isString : function(o) {}

util 辅助模块

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

  • hideUrlBar:function(){} 隐藏URL栏

  • preventScrolling : function() {} 禁止滚动

  • activeScrolling:function(){} 启用滚动

  • scrollToTop:function(duration,runType){} 滚动到顶部动画(css3动画)

  • fixElement:function(ele,options){} 兼容浏览器的fixed定位

  • hoverEffect:function(ele,className){}