可拖动菜单 【总结】

需求

应老罗的要求,做一个可拖动的长条形列表菜单。

这是原来的样子

进入编辑界面,它的编辑添加都不能实时更新,而且操作起来比较麻烦。

所以我估计一下应该有这些需求:

1.修改,取消,确认按钮

2.点击修改,菜单每一项都可以拖动,每一项都可以修改,每一项都可以删除

3.每一个父级都可添加一个子节点或添加一个子集合

4.点击取消,恢复到点击修改之前的状态

5.点击确认,保存这个状态,更新数据,返回数据给数据库

需求分析:

1.首先,菜单是从无到有的,从数据库获取数据后判断是空还是有的,如果是空,显示在界面上是一个添加按钮,这部分我还没做【未完成】

2.分析数据,数据得是有规定格式的json类型的数据,通过数据生成DOM结构,由于事先不知道有几层,所以用递归。

3.点击修改,修改之前应该保存当前状态,DOM的当前状态,数据的当前状态

4.每一项都有一个编辑、删除按钮,不能给每一项都添加这两个DOM节点,太费资源了,最后就是添加到所以节点的底部,鼠标hover的时候判断,应该修改那一项

  a.编辑、删除按钮按下后又分别有取消和确认两个选择

  b.整个菜单只有一个编辑按钮,只有一个删除按钮,鼠标hover到某一项,就把这两个按钮“拉”过来

5.拖动的实现,包括按下、按下后移动、鼠标抬起,三个步骤,DOM节点位置的变换,和数据位置的变换应该是在抬起的时候发生的

6.拖动的时候做一条提示线,提示用户当前是在哪里

实现思路:

首先,我希望,用户在使用的时候,其他人在使用我的代码的时候,可以简单的new一个使用就可以,这就意味这我要把这个需求写成OOP,由于我还不是很了解面向对象编程的方式,所以我的代码里只是简单的把功能分开,操作数据的我写在一个继承里,操作DOM的我写在一个继承里。

数据  -->  DOM的过程,如下:

createDOMtree:function(DataDOM){


//----------------------分析数据结构,生成节点树-------------------------//
function fn(v,ele){


if( !ele ){
var aUl = document.createElement(‘ul‘);
aUl.setAttribute(‘id‘,‘zdx_v0‘);
}


//---------------------------数组走这里------------------------//
if( Array.isArray(v) ){
//如果是数组
for(var i=0,len=v.length; i<len; i++){


//如果是数组
if( Array.isArray(v[i]) ){
fn(v[i]); //递归



//如果是对象
}else if( typeof v[i] === ‘object‘ ){


var aLi = document.createElement(‘li‘);
aLi.setAttribute(‘onoff‘,‘true‘);


//---------给父级li加个标识------------//
aLi.setAttribute(‘attr‘,‘liWrap‘);
//---------给父级li加个标识------end---//



//---------给最外层的li加个标识--------//
if( v[i].v1 ){
aLi.setAttribute(‘v‘,‘v1‘);
}
//---------给最外层的li加个标识----end--//



ele ? ele.appendChild(aLi) : aUl.appendChild(aLi);


var oUl = document.createElement(‘ul‘);
aLi.appendChild(oUl);


fn(v[i],oUl); //递归


//如果是字符串
}else{
var oLi = document.createElement(‘li‘),
oB = document.createElement(‘b‘),
txt = document.createTextNode(v[i]),
oI = document.createElement(‘i‘);


//-------阻止父级事件触发的开关-------------//
oLi.setAttribute(‘onoff‘,‘true‘);
//-------阻止父级事件触发的开关-------------//


//---------给普通li加个标识------------//
oLi.setAttribute(‘attr‘,‘li‘);
//---------给普通li加个标识------end---//



//--------小圆点-----------//
oI.setAttribute(‘class‘,‘iconP‘);
//--------小圆点-----------//



oLi.appendChild(oI);
oB.appendChild(txt);
oLi.appendChild(oB);


(ele) && ( ele.appendChild(oLi) );
(aUl) && ( aUl.appendChild(oLi) );
}
}
//---------------------------数组走这里-------------end-----------//


//---------------------------对象走这里---------------------------//
}else if( typeof v === ‘object‘ ){


//枚举对象每一项
for(var attr in v){


//如果是数组
if( Array.isArray(v[attr]) ){
fn(v[attr],ele); //递归



//如果算是对象
}else if( typeof v[attr] === ‘object‘ ){
fn(v[attr]); //递归


//如果是字符串
}else{


var oSpan = document.createElement(‘span‘),
oB = document.createElement(‘b‘),
txt = document.createTextNode(v[attr]),
oI = document.createElement(‘i‘);


//--------小圆点-----------//
oI.setAttribute(‘class‘,‘iconP‘);
oSpan.appendChild(oI);
//--------小圆点-----------//


oB.appendChild(txt);
oSpan.appendChild(oB);
ele.setAttribute(‘class‘,attr);
ele.appendChild(oSpan);
}
}
//---------------------------对象走这里-----------end-------------//



//---------------------字符串----------------//
}else{
//do someing
}
//---------------------字符串-------end-------//



return aUl;


}





//----------------------分析数据结构,生成节点树------------end-----------//


//-----生成按钮-----//
var oDiv = document.createElement(‘div‘);
oDiv.setAttribute(‘id‘,‘zdx_menu‘);


var btnWrap = document.createElement(‘div‘);
btnWrap.setAttribute(‘id‘,‘zdx_btnWrap‘)


var idNames = [‘zdx_cancel‘,‘zdx_submit‘,‘zdx_modify‘];
var btnNames = [‘取消‘,‘确定‘,‘修改‘];
var oA = null;


for(var i=0,iLen=idNames.length; i<iLen; i++){
oA = document.createElement(‘a‘);
oA.setAttribute(‘id‘,idNames[i]);
oA.appendChild(document.createTextNode(btnNames[i]));
btnWrap.appendChild(oA);
}
//-----生成按钮-----//



//-----包装节点树----//
oDiv.appendChild(btnWrap);
oDiv.appendChild(fn(DataDOM));
//-----包装节点树----//


//返回节点树
return oDiv;


},

 

洋洋洒洒一百多行,在创建节点的时候,顺便添加适当的class,id,来设置样式。

拖动的实现:我没有用网上找到的判断鼠标位置实时更新的方式,我通过给每个节点添加onmouseover事件,并把当前onmouseover到的节点实时保存起来,如果这时候释放鼠标,就会判断,判断鼠标位置是否超过hover到的节点高度的1/2,如果小于这个数,选中的节点放到hover前面,否则放在后面,这里简单调用一下insertBefore或insertAfter就可以了。

数据的更新:我采用的是相对的方式,这个节点相对于同一父级的第一个节点以0开始的第几个,以此父级,父级的父级,父级的父级的父级推,最终得到一个位置链数组,

arr = [1,2,3,4,5,3]; 这个链表示,第二章下的第三节下的第四节下的第五节下的第六节下的第四项。

难点:

拖动的实现

数据的更新

继承重用

难点解决方案:

拖动,本来是通过计算鼠标来“精确”拖动的,不过这样的方式在新增节点后就被破坏了,而且代码冗长逻辑复杂难以理解,后来利用onmouseover的方式,虽然给每一项都添加事件有些浪费,但好在灵活,代码量少,好理解,好拓展,所以就用这种方法了。

