2013年11月

零JS筆記 | 照片牆

1、佈局轉換;


2、設置每一張都比上一次層級高;


3、move時找最近的,把當前拖動元素傳進來 ,最終得到變量nL


4、每一個圖片都沒碰到的情況;


5、需要找最近元素


6、拖動元素傳進函數


7、碰到的3元素找最近的;


8、條件是碰到的並且不包括自身


9、如何找斜邊的最小值;勾股定理


10、使用勾股定理則又是一個方法


11、被拖動元素與找到的最近元素之間運動切換,並且索引切換


12、隨時排使用隨時函數生產;並且也要重置每個圖的索引

window.onload = function () {
//佈局轉換;
var _ul = document.getElementById('ul1')
var _li = _ul.getElementsByTagName('li')
var _inp = document.getElementById('input1')
var izindex = 2;
var arr = []
for (var i = 0; i < _li.length; i++) {
    arr.push([_li[i].offsetLeft, _li[i].offsetTop])
}
for (var i = 0; i < _li.length; i++) {
    _li[i].style.position = 'absolute'
    _li[i].style.left = arr[i][0] + 'px'
    _li[i].style.top = arr[i][1] + 'px'
    _li[i].style.margin = 0;
}
for (var i = 0; i < _li.length; i++) {
    _li[i].index = i;
    drag(_li[i])
}
_inp.onclick = function () { //每一個都要動;
    var randomArr = [0, 1, 2, 3, 4, 5, 6, 7, 8]
    randomArr.sort(function (a, b) {  //隨機排
        return Math.random() - 0.5;
    })
    for (var i = 0; i < _li.length; i++) {
        sMove2(_li[i], {left: arr[randomArr[i]][0], top: arr[randomArr[i]][1]})
        //修正拖動時索引;
        _li[i].index = randomArr[i];
    }
}
function drag(obj) {
    var disX = 0;
    var disY = 0;
    obj.onmousedown = function (ev) {
        obj.style.zIndex = izindex++; //每一張都比上一次層級高;
        var ev = ev || event;
        disX = ev.clientX - obj.offsetLeft;
        disY = ev.clientY - obj.offsetTop;
        document.onmousemove = function (ev) {
            var ev = ev || event;
            obj.style.left = ev.clientX - disX + 'px'
            obj.style.top = ev.clientY - disY + 'px'

            for (var i = 0; i < _li.length; i++) {
                _li[i].style.border = ''
            }
            var nL = nearLi(obj) //1、move時找最近的,把當前拖動元素傳進來 ,最終得到變量nL
            if (nL) {     //2、每一個圖片都沒碰到的情況;
                nL.style.border = '2px red solid'
            }

        }
        document.onmouseup = function () {
            document.onmousemove = document.onmouseup = null;
            //最近元素
            var nL = nearLi(obj) //拖動元素

            if (nL) {
                sMove2(nL, {left: arr[obj.index][0], top: arr[obj.index][1]})
                sMove2(obj, {left: arr[nL.index][0], top: arr[nL.index][1]})
                //索引對調
                nL.index = [nL.index, obj.index];
                obj.index = nL.index[0];
                nL.index = nL.index[1];

                nL.style.border = '';
            }
            else { //沒碰到時回到原始位置;
                sMove2(obj, {left: arr[obj.index][0], top: arr[obj.index][1]})
            }
        }
        return false;
    }
}

function pz(o1, o2) {
    var L1 = o1.offsetLeft;
    var R1 = o1.offsetLeft + o1.offsetWidth;
    var T1 = o1.offsetTop;
    var B1 = o1.offsetTop + o1.offsetHeight;

    var L2 = o2.offsetLeft;
    var R2 = o2.offsetLeft + o2.offsetWidth;
    var T2 = o2.offsetTop;
    var B2 = o2.offsetTop + o2.offsetHeight;

    if (R1 < L2 || L1 > R2 || B1 < T2 || T1 > B2) { //碰不到的四種情況
        return false;
    }
    else {
        return true;
    }
}

function nearLi(o) { //3、拖動元素傳進來;
    var v = 9999;
    var index = -1;
    for (var i = 0; i < _li.length; i++) {    //4、碰到的3元素找最近的;
        if (pz(o, _li[i]) && o != _li[i]) {    // 5碰到的並且不包括自身

            //6、_li[i]即為碰到的3個元素,這裏的jl調用3次,需要利用勾股定理;
            var c = jl(o, _li[i])     //8、3條斜邊得到了 ;
            if (c < v) {    //9、如何找斜邊的最小值;
                v = c;      //10、v = 最小值;
                index = i;  //11、位置,最近的li在整體的位置
            }
        }
    }
    if (index != -1) {
        return _li[index];   //12、return回找到的元素,給上面代碼加紅邊框;
    }
    else {
        return false;
    }
}

function jl(o1, o2) {  //7、兩元素求元素的斜邊 a邊與b邊;    o1為第一張圖,o2可能是其他3張圖 ,因為上面調用了3次;
    var a = o1.offsetLeft - o2.offsetLeft;
    var b = o1.offsetTop - o2.offsetTop;
    return Math.sqrt(a * a + b * b);
}


function sMove2(obj, json, fn) {
    clearInterval(obj._t)
    var iCur = 0;
    var _speed = 0;
    obj._t = setInterval(function () {
        var on = true;
        for (var attr in json) {
            var _target = json[attr]
            if (attr == 'opacity') {
                iCur = Math.round(css(obj, attr) * 100)
            }
            else {
                iCur = parseInt(css(obj, attr));
            }
            _speed = (_target - iCur) / 8;
            _speed = _speed > 0 ? Math.ceil(_speed) : Math.floor(_speed)
            if (iCur !== _target) {
                on = false
                if (attr == 'opacity') {
                    obj.style.opacity = (iCur + _speed) / 100
                    obj.style.filter = 'alpha(opacity=' + iCur + _speed + ')'
                }
                else {
                    obj.style[attr] = iCur + _speed + 'px'
                }
            }
        }
        if (on) {
            clearInterval(obj._t)
            fn && fn.call(obj)
        }
    }, 30)
}

function css(obj, attr) {
    return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj) [attr]
}
}

