backbone 未入門

資源:

backbone中文檔


underscore中文檔

一个实现了web前端MVC模式的JS库
M : model (模型)
V : view (试图)
C : controller (控制器)
就是把模型与视图分离,通过控制器来连接他们
模塊:

Events : 事件驱动方法
Model : 数据模型
Collection : 模型集合器
Router : 路由器(hash)
History : 开启历史管理
Sync : 同步服务器方式
View : 试图(含事件行为和渲染页面)

1)直接創建對像:

/*
var models = new Backbone.Collection;
var views = new Backbone.View;
*/
var model = new Backbone.Model;
model.set('name','hello')
console.log(model.get('name'));

2)给构造函数添加实例方法和静态方法

    var m_1 = new Backbone.Model({'name':'hello'})
    var m_2 = new Backbone.Model({'name':'hi'})
    var coll = new Backbone.Collection()
    coll.add(m_1)
    coll.add(m_2)
    console.log(JSON.stringify(coll)); // 對象解析出字符串;

//Backbone.Model表示模型的構造函數,extend參數 ({json實例方法},{json靜態方法})

    var M = Backbone.Model.extend({
        aaa:function(){
            console.log(123);
        }
    },{
        bbb: function () {
            console.log(456);

        }
    })
    var model = new M
    model.aaa() //實例方法使用實例調用;
    M.bbb();  //靜態使用構造函數直接調用;即相當於多了一個命名空間而已;

//設置默認值:
    var M = Backbone.Model.extend({
        defaults:{
            name:'hello'
        }
    })
    var mo_= new M;
    console.log(mo_.get('name'));

3)继承操作

    var M = Backbone.Model.extend({
        aaa: function () {
            console.log('abc');
        }
    },{
        bbb: function () {
            console.log('def');
        }

    })
    var ChildM = M.extend();
    var mo = new ChildM
    mo.aaa()
    ChildM.bbb()

4)自定义事件

(function () {
    var M = Backbone.Model.extend({
        defaults:{
            name:'hello'
        },
        initialize:function(){
            this.on('change', function () {
                console.log('onchange觸發了');
            })
        }
    })
    var model = new M
    model.set('name','hi')
})();
//指定key值觸發;
(function () {
    var M = Backbone.Model.extend({
        defaults:{
            name:'hello'
        },
        initialize:function(){
            this.on('change:name', function (model) {  //不同的key值觸發;
                console.log(model);
            })
        }
    })
    var model = new M
    model.set('name','hi')
})();


//1、創建模型對像
//2、創建視圖對像,直接在視圖對象裏傳參,指定模型對像,即連接在一起;
//3、對模型修改時,即會觸發視圖對象;

var M = Backbone.Model.extend({
    defaults: {
        name: 'hello'
    }
});

var V = Backbone.View.extend({
    initialize: function () {
        this.listenTo(this.model, 'change', this.show);
    },
    show: function (model) {
        $('body').append('<div>' + model.get('name') + '</div>')
    }
});

var m = new M;          //1、創建模型對像
var v = new V({model: m});  //2、創建視圖對像,直接在視圖對象裏傳參,指定模型對像,即連接在一起;
m.set('name', 'hi')  //3、對模型修改時,即會觸發視圖對象;

5)數據與服務器


(function () {
    Backbone.sync = function (method, model) {
        console.log(method + ': ' + JSON.stringify(model));
        model.id = 1;
    }
    var M = Backbone.Model.extend({
        defaults:{
            name:'hello'
        },
        url:'/user' // ajax提交,一定要指定好url ;
    });
    var m = new M;
    m.save(); //把現在的模型對象保存到服務器上;
    m.save({name:'hi'});  //修改
})();

(function () {
    Backbone.sync = function (method, model) {
        console.log(method + ': ' + JSON.stringify(model));
    }
    var C = Backbone.Collection.extend({
        initialize: function () {
            this.on('reset', function () {
                console.log(123);
            })
        },
        url:'/user' // ajax提交,一定要指定好url ;
    });
    var m = new C;
    m.fetch() //讀取服務器數據;
})();