数据的更新,这个反而没想那么久,用相对的方式,获取数据的准确位置,目前开发阶段使用还未出现bug,如果有机会投入使用,这个数据位置的获取还得做得更好点。

继承重用,由于我刚学面向对象编程,这个继承重用我没有做得很好,在我的代码中出现了很多我觉得可以通过继承来重用的代码,但由于木已成舟,不宜大作改动,所以这个问题留到以后在解决吧

涉及的新知识:

json的字符串化和反字符串为json的两个方法,为了更新json数据而上网查的

JSON.parse( JSON.stringify( tarInfo[0][tarInfo[1]] ).replace(tarV,correctV) );

优化方向:

优化继承,实现更多的重用,将页面中阻止父级事件触发的代码换成【阻止冒泡】(如果可以的话)

用jQ减少代码量

优化我的getId.js

备注:

后期在写代码的时候,如果要和数据库交互的话一定要留点可操作的余地,其他没怎么说的了,写代码要有耐心。

/*
//试验数据
var arr = [

    {
        ‘v1‘:‘第一章‘,
        ‘data‘:[‘一章第1节‘,‘一章第2节‘,‘一章第3节‘,‘一章第4节‘,‘一章第5节‘]
    },

    {
        ‘v1‘:‘第二章‘,
        ‘data‘:[{

            ‘v2‘:‘二章第1节‘,
            ‘data‘:[‘第1节-1‘,‘第1节-2‘,‘第1节-3‘,‘第1节-4‘,‘第1节-5‘,‘第1节-6‘]

        },‘二章第2节‘,{

            ‘v2‘:‘二章第3节‘,
            ‘data‘:[‘第3节-1‘,‘第3节-2‘,{

                ‘v3‘:‘第3节-3‘,
                ‘data‘:[‘第3节-3-1‘,‘第3节-3-2‘,‘第3节-3-3‘,‘第3节-3-4‘,‘第3节-3-5‘]

            },{

                ‘v3‘:‘第3节-4‘,
                ‘data‘:[‘第4节-3-1‘,‘第4节-3-2‘,‘第4节-3-3‘,‘第4节-3-4‘,{

                    ‘v4‘:‘第4节-3-5‘,
                    ‘data‘:[‘第4节-3-5-1‘,‘第4节-3-5-2‘,‘第4节-3-5-3‘,‘第4节-3-5-4‘,‘第4节-3-5-5‘,‘第4节-3-5-6‘]

                }]

            },‘第3节-5‘]

        },‘二章第4节‘,‘二章第5节‘]
    },

    {
        ‘v1‘:‘第三章‘,
        ‘data‘:[‘三章第1节‘,‘三章第2节‘,‘三章第3节‘,‘三章第4节‘,‘三章第5节‘]
    },

    {
        ‘v1‘:‘第四章‘,
        ‘data‘:[‘四章第1节‘,‘四章第2节‘,‘四章第3节‘,‘四章第4节‘,‘四章第5节‘]
    },

    {
        ‘v1‘:‘第五章‘,
        ‘data‘:[‘五章第1节‘,‘五章第2节‘,‘五章第3节‘,‘五章第4节‘,{
            ‘v2‘:‘五-壹‘,
            ‘data‘:[‘五-壹-1‘,‘五-壹-2‘,‘五-壹-3‘,‘五-壹-4‘,‘五-壹-5‘,{
                ‘v3‘:‘五-壹-壹‘,
                ‘data‘:[‘五-壹-壹-1‘,‘五-壹-壹-2‘,‘五-壹-壹-3‘,‘五-壹-壹-4‘]
            }]
        },‘五章第5节‘,‘五章第6节‘,‘五章第7节‘,‘五章第8节asdfasdfasdfasdfasdfadsfasdf‘]
    },

];
*/

//实施继承功能的函数
function extendByObj( child , parent , propertys ){

    var F = function(){};
    F.prototype = parent.prototype;

    child.prototype = new F();

    for(var attr in propertys){
        child.prototype[attr] = propertys[attr];
    }

    child.prototype.constructor = child;

}

//MenuData:操作数据,第一层继承,继承Object
function MenuData(data){}
MenuData.prototype = {

    //---------------------------------插入新的数据------------------------------------------------//
    insertNewData:function(li,t){

        var targetArr = this.traceDataByDOM(this.data,t);
        var tLiData = null;
        var tV = null;
        var correctV = null;

        if( li.getAttribute(‘attr‘) === ‘li‘ ){
            tLiData = li.getElementsByTagName(‘b‘)[0].innerHTML;
        }else if( li.getAttribute(‘attr‘) === ‘liWrap‘ ){

            for( var attr in targetArr[2] ){
                ( typeof targetArr[2][attr] === ‘string‘ ) && ( tV = attr );
            }

            // v的值应该比包含它的数组+1
            correctV = tV[0] + ( parseInt(tV[1]) + 1 );

            tLiData = {
                [correctV] : (li.getElementsByTagName(‘span‘)[0].getElementsByTagName(‘b‘)[0].innerHTML),
                data:[]
            };

        }else{
            tLiData = ‘未能识别数据‘;
        }

        targetArr[0].push( tLiData );

    },
    //---------------------------------插入新的数据------------------------------------------------//

    //-------------------------------修改数据-----------------------------------------------//
    modifyData:function(newValue,li){

        var targetArr = this.traceDataByDOM( this.data , li );

        targetArr[0][targetArr[1]] = newValue;

        console.log( this.data );

    },
    //-------------------------------修改数据-----------------------------------------------//

    //------------------------------删除数据--------------------------------------------------//
    deleteData:function(li){

        var targetArr = this.traceDataByDOM(this.data,li);

        targetArr[0].splice( targetArr[1] , 1 );

        console.log( this.data );

    },
    //------------------------------删除数据--------------------------------------------------//

    //------------------------根据DOM修改其在数据中对应的位置-------------------------------//
    changeOfPositionForData:function( target , t , insertOnOff ){
        //target是选中项,t是target在DOM上的新位置

        console.log(t);
        var tarInfo = this.traceDataByDOM( this.data , target );
        var tInfo = this.traceDataByDOM( this.data , t );

        // 值调整
        ( insertOnOff === ‘after‘ ) && ( tInfo[1] = tInfo[1]+1 );
        ( tarInfo[1] > tInfo[1] && tarInfo[1] == tInfo[1] ) && ( tarInfo[1] = tarInfo[1]+1 );

        var tarV = null;
        var tV = null;
        var correctV = null;

        if( typeof tarInfo[2] === ‘object‘ ){

            // tarInfo[0][tarInfo[1]]指向的是选中的对象
            // tarInfo[2]指向的是包含这个对象的数组
            // tInfo[2]指向的是包含目标项数组

            // 通过for in找到v值
            for( var attr in tarInfo[0][tarInfo[1]] ){
                ( typeof tarInfo[0][tarInfo[1]][attr] === ‘string‘ ) && ( tarV = attr );
            }

            // 通过for in找到v值
            for( var attr in tInfo[2] ){
                ( typeof tInfo[2][attr] === ‘string‘ ) && ( tV = attr );
            }

            // v的值应该比包含它的数组+1
            correctV = tV[0] + ( parseInt(tV[1]) + 1 );

            // 利用JSON.stringify将要改动的json变换成字符串,利用replace替换v的值,再反向回json
            tarInfo[0][tarInfo[1]] =
                JSON.parse(
                    JSON.stringify( tarInfo[0][tarInfo[1]] ).replace(tarV,correctV)
                );

        }

        tInfo[0].splice( tInfo[1] , 0 , tarInfo[0][tarInfo[1]] );
        tarInfo[0].splice( [tarInfo[1]] , 1 );

        console.log(this.data)

    },
    //------------------------根据DOM修改其在数据中对应的位置-------------------------------//

    //------用于找到tNode在数组中的位置的父级,以及具体位置---------//
    traceDataByDOM:function(arr,tNode){

        var tNodePos = this.generatePosChain(tNode);
        var targetParent = arr[ tNodePos[0] ];
        var targetPos = tNodePos[tNodePos.length-1];

        for(var i=1,iLen=tNodePos.length-1; i<iLen; i++){

            targetParent = targetParent.data[ tNodePos[i] ];

        }

        return [ targetParent.data , targetPos , targetParent ];

    },
    //------用于找到tNode在数组中的位置的父级,以及具体位置---------//

    //----tNode的在数组中的具体位置----//
    generatePosChain(tNode){

        var chain = [];
        var prePos = tNode;
        var cnt = 0;
        var tPreSibling = null;

        while( prePos ){

            tPreSibling = prePos.previousSibling;

            while( tPreSibling ){
                if( tPreSibling.getAttribute(‘attr‘) === ‘li‘ || tPreSibling.getAttribute(‘attr‘) === ‘liWrap‘ ){
                    cnt++;
                }
                tPreSibling = tPreSibling.previousSibling;

            }
            chain.push( cnt );
            cnt = 0;
            prePos = prePos.parentNode.parentNode;

            if( prePos.nodeName === ‘DIV‘ ){
                break;
            }
        }
        return chain.reverse();
    }
    //----tNode的在数组中的具体位置----//

};
MenuData.prototype.constructor = MenuData;