See the Pen YympxY by elmok (@elmok) on CodePen.


<script async src="//assets.codepen.io/assets/embed/ei.js"></script>

零JS筆記 | 圖片放大镜

问题:

<div id="div1">
    <div id="div2"></div>
</div>
<script>
    var _div1 = document.getElementById('div1')
    var _div2 = document.getElementById('div2')
    _div1.onmouseover = function () {
        document.title += 1
    }
    _div1.onmouseout = function () {
        document.title += 2
    }
</script>
<style>
    #div1 { width: 200px; height: 200px; background: red; }
    #div2 { width: 100px; height: 100px; background: yellow; }
</style>

從紅---> 黃 2121212121
1、觸發本身元素的out事件,所以+2,當到黃上,冒泡,又觸發本身的over事件+1
2、所以会发生闪动;

解决:
1、js: onmouseenter onmouseleave (子級不會影響父級 )
2、全兼容作法;
3、css: 加層隔開父子級;

window.onload = function () {
    var oDiv1 = document.getElementById('div1');
    var oDiv2 = document.getElementById('div2');

    oDiv1.onmouseover = function (ev) {
        var ev = ev || window.event;

        var a = this, b = ev.relatedTarget; //相對目標,之前的目標,移入目標之前的元素
        if (!elContains(a, b) && a != b) {
            document.title += '1';
        }
    };
    oDiv1.onmouseout = function (ev) {
        var ev = ev || window.event;

        var a = this, b = ev.relatedTarget;
        if (!elContains(a, b) && a != b) {
            document.title += '2';
        }
    };
};

function elContains(a, b) {  //判断两个元素是否是嵌套关系 a是否包含b
    return a.contains ? a != b && a.contains(b) : !!(a.compareDocumentPosition(b) & 16);
}

简单放大镜:

window.onload = function () {
    var _div = document.getElementById('div1')
    var _span = document.getElementsByTagName('span')[0]
    var _div2 = document.getElementById('div2')
    var _img2 = _div2.getElementsByTagName('img')[0]
    _div.onmouseover = function () {
        _span.style.display = 'block'
    }
    _div.onmouseout = function () {
        _span.style.display = 'none'
    }
    _div.onmousemove = function (e) {
        var e = e || event;
        var L = e.clientX - _div.offsetLeft - _span.offsetWidth / 2
        var T = e.clientY - _div.offsetTop - _span.offsetHeight / 2
        if (L < 0) {
            L = 0
        }
        else if (L > _div.offsetWidth - _span.offsetWidth) {
            L = _div.offsetWidth - _span.offsetWidth
        }
        if (T < 0) { //注意這裏不能寫else if
            T = 0
        }
        else if (T > _div.offsetHeight - _span.offsetHeight) {
            T = _div.offsetHeight - _span.offsetHeight
        }
        _span.style.left = L + 'px'
        _span.style.top = T + 'px'
        var scaleX = L / (_div.offsetWidth - _span.offsetWidth) //比例; 0-1
        var scaleY = T / (_div.offsetHeight - _span.offsetHeight) //比例:0-1
//大圖能走的距離為本身距離 - 大圖外層可視區的距離 ;
//此距離  * 比例

        _img2.style.left = -scaleX * (_img2.offsetWidth - _div2.offsetWidth) + 'px'
        _img2.style.top = -scaleY * (_img2.offsetHeight - _div2.offsetHeight) + 'px'


    }
}

See the Pen jbgrXw by elmok (@elmok) on CodePen.


<script async src="//assets.codepen.io/assets/embed/ei.js"></script>

零JQ筆記 | 組件小例

架子:

$(function () {
        var t1 = new Tab();
        ti.init('div1', {})
    })

    function Tab() {
        this.settings = { //默認參數
            event: 'click'
        }
    }
    Tab.prototype.init = function (_parent, opt) {
        $.extend(this.settings, opt);


    }

主要分離3方面:


配置參數:opt:events , delay


方法:methos:nowSel(),getContent


事件:beforeClick,afterClick


注意的點:

1、jq中主動解發 $(_this).trigger('afterClick'),相當於 autoEvent(_this, 'afterClick') ;


2、特別留意this指向問題;


3、jq中$.extend(this.settings, opt),相當於 extend(this.settings, opt)


    $(function () {
        var t1 = new Tab();
        t1.init('div1', {})
        var t2 = new Tab();
        t2.init('div2', {
            event:'mouseover'
        })

        var t3 = new Tab();
        t3.init('div3', {
            event:'mouseover',
            delay:200
        })
        var t4 = new Tab();
        t4.init('div4', {})
        t4.nowSel(2)
        $('#inp1').click(function(){
            console.log(t4.getContent());
        })

        $(t4).on('beforeClick', function () {
            console.log(t4.getContent() + ' before');
        })
        $(t4).on('afterClick', function () {
            console.log(t4.getContent() + ' after');
        })

    })

    function Tab() {
        this._parent = null;
        this._inp = null;
        this._div = null;
        this.cur = 0;
        this.settings = { //默認參數
            event: 'click',
            delay:0
        }
    }
    Tab.prototype.init = function (_parent, opt) {
        $.extend(this.settings, opt);
        this._parent = $('#'+_parent);
        this._inp = this._parent.find('input');
        this._div = this._parent.find('div');
        this.change();
    }
    Tab.prototype.change = function () {
        var _this = this;
        var _t = null;
        this._inp.on(this.settings.event,function(){

            var This = this;
            if(_this.settings.event == 'mouseover' && _this.settings.delay){
                _t = setTimeout(function(){
                    show(This)
                },_this.settings.delay);
            }
            else{
                show(this)
            }
        }).mouseout(function () {
            clearTimeout(_t);
        })
        function show(obj){ //obj指按鈕;

            $(_this).trigger('beforeClick') ; //點擊前

            $(obj).attr('class','active').siblings().removeClass('active');
            _this._div.eq($(obj).index()).css('display','block').siblings('div').css('display','none')
            _this.cur = $(obj).index()  //千萬注意this指向,坑

            $(_this).trigger('afterClick') ; //點擊前
        }
    }
    Tab.prototype.nowSel = function(index){
        this._inp.eq(index).attr('class','active').siblings().removeClass('active');
        this._div.eq(index).css('display','block').siblings('div').css('display','none')
        this.cur = index;
    }
    Tab.prototype.getContent = function () {
        return this._div.eq(this.cur).html()
    }