6)路由與歷史管理

(function () {
    var Workspace = Backbone.Router.extend({
        routes:{
            'help':             'help',
            'search/:query':    'search',  //#search/任意字符;
            'search/:query/p:page': 'search' //#search//kiwis/p7
        },
        help: function () {
            console.log(1);
        },
        search: function (query,page) {
            console.log(2);
        }

    })
    var w = new Workspace
    Backbone.history.start()
    /*
    * 地址後面加#help,彈1;
    * 地址後面加#search/dfk 彈2
    *
    * */
})();

7)事件委託

所有的视图都拥有一个 DOM 元素(el 属性),即使该元素仍未插入页面中去。 视图可以在任何时候渲染,然后一次性插入 DOM 中去,这样能尽量减少 reflows 和 repaints 从而获得高性能的 UI 渲染。 this.el 可以从视图的 tagName, className, id 和 attributes 创建,如果都未指定,el 会是一个空 div。

(function () {
    var V = Backbone.View.extend({
        el:$('body'), //觸發的委託人;
        events:{
            'click input':'aaa',
            'mouseover li':'bbb'
        },
        aaa: function () {
            console.log(1111111);
        },
        bbb: function () {
            console.log(2221222);
        }
    })
    var veiw = new V;
})();



8)前端模板

$(function () {

    var M = Backbone.Model.extend({
        defaults:{
            name:'hello'
        }
    })
    var V = Backbone.View.extend({
        initialize: function () {
            this.listenTo(this.model,'change',this.show)
        },
        show: function (model) {
            $('body').append(this.template(this.model.toJSON()))
        },
        template: _.template($('#template').html())
    })

    var m = new M;
    var v = new V({model:m})
    m.set('name','hdi')
})

調用:

<script type="text/template" id="template">
    <% for(var i=0;i<5;i++) { %>
    <div><%= name %></div>
    <% } %>
</script>


大部分操作:

首先頁面上先對【數據進行修改】 ----> 數據修改包括【模型修改】或【集合修改】--->

當這兩個修改後---> 會觸發相應的【自定義事件】--->

自定義事件找到相應---> 【視圖】--->

回調函數更新視圖----> 視圖的更新通過前端模板獲取到,再生成到---->頁面;

一個模型和一個集合,一個模型對應一個視圖,集合對應大視圖;


<script>
var f = 1;
document.getElementById('tdosclick').onclick = function(){
if(f){

document.getElementById('tdos').style.display = 'block';

}
else{
document.getElementById('tdos').style.display = 'none';
}
f = !f;
}
</script>

移动端开发实例 | 圖片滑動 | 模擬滾動條

圖片滑動
onmousedown -->> ontouchstart按下瞬间 ;
onmousemove -->> ontouchmove移动过程 ;
onmouseup -->> ontouchend手指抬起 ,只针对单手操作 ;
對象操作:

var touchs = e.changedTouches[0]  
//先获取对象属性,手指操作的集合; 几个手指即有几项,所以单指是[0] ;

所以與元素拖動類似,結構是:

_ul.ontouchstart = function(e){
    _ul.ontouchmove  = function(e){
        ...
    }
    _ul.ontouchend  = function(e){
        ...
         this.ontouchmove = this.ontouchend = null;
    }
}

第一張圖與最後一張圖時速度變慢,所以使用移動距離為1/3

this.style.left = (touchs.pageX - downX) / 3 + 'px'

若第一張與第二張中間切換時,速度不同會出現跳動,所以需要再move過界時重新獲取downX,並且設置開頭只獲取一次;

   b = false
   downX = touchs.pageX

如果快速移動時,可快速滑動,需要設置時間,start時的時間,到end的時間