//DataToDOM:根据数据渲染DOM,根据DOM更新数据
function DataToDOM(){}
extendByObj( DataToDOM , MenuData , {

    /*
    创建DOM节点树方法
    插入DOM节点树到页面的方法
    移动节点的方法
    删除节点的方法
    */
    createDOMtree:function(DataDOM){

        //----------------------分析数据结构,生成节点树-------------------------//
        function fn(v,ele){

            if( !ele ){
                var aUl = document.createElement(‘ul‘);
                aUl.setAttribute(‘id‘,‘zdx_v0‘);
            }

            //---------------------------数组走这里------------------------//
            if( Array.isArray(v) ){
                //如果是数组
                for(var i=0,len=v.length; i<len; i++){

                    //如果是数组
                    if( Array.isArray(v[i]) ){
                        fn(v[i]);    //递归

                    //如果是对象
                    }else if( typeof v[i] === ‘object‘ ){

                        var aLi = document.createElement(‘li‘);
                        aLi.setAttribute(‘onoff‘,‘true‘);

                        //---------给父级li加个标识------------//
                        aLi.setAttribute(‘attr‘,‘liWrap‘);
                        //---------给父级li加个标识------end---//

                        //---------给最外层的li加个标识--------//
                        if( v[i].v1 ){
                            aLi.setAttribute(‘v‘,‘v1‘);
                        }
                        //---------给最外层的li加个标识----end--//

                        ele ? ele.appendChild(aLi) : aUl.appendChild(aLi);

                        var oUl = document.createElement(‘ul‘);
                        aLi.appendChild(oUl);

                        fn(v[i],oUl);    //递归

                    //如果是字符串
                    }else{
                        var oLi = document.createElement(‘li‘),
                            oB = document.createElement(‘b‘),
                            txt = document.createTextNode(v[i]),
                            oI = document.createElement(‘i‘);

                        //-------阻止父级事件触发的开关-------------//
                        oLi.setAttribute(‘onoff‘,‘true‘);
                        //-------阻止父级事件触发的开关-------------//

                        //---------给普通li加个标识------------//
                        oLi.setAttribute(‘attr‘,‘li‘);
                        //---------给普通li加个标识------end---//

                        //--------小圆点-----------//
                        oI.setAttribute(‘class‘,‘iconP‘);
                        //--------小圆点-----------//

                        oLi.appendChild(oI);
                        oB.appendChild(txt);
                        oLi.appendChild(oB);

                        (ele) && ( ele.appendChild(oLi) );
                        (aUl) && ( aUl.appendChild(oLi) );
                    }
                }
            //---------------------------数组走这里-------------end-----------//

            //---------------------------对象走这里---------------------------//
            }else if( typeof v === ‘object‘ ){

                //枚举对象每一项
                for(var attr in v){

                    //如果是数组
                    if( Array.isArray(v[attr]) ){
                        fn(v[attr],ele);        //递归

                    //如果算是对象
                    }else if( typeof v[attr] === ‘object‘ ){
                        fn(v[attr]);        //递归

                    //如果是字符串
                    }else{

                        var oSpan = document.createElement(‘span‘),
                            oB = document.createElement(‘b‘),
                            txt = document.createTextNode(v[attr]),
                            oI = document.createElement(‘i‘);

                        //--------小圆点-----------//
                        oI.setAttribute(‘class‘,‘iconP‘);
                        oSpan.appendChild(oI);
                        //--------小圆点-----------//

                        oB.appendChild(txt);
                        oSpan.appendChild(oB);
                        ele.setAttribute(‘class‘,attr);
                        ele.appendChild(oSpan);
                    }
                }
            //---------------------------对象走这里-----------end-------------//

            //---------------------字符串----------------//
            }else{
                //do someing
            }
            //---------------------字符串-------end-------//

            return aUl;

        }

        //----------------------分析数据结构,生成节点树------------end-----------//

        //-----生成按钮-----//
        var oDiv = document.createElement(‘div‘);
        oDiv.setAttribute(‘id‘,‘zdx_menu‘);

        var btnWrap = document.createElement(‘div‘);
        btnWrap.setAttribute(‘id‘,‘zdx_btnWrap‘)

        var idNames = [‘zdx_cancel‘,‘zdx_submit‘,‘zdx_modify‘];
        var btnNames = [‘取消‘,‘确定‘,‘修改‘];
        var oA = null;

        for(var i=0,iLen=idNames.length; i<iLen; i++){
            oA = document.createElement(‘a‘);
            oA.setAttribute(‘id‘,idNames[i]);
            oA.appendChild(document.createTextNode(btnNames[i]));
            btnWrap.appendChild(oA);
        }
        //-----生成按钮-----//

        //-----包装节点树----//
        oDiv.appendChild(btnWrap);
        oDiv.appendChild(fn(DataDOM));
        //-----包装节点树----//

        //返回节点树
        return oDiv;

    },

    //插入节点树到界面里
    insertDOMtreeTo:function(parent,DOMtree){

        parent.appendChild(DOMtree);

    },

    //删除节点
    delNode:function(tNode){
        tNode.parentNode.removeChild(tNode);
    },

    //根据DOM更新数据
    renewAttr:function(tNodeParent,nowNodeParent){
        var oriLi = tNodeParent.getElementsByTagName(‘li‘),
            nowLi = nowNodeParent.getElementsByTagName(‘li‘);

        var len = oriLi.length > nowLi.length ? oriLi.length : nowLi.length,
            o = null,
            n = null;

        for(var i=0; i<len; i++){
            o = oriLi[i];
            n = nowLi[i];

            if( o ){
                o.setAttribute(‘cid‘,i);
            }
            if( n ){
                n.setAttribute(‘cid‘,i);
            }
        }
    },

    value:function(){
        return this.data;
    }

});