http://tangram.baidu.com/magic/

零JS筆記 | 面向對象 | 自定義事件

什麼是組件?

對面向對象的深入應用(UI組件、功能組件)
將配置參數、方法、事件,三者分離
創建自定義事件:
有利於多人協作開發;
如何去掛載自定義事件與事件函數

自定義事件:主要與函數有關,讓函數具備事件某些特性
(比如,多个函数也可如事件都执行,而不是像同名函数后覆盖前)

原理:

window.onload = function () {
    var _div = document.getElementById('div1')
    var _span = document.getElementById('span1')

    bind(_div, 'click', function () {
        console.log(1);
    })
    bind(_div, 'click', function () {
        console.log(2);
    })

    bind(_span, 'show', function () {
        console.log(3);
    })
    bind(_span, 'show', function () {
        console.log(4);
    })
    bind(_span, 'hide', function () {
        console.log(5);
    })

//觸發自定義事件: 

    autoEvent(_span, 'show') // 3,4
    autoEvent(_span, 'hide') // 3,4


    function bind(obj, events, fn) {   //建立关系 ;
        //obj:楼层;
        //events:书架
        //fn:一本书

        obj.listeners = obj.listeners || {} //樓層
        obj.listeners[events] = obj.listeners[events] || []; //樓層下創建書架
        obj.listeners[events].push(fn); //push方法把對應的書存到書架下


        if (obj.addEventListener) {
            obj.addEventListener(events, fn, false)
        }
        else {
            obj.attachEvent('on' + events, fn)
        }
    }

    function autoEvent(obj, events) {   //主动触发自定义事件;
        for (var i = 0; i < obj.listeners[events].length; i++) {
            obj.listeners[events][i]();   //循環數組執行即可
        }

    }

}

改寫實例:

window.onload = function () {
    var d1 = new Drag()
    var d2 = new Drag()
    var d3 = new Drag()
    var d4 = new Drag()
    d1.init({
        id: 'div1'
    })
    d2.init({
        id: 'div2'
    })
    bind(d2, '_down', function () {
        document.title = 'down'
    })
    d3.init({
        id: 'div3'
    })
    bind(d3, '_up', function () {
        document.title = 'up'
    })
    d4.init({
        id: 'div4'
    })
    bind(d4, '_up', function () {
        document.title = 'bybybybyb'
    })

//所以,最大的好處:如果想讓最後一個變大,只需要再綁定一次即可;而不是寫在原有代碼裏;

    bind(d4, '_up', function () {
        document.getElementById('div4').style.width = '200px'
    })
}
function Drag() {
    this.obj = null;
    this.disX = 0;
    this.dixY = 0;
    this.settings = {}
}
Drag.prototype.init = function (opt) {
    this.obj = document.getElementById(opt.id)
    var _this = this;
    extend(this.settings, opt)
    this.obj.onmousedown = function (ev) {
        var ev = ev || event;
        _this.fnDown(ev)
//執行
        autoEvent(_this, '_down')

        document.onmousemove = function (ev) {
            var ev = ev || event;
            _this.fnMove(ev)
        }
        document.onmouseup = function () {
            _this.fnUp();
//執行
            autoEvent(_this, '_up')

        }
        return false //最後加阻止默認事件;
    }
}
Drag.prototype.fnDown = function (ev) {
    this.disX = ev.clientX - this.obj.offsetLeft;
    this.disY = ev.clientY - this.obj.offsetTop;
}
Drag.prototype.fnMove = function (ev) {
    this.obj.style.left = ev.clientX - this.disX + 'px'
    this.obj.style.top = ev.clientY - this.disY + 'px'
}
Drag.prototype.fnUp = function () {
    document.onmousemove = document.onmouseup = null;
}
function extend(o1, o2) {
    for (var attr in o2) {
        o1[attr] = o2[attr]
    }
}
function bind(obj, events, fn) {
    obj.listeners = obj.listeners || {};
    obj.listeners[events] = obj.listeners[events] || [];
    obj.listeners[events].push(fn);

    if (obj.nodeType) { //判斷是否為dom元素
        if (obj.addEventListener) {
            obj.addEventListener(events, fn, false)
        }
        else {
            obj.attachEvent('on' + events, fn)
        }
    }
}

function autoEvent(obj, events) {
    if (obj.listeners && obj.listeners[events]) { //判斷是否存在
        for (var i = 0; i < obj.listeners[events].length; i++) {
            obj.listeners[events][i]()
        }
    }

}

零JS筆記 | 面向對象 | 組件

   提高对象的复用性
如何配置参数和默认参数
   对面向对象的深入应用(UI组件,功能组件)
   将 配置参数、方法、事件,三者进行分离
创建自定义事件
   有利于多人协作开发代码
   如何去挂载自定义事件与事件函数

