可拖动菜单 总结

Posted mflnhg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可拖动菜单 总结相关的知识,希望对你有一定的参考价值。

需求

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

这是原来的样子

技术分享图片

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

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

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;

 

技术分享图片

 

 技术分享图片

 

 技术分享图片

 




























































































以上是关于可拖动菜单 总结的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在 Android 的可穿戴设备中创建类似可拖动菜单的东西?

用javascript 树形菜单(可拖动效果)

ngx-bootstrap bs-sortable 在将菜单项拖动到可排序部分时显示先前拖动的项目

滑块菜单片段中的可交换选项卡

Final Cut Pro X中的音视频片段如何自由拖动?

Exoplayer 音频播放背景,甚至视频已关闭