//Interaction:交互,实现拖拽
function Interaction(parent,data){

    this.data = data;

    this.DOMBackup = null;

    this.DataBackup = null;

    this.DOMtree = this.createDOMtree(data,this.colors);

    this.insertDOMtreeTo(parent,this.DOMtree);

    this.btn();

    this.redact();

    this.roll(‘init‘);

    this.value

}

extendByObj( Interaction , DataToDOM , {

    //编辑、删除、确认编辑、取消编辑、确认删除、取消删除按钮
    redact:function(){

        var zdx_v0 = $(‘zdx_v0‘);
        var oI = null;
        var oITxtNode = null;

        var cssNames = [‘fa fa-pencil-square-o‘,‘fa fa-trash-o‘,‘fa fa-check‘,‘fa fa-times‘,‘‘,‘‘];
        var idNames = [‘modifyIcon‘,‘deleteIcon‘,‘checkIcon‘,‘repealIcon‘,‘tDeleteCheck‘,‘tDeleteRepeal‘];
        var btnTitles = [‘编辑‘,‘删除‘,‘确认编辑‘,‘取消编辑‘,‘确认删除‘,‘取消删除‘];
        var oITxt = [‘‘,‘‘,‘‘,‘‘,‘确认删除‘,‘取消‘];

        for(var i=0,iLen=idNames.length; i<iLen; i++){

            oI = document.createElement(‘i‘);

            cssNames[i]        &&        oI.setAttribute(‘class‘,cssNames[i]);
            btnTitles[i]     &&        oI.setAttribute(‘title‘,btnTitles[i]);
            true            &&        oI.setAttribute(‘attr‘,‘icon‘);
            idNames[i]        &&        oI.setAttribute(‘id‘,idNames[i]);
            oITxt[i]        &&        ( oITxtNode = document.createTextNode(oITxt[i]) );
            oITxtNode        &&        oI.appendChild( oITxtNode );
            oITxtNode        &&        (oITxtNode = null);
            zdx_v0            &&        zdx_v0.appendChild(oI);

        }

    },

    //修改,取消,确认按钮
    btn:function(){

        var cancel = $(‘zdx_cancel‘);
        var submit = $(‘zdx_submit‘);
        var modify = $(‘zdx_modify‘);
        var zdx_v0 = null;
        var liWraps = null;
        var zdx_menu = $(‘zdx_menu‘);
        var _this = this;
        var addBtn = getAttrEle( ‘li‘ , zdx_v0 , ‘attr‘ , ‘btnChild‘ );

        //--------------------------------------修改事件-------------------------------------------//
        modify.onclick = function(){

            //编辑前备份当前节点的状态
            _this.DOMBackup = $(‘zdx_v0‘).cloneNode(true);
            _this.DataBackup = copyData( _this.data );

            //----隐藏当前按钮和删除按钮----//
            this.style.display = ‘none‘;
            cancel.style.display = ‘block‘;
            submit.style.display = ‘block‘;
            //----隐藏当前按钮和删除按钮----//

            //--即时获列表,因为点击取消再次点击修改获得的列表是上一次的,所以...---//
            zdx_v0 = $(‘zdx_v0‘);
            //--即时获列表---//

            //调用drag方法,使所以按li有相关功能
            _this.drag(true);

            //-----------点击的时候新增供添加的按钮---------//
            liWraps = getAttrEle( ‘li‘ , zdx_v0 , ‘attr‘ , ‘liWrap‘ );
            for(var q=0,qLen=liWraps.length; q<qLen; q++){
                _this.btnForCreat( liWraps[q] );
            }
            //-----------点击的时候新增供添加的按钮---------//

            //---重头初始化卷起收起方法----//
            _this.roll(‘init‘);
            //---重头初始化卷起收起方法----//

        }
        //--------------------------------------修改事件-------------------------------------------//

        //--------------------------------------取消事件-------------------------------------------//
        cancel.onclick = function(){

            submit.style.display = ‘none‘;
            cancel.style.display = ‘none‘;
            modify.style.display = ‘block‘;

            //暴力取消——删除掉原来的,用备份的
            zdx_menu.removeChild(zdx_v0);
            zdx_menu.appendChild( _this.DOMBackup );
            _this.data = _this.DataBackup;

            //---找到所以的新增按钮并删除---//
            zdx_v0 = $(‘zdx_v0‘);
            addBtn = getAttrEle( ‘li‘ , zdx_v0 , ‘class‘ , ‘addNewNode‘ );

            for(var i=0,iLen=addBtn.length; i<iLen; i++){
                addBtn[i].parentNode.removeChild(addBtn[i]);
            }
            //---找到所以的新增按钮并删除---//

            //---重头初始化卷起收起方法----//
            _this.roll(‘init‘);
            //---重头初始化卷起收起方法----//

        }
        //--------------------------------------取消事件-------------------------------------------//

        //--------------------------------------确认事件-------------------------------------------//
        submit.onclick = function(){

            submit.style.display = ‘none‘;
            cancel.style.display = ‘none‘;
            modify.style.display = ‘block‘;

            //调用drag并传入false,使所有的功能失效
            _this.drag(false);

            //---找到所以的新增按钮并删除---//
            zdx_v0 = $(‘zdx_v0‘);
            addBtn = getAttrEle( ‘li‘ , zdx_v0 , ‘class‘ , ‘addNewNode‘ );

            for(var i=0,iLen=addBtn.length; i<iLen; i++){
                addBtn[i].parentNode.removeChild(addBtn[i]);
            }
            //---找到所以的新增按钮并删除---//

        }
        //--------------------------------------确认事件-------------------------------------------//

    },

    //添加新的父节点,添加新的子节点按钮
    //--------------------用于添加两个按钮,接收一个liWrap的li,并添加到其最后一个li后面-----------------//
    btnForCreat:function(liWrap){

        var oLi = null;
        var oI = null;
        var oB = null;
        var oBTxt = null;
        var oInput = null;
        var target = null;
        var oIcon = null;
        var txt = [‘添加新的父节点‘,‘添加新的子节点‘];
        var ids = [‘btn-parent‘,‘btn-child‘];
        var attrs = [‘btnParent‘,‘btnChild‘];

        //找到最后一个li
        target = liWrap.getElementsByTagName(‘ul‘)[0].lastElementChild;

        for(var j=0; j<2; j++){

            oLi = document.createElement(‘li‘);
            oB = document.createElement(‘b‘);
            oBTxt = document.createTextNode(txt[j]);
            oInput = document.createElement(‘input‘);
            oIcon = document.createElement(‘i‘);

            oLi.setAttribute(‘class‘,‘addNewNode‘);
            oLi.setAttribute(‘attr‘,attrs[j]);
            oLi.setAttribute(‘onoff‘,‘true‘);
            oIcon.setAttribute(‘class‘,‘fa fa-plus oIcon‘);
            oInput.setAttribute(‘class‘,‘oInput‘);
            oInput.style.display = ‘none‘;

            oLi.appendChild(oIcon);
            oB.appendChild(oBTxt);
            oLi.appendChild(oB);
            oLi.appendChild(oInput);

            //添加到最后一个li后面
            insertAfter(oLi,target);

        }

        //调用按钮事件绑定方法
        this.bindCreateNodeEvent();

        //调用drag方法,主要是在drag里面有一些判定,判定这两个按钮不能被拖动,没有mouseover事件
        this.drag(true);
        return;

    },
    //--------------------用于添加两个按钮----------------------------------------------------------//

    //给添加按钮绑定事件
    bindCreateNodeEvent:function(){

        var _this = this;
        var zdx_v0 = $(‘zdx_v0‘);

        //-----每次调用都找出页面上所有的添加按钮------//
        var btnChilds = getAttrEle( ‘li‘ , zdx_v0 , ‘attr‘ , ‘btnChild‘ );
        var btnParents = getAttrEle( ‘li‘ , zdx_v0 , ‘attr‘ , ‘btnParent‘ );
        //-----每次调用都找出页面上所有的添加按钮------//

        var oLi = null;
        var oUl = null;
        var oSpan = null;
        var oSpanTxt = null;
        var oI = null;
        var oB = null;
        var oBTxt = null;
        var tGrade = 0;

        //---把按钮需要绑定的事件封装成函数-----------------------------------------------------//
        function fn(type,target){

            oLi = document.createElement(‘li‘);
            oI = document.createElement(‘i‘);
            oB = document.createElement(‘b‘);
            oI.setAttribute(‘class‘,‘iconP‘);
            oLi.appendChild(oI);

            //如果是“小”按钮,只添加一个新的li在其前面
            if(type == ‘btnChilds‘){

                oBTxt = document.createTextNode(‘未命名子节点‘);
                oLi.setAttribute(‘onoff‘,‘true‘);
                oLi.setAttribute(‘attr‘,‘li‘);

                oB.appendChild(oBTxt);
                oLi.appendChild(oB);
                // target是按钮本身,此刻的target是“添加新的节点”的按钮,新建的单个li插入到这个按钮前面
                insertBefore(oLi,target);
                _this.insertNewData( oLi , target.previousSibling );

            //如果是“大”按钮,则需要,新增一个liWrap的li,里面也需要两个用来添加节点的按钮
            }else if( type == ‘btnParents‘ ){

                oUl = document.createElement(‘ul‘);
                oSpan = document.createElement(‘span‘);
                oBTxt = document.createTextNode(‘未命名父节点‘);

                //需要给新的liWrap的li下的ul设一个等级
                tGrade = ‘v‘ + (
                    parseInt(
                        getParent(target,‘UL‘).getAttribute(‘class‘)[1] ) + 1
                    );

                oLi.setAttribute(‘attr‘,‘liWrap‘);
                oLi.setAttribute(‘onoff‘,‘true‘);
                oUl.setAttribute(‘class‘,tGrade);

                oB.appendChild(oBTxt);
                oSpan.appendChild(oI);
                oSpan.appendChild(oB);
                oUl.appendChild(oSpan);
                oLi.appendChild(oUl);

                //给新建的liWrap插入两个用于添加节点的按钮
                _this.btnForCreat(oLi);

                //将他新建的liWrap插入到正确位置
                insertBefore(oLi,target.previousSibling);
                _this.insertNewData( oLi , target.previousSibling.previousSibling );

            }

            // 需要将新的节点“纳入”到整体中,调用drag,主要是它会遍历所有的节点
            _this.drag(true);

        }
        //---把按钮需要绑定的事件封装成函数-----------------------------------------------------//

        for(var i=0,iLen=btnChilds.length; i<iLen; i++){

            btnChilds[i].onclick = function(){
                fn(‘btnChilds‘,this);
            }

            btnParents[i].onclick = function(){
                fn(‘btnParents‘,this);
                //需要给新增的liWrap里的添加节点的按钮绑定事件,调用一遍当前方法,传入这个新建的liWrap
                _this.bindCreateNodeEvent();
            }

        }

    },

    //实现,拖动,编辑,删除功能
    drag:function(onOff){
        //onoff为true:开启编辑功能
        //onoff为false:关闭编辑功能

        //全局this
        var _this = this;

        //基本
        var zdx_v0 = $(‘zdx_v0‘);
        var allEle = zdx_v0.getElementsByTagName(‘li‘);
        var allSpan = zdx_v0.getElementsByTagName(‘span‘);

        //鼠标hover
        var t = null;
        var markList = [];
        var tParent = null;
        var oriH = null;
        var target = null;

        //提示线
        var aimLine = $(‘aimLine‘);
        var aimLinePop = null;
        var aimLinePopTxt = null;
        var top = null;
        var aimT = 0;

        //编辑,删除节点获得
        // iconNodes[0] = $(‘modifyIcon‘),
        // tDelete = $(‘deleteIcon‘),
        // tCheck = $(‘checkIcon‘),
        // tRepeal = $(‘repealIcon‘),
        // tDeleteCheck = $(‘tDeleteCheck‘),
        // tDeleteRepeal = $(‘tDeleteRepeal‘)
        var iconNodes = [
            $(‘modifyIcon‘),
            $(‘deleteIcon‘),
            $(‘checkIcon‘),
            $(‘repealIcon‘),
            $(‘tDeleteCheck‘),
            $(‘tDeleteRepeal‘)
        ];

        //编辑,删除节点位置
        var redactPos = null;

        //编辑输入框
        var oInput = null;
        var oriInput = null;

        //辅助变量
        var insertOnOff = null;
        var eB = null;
        var modifyOnOff = false;
        var moveAble = true;
        iconNodes[0].onOff = true;
        iconNodes[1].onOff = true;

        //把上一次留下的提示线删了
        if(aimLine){
            aimLine.parentNode.removeChild(aimLine);
        }

        for(var i=0,iLen=allEle.length; i<iLen; i++){

            allEle[i].onmouseover = function(e){
                //是否开启此功能,通过再次给每个li绑定事件的机会,让它们绑定一个空
                if(onOff === false){
                    return;
                }

                //-----------------阻止父li的mouseover事件的触发----------后期用监听改进------------------//
                tParent = getParent(this,‘LI‘);

                if( this.getAttribute(‘onoff‘) === ‘true‘ ){
                    //将取得的正确的this保存下来
                    t = this;
                    if( tParent ){
                        tParent.setAttribute(‘onoff‘,‘false‘);
                        markList.push( tParent );
                    }

                }else{

                    if( tParent ){
                        tParent.setAttribute(‘onoff‘,‘false‘);
                        markList.push( tParent );
                    }else{
                        //若tParent为空,说明再往上没有li了,for循环将修改过的li属性再恢复
                        for( var i=0,iLen=markList.length; i<iLen; i++ ){
                            markList[i].setAttribute(‘onoff‘,‘true‘);
                        }

                    }
                    return;
                }
                //-----------------阻止父li的mouseover事件的触发----------end------------------//

                //b节点,存放字符串的节点
                eB = t.getElementsByTagName(‘b‘)[0];

                //---------------------设置“编辑”、“删除”两个按钮的位置-------------------------//
                redactPos = offsetToBODY(t) - offsetToBODY(zdx_v0) + 5;

                // modifyOnOff:编辑,或删除状态开启,隐藏这两个按钮,否则显示
                if( !modifyOnOff ){

                    if( t.getAttribute(‘class‘) === ‘addNewNode‘ ){
                        iconNodes[0].style.display = ‘none‘;
                        iconNodes[1].style.display = ‘none‘;
                    }else{
                        iconNodes[0].style.display = ‘block‘;
                        iconNodes[1].style.display = ‘block‘;
                    }
                }

                if(moveAble){

                    for(var q=0,qLen=iconNodes.length; q<qLen; q++){
                        iconNodes[q].style.top = redactPos + ‘px‘;

                        if( t.getAttribute(‘attr‘) === ‘liWrap‘ && t.getAttribute(‘v‘) === ‘v1‘ ){
                            iconNodes[q].style.top = redactPos + 9 + ‘px‘;
                        }

                    }

                }
                //---------------------设置“编辑”、“删除”、“添加”两个按钮的位置-------------------------//

                iconNodes[1].onclick = function(){

                    //------点击禁止按钮移动---------//
                    moveAble = false;
                    //------点击禁止按钮移动---------//

                    modifyOnOff = true;
                    iconNodes[1].style.display = ‘none‘;
                    iconNodes[0].style.display = ‘none‘;

                    iconNodes[4].style.display = ‘block‘;
                    iconNodes[5].style.display = ‘block‘;

                    if(eB.parentNode.nodeName === ‘SPAN‘){
                        eB.style.color = ‘#ffc3ce‘;
                    }

                    if(eB.parentNode.nodeName === ‘LI‘){
                        eB.style.color = ‘#dcdcdc‘;
                    }

                }

                iconNodes[0].onclick = function(){

                    //------点击禁止按钮移动---------//
                    moveAble = false;
                    //------点击禁止按钮移动---------//

                    //------隐藏按钮----------//
                    iconNodes[0].style.display = ‘none‘;
                    iconNodes[1].style.display = ‘none‘;
                    //------隐藏按钮----------//

                    //-------显示另一组按钮---------//
                    iconNodes[2].style.display = ‘block‘;
                    iconNodes[3].style.display = ‘block‘;
                    //-------显示另一组按钮---------//

                    //编辑状态开启
                    modifyOnOff = true;

                    //原文本获取
                    eB.style.opacity = 0;
                    oriInput = eB.innerHTML;

                    //插入输入框
                    oInput = document.createElement(‘input‘);
                    oInput.setAttribute(‘class‘,‘oInput‘);
                    oInput.value = ‘点击此处输入内容‘;

                    insertAfter( oInput , eB );
                }

                iconNodes[0].onmousedown = function(){
                    iconNodes[0].onOff = false;
                }

                iconNodes[1].onmousedown = function(){
                    iconNodes[1].onOff = false;
                }

                //-----------输入框获取焦点、失去焦点事件-------------//
                if(oInput){
                    oInput.onfocus = function(){
                        if(oInput.value === ‘点击此处输入内容‘){
                            oInput.value = ‘‘;
                        }
                    }

                    oInput.onblur = function(){
                        if(oInput.value === ‘‘){
                            oInput.value = ‘点击此处输入内容‘;
                        }
                    }
                }
                //-----------输入框获取焦点、失去焦点事件-------------//

                //------------确定输入内容-------------------//
                iconNodes[2].onclick = function(){

                    iconNodes[2].style.display = ‘none‘;
                    iconNodes[3].style.display = ‘none‘;

                    iconNodes[0].style.display = ‘block‘;
                    iconNodes[1].style.display = ‘block‘;

                    if( oInput.value != oriInput && oInput.value != ‘‘ && oInput.value != ‘点击此处输入内容‘ ){
                        eB.innerHTML = oInput.value;
                        // 调用修改数据方法
                        _this.modifyData( oInput.value , oInput.parentNode );
                    }

                    oInput.parentNode.removeChild(oInput);
                    eB.style.opacity = 1;

                    modifyOnOff = false;
                    moveAble = true;
                }

                //------------确定输入内容-------------------//

                //------------取消输入内容-------------------//
                iconNodes[3].onclick = function(){

                    iconNodes[2].style.display = ‘none‘;
                    iconNodes[3].style.display = ‘none‘;

                    iconNodes[0].style.display = ‘block‘;
                    iconNodes[1].style.display = ‘block‘;

                    oInput.parentNode.removeChild(oInput);

                    eB.innerHTML = oriInput;
                    eB.style.opacity = 1;
                    oriInput = null;

                    modifyOnOff = false;
                    moveAble = true;
                }
                //------------取消输入内容-------------------//

                //------------确定删除内容-------------------//
                iconNodes[4].onclick = function(){
                    iconNodes[4].style.display = ‘none‘;
                    iconNodes[5].style.display = ‘none‘;

                    iconNodes[0].style.display = ‘block‘;
                    iconNodes[1].style.display = ‘block‘;

                    modifyOnOff = false;
                    moveAble = true;

                    _this.deleteData(t);
                    t.parentNode.removeChild(t);

                }
                //------------确定删除内容-------------------//

                //------------取消删除内容-------------------//
                iconNodes[5].onclick = function(){
                    iconNodes[4].style.display = ‘none‘;
                    iconNodes[5].style.display = ‘none‘;

                    iconNodes[0].style.display = ‘block‘;
                    iconNodes[1].style.display = ‘block‘;

                    if(eB.parentNode.nodeName === ‘SPAN‘){
                        eB.style.color = ‘‘;
                    }

                    if(eB.parentNode.nodeName === ‘LI‘){
                        eB.style.color = ‘‘;
                    }

                    modifyOnOff = false;
                    moveAble = true;

                }
                //------------取消删除内容-------------------//

            }    //allEle[i].onmouseover结束

            allEle[i].onmouseout = function(){

                if(!moveAble){
                    return;
                }

                if( onOff === false ){
                    return;
                }

                //-----------防止闪烁-----------------------//
                iconNodes[0].onmouseover = function(){
                    iconNodes[0].style.display = ‘block‘;
                    iconNodes[1].style.display = ‘block‘;
                }

                iconNodes[1].onmouseover = function(){
                    iconNodes[0].style.display = ‘block‘;
                    iconNodes[1].style.display = ‘block‘;
                }
                //-----------防止闪烁----------end----------//

            }    //allEle[i].onmouseout结束

            allEle[i].onmousedown = function(e){

                //---------zdx_modify控制的开关---------------//
                if(onOff === false){
                    return;
                }
                //---------由zdx_modify控制的开关---------------//

                //---------由编辑、删除、确定编辑、取消编辑、确定删除、取消删除控制的开关--------//
                if(!moveAble){
                    return;
                }
                //---------由编辑、删除、确定编辑、取消编辑、确定删除、取消删除控制的开关--------//

                //------注意事项-----//
                /*
                由于界面上所有的li都有绑上事件,
                且这些有事件的li还有嵌套关系,
                在chrome里点击的时候是被点击的li
                先执行事件再执行父级li,所以,我
                写了一个阻止父级li执行事件的判断,
                就是利用自定义属性定义的开关,然后
                在不允许执行事件的父级li里提前return掉。
                这里可能有个隐藏的坑,就是我所有的
                变量都定义在最外层,在阻止父级判断里
                用到的变量最终的值取决于判断的执行和
                最后一个父级li执行完毕后赋予的值,所以
                要小心,不要在【阻止父级li的判断】里随意
                保存重要的值!!!
                */

                //-----------------阻止父li的mouseover事件的触发----------后期用监听改进------------------//
                tParent = getParent(this,‘LI‘);

                if( this.getAttribute(‘onoff‘) === ‘true‘ ){
                    //将取得的正确的this保存下来
                    target = this;

                    if(tParent){
                        tParent.setAttribute(‘onoff‘,‘false‘);
                        markList.push( tParent );
                    }

                }else{

                    if( tParent ){
                        tParent.setAttribute(‘onoff‘,‘false‘);
                        markList.push( tParent );
                    }else{
                        //若tParent为空,说明再往上没有li了,for循环将修改过的li属性再恢复
                        for( var i=0,iLen=markList.length; i<iLen; i++ ){
                            markList[i].setAttribute(‘onoff‘,‘true‘);
                        }

                    }
                    return;
                }
                //-----------------阻止父li的mouseover事件的触发----------end------------------//

                //----------------编辑按钮、或删除按钮被点中不允许移动节点,创建提示线-----------//
                if( !iconNodes[0].onOff || !iconNodes[1].onOff ){
                    iconNodes[0].onOff = true;
                    iconNodes[1].onOff = true;
                    return;
                }
                //----------------编辑按钮、或删除按钮被点中不允许移动节点,创建提示线-----------//

                //------判断是不是添加节点的按钮--------//

                if(t.getAttribute(‘class‘) === ‘addNewNode‘){
                    return;
                }

                //------判断是不是添加节点的按钮--------//

                //-----------------创建一条提示线,作为到className为zdx_v0的最后一个子节点------------//
                if( !$(‘aimLine‘) ){
                    aimLine = document.createElement(‘div‘);
                    aimLine.setAttribute(‘id‘,‘aimLine‘);

                    aimLinePop = document.createElement(‘p‘);
                    aimLinePop.setAttribute(‘id‘,‘aimLinePop‘);

                    aimLine.appendChild(aimLinePop);
                    zdx_v0.appendChild(aimLine);

                    aimLine = $(‘aimLine‘);
                    aimLinePop = $(‘aimLinePop‘);

                }
                aimLine.style.display = ‘block‘;
                //-----------------创建一条提示线,作为到className为zdx_v0的最后一个子节点-----end----//

                //----------------高亮选中项---------------//
                target.style.background = ‘#ffd4dc‘;
                //----------------高亮选中项-------end-----//

                zdx_v0.onmousemove = function(e){

                    //----------加工一下t,就mouseover获得的t而言,我们只需要单个的li或span-----------------//
                    if( t.getElementsByTagName(‘li‘).length > 0 ){
                        t = t.getElementsByTagName(‘span‘)[0];
                    }

                    tH = getStyle(t,‘height‘,true);
                    //----------加工一下t,就mouseover获得的t而言,我们只需要单个的li或span------end--------//

                    //----------top始终相对于li计算-----------------//
                    top = e.clientY - offsetToBODY(t) + (document.documentElement.scrollTop);
                    //----------top始终相对于li计算-----------------//

                    //-----------------------小于元素高度1/2判断----------------------------------//
                    if( top < tH/2 && t.getAttribute(‘class‘) !== ‘addNewNode‘ ){

                        aimLinePop.innerHTML = ‘插入到【‘+eB.innerHTML+‘】前面‘;

                        aimT = offsetToBODY(t) - offsetToBODY(zdx_v0);

                        aimLine.style.top = aimT + ‘px‘;

                        if( t.nodeName === ‘SPAN‘ ){
                            t = getParent(t,‘LI‘);
                        }

                        insertOnOff = ‘before‘;

                    }
                    //-----------------------小于元素高度1/2判断---------------end-----------------//

                    //-----------------------大于元素高度1/2判断------------------------------------//
                    if( top > tH/2 && t.getAttribute(‘class‘) !== ‘addNewNode‘  ){

                        aimLinePop.innerHTML = ‘插入到【‘+eB.innerHTML+‘】后面‘;

                        if( t.nodeName === ‘SPAN‘ ){
                            console.log( t.onOff );
                            if( t.onOff ){
                                aimLinePop.innerHTML = ‘插入到【‘+eB.innerHTML+‘】里面‘;
                            }else{
                                t = t.parentNode.parentNode;
                            }
                        }

                        aimT = offsetToBODY(t) - offsetToBODY(zdx_v0) + tH;

                        aimLine.style.top = aimT + ‘px‘;

                        insertOnOff = ‘afert‘;

                    }
                    //-----------------------大于元素高度1/2判断-----------------end-----------------//

                }    //zdx_v0.onmousemove结束

            }    //zdx_v0.onmousedown结束

            zdx_v0.onmouseup = function(){

                if(onOff == false){
                    return;
                }

                //-----------只有目标节点的等级比选中节点等级高才能插入成功---------//
                t.grade = parseInt( getParent(t,‘UL‘).className[1] );
                target.grade = parseInt( getParent(target,‘UL‘).className[1] );

                //-------判断插入到t上面还是下面---------//
                if(  insertOnOff === ‘before‘ && !contains(t,target) ){

                    //----------边界判断,如果目标t的ul是v1,应该应该作为v1的最后一项非添加按钮的li-------//
                    if( t.previousSibling.getAttribute(‘v‘) === ‘v1‘ ){

                        t.preUlLast = t.previousSibling.getElementsByTagName(‘ul‘)[0].lastElementChild;
                        t = t.preUlLast.previousSibling.previousSibling;

                        if( target != t ){
                            _this.changeOfPositionForData( target , t , ‘after‘ );
                            insertAfter( target , t );
                        }

                    }else{

                        if( target != t ){
                            _this.changeOfPositionForData( target , t ,‘before‘ );
                            insertBefore( target , t );
                        }

                    }
                    //----------边界判断,如果目标t的ul是v1,应该应该作为v1的最后一项非添加按钮的li-------//

                }else if( insertOnOff === ‘afert‘ && !contains(t,target)  ){

                    if( target != t ){
                        _this.changeOfPositionForData( target , t , ‘after‘ );
                        insertAfter( target , t );
                    }

                }else{

                    /*do something*/

                }
                //-------判断插入到t上面还是下面----------//

                //-----------只有目标节点的等级比选中节点等级高才能插入成功---------//

                //------隐藏提示线,恢复原状------//
                if( aimLine ){
                    aimLine.style.display = ‘none‘;
                    aimLine.style.top = ‘‘;
                    target.style.background = ‘‘;
                }

                zdx_v0.onmousemove = null;
                //------隐藏提示线,恢复原状------//

            }    //zdx_v0.onmouseup结束

        }    //for结束

    },

    //计算ul的高度
    calculateUl:function(liWrap){

        var cnt = 0;

        cnt = getStyle(liWrap,‘height‘,true);

        return cnt;

    },

    //ul收起,降下方法
    roll:function(v){

        var zdx_v0 = $(‘zdx_v0‘);
        var liWraps = getAttrEle( ‘li‘ , zdx_v0 , ‘attr‘ , ‘liWrap‘ );
        var t = null;
        var markList = [];
        var tV1 = null;
        var tParent = null;
        var eUl = null;

        if( v === ‘init‘ ){

            for(var i=0,iLen=liWraps.length; i<iLen; i++){

                //----默认只显示一级菜单-----//
                if( liWraps[i].getAttribute(‘v‘) !== ‘v1‘ ){

                    liWraps[i].style.height = getStyle(

                        liWraps[i].getElementsByTagName(‘span‘)[0],
                        ‘height‘

                    );

                    // liWraps[i].style = ‘transition: height .5s; ‘+ liWraps[i].style.height +‘;‘

                    //开关为开
                    liWraps[i].getElementsByTagName(‘span‘)[0].onOff = false;

                }else{

                    //开关为关
                    liWraps[i].getElementsByTagName(‘span‘)[0].onOff = true;

                }
                //----默认只显示一级菜单-----//

                liWraps[i].getElementsByTagName(‘span‘)[0].onclick = function(){

                    console.log( this );
                    t = this;

                    if( !this.open ){

                        this.open =
                        getStyle(
                            this,
                            ‘height‘,
                            true
                        )
                        +
                        getStyle(
                            this.nextSibling,
                            ‘height‘,
                            true
                        ) * (this.parentNode.getElementsByTagName(‘li‘).length-1);

                    }

                    if(!this.close){
                        this.close = getStyle(
                            this,
                            ‘height‘,
                            true
                        );
                    }

                    if(this.onOff){
                        this.parentNode.parentNode.style.height = this.close + ‘px‘;
                        this.onOff = !this.onOff;
                    }else{

                        this.parentNode.parentNode.style.height = ‘‘;
                        this.onOff = !this.onOff;

                    }

                }
            }

        }

    },

});    // Interaction结束