組件開發,多組對象;像兄弟之間的關係 (代碼利用的一種形式;)
推理過程:

    function show(opt){
    }
    show({
        id:'div1',
        toDown:function(){},
        toUp:function(){}
    })

    var a = { name:'小明' }  //配置參數   1、優先級較高 2、key值一定要相同 ;
    var b = { name:'小強' }  //默認參數

    extend(b,a) //b的name被a的name覆蓋了;

    console.log(b.name);  //小明,(小強被小明蓋了)

    function extend(o1,o2){
        for(var attr in o2){
            o1[attr] = o2[attr]
        }
    }

重點:寫配置參數---> 寫默認參數--->用配置覆蓋默認---->調用默認方法;

所以,搭架子


var f1 = new Fn();
f1.init({

});

function Fn(){
    
    this.settings = {
            
    }
}
Fn.prototype.init = function(opt){
    extend(this.settings,opt)
}

function extend(o1,o2){
    for(var attr in o2){
        o1[attr] = o2[attr]
    }    
}
//改寫:定義配置參數;
        d1.init({
            id:'div1'
        })

        d2.init({
            id:'div2',
            _down:function(){
                document.title = 'down'
            }
        })
        d3.init({
            id:'div3',
            _down:function(){
                document.title = 'down-down-down'
            },
            _up: function () {
                document.title='up-up-up'
            }
        })
        d4.init({
            id:'div4',
            _up:function(){
                document.title = 'bybybyby'
            }
        })

//沒有值的情況:

    function Drag() {
        this.obj = null;
        this.disX = 0;
        this.dixY = 0;
        this.settings = {    //配置覆蓋默認,然後去調用默認的值;
            _down: function () {},
            _up: function () {}
        }
    }

//執行:

    Drag.prototype.init = function (opt) {
        this.obj = document.getElementById(opt.id)
        var _this = this;

        extend(this.settings, opt)   //使this.settings的值 == opt的值,如果opt沒有,則找默認的

        this.obj.onmousedown = function (ev) {
            var ev = ev || event;
            _this.fnDown(ev)  //ev要傳進來,下面才不用定義 ;

            _this.settings._down()  //調用默認

            document.onmousemove = function (ev) {
                var ev = ev || event;
                _this.fnMove(ev)
            }
            document.onmouseup = function () {
                _this.fnUp();

                _this.settings._up() //調用默認

            }
            return false //最後加阻止默認事件;
        }
    }


//其他:

    Drag.prototype.fnDown = function (ev) {
        this.disX = ev.clientX - this.obj.offsetLeft;
        this.disY = ev.clientY - this.obj.offsetTop;
    }
    Drag.prototype.fnMove = function (ev) {
        this.obj.style.left = ev.clientX - this.disX + 'px'
        this.obj.style.top = ev.clientY - this.disY + 'px'
    }
    Drag.prototype.fnUp = function () {
        document.onmousemove = document.onmouseup = null;
    }
    function extend(o1, o2) {
        for (var attr in o2) {
            o1[attr] = o2[attr]
        }
    }

核心:

//1、寫默認
        this.settings = {
            _down: function () {},
            _up: function () {}
        }
//3、改寫默認,即把外面調用的函數賦值給默認 覆蓋默認,所以再執行如果外面有,則執行,如無則執行默認

        extend(this.settings, opt) 

//2、調執行默認
        _this.settings._down()
        _this.settings._up()

組件彈窗

window.onload = function () {
    var _inp = document.getElementsByTagName('input')
    _inp[0].onclick = function () {
        var d1 = new Dialog();
        d1.init({ //配置參數
            cur: 0,
            title: '登入'
        });
    }
    _inp[1].onclick = function () {
        var d2 = new Dialog();
        d2.init({
            cur: 1,
            w: 100,
            h: 400,
            dir: 'right',
            title: '公告'
        })
    }
    _inp[2].onclick = function () {
        var d2 = new Dialog();
        d2.init({
            cur: 2,
            mask: true
        })
    }
}
function Dialog() {
    this._login = null;
    this._mask = null;
    this.settings = {  //默認參數
        w: 300,
        h: 300,
        dir: 'center',
        title: '',
        mask: false
    }
}
Dialog.prototype.json = {};             //目的:只能彈一次: 先定義空json
Dialog.prototype.init = function (opt) {

    extend(this.settings, opt)

    if (this.json[opt.cur] == undefined) { //第一次走這裏;
        this.json[opt.cur] = true;
    }

    if (this.json[opt.cur]) {       //為true時就走創建
        this.create();
        this.fnClose();
        if (this.settings.mask) {
            this.createMask();
        }
        this.json[opt.cur] = false; //後fase跟undefined也等於false,也不會走上面;
    }
}
Dialog.prototype.create = function () {
    this._login = document.createElement('div');
    this._login.className = 'login'
    this._login.innerHTML = '<div class="title"><span>' + this.settings.title + '</span><span class="close">X</span></div><div class="content"></div>'

    document.body.appendChild(this._login);
    this.setDate();
}
Dialog.prototype.setDate = function () {
    this._login.style.width = this.settings.w + 'px'
    this._login.style.height = this.settings.h + 'px'
    if (this.settings.dir == 'center') {
        this._login.style.left = (viewWidth() - this._login.offsetWidth) / 2 + 'px'
        this._login.style.top = (viewHeight() - this._login.offsetHeight) / 2 + 'px'
    }
    else if (this.settings.dir = 'right') {
        this._login.style.left = (viewWidth() - this._login.offsetWidth) + 'px'
        this._login.style.top = (viewHeight() - this._login.offsetHeight) + 'px'
    }
}
Dialog.prototype.fnClose = function () {
    var _this = this;
    var _close = this._login.querySelector('.close')
    _close.onclick = function () {
        document.body.removeChild(_this._login)
        if (_this.settings.mask) {
            document.body.removeChild(_this._mask)
        }
        _this.json[_this.settings.cur] = true; //關閉後再設回;
    }
}
Dialog.prototype.createMask = function () {
    this._mask = document.createElement('div')
    this._mask.id = 'mask'
    document.body.appendChild(this._mask)
    this._mask.style.width = viewWidth() + 'px'
    this._mask.style.height = viewHeight() + 'px'
}
function viewWidth() {
    return document.documentElement.clientWidth;
}
function viewHeight() {
    return document.documentElement.clientHeight;
}
function extend(o1, o2) {
    for (var attr in o2) {
        o1[attr] = o2[attr]
    }
}