downTime = Date.now(); 

    _ul.ontouchend = function(e){
    ...
    Date.now() - downTime < 300  
    }
<div id="div">
    <ul id="ul1">
        <li><img src="iosimg/1.jpg" alt=""/></li>
        <li><img src="iosimg/2.jpg" alt=""/></li>
        <li><img src="iosimg/3.jpg" alt=""/></li>
        <li><img src="iosimg/4.jpg" alt=""/></li>
        <li><img src="iosimg/5.jpg" alt=""/></li>
    </ul>
</div>
var _div = document.getElementById('div')
var _ul = document.getElementById('ul1')
var _li = _ul.getElementsByTagName('li')
var w = _li[0].offsetWidth;
_ul.style.width = w * _li.length + 'px'
document.ontouchmove = function (e) {  //阻止默認滑動
    e.preventDefault()
}

var downX = 0;   //手指點下的坐標
var downLeft = 0;
var downTime = 0;
var inow = 0;
_ul.ontouchstart = function (e) {
    var touchs = e.changedTouches[0]  //先获取对象属性,手指操作的集合; 几个手指即有几项,所以单指是[0]

    downX = touchs.pageX
    downLeft = this.offsetLeft;
    var b = true;
    downTime = Date.now();

    _ul.ontouchmove = function (e) {
        var touchs = e.changedTouches[0]
        if (this.offsetLeft >= 0) {
            if (b) { //第二张一点开始滑到,到第一张时,如果不重新获取downX值,第二张速度仅为1/3,所以会突然跳动,设开头的意思是在move移动中,只需获取一次,不然只要move则每一秒都会重新获取;
                b = false
                downX = touchs.pageX
            }
            this.style.left = (touchs.pageX - downX) / 3 + 'px'

        }
        else if (this.offsetLeft < _div.offsetWidth - _ul.offsetWidth) {
            if (b) { //第二张一点开始滑到,到第一张时,如果不重新获取downX值,第二张速度仅为1/3,所以会突然跳动,设开头的意思是在move移动中,只需获取一次,不然只要move则每一秒都会重新获取;
                b = false
                downX = touchs.pageX
            }
            this.style.left = (touchs.pageX - downX) / 3 + (_div.offsetWidth - _ul.offsetWidth) + 'px'

        }
        else {
            this.style.left = touchs.pageX - downX + downLeft + 'px'
        }
    }
    _ul.ontouchend = function (e) {
        var touchs = e.changedTouches[0]
        if (touchs.pageX < downX) { //向左
            if (inow != _li.length - 1) {
                if (downX - touchs.pageX > w / 2 || Date.now() - downTime < 300 && downX - touchs.pageX > 30) {  //必须过一半才滑动
                    inow++ //确定方向,快速滑动,防止点击
                }
            }
            tMove(this, {left: -w * inow}, 500, 'easeOut')

        }
        else { //向右
            if (inow != 0) {
                if (touchs.pageX - downX > w / 2 || Date.now() - downTime < 300 && touchs.pageX - downX > 30) {
                    inow--
                }
            }
            tMove(this, {left: -w * inow}, 500, 'easeOut')
        }
        this.ontouchmove = this.ontouchend = null;
    }
}
    *{ margin: 0; padding: 0;}
    #div{ width: 470px; height: 150px; margin: 50px; position: relative;overflow: hidden; }
    #ul1{ position: absolute; left: 0; } /*这种而已没有宽度则li不会有float效果;*/
    #ul1 li{ width: 470px; height: 150px; float: left;list-style:none;}

模擬滾動條:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title><meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"/>
    <meta name="format-detection" content="telephone=no"/>
    <meta name="format-detection" content="email=no"/>
</head>
<body>
<style>
    *{ margin: 0; padding: 0;}
    #div1{ width: 200px; height: 200px;border:1px solid #000; position: relative; margin:100px;}
    #ul1{ position: absolute; top: 0;width: 100%;}
    #bar{ width: 2px; height: 100px; position: absolute; top: 0;right: 2px; background: #999; border-radius: 20px; display: none;}/* divH/ulH = barH/divH borH = divH*divH/ulH */