var generateMenu = Interaction;

原文地址:https://www.cnblogs.com/mflnhg/p/9744943.html

时间: 2024-11-10 14:42:36

可拖动菜单 【总结】的相关文章

通用权限管理系统之权限菜单zTree树的展示及移动的处理方法

在通用权限管理系统中,有很多数据结构是有父子关系的,如组织机构,部门,权限菜单等,在展示的时候,大多数是通过zTree树的形式展现的,如下: 权限菜单展示 这种数据后台输出比较容易处理,参考如下获取某个子系统的全部操作菜单: 后台输出zTree树的数据 /// <summary> /// 获取module树结构数据 /// </summary> /// <param name="systemCode"></param> /// <r

Android自定义View之仿QQ侧滑菜单实现

最近,由于正在做的一个应用中要用到侧滑菜单,所以通过查资料看视频,学习了一下自定义View,实现一个类似于QQ的侧滑菜单,顺便还将其封装为自定义组件,可以实现类似QQ的侧滑菜单和抽屉式侧滑菜单两种菜单. 下面先放上效果图: 我们这里的侧滑菜单主要是利用HorizontalScrollView来实现的,基本的思路是,一个布局中左边是菜单布局,右边是内容布局,默认情况下,菜单布局隐藏,内容布局显示,当我们向右侧滑,就会将菜单拉出来,而将内容布局的一部分隐藏,如下图所示: 下面我们就一步步开始实现一个