See the Pen avezwe by elmok (@elmok) on CodePen.


<script async src="//assets.codepen.io/assets/embed/ei.js"></script>

零JS筆記 | 面向對象 | 繼承

继承:在原有對象的基础上,略作修改,得到一个新对象,不影响原对象的功能;
如何添加?
属性继承: 调用父类的构造函数;父类.call(this,参数,参数。。。);
方法继承: 父类的原型直接给子类的原形

function CreatePerson(name, sex) {
    this.name = name;
    this.sex = sex;
}
CreatePerson.prototype.showname = function () {
    console.log(this.name);

}
var p1 = new CreatePerson('小明', '男');
p1.showname();

///CreateStar繼承CreatePerson

function CreateStar(name, sex, job) { //子
//調用相當於執行;调用父类构造函数 ,不加call,则this指向window,必须使用this指向实例;
    CreatePerson.call(this, name, sex) 
    this.job = job;
}
CreateStar.prototype = CreatePerson.prototype

var p2 = new CreateStar('张敬轩', '男', '歌手');

p2.showname()

以上存在问题:一个原型给另一个原型,即对像给对像,所以出现了引用(修改一个会影响另一个;)



一、拷貝繼承;

如何添加?
属性继承: 调用父类的构造函数;父类.call(this,参数,参数。。。);
方法继承: for in形式實現 extend()函數,jq

function CreatePerson(name, sex) {
    this.name = name;
    this.sex = sex;
}
CreatePerson.prototype.showname = function () {
    console.log(this.name);

}
var p1 = new CreatePerson('小明', '男');
p1.showname();

///CreateStar繼承CreatePerson

function CreateStar(name, sex, job) { //子
//調用相當於執行;调用父类构造函数 ,不加call,则this指向window,必须使用this指向实例;
    CreatePerson.call(this, name, sex) 
    this.job = job;
}
//for in繼承
  extend( CreateStar.prototype ,CreatePerson.prototype)

var p2 = new CreateStar('张敬轩', '男', '歌手');

p2.showname()

    function extend(o1,o2){
        for(var attr in o2){
            o1[attr] = o2[attr];
        }
    }
//函數的的特點不能修改,只能重新賦值,所以雖然函數也是對象,但不會出問題;

拖拽繼承小例;

window.onload = function () {
    var d1 = new Drag('div1')
    d1.init()
    var d2 = new ChildDrag('div2')
    d2.init()
}
function Drag(id) {
    this.obj = document.getElementById(id)
    this.disX = 0;
    this.dixY = 0;
}
Drag.prototype.init = function () {
    var _this = this;
    this.obj.onmousedown = function (ev) {
        var ev = ev || event;
        _this.fnDown(ev)  //ev要傳進來,下面才不用定義 ;
        document.onmousemove = function (ev) {
            var ev = ev || event;
            _this.fnMove(ev)
        }
        document.onmouseup = function () {
            _this.fnUp();
        }
        return false //最後加阻止默認事件;
    }
}
Drag.prototype.fnDown = function (ev) {
    this.disX = ev.clientX - this.obj.offsetLeft;
    this.disY = ev.clientY - this.obj.offsetTop;
}
Drag.prototype.fnMove = function (ev) {
    this.obj.style.left = ev.clientX - this.disX + 'px'
    this.obj.style.top = ev.clientY - this.disY + 'px'
}
Drag.prototype.fnUp = function () {
    document.onmousemove = document.onmouseup = null;
}

function ChildDrag(id) {
    Drag.call(this, id) //指向與傳參數
}

//繼承Drag類
extend(ChildDrag.prototype, Drag.prototype);

//繼承後重新改寫move限制範圍;
ChildDrag.prototype.fnMove = function (ev) {
    var L = ev.clientX - this.disX;
    var T = ev.clientY - this.disY;
    if (L < 0) {
        L = 0;
    }
    else if (L > document.documentElement.clientWidth - this.obj.offsetWidth) {
        L = document.documentElement.clientWidth - this.obj.offsetWidth
    }
    this.obj.style.left = L + 'px'
    this.obj.style.top = T + 'px'

}
function extend(o1, o2) {
    for (var attr in o2) {
        o1[attr] = o2[attr]
    }
}



一、類繼承;
利用構造函數的方式;

b1找showName,b1下沒有,但因為賦值(Bbb.prototype = new Aaa();),則通過原型鏈找Bbb.prototype 相當於找 new Aaa(),new Aaa()再通過原型鏈找Aaa.prototype

    //父
    function Aaa() {
        this.name = '小明'
    }
    Aaa.prototype.showName = function () {
        console.log(this.name);
    }
    //子
    function Bbb() {

    }
    //子原型,= 誰去給值給子類原型:父類創建出來的對象 ;
    Bbb.prototype = new Aaa(); //其實也是引用

    var b1 = new Bbb();
    b1.showName()

問題一:constructor

 console.log(b1.constructor);  //變成function Aaa(){}了;修改了;

//修正
 Bbb.prototype = new Aaa(); //其實也是引用
 Bbb.prototype.constructor = Bbb; //修正指向;

問題二:引用時,值的改變會相互影響 ;所以,完整個類繼承的寫法是:

    
    function Bbb(){
        Aaa.call(this)
    }
    
    var F  = function () {}
    F.prototype = Aaa.prototype; //只會給showName,不會接收到屬性;,所以需要設置接收屬性;
    Bbb.prototype = new F();
    Bbb.prototype.constructor = Bbb; //修正指向;