</style>
<div id="div1">
    <ul id="ul1">
    </ul>
    <div id="bar"></div>
</div>
</body>
<script>
    document.ontouchmove = function (e) {
        e.preventDefault()
    }
    var _div = document.getElementById('div1')
    var _ul = document.getElementById('ul1')
    var _bar = document.getElementById('bar')
    for(var i=0;i<101;i++){
        var _li = document.createElement('li')
        _li.innerHTML = i;
        _ul.appendChild(_li)
    }
    var downY = 0;
    var downTop = 0;
    var prevY = 0;

    var _t = null;

    var barH = _div.offsetHeight*_div.offsetHeight/_ul.offsetHeight
    if(barH<=40){
        barH = 40;
    }
    else if(_ul.offsetHeight<_div.offsetHeight){
        barH = 0;
    }
    _bar.style.height =barH + 'px'
    
    _ul.ontouchstart = function (e) {
        var touchs = e.changedTouches[0]

        downY = touchs.pageY
        downTop = this.offsetTop;
        prevY = touchs.pageY;

        var _speedY = 0;
        var b = true;

        _ul.ontouchmove= function (e) {

            _bar.style.opacity = 1;
            _bar.style.display = 'block';

          var touchs = e.changedTouches[0]
            _speedY = touchs.pageY - prevY; //出手速度 move时的点 - 前一个点,
            prevY = touchs.pageY;  //注意永运是最后一个点 - 前一个点,所以给值后要把prevY还原回前一个点;注意理解;
            if(this.offsetTop>=0){ //头部
                if(b){
                    b = false;
                    downY = touchs.pageY
                }
                this.style.top = (touchs.pageY - downY)/3 + downTop + 'px'
                _bar.style.height = barH * (1- this.offsetTop/_div.offsetHeight) +'px'//原高度 * 比例
                _bar.style.top = 0
            }
            else if(this.offsetTop<=_div.offsetHeight - _ul.offsetHeight){
                if(b){
                    b = false;
                    downY = touchs.pageY
                }
                this.style.top = (touchs.pageY - downY)/3 + _div.offsetHeight - _ul.offsetHeight + 'px'
                _bar.style.height = barH * (1- Math.abs((this.offsetTop-(_div.offsetHeight - _ul.offsetHeight))/_div.offsetHeight)) +'px'//原高度 * 比例  //尾部找一个0-1越来越小的值
                _bar.style.top = _div.offsetHeight - _bar.offsetHeight + 'px'
            }
            else{this.style.top = touchs.pageY - downY + downTop + 'px';

            //在move时找bar的滚动位置比例
                var scaleY = this.offsetTop/(_div.offsetHeight - _ul.offsetHeight) //最小值即move时不断变化的this.offsetTop,最大值为div.offsetHeight - _ul.offsetHeight; 0-1的比值
                _bar.style.top = scaleY * (_div.offsetHeight - _bar.offsetHeight)+'px'
            }
        }
        _ul.ontouchend = function () {
            this.ontouchmove = this.ontouchend = null;
            //1/手指起时开始做运动
            //_speedY
            var _this = this
            clearInterval(_t)
            _t = setInterval(function () {
                if(Math.abs(_speedY)<=1 || _this.offsetTop>50 || _this.offsetTop<=_div.offsetHeight - _ul.offsetHeight - 50){  //停
                    clearInterval(_t)
                    if(_this.offsetTop>=0){ //限制头
                        tMove(_this,{top:0},400, function () {
                            tMove(_bar,{opacity:0},400, function () {
                                this.style.display = 'none'
                            })

                        })
                        tMove(_bar,{height:barH},400)
                    }
                    else if(_this.offsetTop <= _div.offsetHeight - _ul.offsetHeight  ){ //限制尾
                        tMove(_this,{top:_div.offsetHeight - _ul.offsetHeight },400, function () {
                            tMove(_bar,{opacity:0},400, function () {
                                this.style.display = 'none'
                            })

                        })
                        tMove(_bar,{height:barH,top:_div.offsetHeight - barH},400, function () {
                            tMove(_bar,{opacity:0},400)
                            _bar.style.display = 'none'
                        })
                    }
                    else{  tMove(_bar,{opacity:0},400, function () {
                        this.style.display = 'none'
                    })

                    }
                }
                else{  //走
                    _speedY *=0.95;
                    _this.style.top = _this.offsetTop+ _speedY + 'px'

                    //bar头尾加运动

                    if(_this.offsetTop>=0){
                        _bar.style.height = barH * (1- _this.offsetTop/_div.offsetHeight) +'px'//原高度 * 比例
                        _bar.style.top = 0
                    }
                    else if(_this.offsetTop<=_div.offsetHeight - _ul.offsetHeight){
                        _bar.style.height = barH * (1- Math.abs((_this.offsetTop-(_div.offsetHeight - _ul.offsetHeight))/_div.offsetHeight)) +'px'//原高度 * 比例  //尾部找一个0-1越来越小的值
                        _bar.style.top = _div.offsetHeight - _bar.offsetHeight + 'px'
                    }
                    else{}
                    //在move时找bar的滚动位置比例
                    var scaleY = _this.offsetTop/(_div.offsetHeight - _ul.offsetHeight) //最小值即move时不断变化的this.offsetTop,最大值为div.offsetHeight - _ul.offsetHeight; 0-1的比值
                    _bar.style.top = scaleY * (_div.offsetHeight - _bar.offsetHeight)+'px'
                    tMove(_bar,{top:scaleY * (_div.offsetHeight - _bar.offsetHeight)},400)
                }
            },30)
        }
    }

    function tMove(obj, json, times, fx, fn) {
        if (typeof times == 'undefined') {
            times = 400;
            fx = 'linear';
        }
        if (typeof times == 'string') {
            if (typeof fx == 'function') {
                fn = fx;
            }
            fx = times;
            times = 400;
        }
        else if (typeof times == 'function') {
            fn = times;
            times = 400;
            fx = 'linear';
        }
        else if (typeof times == 'number') {
            if (typeof fx == 'function') {
                fn = fx;
                fx = 'linear';
            }
            else if (typeof fx == 'undefined') {
                fx = 'linear';
            }
        }
        var iCur = {
        }; //不變,不能寫在定時器裏  b
        for (var attr in json) {
            iCur[attr] = 0;
            if (attr == 'opacity') {
                iCur[attr] = Math.round(css(obj, attr) * 100);
            }
            else {
                iCur[attr] = parseInt(css(obj, attr));
            }
        }
        var startTime = now();
        clearInterval(obj._t);
        obj._t = setInterval(function () {
            var changeTime = now();
            var t = times - Math.max(0, startTime - changeTime + times);
            //在time的範圍內越來越小  2000-0;
            for (var attr in json) {
                var value = Tween[fx](t, iCur[attr], json[attr] - iCur[attr], times); //目的,通過js獲取tbcd值
                if (attr == 'opacity') {
                    obj.style.opacity = value / 100;
                    obj.style.filter = 'alpha(opacity=' + value + ')';
                }
                else {
                    obj.style[attr] = value + 'px';
                }
            }
            if (t == times) {
                clearInterval(obj._t);
                fn && fn.call(obj);
            }
        }, 13)
    }
    function now() {
        return (new Date()).getTime();
    }
    var Tween = {
        linear: function (t, b, c, d) { //匀速
            return c * t / d + b;
        },
        easeIn: function (t, b, c, d) { //加速曲线
            return c * (t /= d) * t + b;
        },
        easeOut: function (t, b, c, d) { //减速曲线
            return - c * (t /= d) * (t - 2) + b;
        },
        easeBoth: function (t, b, c, d) { //加速减速曲线 缓冲
            if ((t /= d / 2) < 1) {
                return c / 2 * t * t + b;
            }
            return - c / 2 * ((--t) * (t - 2) - 1) + b;
        },
        easeInStrong: function (t, b, c, d) { //加加速曲线
            return c * (t /= d) * t * t * t + b;
        },
        easeOutStrong: function (t, b, c, d) { //减减速曲线
            return - c * ((t = t / d - 1) * t * t * t - 1) + b;
        },
        easeBothStrong: function (t, b, c, d) { //加加速减减速曲线
            if ((t /= d / 2) < 1) {
                return c / 2 * t * t * t * t + b;
            }
            return - c / 2 * ((t -= 2) * t * t * t - 2) + b;
        },
        elasticIn: function (t, b, c, d, a, p) { //正弦衰减曲线(弹动渐入)
            if (t === 0) {
                return b;
            }
            if ((t /= d) == 1) {
                return b + c;
            }
            if (!p) {
                p = d * 0.3;
            }
            if (!a || a < Math.abs(c)) {
                a = c;
                var s = p / 4;
            } else {
                var s = p / (2 * Math.PI) * Math.asin(c / a);
            }
            return - (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
        },
        elasticOut: function (t, b, c, d, a, p) { //正弦增强曲线(弹动渐出)
            if (t === 0) {
                return b;
            }
            if ((t /= d) == 1) {
                return b + c;
            }
            if (!p) {
                p = d * 0.3;
            }
            if (!a || a < Math.abs(c)) {
                a = c;
                var s = p / 4;
            } else {
                var s = p / (2 * Math.PI) * Math.asin(c / a);
            }
            return a * Math.pow(2, - 10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
        },
        elasticBoth: function (t, b, c, d, a, p) {
            if (t === 0) {
                return b;
            }
            if ((t /= d / 2) == 2) {
                return b + c;
            }
            if (!p) {
                p = d * (0.3 * 1.5);
            }
            if (!a || a < Math.abs(c)) {
                a = c;
                var s = p / 4;
            }
            else {
                var s = p / (2 * Math.PI) * Math.asin(c / a);
            }
            if (t < 1) {
                return - 0.5 * (a * Math.pow(2, 10 * (t -= 1)) *
                        Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
            }
            return a * Math.pow(2, - 10 * (t -= 1)) *
                    Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
        },
        backIn: function (t, b, c, d, s) { //回退加速(回退渐入)
            if (typeof s == 'undefined') {
                s = 1.70158;
            }
            return c * (t /= d) * t * ((s + 1) * t - s) + b;
        },
        backOut: function (t, b, c, d, s) {
            if (typeof s == 'undefined') {
                s = 3.70158; //回缩的距离
            }
            return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
        },
        backBoth: function (t, b, c, d, s) {
            if (typeof s == 'undefined') {
                s = 1.70158;
            }
            if ((t /= d / 2) < 1) {
                return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
            }
            return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
        },
        bounceIn: function (t, b, c, d) { //弹球减振(弹球渐出)
            return c - Tween['bounceOut'](d - t, 0, c, d) + b;
        },
        bounceOut: function (t, b, c, d) {
            if ((t /= d) < (1 / 2.75)) {
                return c * (7.5625 * t * t) + b;
            } else if (t < (2 / 2.75)) {
                return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;
            } else if (t < (2.5 / 2.75)) {
                return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
            }
            return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
        },
        bounceBoth: function (t, b, c, d) {
            if (t < d / 2) {
                return Tween['bounceIn'](t * 2, 0, c, d) * 0.5 + b;
            }
            return Tween['bounceOut'](t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
        }
    }
    function css(obj, attr) {
        return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj) [attr]
    }
</script>
</html>