简单的侧滑菜单实现

本文参考自郭霖和鸿洋的多篇文章,无法逐一列举了 实现思路 利用自定义的HorizontalScrollView实现. HorizontalScrollView中管理两个视图,一个视图为"菜单",另一个为"正文".初始时"菜单"部分在屏幕可视区域以外.当利用HorizontalScrollView的滑动机制进行水平滑动时,将隐藏在屏幕外的"菜单"部分"拖入"屏幕可视区域. 效果增强 以自定义的方式继承Hori

jQuery移动优先的炫酷环形菜单插件

FerroMenu是一款炫酷的移动优先的jquery环形菜单特效插件.该环形菜单插件可以让你很轻松的创建一个环形菜单,并且该菜单可以在屏幕上随意拖动到9个位置上(东.南.西.北.中方向和东南.西北.东北和西南方向). 该环形菜单的菜单项可以是锚链接.外部链接或javascript等等.该菜单展开的最终效果有点类似于超酷jQuery环形按钮菜单效果插件.FerroMenu环形气泡菜单的特点有: 可以将菜单拖动到屏幕的9个位置上:东.南.西.北.中方向和东南.西北.东北和西南方向. 可以通过拖动来移

Xcode6使用storyboard在TabBarController上建立三个以上Item

在Xcode5上做以上的操作没有问题,这次是要在Xcode6上实现之,特记录以备用. 首先新建一个storyboard文件.取名Custom.storyboard.拖动菜单添加一个TabBarComtroller.由于XCode6使用了Use Size Classes功能.所有拖出来的Controller都是600x800大小.见图 恢复到以前的界面(恢复到Xcode6以前的界面,这个是为了习惯之前界面的人士): 通过取消Use Size Classes项并选择Disable Size Clas