推斷過程:

function Aaa() {
//        this.name = '小明'
    this.name = [1,2,3]
}
Aaa.prototype.showName = function () {
    console.log(this.name);
}
//子
function Bbb() {
    Aaa.call(this)
}
//子原型,= 誰去給值給子類原型:父類創建出來的對象 ;
//  Bbb.prototype = new Aaa(); //其實也是引用
//  Bbb.prototype.constructor = Bbb; //修正指向;

var F  = function () {}
F.prototype = Aaa.prototype; //只會給showName,不會接收到屬性;,所以下面需要設置接收屬性;
Bbb.prototype = new F();
Bbb.prototype.constructor = Bbb; //修正指向;
//屬性與方法的繼承要分開繼承;
var a1 = new Aaa()
var b1 = new Bbb();
b1.showName()
//   console.log(b1);
//b1找showName,b1下沒有,則通過原型鏈找Bbb.prototype 相當於找 new Aaa(),new Aaa()再通過原型鏈找Aaa.prototype

//如何用一句話來完成繼承;
//Bbb.prototype = new Aaa(); 但不坑

b1.name.push(4)
var b2 = new Bbb()
console.log(b1.name);
console.log(b2.name); //也變成1,2,3,4;
console.log(b1.constructor);  //變成function Aaa(){}了;修改了;

所以,属性继承使用call,使用F只继承方法



三、原型繼承

var a = {
    name: '小強'
}
var b = cloneObj(a)

b.name = '小強修改'  //相當於在b下面添加了;所以不需要向後找,
console.log(a.name); //則不會受影響了;

console.log(b.name);
function cloneObj(obj) {
    var F = function () {}
    F.prototype = obj;
    return new F
}

解析:f1 (new出來)通過原型鏈F.pro == obj -->name在obj下面,然後直接return f1 ,則f1 == b;
所以 b找name,相當於b 找f1 ,f1找不到則通過原型鏈F.pro == obj,找到name = '小強'
當給b.name = '小強修改',時,相當於給b下面添加了一個屬性name,則再彈b時不需要沿原型鏈找,所以a.name也不會受影響



繼承三種方法:拷貝、類式、原型;

拷貝:通用型,有new無new都可以;

類式:new構造函數情況;

原型:無new的對象;

當然也有其他繼承:寄生式、、、

零JS筆記 | 面向對象 | 屬性方法

面向對象幾特點:

  • OOP面向對象
  • 抽象:抓核心問題;
  • 封裝:只能通過對象來訪問方法
  • 繼承:從已有對象上繼承出新的對象 //改特殊部分
  • 多態:多對象的不同形態 一個usb接口提供不同功能

對象組成:方法(行為,操作) 函數:過程,動態的
屬性:變量,狀態,靜態;

var arr = []
arr.number = 10;
/* 對象下面的變量叫對象的屬性;*/
console.log(arr.number);
console.log(arr.length);
arr.test = function () { //對象下面的函數叫對象的方法;
    alert(123)
}
arr.test()

//加括號是方法,不加括號是屬性;

    var obj = new Object(); //空對象
    obj.name = '小明';
    obj.show = function () {
        console.log(this.name);
    }
    obj.show()

为对象添加属性和方法
Object对象
this指向
创建两个对象 : 重复代码过多



工廠模式; === 面向對象中的封裝函數
理论上的状态:

    function cPerson(name){
        //原料
        var obj = new Object()
        //加工
        obj.name = name;
        obj.showName = function () {
            console.log(this.name);
        }
        //出廠
       return obj;
    }
   var p1 =  cPerson('小明')
    p1.showName()
    var p2 = cPerson('小強')
    p2.showName()

當new去調用一個函數,這裏函數中的this == 創建出來的對象;而且函數的返回值直接即是this; 隱式返回;
所以問題是:this在哪? 原料是什麼,怎麼加工,出廠後返回值是什麼?

    function CPerson(name){
        //this哪?
        //原料
        //加工
        this.name = name;
        this.showName = function () {
            console.log(this.name);
        }
        //出廠
       // return obj;   //正常的返回沒有return會返回undefined; 如果是用new調用的話,則是返回this;
    }

創建2對象:

var p1 = new CPerson('小強');
var p2 = new CPerson('小明')

    console.log(p1.showName);
    console.log(p2.showName);
    console.log(p1.showName == p2.showName); //false;
//為什麼得false?
//問題:因為引用地址不相同,所以比如創建2000個對象,
//即會有2000個地址,所以必須使用引用相同,變為真;,所以是原型 ;

基本類型比較,對象賦值

    var a = 5 ;
    var b = 5;
    console.log(a === b); //基本類型的比較,只要值相同就行;true;

    var a = [1,2,3];
    var b = [1,2,3];
    console.log(a == b);  //對象 值相同,引用地址不同相同,所以是false;

    var a = [1,2,3]
    var b = a;
    console.log(a == b);   //值相同,引用相同 true;

    var a = [1,2,3]
    var b = a;//對象,把a的值跟地址都給了b 剪切
    b.push(4)
    console.log( b ) //[1,2,3,4]
    console.log( a ) //[1,2,3,4] 

    var a = [1,2,3]
    var b = a;//對象,把a的值跟地址都給了b 剪切
    b = [1,2,3,4]
    console.log( b ) //[1,2,3,4]
    console.log( a ) //[1,2,3] //出現= 必然在內存重新生成地址,所以不會改變a 

原型:原型去改寫對象下面公用的方法或屬性 ;讓公用的方法或屬性在內在中只存在一份,提高性能;

//原型 == class
//普通 == style

自行定義arr.sum方法

     var arr = [1,2,3,4,5]
     var arr2 = [2,3,34,4,23]
     arr.sum = function () {
     var result = 0;
     for(var i=0;i<this.length;i++){
     result += this[i]
     }
     return result;
     }
     console.log(arr.sum())