终极秘籍教你怎么找回被盗iPhone 查询ICCID

iPhone不慎丢失后怎么办?普通青年:立刻报警,基本没用.文艺青年:用Find my iPhone查找位置.但那只是个大概位置,iPhone关机后更是没戏,接着是用iCloud锁定手机,发送警告信息乃至清除数据?这虽然保护了个人隐私,但很难找回,小偷会自己或托人重刷系统. 普通青年和文艺青年的方法一般都找不回手机,除非运气极佳,二逼青年可能会直接买个新的吧. 绝处逢生,为丢失iPhone的青年带来希望的终极大招来了,那就是“查询ICCID”,这个方法很直接,运气好的话可以直接帮你找到正在使用你

2015最流行的Android组件、工具、框架大全(转)

转自:2015最流行的Android组件.工具.框架大全 Android 是目前最流行的移动操作系统之一. 随着新版本的不断发布, Android的功能也日益强大, 涌现了很多流行的应用程序, 也催生了一大批的优秀的组件.本文试图将目前流行的组件收集起来以供参考, 如果你发现本文还没有列出的组件,欢迎在评论中贴出来,我会定期的更新本文. 部分图片需国内或许不能访问才能显示 很好的中文教程Google Android官方培训课程中文版 awesome-android, android列表. 另,g

IE11 全新的F12开发者工具

我讨厌debug,相信也没多少开发者会喜欢.但是当代码出错之后肯定是要找出问题出在哪里的.不过网页开发的时候遇到 BUG 是一件再正常不过的事情了,我们不能保证自己的代码万无一失,于是使用浏览器的开发者工具调试是我们解决问题最快捷的方法了.微软在 Windows 8.1 预览版中带来了全新的 IE11 浏览器,不光加入了诸如 WebGL 支持等功能,还将F12开发者工具进行了重新设计,这是IE有史以来开发者工具最大的的更新. 随着网站复杂程度的增加,原有的IE开发者工具已经渐渐不能满足开发者的需

最流行的android组件大全

目录 [−] 工具和教程 UI组件 类库 游戏引擎 Android HTML5应用 Android 是目前最流行的移动操作系统(还需要加之一吗?). 随着新版本的不断发布, Android的功能也日益强大, 涌现了很多流行的应用程序, 也催生了一大批的优秀的组件.本文试图将目前流行的组件收集起来以供参考, 如果你发现本文还没有列出的组件,欢迎在评论中贴出来,我会定期的更新本文.部分图片需要FQ才能显示 更新日志2014-11-07 增加最近一段时间新涌现的项目.2014-12-17 增加更多的组