//原型prototype,寫在構造函數的下面 ;

    var arr = [1,2,3,4,5];
    var arr2 = [2,3,34,4,23]
    Array.prototype.sum = function () {
        var result = 0;
        for(var i=0;i<this.length;i++){
            result += this[i]
        }
        return result;
    }

    console.log(arr.sum());
    console.log(arr2.sum());

    var arr3 = []
    arr3.number = 10; //style
    Array.prototype.number = 20;   //class
    console.log(arr3.number);  //style優先級> class,所以彈出的10 ;



如何把過程寫法改為原型寫法;

 1、原型保存那些不變即公用的屬性及方法;屬性是變化的,則不能放到原型上,所以放到構造函數裏;
 2、
         function 構造函數(){
             this.屬性
          }
         構造函數.原型.方法 = function () {

          }
          var 對象1 = new 構造函數();
          對象1.方法()

總結:相同的属性和方法可以加载原型上,混合的编程模式,构造函数加属性,原型加方法



改寫tab選項卡:

1、不要函數套函數

2、可以有全局變量;

3、把onload中不是賦值的語句放到單獨的函數中;
改成面向對象:全局變量就是屬性;函數就是方法;onload中創建對象;改this指向(在事件或定時器時this指向易被改 )

function Tab(id) {
    this.box = document.getElementById(id);
    this.btn = this.box.getElementsByTagName('input')
    this.div = this.box.getElementsByTagName('div')
    this.num = 0;
}
Tab.prototype.init = function () {
    var _this = this;
    for (var i = 0; i < this.btn.length; i++) {
        this.btn[i].index = i;
        this.btn[i].onclick = function () {
            _this.change(this)  // //this是按鈕的this  _this是對像,即change由對象調用,所以下面的this不換;正確了
        };
    }
}
Tab.prototype.change = function (obj) { //change是在init調用,所以this指向init裏,必須修改
    for (var j = 0; j < this.btn.length; j++) {
        this.btn[j].className = ''
        this.div[j].style.display = 'none'
    }
    obj.className = 'on'  //傳進來按鈕的this
    this.div[obj.index].style.display = 'block' //傳進來按鈕的this
}
Tab.prototype.autoplay = function () {
    var _this = this;
    setInterval(function () {
        if (_this.num == _this.btn.length - 1) {
            _this.num = 0;
        }
        else {
            _this.num++
        }

        for (var j = 0; j < _this.btn.length; j++) {
            _this.btn[j].className = ''
            _this.div[j].style.display = 'none'
        }
        _this.btn[_this.num].className = 'on'  //傳進來按鈕的this
        _this.div[_this.num].style.display = 'block' //傳進來按鈕的this
    }, 1000)

}
<div id="box">
    <input type="button" value="1" class="on"/>
    <input type="button" value="2"/>
    <input type="button" value="3"/>
    <div style="display: block;">0001</div>
    <div>0002</div>
    <div>0003</div>
</div>

ev只能出現在事件函數中;return false 也要出現在事件函數中

  ---
    this._div.onmousedown = function(){
    This.fnDown()
    }
  --
    Drag.prototype.fnDown = function(ev){
        var ev = ev || event; 

    return false 
    }

//以上報錯;正確是:

  ---
    this._div.onmousedown = function(ev){ //事件函數
    var ev = ev || event; 
    This.fnDown(ev)
    return false 
    }
  --
    Drag.prototype.fnDown = function(ev){

    }



包裝對象;

    //包装对象 ;
    var str = 'hello'  //是类型,不是对像
    str.charAt(0)   //当调用方法时,基本类型会找到对象的包装对象类型,然后包装把所有的属性方法都给基本类型,然后包装对象消失;
    //包装对象送快递,送完后即有里面的东西
    str.indexOf('e')

//所以問題是:    console.log(typeof str); //string;不是对象;
//字符串怎么有方法 ? charAt(0)?
基本类型都有自己对应的包装对象:String Number Boolean; Array Date对象中的构造函数;这些类型怎么创建对象 ;

var str2 = new String('hello')
console.log(typeof str2) //這裏是obj了,即通過new創建的都是對象;
console.log(str.charAt(1))//所以有對象;

//String.prototype.chatAt = function(){}


當
var str = 'hello'  //這裏是字符串

str.charAt(0); //當字符串調方法時:基本類型會找到對應的包裝對像string對像,string下有原型方法 string.protype.charAt = function() {};

如何給字符串加方法?

String.prototype.lastValue = function(){
    return this.chatAt(this.lenght - 1)
}
var str3 = 'hello'
console.log( str3.laseValue() ) //o

注意:

var str = 'hello'
str.number = 10 ; //通过包装对象string添加,加完后包装对象消失

alert(str.number) //所以这里弹undefined ,如须使有效果须加在原型上:String.prototype.number = 10

如何給基本類型加屬性?
基本类型要加一个属性,到这里程序会找包装对象,然后在包装对象里创建一个对象,包装对象消失;然后再调用 str4.number时,其它会重新创建又一个对象,所以找不到是undefined; (没有加到原型里的情况;)

var str4  = 'hello'; 
str4.number = 10;
console.log(str4.number) //undefined;

當然如果通過new創建則是10,或直接加到原型 String.prototype.number = 10,也是10


原型鏈 _proto_ :【实例对象】与【原型】之间的连接,叫原型链
当a1调用num,基本a1是找不到的,找不到怎样----》再找原型链;_proto_

原型链的最外层是object;

    //实例对象与原型之间的连接,叫原型链
    function Aaa() {
        // this.num = 20;
    }
    //   Aaa.prototype.num = 10;  //Aaa.prototype即一个对象    //num即原型对象下的一个属性
    var a1 = new Aaa();                //实例对象
    Object.prototype.num = 30            
    console.log(a1.num);                                //之间的链接



面向對象的屬性:

hasownprototy:判斷屬性是否屬於 對象自身下面的屬性 [只有自己有,別人不能有的]

var arr = [];
    arr.num = 10;
Array.prototype.num2 = 20;
console.log(arr.hasOwnproperty('num')) //true;
console.log(arr.hasOwnproperty('num2')) //false,不是arr數組獨有;
function Bbb(){}

var b1 = new Bbb();
console.log(b1.hasOwnProoerty) ///究竟在哪;在原型链接下,object.prototype上,在顶部上;

console.log(b1.hasOwnProperty == Object.prototype.hasOwnProperty ) //true;

constructor: 查看對象構造函數,即由哪個函數構造出來的實例;

function Aaa(){}
var a1 = new Aaa();
console.log( a1.constructor ) //彈出本身的屬性,a1由哪個函數造出來的; function Aaa(){}

var arr2 = []
console.log( arr2.constructor ) //function Array() { [native code] } //私有方法看不到;

可以用來作判斷:

console.log( arr2.constructor == Array )  //true;


constructor怎麼來的?

當寫一個構造函數function Aaa(){ }
寫完後,即會自動生成: Aaa.prototype.constructor == Aaa 自動添加;

//當手動寫時,
var aa1 = new Aaa()
Aaa.prototype.constructor == Array; //一般不要去改,了解即可;

//則會自動生成的覆蓋了;
console.log(aa1.constructor == Array) //true;

<quoteblock>
只有constructor屬性才是程序自動生成的,每個函數都會生成,其他的不是 ;
</quoteblock>

//b1调用的其实不是自身的,而是最外层的;
console.log(b1.constructor.hasOwnProperty);


不經意改掉constructor情況;

function Ccc(){}
Ccc.prototype.num = 10;
Ccc.prototype.name = '小強'
Ccc.prototype.age = 20
console.log(c1.constructor); //function Ccc(){}

Ccc.prototype是一個對象,所以可寫成json形式:

Ccc.prototype = { //即把Ccc.prototype=  重新赋值,所以constructor会改
    name:'小強',
    age:20
}
var c1 = new Ccc();
console.log(c1.constructor)
 //function Object(){}找的就是json对应的constructor了,全覆盖上一条条自动生成的constructor

所以,constructor變成Object了,需要修正constructor指向,使之指回調用的函數;

    Ccc.prototype = {
        constructor : Ccc,
        name:'小明',
        age : 20
    }


for in 時,系統自動的屬性是for in不到的;
1、系統自添加的屬性;

function Ddd(){}
var d1 = new Ddd();
for(var attr in Ddd.prototype){
       console.log('能打印出來嗎?不能!')
}

2、自定義的屬性;

Ddd.prototype.name = 'abc';
for(var attr in Ddd.prototype){
        console.log('這裏是可打印出來的,即能找到;')
}

3、自定義的constructor屬性

Ddd.prototype.constructor = Aaa
for(var attr in Ddd.prototype){
        console.log(attr) //也不能打印出來;
}



instanceof運算符;
對象與構造函數在原型鏈接上是否有關係;

    function Eee(){}
    var e1 = new Eee()
    console.log(e1 instanceof Eee); //true;是否在同一个原型链接上;
    console.log(e1 instanceof Array); //false;是否在同一个原型链接上;
    console.log(e1 instanceof Object); //true;是否在同一个原型链接上;每一个对象最外层都是true; 任何对象 instanceof都为true;

所以,除constructor外;instanceof也可使類型判斷;

arr instanceof Array  //true;


类型判断三方法: constructor instanceof toString



問題:如何判斷一個變量是一個數組;
toString() Object方法;
toString在哪;系统对像下面都是自带的,自已写的对象都是通过原型链接找Object下面的;

var arr4 = []
console.log(arr4.toString) //可找到;function toString(){}
console.log(arr4.toString == Object.prototype.toString) //系統對象false;
function Fff(){}
var f1 = new Fff();
console.log(f1.toString) //toString在Object上;
console.log(f1.toString == Object.prototype.toString); //自已写的对象 true;

toString(),把对象转成字符串;

var arr5 = [1,2,3]
console.log(typeof arr5.toString())  //string
console.log(arr5.toString()); // [1,2,3]与数组一样的形式;

自己写可以需要写成自己的形式:

console.log('111' + typeof arr5);//还是Object,不会改变自身;
    Array.prototype.toString = function () {
        return this.join('+')
    }

    console.log(arr5.toString());
    '1+2+3'

進制轉換;

    var num6= 255;
    console.log(num6.toString(16)); //ff,转成16进制;
    console.log(num6.toString(2)); //11111111,转成2进制;

最重要的類型判斷;完美版;

var arr7 = []
    console.log(Object.prototype.toString.call(arr7)); //[object Array]
    var arr8 = {}
    console.log(Object.prototype.toString.call(arr8)); //[object Object]
    var arr9 = new Date()
    console.log(Object.prototype.toString.call(arr9)); //[object Date]
    var arr10 = new RegExp()
    console.log(Object.prototype.toString.call(arr10)); //[object RegExp]
    var arr11 = null;
    console.log(Object.prototype.toString.call(arr11)); //[object Null]

所以,判斷方法是:

console.log(Object.prototype.toString.call(arr7) == '[object Array]');

總結:判斷類型的三種方法,constructor,instanceof, toString.call()
前兩種在某些情況可能不行,如iframe

    window.onload = function () {
        var _f = document.createElement('iframe');
        document.body.appendChild(_f)
        var _farray = window.frames[0].Array //frames集合第0个,.Array找到iframe下面的Array,
        var arr = new _farray();//其实是跨页面了;

        console.log(arr.constructor == Array); //false 跨iframe里失效,但实际上确实是数组;
        console.log(arr instanceof Array); //false 也失效;
        console.log(Object.prototype.toString.call(arr) == '[object Array]');
        // true了;
    }

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>