前端复习基础(阶段2)

377 阅读11分钟

动画帧

 var box = document.querySelector(".box");
        var l = 0
        var timer = null;
        function move(){
            l+=10;
            box.style.left = l+'px'
            if(l>=300){
                cancelAnimationFrame(timer);
                console.log(1111);
                return;
            }
            // 专注于动画,根据计算机的重绘频率:16.7ms/hz,进行刷新,性能高于定时器;(间隔定时器不够准确)
           timer = requestAnimationFrame(move);
        }
        box.addEventListener("click",()=>{
           timer = requestAnimationFrame(move);
        });

自定义获取css

  /**自定义获取或者设置样式的函数**/
    //   arg1:el,arg2:attr, arg3:val;
    function css(...args){
        if(arguments.length==2){
            var val = "";
            switch(arguments[1]){
                case 'width':
                case 'height':
                      val=parseFloat(getComputedStyle(arguments[0])[arguments[1]]);
                    break;
                case 'zIndex':
                case 'backgroundColor':
                default:    
                    val = getComputedStyle(arguments[0])[arguments[1]] ; 
                    break; 
            }
            return val;
        }else if(arguments.length==3){
            switch(arguments[1]){
                case "width":
                case "height":
                arguments[0].style[arguments[1]] = arguments[2] +'px';
                break;
                case 'zIndex':
                case 'backgroundColor':
                default:
                arguments[0].style[arguments[1]] = arguments[2];

            }
            
        }
      }

自定义运动框架

/**自定义运动框架**/
      /**
       * 参数是个对象;
       * obj={
       *    el:元素对象,
       *    attr:元素属性(该属性也是个对象),
       *    duration:持续时间,
       *    target:目标距离 (该属性也是个对象),
       *    type:运动形势,
       *    fn:()=>{}//回调函数
       * }
       * **/
      function motion(obj){
        // 解构   
        let {el,attr,duration,target,type} = obj;
        if(!el){
                alert("请传入元素");
                return
            }else if(!attr){
                alert("请传入所要改变的属性");
                return
            }else if(!target){
                alert("强传入改变的值");
                return
            }
            // 以毫秒为单位  
            duration = obj.duration || 1000;
            // 运动距离  
            //   obj.target = obj.target || 300;
            //   运动形势
            type= obj.type || 'easeOut';
             // 当前次数
             var t = 0;
            // 定义速度
            var speed= 1000/60;
            // console.log(speed);
            // d:总次数;次数需要向上取整(有可能是小数)
            var d = Math.ceil(duration/speed);
            //  console.log(d);
            var des ={};
            for(key in attr){
                    des[key] = target[key]-attr[key];
                }
            // console.log(des);    
            el.timer = requestAnimationFrame(move);
            function move(){
                // 一定要先判断后设置样式
                if(t>=d){
                        cancelAnimationFrame(el.timer);
                        obj.fn&&obj.fn();
                        return
                    }else{
                        el.timer=requestAnimationFrame(move);  
                    }
                t++;
                // console.log(t);    
                for(key in des){
                    el.style[key] =Tween[type](t,attr[key],des[key],d)+'px';

                }
                
               
            }
      

        }

调用该框架

      var w = css(box,'width');
      //   console.log(w);
      var h = css(box,"height"); 
      box.addEventListener("click",function(){
            motion({
                el:box,
                attr:{
                    width:w,
                    
                },
                duration:1000,
                target:{
                    width:500,
                    
                },
                type:"elasticIn",
                fn:function(){
                    motion({
                el:box,
                attr:{
                    
                    height:h,
                },
                duration:1000,
                target:{
                   
                    height:600,
                },
                type:"elasticIn",
               
                })
            }
                
            });
      });

时钟案例

        var list = document.querySelector("#lattice-list");
        var h = document.querySelector(".hour");
        var m = document.querySelector(".min");
        var s = document.querySelector(".sec");

        for(var i=0;i<12;i++){
            list.innerHTML+=`<li style="transform:rotate(${i*30}deg)"></li>`
        }
        function clock(){
            var date = new Date();
            var sec = date.getSeconds();
            var min = date.getMinutes()+sec/60;
            var hour = date.getHours()+min/60;
            h.style.transform="rotate("+(30*hour)+"deg)";
            m.style.transform="rotate("+(6*min)+"deg)";
            s.style.transform="rotate("+(6*sec+45)+"deg)";
        }
        clock();
        setInterval(()=>{
            clock();
        },1000);

幻灯片案例

    var lis = document.querySelectorAll("li");
    lis = Array.from(lis);
    console.log(lis.length);
    var images = document.querySelectorAll("li img");
    images = Array.from(images);
    var next = document.querySelector(".next_div");
    var arr = [];
    // 保存每个图片原来的样式
    lis.forEach((item,index)=>{
            var obj = {};
            obj.l = css(item,"left");
            obj.t = css(item,"top");
            obj.z = css(item,"z-index");
            obj.o = css(item,"opacity");
            obj.img = {};
            obj.img.w = css(images[index],"width");
            obj.img.h = css(images[index],"height");
            arr.push(obj);

        });
    // 点击时,改变原来数组的顺序,让现在的数组,变换成原来的样式
    next.addEventListener("click",function(){
        lis.unshift(lis.pop());
        images.unshift(images.pop());
        arr.forEach((item,index)=>{
            mTween({
               el: lis[index],
               attr:{
                   left:item.l,
                   top:item.t,
                   zIndex:item.z,
                   opacity:item.o
               }
            });
            mTween({
               el: images[index],
               attr:{
                   width:item.img.w,
                   height:item.img.h
               }
            });

        });
         
       
    });

Windows日历(案例)

思路

  1. 运用js html css 技术 以及封装框架(自定义获取样式方法)
  2. 该项目分为 表盘木块 日历模块

公共方法

 // 星期数组
    var week=['日','一','二','三','四','五','六'];
    // 获取元素函数  
    function getEl(selector){
         return document.querySelector(selector);
     }
    // 日期补0;
    function add0(num){
       return num<10?"0"+num:""+num;
   }

时钟模块

 
    /**********************时钟模块**********************/
    (function(){
        var list = getEl("#lattice-list");
        var hour = getEl(".hour");
        var min = getEl(".min");
        var sec = getEl(".sec");
        list.innerHTML = createLattice();
        //  生成表盘
        function createLattice(){
            var inner = "";
            var deg = 360/12;
            for(var i =0; i<12;i++){
                inner+=`<li class="lattice" style="transform:rotate(${i*deg}deg)"></li>`
            }
            return inner;
        }
        clock();
        // 刷新时间
        setInterval(clock,30);
        // 生成时间
        function clock(){
            var date = new Date();
            var ms = date.getMilliseconds();
            var s = date.getSeconds()+ms/1000;
            var m = date.getMinutes()+s/60;
            var h = date.getHours()+m/60;
            var secDeg = 6*s+45;
            var minDeg = 6*m;
            var horDeg = 30*h;
            // 换算指针旋转度数
            css(sec,"rotate",secDeg);
            css(min,"rotate",minDeg);
            css(hour,"rotate",horDeg);
        }
    })();

时钟旁边日期模块

/**********************时钟旁边日期**********************/
    (function(){
        var now =getEl("#now");
        var option = getEl("#option");
        var date = new Date();
        var y = date.getFullYear();
        var m = add0(date.getMonth()+1);
        var day = add0(date.getDate());
        var w = date.getDay();
        // console.log(y+'=='+m+'==='+day+'====='+week[w]);
        // option.innerHTML=`${y}年${m}月`;
        // 表盤旁邊日期
        now.innerHTML =`<p>${y}${m}${day}日</p><p>星期${week[w]}</p>`;
    })();

日期模块

// 设置日历所对应的日期
            function initDateView(board,year,month){
                    // 设置星期日历表头 
                    var str="";   
                    var str = "<ul class='week'>";
                    for(var i=0;i<7;i++){
                        str +=`<li class="date-cell">${week[i]}</li>`;
                    }
                    // 设置日历对应的日期
                    // console.log(str);
                    str+="</ul>"
                    str+='`<ul class="date">';
                    
                    /**
                        * 日历显示分为三种情况:
                        * 1:显示上个月的日期;
                        * 2: 显示当前月的日期;
                        * 3: 显示下个月的日期;
                        * 条件一:首先知道这个月第一天对应星期几(如果这个月第一天星期6)上个月所占日历第一行的位置就是 6-0=6天(周日对应的是0)
                        * 条件二:其次还要知道上个月一共多少天 上个月天数知道了,我们可以用上个月天数-(这个月第一天对应的星期-对应的行号i-1)即可
                        * 
                        * **/
                        // var date = new Date();
                        // var y = date.getFullYear();
                        // var m = date.getMonth();
                        // 获取上个月的最后一天,我们就可以知道上个月多少天
                        var lastMonthDates = new Date(year,month,0).getDate();
                        // console.log(lastMonthDates);
                        // 如果知道这个月的第一天是星期几的话我们就可以知道上个月预留多少天
                        var thisMonthDay = new Date(year,month,1).getDay();
                        // console.log(thisMonthDay);
                        // 这个月的最后一天
                        var thisMonthDates = new Date(year,month+1,0).getDate();
                        // console.log(thisMonthDates);
                    for(var i=0;i<42;i++){
                        //上个月所占的格子
                            // 如果当前i<这个月第一天所对应的星期,就说明是上一个月的    
                        if(thisMonthDay>i){
                            var num = lastMonthDates-(thisMonthDay-i-1); 
                            str +=`<li class="date-cell other-date">${lastMonthDates-(thisMonthDay-i-1)}</li>`
                            // console.log(num);
                            // 当前i加上个月份所占的格子数<格子总数时
                        }else if(i-thisMonthDay<thisMonthDates){
                            // 设置当前日期样式
                            if(year==nowYear && month==nowMonth && nowDate==i-thisMonthDay+1){
                                str += `<li class="date-cell active">${i-thisMonthDay+1}</li>`
                            }else{
                                str += `<li class="date-cell ">${i-thisMonthDay+1}</li>`;
                            }
                            
                        }else{
                            //  剩余的条件就是下个月的  
                            str += `<li class="date-cell other-date">${i-thisMonthDay-thisMonthDates+1}</li>`;  
                        }
                        
                    }
                    str += "</ul>"
                        board.innerHTML =str;
                    
            }   

月份模块

             // 初始化月份視圖
            function initMonthView(board,year){
                    var str ="<ul class='month'>";
                    for(var i =1;i<13;i++){
                        if(year==nowYear && nowMonth==i-1){
                            str+=`<li class="month-cell active">${i}月</li>`;
                        }else{
                            str+=`<li class="month-cell">${i}月</li>`
                        }
                    }
                    str+="</ul>";
                    board.innerHTML = str;
                    
                    var lis = board.querySelectorAll("li");
                    lis.forEach(item=>{
                       item.addEventListener("click",()=>{
                           nextOptionType = 0;
                           nowMonth = parseInt(item.innerHTML)-1;
                           tabViews();
                       });
                    })
                }

年份模块

            // 初始化年份視圖;
            function initYearsView(board,year){
                    /**
                     * 1:年份的視圖展示是每排4個總共16個;
                     * 2:分為 上段年份4;當前年份12個 以後2個年份
                     * 3:獲取當前年份所在年份範圍;
                     * 
                     * **/
                    // var currentYear = new Date().getFullYear();
                    var startYear = Math.floor(year/10)*10;
                    var endYear = startYear+9;
                    var str ="<ul class='year'>";
                    // console.log(startYear);
                    for(var i =0;i<16;i++){
                        // createEle('li',yearUl,)
                        if(i<4){
                            str+=`<li class="year-cell other-yaer">${startYear-(4-i)}</li>`
                        }else if(i<14){
                            if(nowYear == startYear+(i-4)){
                                str+=`<li class="year-cell active">${startYear+(i-4)}</li>`
                            }else{
                                str+=`<li class="year-cell">${startYear+(i-4)}</li>`
                            }
                            
                        }else{
                            str+=`<li class="year-cell other-yaer">${endYear+(i-14)+1}</li>`
                        }
                        
                    }
                    str +="</ul>"
                    board.innerHTML = str;
                    // li 添加点击事件
                    var lis =board.querySelectorAll("li");
                    lis.forEach(item=>{
                        item.addEventListener("click",()=>{
                        nowYear = Number(item.innerHTML);
                        nextOptionType=1;
                        tabViews();
                      });
                    })
                    
                } 

视图切换模块

/**********************视图切换模块**********************/
    (function(){
            var board = getEl(".board");
            var option = getEl("#option");
            var main = getEl("#main");
            var prev = getEl("#prev");
            var next = getEl("#next");
            // console.log(option);
            var date = new Date();
            // 现在的时间;
            var nowYear= date.getFullYear();
            var nowMonth = date.getMonth();
            var nowDate = date.getDate();
            // 设置的时间;
            var setYear= nowYear;
            var setMonth = nowMonth;
            var setDate = nowDate;
            var optionType = 0;//0:代表显示日期;1:代表显示月份;2:代表显示年份;
            // 设置动画切换
            var nextOptionType;
            initDateView(board,setYear,setMonth);
            initOptionView();
            // option添加点击事件
            option.addEventListener("click",()=>{
                nextOptionType = optionType+1;
                
               if(nextOptionType>2){
                   nextOptionType=2;
               }else{
                    tabViews();
               }
                initOptionView();
               
                console.log(optionType+"============"+nextOptionType);  

            });
            // initMonthView(board,setYear);
            // initYearsView(board,setYear);
            // 设置option所显示的对应样式
            function initOptionView(){
                switch(optionType){
                    case 0:
                        // console.log(1111);
                        option.innerHTML = nowYear + '年' + (nowMonth+1) + '月';
                        console.log(nowMonth);
                        break;
                    case 1:
                        option.innerHTML = nowYear + '年';
                        break;
                    case 2:
                        var startYear = Math.floor(nowYear/10)*10;
                        var endYear = startYear + 9;
                        option.innerHTML = startYear + ' - ' + endYear;
                        break;        
                }
            }
            // 切换动画实际上就是控制board隐藏和显示
            function tabViews(){
                // 从日到年的切换
                if(optionType<nextOptionType){
                    main.innerHTML =`<div class="board toHide"></div> <div class="board toShow"></div>`;
                    var board = main.querySelectorAll(".board");
                    // 动画结束后删除隐藏的元素
                    board.forEach(item => {
                        item.addEventListener("animationend",()=>{
                            if(item.classList.contains("toHide")){
                            main.removeChild(item);
                            }
                        });
                    });
                    switch(nextOptionType){
                    
                    case 1:
                         //日切换到月
                         initDateView(board[0],setYear,setMonth);
                         initMonthView(board[1],setYear);
                         optionType = nextOptionType;
                        
                        break;
                    case 2:
                        // 从月切换到年
                        initMonthView(board[0],setYear);
                        initYearsView(board[1],setYear);
                        // console.log( typeof optionType );
                        optionType = nextOptionType;
                        break;        
                }
            }else{
                main.innerHTML =`<div class="board toBlow"></div> <div class="board toNarrow"></div>`;
                    var board = main.querySelectorAll(".board");
                    // 动画结束后删除隐藏的元素
                    board.forEach(item => {
                        item.addEventListener("animationend",()=>{
                            if(item.classList.contains("toBlow")){
                            main.removeChild(item);
                            }
                        });
                    });
                    switch(nextOptionType){
                    case 0:
                        //月切换到到日
                        initDateView(board[1],setYear,setMonth);
                        initMonthView(board[0],setYear);
                        optionType = nextOptionType;
                        break;
                    case 1:
                        // 从年切换到月
                        initYearsView(board[0],setYear);
                        initMonthView(board[1],setYear,setMonth);
                        optionType = nextOptionType;
                        break;        
                }
            }
            initOptionView();
        }
         // 给上下按钮添加点击事件
            prev.addEventListener("click",()=>{
                scrollDateView(-1);
            });
            next.addEventListener("click",()=>{
               
                scrollDateView(1);
            });
            function getTime(){
                var date = new Date(nowYear,nowMonth);
                nowYear =  date.getFullYear();
                nowMonth = date.getMonth();
            }
            // 根据方向来判断动画执行
            function scrollDateView(dir){
               
                if(dir>0){
                    // 向下按钮
                    // 向上滑动
                    main.innerHTML =`<div class="board topOut"></div> <div class="board toTop"></div>`;
                    var board = main.querySelectorAll(".board");
                    // console.log(optionType);
                    switch(optionType){
                        case 0 :
                                // 对月份减1;
                            initDateView(board[0],nowYear,nowMonth);
                            nowMonth = nowMonth+1; 
                            // 防止日期超出范围
                            getTime();
                            initDateView(board[1],nowYear,nowMonth); 
                          break;
                        case 1:
                            initYearsView(board[0],nowYear);
                            nowYear = nowYear+1; 
                            getTime();
                            initYearsView(board[1],nowYear);
                         break;
                        case 2:
                            initYearsView(board[0],nowYear);
                            nowYear = nowYear+10;
                            getTime(); 
                            initYearsView(board[1],nowYear);
                          break;    
                  }
                }else{
                    // 向上按钮
                    // 向下滑动
                    main.innerHTML =`<div class="board bottomOut"></div> <div class="board toBottom"></div>`;
                    var board = main.querySelectorAll(".board");
                    // console.log(optionType);
                    switch(optionType){
                        case 0 :
                            // 对月份减1;
                            initDateView(board[0],nowYear,nowMonth);
                            nowMonth = nowMonth-1; 
                            // 防止日期超出范围
                            getTime();
                            initDateView(board[1],nowYear,nowMonth); 
                          break;
                        case 1:
                            initYearsView(board[0],nowYear);
                            nowYear = nowYear-1; 
                            getTime();
                            initYearsView(board[1],nowYear);
                         break;
                        case 2:
                            initYearsView(board[0],nowYear);
                            nowYear = nowYear-10;
                            getTime(); 
                            initYearsView(board[1],nowYear);
                          break;    
                  }
                }
                initOptionView();
            }
    })();

Dom

获取元素

         // 获取子节点:包括文本(空格 内容) 和 元素
        var list = box.childNodes;
        // console.log(list);
        // 获取的只有标签
        var child = box.children;
        // console.log(child);
        // 获取第一个子节点 包含文本 
        var first = box.firstChild;
        // 获取第一个字元素(不包含文本)
        var ele = box.firstElementChild;
        console.log(first,ele);
        // 获取下一个兄弟节点(包含文本)
        var text = box.nextSibling;
        console.log(text);
        // 获取下一个兄弟元素
        var tag =  box.nextElementSibling;
        // console.log(tag);
        // 上一个兄弟元素
        var pre = box.previousElementSibling;
        // 只有标签包含标签,获取的只有父元素
        var father = box.parentNode;
        // console.log(father);
        // 获取定位父级(一个元素的父元素每有加定位,他的默认参照物为body)
        var offset = box.offsetParent;
        // console.log(offset);

创建节点

        // 创建节点
        var d = document.createElement("div");

插入节点

        // 插入元素
        document.body.append(d);
        // 插入子节点
        document.body.appendChild(d);
        // 在指定元素之前插入节点
        document.body.insertBefore(d,box);

替换节点(会删除旧节点)

box.replaceChild(d,p);

删除节点

        // 删除节点
        box.removeChild(d);
        // 也可以删除自己
        box.remove();

克隆元素

        // 克隆元素(true:深度克隆)
        var clone = box.cloneNode(true);

动态文件夹(案例)

       var create = document.querySelector("#create");
       var folder = document.querySelector("#folder");
       create.addEventListener("click",()=>{
           var li = document.createElement("li");
           li.innerHTML = `<div class="checkbox"></div>
                <div class="name">新建文件夹</div>`;
            li.addEventListener("click",()=>{
                // 如果li可以点击就说明已经创建成功
                var checkbox = li.querySelector(".checkbox");
                if(li.classList.contains("border")){
                    li.classList.remove("border");
                    checkbox.innerText = "";
                }else{
                    checkbox.innerText = "√";
                    li.classList.add("border");
                }
           });
        
           folder.append(li);
           
       })

学生管理系统(案例)

 (function(){
        var btn = document.querySelector("#addBtn");
        var usernameInp = document.querySelector("#username");
        var ageInp = document.querySelector("#age");
        var genderInp = document.querySelector("#gender");
        var username = usernameInp.value;
        var age = ageInp.value;
        var gender = genderInp.value;
        var tbody = document.querySelector("tbody");
        var checkAll = document.querySelector("#checkAll");
        var id = 0;
        btn.addEventListener("click",()=>{
            checkAll.checked =false;
            var tr = document.createElement("tr");
            var th1 = document.createElement("th");
            th1.innerHTML = `<input type="checkbox"/> `;
            tr.append(th1);
            var checkBtn = th1.querySelector("input");
            checkBtn.addEventListener("change",function(){
                var flag =isCheckAll();
                if(flag){
                    checkAll.checked =true;
                }else{
                    checkAll.checked =false;
                }
            })
            var th2 = document.createElement("th");
            id++
            th2.innerHTML = id;
            tr.append(th2);
            var th3 = document.createElement("th");
            th3.innerText = username;
            tr.append(th3);
            var th4 = document.createElement("th");
            th4.innerText = age;
            tr.append(th4);
            var th5 = document.createElement("th");
            th5.innerText = gender;
            tr.append(th5);
            var th6 = document.createElement("th");
            th6.innerHTML = `<a href="javascript:;">↑</a><a href="javascript:;">↓</a>`;
            tr.append(th6);
            var sortBtns =th6.querySelectorAll("a");
            console.log(sortBtns.length);
            //在某元素之前插入该元素
            sortBtns[0].addEventListener("click",function(){
                var parent = this.parentNode.parentNode;
                var sibling =parent.previousElementSibling;
                console.log(sibling);
                // sibling为null inserbefore 会按照 append来插入元素 
                tbody.insertBefore(parent,sibling);
            });
             //在某元素之后插入该元素
             sortBtns[1].addEventListener("click",function(){
                var parent = this.parentNode.parentNode;
                var sibling =parent.nextSibling;
                    // if(sibling){
                    //     sibling=sibling.nextSibling;
                    //     tbody.insertBefore(parent,sibling);
                    // }
                    if(sibling){
                        tbody.insertBefore(sibling,parent);
                    }else{
                        // 插入到第一个
                        tbody.insertBefore(parent,tbody.childNodes[0]);
                    }
                        
                   
                
            });
            var th7 = document.createElement("th");
            th7.innerHTML = `<a href="javascript:;">删除</a>`;
            var removeBtn = th7.querySelector("a");
            removeBtn.addEventListener("click",function(){
                var parent =this.parentNode.parentNode;
                parent.remove();
            });
            tr.append(th7);
            
            tbody.append(tr);
           

                              
        });
         // 给全选按钮添加点击事件
         checkAll.addEventListener("click",function(){
            var checkItem = tbody.querySelectorAll("input[type=checkbox]");
            if(this.checked){
                checkItem.forEach((item)=>{
                    item.checked = true;
                });
            }
         });
        //  是否全选
        function isCheckAll(){
            var checkItem = tbody.querySelectorAll("input[type=checkbox]");
            var flag =[...checkItem].every(item => item.checked && checkItem.length>0);
            return flag;
        }

    })();

nodetype

        var div = document.querySelector("div");
        var list = div.childNodes;
        console.log(list);
        console.log(document.nodeType);
        /**
         * nodeType:
         * 1:元素节点:1;
         * 2:属性节点:2;
         * 3:文本节点: 3;
         * 4:注释节点:8;
         * 5:文档节点:9;
         * 
         * 
         **/
        list.forEach(item=>{
            console.log(item.nodeType);
        });
        // 获取节点名称
        var name = div.nodeName;
        console.log(name);

设置属性

        /**
         * dom属性获取
         * 自定义属性是官方没有定义的
         * **/
        // 自定义属性不会显示dom视图当中
        // div.name = "tag";
        var arr = div.attributes;
        console.log(arr);
        // 如果想让自定义属性显示在dom视图中可以通过setAttribute
        div.setAttribute("name","tag");
        // 利用div.tag方式设置属性,通过getAttribute("tag")获取不到
        div.tag = "tag";
        div.getAttribute("tag");
        // 删除属性
        div.removeAttribute("key");
        // 是否含有某个属性
        div.hasAttribute("key");
        // h5新增自定义属性
        div.dataset.index = 123;
       var value =  div.dataset.index;
       console.log(value);
       //通过getgetAttribute()获取方式,保护命名规则    
       value =  div.getAttribute("data-index");
       console.log(value);
       //dataset设置属性这样获取不到   
        value = div.index
       console.log(value);

offset属性

        /**offset**/
        var box = document.querySelector(".box");
        // offsetWidth:包含该元素的border
        var w = box.offsetWidth
        // 相对于父容器来计算距离顶部的距离,如果没有定位默认参照body
        var t = box.offsetTop;
        console.log(t);

client

         /**client**/
        // 不包含该元素的border
        var w = box.clientWidth;
        // console.log(w);
        // clientLeft 获取该元素的left-border的width
         var l =box.clientLeft;
         console.log(l);

scroll

       // 如果内容比盒子大获取的是实际内容的宽度,
       var w =  box.scrollWidth;
        // 顶部吸附效果
        window.addEventListener("scroll",()=>{
             // 获取该控件距可视区的位置距离封装在该对象中
            var rect = search.getBoundingClientRect();
            if(rect.bottom<0){
                banner.style.display = "block";
            }else{
                banner.style.display = "none";
            }
        });
       

window内置属性

        // 包括纵向滚动条的宽度(不包含滚动条)
        var w =window.innerWidth;
        // 关闭网页
        // window.close();
        // 跳转到新的网页
        // window.open("http://www.baidu.com");
        console.log(w);
        // 浏览器窗口大小发生改变会触发该事件
        window.addEventListener("resize",()=>{
            console.log(window.innerWidth);
        });
        var btn = document.querySelector("input");
        btn.addEventListener("click",()=>{
            // 设置滚动的距离
            window.scrollTo(0,0);
        });

document

        // 不包含滚动条
       var dw = document.documentElement.clientWidth;

无限下拉菜单

            var data = data;
            // return省略{}也要省略return 
            function getChildren(id){
                return data.filter(item=>item.pid==id);
            }
            // 该参数必须是个数组
            function renderUI(arr){
                    console.log(arr);
                    var str = "<ul>"
                    arr.forEach(item => {
                    str +=`<li>
                               <p>${item.title}</p>
                               ${getChildren(item.id)&&renderUI(getChildren(item.id))}
                          </li>`;
                });
                    str +="</ul>";
                    return str;


            }
            // console.log(getChildren(-1));
            // console.log(renderUI(getChildren(-1)));

            menu.innerHTML = renderUI(getChildren(-1));
            menu.addEventListener("click",(e)=>{
                var obj =e.target;
                if(obj.tagName=="P"){
                    obj.nextElementSibling.classList.toggle("show");
                }
            });

返回顶部(案例)

 (function(){
        var search = document.querySelector("#search");
        var banner = document.querySelector("#banner");
        var float = document.querySelector("#float");
        var backTop = document.querySelector("#backTop");
        // 获取侧边栏的绝对位置
        var fT = getFloatPosition(float).fTop;
        // 顶部吸附效果
        function adsorb(){
            var sRect = search.getBoundingClientRect();
            if(sRect.bottom<0){
                banner.style.display = "block";
            }else{
                banner.style.display = "none";
            }
        }
        // 侧边栏导航的绝对位置的获取
        /**
         * 侧边栏的绝对位置:window.scrollY+rect.top;
         * 原因:屏幕大小是固定,rect.top获取的是相对尾椎的距离,
         * 只有加上window.scrollY这是根据内容的实际坐标来获取的位置距离
         * 这么做才能得到侧边栏的绝对位置 
         * **/
        function getFloatPosition(el){
            var fRect = el.getBoundingClientRect();
            var fY = window.scrollY;
            var fX = window.scrollX;
            var ftop = fRect.top;
            var fleft = fRect.left;
            return{
                fTop:fY+ftop,
                fLeft:fX+fleft
            } 
        }
        // 设置侧边栏切换条件
        function getPageOffset(){
            var bannerH = banner.offsetHeight;
            if(scrollY+bannerH>fT){
                float.style.position="fixed";
                float.style.top = bannerH +'px';
            }else{
                float.style.position="absolute";
                float.style.top = "50%";
            }
        
        }
         // 返回顶部 
         function backUp(){
            //  滚动超过一屏让其显示
             if(scrollY>innerHeight){
                backTop.style.display="block";
             }else{
                backTop.style.display="none"; 
             }
         }
        //  点击返回顶部
         backTop.addEventListener("click",()=>{
            document.body.scrollTop = document.documentElement.scrollTop=0;
         });
        window.addEventListener("scroll",()=>{
            adsorb();
            getPageOffset();
            backUp();
        });
       
        
        

    })();

location

       // 网站信息是个对象
        console.log(location);
        // 网址
        console.log(location.href);
        // "#"后面的值就是哈希值
        console.log(location.hash);//获取带带#的值
        // 获取get请求参数的字段
        console.log(location.search);
        // 利用hash值切换界面
        var btns = document.querySelectorAll("a");
        var content = document.querySelector(".content");
        // 监听hashchange事件
        window.addEventListener("hashchange",()=>{
            switch(location.hash){
                case "#about":
                    content.innerHTML = "<h2>关于我们</h2>";
                    break;
                case "#join":
                    content.innerHTML = "<h2>加入我们</h2>";
                    break;    
            }
        });
        btns[2].addEventListener("click",()=>{
            // 刷新界面
            location.reload();
        });

history

        // 后退俩个历史记录
        btn.addEventListener("click",()=>{
            history.go(-2);
        });
         // 后退1个历史记录
        btns[1].addEventListener("click",()=>{
            history.back();
        });
        // 前进一个历史记录
        btns[0].addEventListener("click",()=>{
            history.forward();
        });
        // 前进俩个历史记录
        btns[1].addEventListener("click",()=>{
            history.go(2);
        });

navigator

        // 可以获取用户的浏览器信息,以及操作系统
        console.log(navigator.userAgent);
        // 获取浏览器内核名称 chrome内核:Netscape
        console.log(navigator.appName);
        // 获取浏览器的版本号
        console.log(navigator.appVersion);

history

        /**终端设备信息**/
        console.log(screen);
        // 设备宽度 不会随窗口大小而改变
        console.log(screen.width);
        // 设备高度
        console.log(screen.height);

hashchange(案例)

 {   
        var lis = document.querySelectorAll(".nav li");
        var container = document.querySelector(".list-group");
        var pagination = document.querySelector(".pagination");
        //获取数据
        var data = data;
        // 监听hashchange事件
        window.addEventListener("hashchange",()=>{
            var hash = location.hash;
            // 截取hash
             hash = hash.substring(2);
            // 转化成数组
            var hashArray = hash.split("/");
             // 默认选中
            lis.forEach(item=>{
                    item.classList.remove("active");
                });
            
            if(hashArray[0]=='sh'){
                lis[0].classList.add("active");
                // 详情页是否存在
                if(hashArray[1]=='details'){
                    renderDetailsPage(
                        {
                            type:'society',
                            pid: hashArray[2]
                        }
                    );
                }else{
                        renderList(
                            {
                                type:'society',
                                pageNumber:hashArray[1]?hashArray[1]:0,

                            }
                    );
                }
            }else if(hashArray[0]=='xy'){
                lis[1].classList.add("active");
                // 详情页是否存在
                if(hashArray[1]=='details'){
                    renderDetailsPage(
                        {
                            type:'campus',
                            id: hashArray[2]
                        }
                    );
                }else{
                        renderList(
                        {
                            type:'campus',
                            pageNumber:hashArray[1]?hashArray[1]:0,

                        }
                    );
                }
            }
           
        });
         // 初始化社会数据
         function renderList(props){
                let {type,pageNumber} = props;
                var newArray = data[type];
                var len = 5;
                var start = parseInt(pageNumber)*len;
                var end =(parseInt(pageNumber)+1)*len;
                var newData = newArray.filter((item,index)=>{return index>=start && index<end});
                console.log(newData.length);
                var str="";
                newData.forEach(item=>{
                      str+=`<li class="list-group-item">
                            <a href="#/${item.type}/details/${item.id}">
                                <h4 class="list-group-item-heading">职位需求:${item.job}需求人数:${item.nub}名</h4>
                                <p class="list-group-item-text">${item.ask}</p>
                            </a>
                        </li>`;
                });
                container.innerHTML = str;
                renderPageList({type,pageNumber});
            }
            // 初始化分页
            function renderPageList(props){
                let {type,pageNumber}=props;
                var pages = Math.ceil(data[type].length/5);
                var subType =data[type][0].type;
                var str = "";
                [...'.'.repeat(pages)].forEach((item,index)=>{
                    str+=`<li class="${index==pageNumber?"active":"false"}"><a href="#/${subType}/${index}">${index+1}</a></li>`
                });
                pagination.innerHTML = str;

            };

            renderList({
                type:"society",
                pageNumber:0
            });
            // 初始化详情页
            function renderDetailsPage(props){
                let{type,pid} = props;
                var detail = data[type].filter((item,index)=>{return item.id==pid})[0];
                console.log(detail);
                var str = ` 
                <div class="panel panel-default">
                    <div class="panel-heading">招聘岗位:${detail.job}</div>
                        <div class="panel-body">
                            <p>${detail.ask}</p>
                            <p>招聘人数:${detail.nub}人</p>
                            <p>发布时间:${detail.data}</p>
                        </div> 
                </div>  `;
                container.innerHTML = str;
                pagination.style.display = "none";
            }

    }

事件

事件机制

  • 事件冒泡 js的事件机制执行顺序,由内向外!
  • 默认为false, 为true,为捕获执行,由外向内=》由内向外,父控件先捕获,子控件在冒泡

mouseenter 和 mouseleave

  • 如果我们用mouseover和mouseout来做事件,当鼠标移到子控件身上会触发父控件的mouseout事件,但我们实际没有移出父控件。这种情况下用mouseenter 和 mouseleave更为合适

事件案例

 (function(){
        var title = document.querySelector(".title");
        var list = document.querySelector(".list");
        var menu = document.querySelector(".menu");
        menu.addEventListener("click",(e)=>{
            // 阻止事件冒泡
            e.stopPropagation();
            if(getComputedStyle(list)['display'] === "block"){
                list.style.display = "none";
            }else{
                list.style.display = "block";
            }
            
        });
        document.body.addEventListener("click",()=>{
            list.style.display = "none";
        });
        // 事件委托
        list.addEventListener("click",(e)=>{
            if(e.target.tagName =="LI"){
                title.innerText =e.target.innerText; 
            }
        })

    })();

事件函数(参数)

            a.addEventListener("click",(e)=>{
                // 阻止默认行为
                e.preventDefault();
                // 清除默认行为
                // once:true 只能触发一次
                // capture:是否以事件捕获向上传递
            },{passive:true});

鼠标右键(事件)

        // 阻止浏览器右键菜单
        document.addEventListener("contextmenu",(e)=>{
            e.preventDefault();
        },{passive:true});

限制移动盒子(案例)

function css(el,attr){
            return parseFloat(getComputedStyle(el)[attr]);
        }
        var container = document.querySelector(".container");
        var box = document.querySelector(".box");
        var cw = css(container,"width");
        var bw = css(box,"width");
        box.addEventListener("mousedown",(e)=>{
            var startX = e.clientX;
            var startY = e.clientY;
            var l = css(box,"left");
            var t = css(box,"top");
            function move(e){
                console.log(css(box,"left"));
                var distanceX = e.clientX-startX;
                var distanceY = e.clientY-startY;
                var endl = l+distanceX;
                var endt = t+distanceY;
                var maxL = css(container,"width")-css(box,"width");
                var maxT = css(container,"height")-css(box,"height");
                if(endl<0){
                    endl = 0;
                }
                if(endt<0){
                    endt = 0;
                }
                if(endt>maxT){
                    endt = maxT;
                }
                if(endl>maxL){
                    endl = maxL;
                }

                box.style.left = endl+"px";
                box.style.top = endt+"px";
            }
            window.addEventListener("mousemove",move);
            window.addEventListener("mouseup",(e)=>{
                // 阻止默认选中
                e.preventDefault();
                window.removeEventListener("mousemove",move);
            },{once:true});
        });

放大镜(案例)

(function(){
         var left = document.querySelector("#left");
         var mask = document.querySelector("#mask");
         var right = document.querySelector("#right");
         var img2 = document.querySelector("#img2");
         function css(el,attr){
           return parseFloat(getComputedStyle(el)[attr]);
         }
         left.addEventListener("mouseenter",(e)=>{
           mask.style.display = "block";
           right.style.display = "block";
          //  console.log(css(img2,"width"));
           var scaleW = css(right,"width")/css(img2,"width");
           var scaleH = css(right,"height")/css(img2,"height");
          //  console.log(scaleW,scaleH);
           mask.style.width = css(left,"width")*scaleW +'px';
           mask.style.height = css(left,"height")*scaleH+'px';
              left.addEventListener("mousemove",(e)=>{
                // console.log(e.clientX);
                var lRect = left.getBoundingClientRect();
                var l = e.clientX-lRect.left;
                var t = e.clientY-lRect.top;
                var mask_l =l-css(mask,"width")/2;
                var mask_t = t-css(mask,"height")/2;
                mask.style.left =mask_l+'px';
                mask.style.top = mask_t+'px';
                var showScaleWidth = img2.offsetWidth/left.offsetWidth;
                var showScaleHeight = img2.offsetHeight/left.offsetHeight;
                // console.log(showScaleHeight);
                img2.style.left = -mask_l * showScaleWidth+'px';
                img2.style.top = -mask_t * showScaleHeight+'px';
                
           });

         })
       })();

拖拽综合(案例)

        function css(el,attr){
                    return parseFloat(getComputedStyle(el)[attr]);
                }
        var box = document.querySelector(".box");
        var l=0;
        var t=0;
        box.addEventListener("mousedown",(e)=>{
            clearInterval(timer);
            var oldL = css(box,"left");
            var odlT = css(box,"top");
            var startX = e.clientX;
            var startY = e.clientY;
            var nBox = document.createElement("div");
            nBox.className="newBox";
            document.body.append(nBox);
            function move(e){       
            var distanceX = e.clientX-startX;
            var distanceY = e.clientY-startY;
            l = oldL+distanceX;
            t = odlT+distanceY;
            nBox.style.left = l+'px';
            nBox.style.top = t+'px';
        }
            document.addEventListener("mousemove",move);
            document.addEventListener("mouseup",(e)=>{
                document.removeEventListener("mousemove",move);
                box.style.left= l+'px';
                box.style.top = t+'px';
                nBox.remove();
                // 清空浏览器的默认行为
                e.preventDefault();
            },{once:true})
           
        });
        var isLeft = false;
        var isTop = false;
        var isRight = false;
        var isBottom = false;
        var run = ()=>{
            if(isLeft){
                l-=10;
            }
            if(isTop){
                t-=10;
            }
            if(isBottom){
                t+=10;
            }
            if(isRight){
                l+=10
            }
            box.style.left = l+'px';
            box.style.top = t+'px';
        };
        var timer = setInterval(run,30);
        window.addEventListener("keydown",(e)=>{
             clearInterval(timer);
             timer=setInterval(run,30);
            switch(e.keyCode){
                case 37:
                    isLeft = true;
                    break;
                case 38:
                    isTop = true;
                    break;
                case 39:
                    isRight = true;
                    break;
                case 40:
                    isBottom = true;
                    break;            
            }
            
        });
        window.addEventListener("keyup",(e)=>{
            switch(e.keyCode){
                case 37:
                    isLeft = false;
                    break;
                case 38:
                    isTop = false;
                    break;
                case 39:
                    isRight = false;
                    break;
                case 40:
                    isBottom = false;
                    break;            
            }
            clearInterval(timer);
        });

自定义滚动条

 let arr = ['河北', '山西', '辽宁', '吉林', '黑龙江', '江苏', '浙江', '安徽', '福建', '江西','山东', '河南', '湖北', '湖南', '广东', '海南', '四川', '贵州', '云南', '陕西', '甘肃', '青海', '台湾',
            '北京', '天津', '上海', '重庆'
        ];
        var list = document.querySelector(".list");
        var wrap = document.querySelector(".wrap");
        var scrollWrap = document.querySelector(".scroll-wrap");
        var scrolls = document.querySelector(".scroll");
        var newArr = arr.map((item,index)=>{return `<li>${item}</li>`;});
        list.innerHTML=newArr.join("");
        function css(el,attr,val){
            if(arguments.length==3){
                el.style[attr] = val+'px';
            }else{
                return parseFloat(getComputedStyle(el)[attr]);
            }
        }
        var scale = css(wrap,'height')/css(list,'height');
        css(scrolls,'height',css(scrollWrap,"height")*scale);
        var ld = css(list,'height')-css(wrap,"height");
        var sd = css(scrollWrap,'height')-css(scrolls,'height');
        // 实现滚动条的拖拽
        scrolls.addEventListener('mousedown',(e)=>{
            var t = css(scrolls,'top');
            var startY = e.clientY;
            let move =(e)=>{
                var endY = e.clientY-startY;
                var distanceY = endY+t;
                distanceY = Math.max(0,distanceY);
                distanceY = Math.min(sd,distanceY);
                scrolls.style.top = distanceY+'px';
                list.style.top = -(distanceY/sd*ld)+'px';
                e.preventDefault();
            }
            document.addEventListener("mousemove",move);
            document.addEventListener("mouseup",(e)=>{
                document.removeEventListener("mousemove",move);
                e.preventDefault();
            },{once:true});
        });
        function myScroll(el,upFn,downFn){
            el.addEventListener("mousewheel",function(e){
                if(e.wheelDelta>0){
                    console.log('向上');
                    upFn&&upFn.call(el);
                }else{
                    console.log('向下');
                    downFn&&downFn.call(el);
                }
                e.preventDefault();
            });
            el.addEventListener('DOMMouseScroll',function(e){
                if(e.detail>0){
                    console.log('向下');
                    downFn&&downFn.call(el);
                }else{
                    console.log('向上');
                    upFn&&upFn.call(el);
                }
                e.preventDefault();
            });
        }
        // 向上滑动滚动条的top值减少,list的top增加
        myScroll(wrap,function(){
            var t = css(scrolls,'top');
            t-=10;
            t = Math.max(0,t);
            scrolls.style.top =t+'px';
            list.style.top = -(ld*t/sd)+'px';
        },function(){
            var t = css(scrolls,'top');
            t+=10;
            t = Math.min(sd,t);
            scrolls.style.top =t+'px';
            list.style.top = -ld*(t/sd)+'px';
        });

画方框(案例)

        function css(el,attr,val){
                    if(attr==='backgroundColor'){
                        el.style[attr]=val;
                    }else if(arguments.length==3){
                        el.style[attr]=val+'px';
                    }else{
                        return parseFloat(getComputedStyle(el)[attr]);
                    }


                }
        window.addEventListener("mousedown",(e)=>{
            var startX = e.clientX;
            var startY = e.clientY;
            var box = document.createElement("div");
            box.classList.add('squart');
            document.body.append(box);
            let move = (e)=>{
                var endX = e.clientX;
                var endY = e.clientY;
                var width = Math.abs(endX-startX);
                var height = Math.abs(endY-startY);
                var l = Math.min(startX,endX);
                var t = Math.min(startY,endY);
                css(box,'width',width);
                css(box,'height',height);
                css(box,'left',l);
                css(box,'top',t);
            }
            window.addEventListener('mousemove',move);
            window.addEventListener('mouseup',(e)=>{
                window.removeEventListener('mousemove',move);
                e.preventDefault();
            },{once:true});
            e.preventDefault();
        });

正方形碰撞检测

        var box1 = document.querySelector("div");
        var box2 = document.querySelector(".box2");
        function css(el,attr,val){
            if(attr==='backgroundColor'){
                el.style[attr]=val;
            }else if(arguments.length==3){
                el.style[attr]=val+'px';
            }else{
                return parseFloat(getComputedStyle(el)[attr]);
            }
            
            
        }
        box1.addEventListener("mousedown",function(e){
            var startX = e.clientX;
            var startY = e.clientY;
            var l = css(box1,'left');
            var t = css(box1,'top');
            function move(e){
                var disX = e.clientX-startX+l;
                var disY = e.clientY-startY+t;
                css(box1,'left',disX);
                css(box1,'top',disY);
                var flag = isCollision(box1,box2);
                if(flag){
                    css(box1,'backgroundColor','yellow');
                }else{
                    css(box1,'backgroundColor','pink');
                }
            }
            document.addEventListener("mousemove",move);
            document.addEventListener("mouseup",function(e){
                document.removeEventListener('mousemove',move);
                e.preventDefault();
            },{once:true});
            e.preventDefault();
        });
        function isCollision(el1,el2){
            // 检测是否碰撞让元素与参照物四个方向都要进行比较,
            //当四中情况同时满足我们才能确定发生碰撞;
            var el1Rect = el1.getBoundingClientRect();
            var el1T = el1Rect.top;
            var el1L = el1Rect.left;
            var el1B = el1Rect.bottom;
            var el1R = el1Rect.right;
            var el2Rect = el2.getBoundingClientRect();
            var el2T = el2Rect.top;
            var el2L = el2Rect.left;
            var el2B = el2Rect.bottom;
            var el2R = el2Rect.right;
            if(el1R>el2L && el1L<el2R && el1T<el2B && el1B>el2T){
                return true;
            }
            return false;
        }

选框(案例)

    function css(el,attr,val){
            if(attr==='backgroundColor'){
                el.style[attr]=val;
            }else if(arguments.length==3){
                el.style[attr]=val+'px';
            }else{
                return parseFloat(getComputedStyle(el)[attr]);
            }
            
            
        }
    // 插入小格子
    [...'.'.repeat(15)].forEach((item,index)=>{
        document.body.innerHTML+=`<div class="div">${index+1}</div>`;
    });
    var box2 = document.querySelector(".box2");
    var arr=[];
    var list = document.querySelectorAll(".div");
    list = Array.from(list);
    document.addEventListener("mousedown",(e)=>{
        var startX = e.clientX;
        var startY = e.clientY;
        var box = document.createElement("div");
        box.classList.add("box");
        document.body.append(box);
        let move =(e)=>{
            var endX = e.clientX;
            var endY = e.clientY;
            var width = Math.abs(endX-startX);
            var height = Math.abs(endY-startY);
            var l = Math.min(endX,startX);
            var t = Math.min(endY,startY);
            css(box,'width',width);
            css(box,'height',height);
            css(box,'top',t);
            css(box,'left',l);
            // 发生碰撞存储元素
            arr = list.filter((item,index)=>{
                if(isCollision(box,item)){
                    item.classList.add("active");
                    return item;
                };

            });
            e.preventDefault();
        }
        document.addEventListener("mousemove",move);
        document.addEventListener("mouseup",(e)=>{
            document.removeEventListener('mousemove',move);
            box.remove();
            arr.forEach(item=>{
                // 如果原来页面中有该元素,append方法起到剪切的作用
                box2.append(item);
                item.classList.remove("active");
            });

            e.preventDefault();
        },{once:true});
        e.preventDefault();
    });
    function isCollision(el1,el2){
            // 检测是否碰撞让元素与参照物四个方向都要进行比较,
            //当四中情况同时满足我们才能确定发生碰撞;
            var el1Rect = el1.getBoundingClientRect();
            var el1T = el1Rect.top;
            var el1L = el1Rect.left;
            var el1B = el1Rect.bottom;
            var el1R = el1Rect.right;
            var el2Rect = el2.getBoundingClientRect();
            var el2T = el2Rect.top;
            var el2L = el2Rect.left;
            var el2B = el2Rect.bottom;
            var el2R = el2Rect.right;
            if(el1R>el2L && el1L<el2R && el1T<el2B && el1B>el2T){
                return true;
            }
            return false;
        }

圆形碰撞

 var box1 = document.querySelector(".box1");
        var circle = document.querySelector('#circle');
        function css(el,attr,val){
            if(arguments.length==3){
                el.style[attr] =val+'px'; 
            }else{
                return parseFloat(getComputedStyle(el)[attr]);
            }
        }
        circle.addEventListener("mousedown",(e)=>{
            var startX = e.clientX;
            var startY = e.clientY;
            var l = css(circle,'left');
            var t = css(circle,'top');
            let move = (e)=>{
                var distanceX = e.clientX-startX+l;
                var distanceY = e.clientY-startY+t;
                css(circle,'left',distanceX);
                css(circle,'top',distanceY);
                var flag = circleCollision(circle,box1);
                if(flag){
                   circle.style.backgroundColor = '#999';
                }else{
                    circle.style.backgroundColor = 'pink';
                }
                e.preventDefault();
            };
            document.addEventListener("mousemove",move);
            document.addEventListener("mouseup",(e)=>{
                document.removeEventListener('mousemove',move);
                e.preventDefault();
            },{once:true});
            e.preventDefault();
        });
        // 圆形碰撞
        function circleCollision(el1,el2){
            var el1W = el1.offsetWidth;
            var el1H = el1.offsetHeight;
            var el1R = el1.getBoundingClientRect();
            var el1T = el1R.top;
            var el1L = el1R.left;
            var el1Center={
                x:el1L+el1W/2,
                y:el1T+el1H/2
            }
            var el2W = el2.offsetWidth;
            var el2H = el2.offsetHeight;
            var el2R = el2.getBoundingClientRect();
            var el2T = el2R.top;
            var el2L = el2R.left;
            var el2Center={
                x:el2L+el2W/2,
                y:el2T+el2H/2
            }
           return Math.sqrt(Math.pow((el2Center.x-el1Center.x),2)+ Math.pow((el2Center.y-el1Center.y),2))<=(el1W/2+el2W/2)
        }

百度网盘(案例)

定义公共方法

    var topId = 0;
    var nowId = 0;
    var topPid = -1;
    /*通过id获取数据*/
    function getItemById(id){
        return data.filter(item=>item.id==id)[0];
    }
    /*通过父级id获取子集*/
    function getChildrenByPid(id){
        return data.filter(item => item.pid==id);
    }
    // 通过子元素查找父级
    function getParent(pid){
        var parent={};
        data.forEach(item => {
            if(item.id==pid){
                parent = item;
            }
        });
        return parent;
    }
    // 获取所有的父级
    function getAllParent(pid){
        var arr=[];
        while(pid>topPid){
            var parent = getParent(pid);
            // 再继续查找父集
            pid = parent.pid;
            arr.unshift(parent);
        }
        return arr;

    }

右侧路径渲染

        // 渲染右侧顶部路径区域
        function renderBreadNav(){
        var str=``;
        // 获取当前渲染的路径信息
        var currentItem = getItemById(nowId);
        // 获取当前路径的所有父集
        var arr = getAllParent(currentItem.pid);
        arr.forEach(item=>{
            str+=`<a data-id="${item.id}">${item.title}</a>`;
        });
        str+=`<span>${currentItem.title}</span>`
        return str;
        
    }

右侧文件夹区域渲染

// 渲染右侧下方文件夹内容区域
    function renderFolders(){
        var inner=``;
        var childrenList = getChildrenByPid(nowId);
        childrenList.forEach(item=>{
            inner+=` <li class="folder-item" data-id="${item.id}">
                        <img src="img/folder-b.png" alt="">
                        <span class="folder-name">${item.title}</span>
                        <input type="text" class="editor" value="${item.title}">
                        <label class="checked">
                            <input type="checkbox" />
                            <span class="iconfont icon-checkbox-checked"></span>
                        </label>   
                    </li>`;
        });
        return inner;
    }

左侧树状图渲染

// 左侧侧边栏树状结构的渲染
    /**
     * 1.level:设置p:padding-left呈现出树状解构,每次递归让level+1;
     * 2.通过当前id,来判断父级是否包含当前路径,如果包含,就让其打开;
     */
    function renderTreeMenu(pid,level){
        var inner = "";
        var children = getChildrenByPid(pid);
        // nowId是不变的,通过点击事件来改变
        var currentItem = getItemById(nowId);
        // allParent永远存的是当前id
        var allParent = getAllParent(currentItem.pid);
        allParent.push(currentItem);
        // console.log(allParent);
        inner =` <ul>
                    ${children.map(item =>{
                        var childrenItem = getChildrenByPid(item.id);
                                        // 当前id递归中的子集li的class='open'
                        return item = 
                        `<li class="${allParent.includes(item)?"open":""}">
                                        <p style="padding-left:${40+level*20}px" class="${childrenItem.length?"has-child":""} ${item.id==nowId?"active":""}" data-id=${item.id}><span>${item.title}</span></p>
                                        ${childrenItem.length? renderTreeMenu(item.id,level+1):""}
                        </li>`;                       
                    }).join("")}
                </ul>`;
        return inner;
    }

界面渲染(基础篇)

/*添加事件(事件委托) */
    // 侧边栏添加click事件
    menuList.addEventListener("click",function(e){
        // 点击span时,我们要把事件源换成p标签
        var item = e.target.tagName=='SPAN'? e.target.parentNode:e.target;
        if(item.tagName=="P"){
            nowId = item.dataset.id;
            render();
        }
    });
     

    // 路径导航添加click事件
     breadNav.addEventListener("click",(e)=>{
         if(e.target.tagName=='A'){
             nowId = e.target.dataset.id;
             render();
         }
     });
    //文件夹内容区域添加click事件
    folders.addEventListener("click",(e)=>{
        console.log(e.target);
        var item = e.target.tagName=="IMG"?e.target.parentNode:e.target;
        if(item.tagName=='LI'){
            nowId = item.dataset.id;
            render();
        }
    });

ES6

变量

// let 有作用域的概念,var 全局作用,用其声明会预解析
        for(let i = 0;i<4;i++){
            setTimeout(()=>{
                console.log(i);
            },100)
        }
        for(var i = 0;i<4;i++){
            setTimeout(()=>{
                console.log(i);
            },100)
        }

常量

       // 常量没有预解析
        const varabel=12;
        console.log(varabel);

解构

数组解构
        // 数组解构不需要{}
        let arr =[1,2,3];
        var  [a,b,c]= arr;
字符串解构
        // 字符串的解构
        let str = "wangao";
        let [a,b,c] = str;
        console.log(a);

扩展运算符

[...'.'.repeat(3)].forEach(item=>console.log(item));

展开运算符

        // 通过展开运算符我们可以把伪数组转化成数组
        let arr = [...nodeList];
        // 展开运算符的妙用
        let arr= [1,2,3,4];
        let [a,b,...c] = arr;
        console.log(c);
合并对象
        // 展开运算符
        let obj={
            a:12,
            b:14
        };
        let obj2 = {
            c:13,
            d:14
        };
        // 通过展开运算符可以合并对象,展开运算符具有克隆的作用
        let obj4={...obj,...obj2};
        console.log(obj4);

set集合

        // set 去重
        let arr = [1,1,2,2,3,3];
        let set = new Set(arr);
        // 获取集合长度
        var length = set.size;
        console.log(length);
        // 添加元素
        set.add(8);
        // 删除元素
        set.delete(3);
        // 是否包含指定元素
        var flag = set.has(2);
        console.log(flag);
        // 清空集合
        set.clear();
        console.log(set);

map集合

        let arr =[[1,2],[3,4]];
        let map = new Map(arr);
        map.forEach((key,value)=>{
            console.log(key+'=>'+value);
        });
        // 添加
        map.set(5,6);
        // 修改
        map.set(5,7);
        
        // 获取某元素
        let value =map.get(3);
        console.log(value);
        // 包含某元素
        let flag = map.has(3);
        console.log(flag);
        // 删除某元素
        map.delete(1);
        console.log(map);
        // 清空集合
        map.clear();

箭头函数

        // ...args:可变参数,是一个数组
        // 箭头函数当函数体只有一句可以省略“{}”;
        let fn = (...args )=>console.log(args);
        let result = fn(3);
        console.log(result);
        // 箭头函数的this指向跟其定义在作用域的对象有关
        let fun = ()=>console.log(this);
        // 在window中定义
         fun();
        //  如果在箭头函数中定义箭头函数,并寻找this,我们要看箭头函数中的上级作用域,
        // 如果是在普通方法中,就属于当前作用域的引用
        document.addEventListener("click",function(){
            let fun = ()=>console.log(this);
            fun();
        });

数组新增方法

Array.from()
         let arr = [1,2,3,4];
        // 复制数组,也可以把伪数组转成数组
        arr2 = Array.from(arr);
        // 改变arr2元素的值,不会改变原有数组arr的值
        arr2[1]=10;
        console.log(arr);
Aarray.of()
       // 声明新数组
        let arr3 = Array.of(1,4,8,10);
        console.log(arr3);
find()和findIndex()
      /** 
        * find方法可以返回第一个满足条件
        * 的值,当满足条件,返回该值,并
        * 停止查找。同理findIndex()原理一
        * 样,返回对应的索引
        * **/
       var num =arr.find(item=>{
           console.log(item);
           return item>5;
       });
       console.log(num);
includes()
       let arr = [1,3,5,7,9];
       //是否包含某元素,返回值为false    
       let flag = arr.includes(3)
       console.log(flag);
flat()
       let arr = [[1,3],[[1,2,[3,4,5]]],[5,7,9]];
       //数组扁平化方法 flat();参数代表扁平的层数
       var arr3 = arr.flat(Infinity); 
       console.log(arr3);
flatMap()
       let arr = [[1,2],[3,4,5],[6,7,9]];
       //遍历二维数组,返回值也是个数组
       var arr2 = arr.flatMap((item)=>{
        //    console.log(item);
           var item2 = item.filter(ele=>ele>4);
           return item2;
       });    
       console.log(arr2);

新增字符串方法

       let str = "helloworld";
        // arg1:指定的字符,arg2:字符当中对应的索引,注意结束位置的索引length+1(原理迭代器的指针查找)
        let flag =str.endsWith('d',10);
        console.log(flag);
        // 同理startswith()与之一样,也可以不指定索引
        let flag2 = str.startsWith("hel");
        console.log(flag2);
        // 是否包含指定字符串
        let result = str.includes("hel");
        console.log(result);
        // 重复字符串
        ".".repeat(10);

object

let obj1= {
            a:123,
            b:456
        }
        let obj2 ={
            c:789,
            d:1012,
        }
        // 如果不想改变原来的数据结构,我们要传一个{},剩余参数合并的目标对象
        let obj3 = Object.assign({},obj1,obj2);
        console.log(obj3);
        // is()类似于===,不推荐比较number类型的数据
        let flag = Object.is(obj1,obj2);
        console.log(flag);
对象的简洁
 // 对象简介表示,[n]属性名的定义,省略function
        let a =10;
        let n ='d';
        let obj ={
            a,
            [n]:13,
             add(c,d){
                return c+d;
            }
        }

Ajax

封装Ajax函数
            let ajaxNet=(obj)=>{
                let {type,url,args,success} = obj;
                // 创建对象
                let http = new XMLHttpRequest();
                type = type ||"GET";
                switch(type.toLowerCase()){
                    case 'get':
                        http.open(type,url+'?'+obj2String(args),true);
                        http.addEventListener('load',()=>{
                            if(http.readyState=='4' && http.status==200){
                                success && success(http.responseText);
                            }
                        });
                        http.send();
                        break;
                    case 'post':
                        // 创建连接
                        http.open(type,url,true);
                        // 监听load事件
                        http.addEventListener('load',()=>{
                            // 通过状态码来判断是否访问成功
                            if(http.readyState=='4'&& http.status==200){
                                success && success(http.responseText);
                            }
                        });
                        // post请求需要添加请求头
                        http.setRequestHeader("Content-type",'application/x-www-form-urlencoded');
                        // post请求参数放在send中
                        http.send(obj2String(args));
                        break;

                }
                
            }
Ajax案例
           // 渲染UL
            function renderUl(data,nowpage){
                let newArr =data.map((item)=>{
                    return`<li>${item.title}</li>`;
                });
                return newArr.join("");
            }
            // 渲染ol
            function renderOl(data,nowPage=1){
                let newOl = data.map((item,index) => {
                    return`<li class="${nowPage==index+1?"active":""}">${index+1}</li>`;
                });
                return newOl.join("");
            }
            // 对象转化成字符串
            // key=str&key2=str2?
            function obj2String(obj){
                let arr = [];
                for (let key in obj) {
                    arr.push(key+'='+obj[key]);
                }
                return arr.join('&');
            }
            // 封装Ajax函数
            let ajaxNet=(obj)=>{
                let {type,url,args,success} = obj;
                // 创建对象
                let http = new XMLHttpRequest();
                type = type ||"GET";
                switch(type.toLowerCase()){
                    case 'get':
                        http.open(type,url+'?'+obj2String(args),true);
                        http.addEventListener('load',()=>{
                            if(http.readyState=='4' && http.status==200){
                                success && success(http.responseText);
                            }
                        });
                        http.send();
                        break;
                    case 'post':
                        // 创建连接
                        http.open(type,url,true);
                        // 监听load事件
                        http.addEventListener('load',()=>{
                            // 通过状态码来判断是否访问成功
                            if(http.readyState=='4'&& http.status==200){
                                success && success(http.responseText);
                            }
                        });
                        // post请求需要添加请求头
                        http.setRequestHeader("Content-type",'application/x-www-form-urlencoded');
                        // post请求参数放在send中
                        http.send(obj2String(args));
                        break;

                }
                
            }
            let ul = document.querySelector("ul");
            let ol = document.querySelector("ol");
            // 默认加载
            ajaxNet({
                url:'http://localhost:8787/getNews',
                args:{
                    page:1,
                    count:4
                },
                success:(res)=>{
                    let json = JSON.parse(res);
                    let{data,totalPage} = json;
                    ul.innerHTML= renderUl(data);
                    console.log(json);
                    console.log([...'.'.repeat(totalPage)]);
                    ol.innerHTML = renderOl([...'.'.repeat(totalPage)]);

                }

            });
            // 事件委托
            ol.addEventListener("click",(e)=>{
                if(e.target.tagName=="LI"){
                    let page = e.target.innerHTML;
                    ajaxNet({
                        url:'http://localhost:8787/getNews',
                        args:{
                            page,
                            count:4
                        },
                        success:(res)=>{
                            let json = JSON.parse(res);
                            let{data,totalPage} = json;
                            ul.innerHTML= renderUl(data);
                            console.log(json);
                            console.log([...'.'.repeat(totalPage)]);
                            ol.innerHTML = renderOl([...'.'.repeat(totalPage)],page);

                        }

                    });

                }
            });

tudo(案例)

{
    /** 数据渲染 **/
    let data = [
        {
            id:0,
            title:'起床',
            todo:false,
            edit:false
        },{
            id:1,
            title:'吃饭',
            todo:false,
            edit:false
        },{
            id:2,
            title:'睡觉',
            todo:true,
            edit:false
        },{
            id:3,
            title:'打豆豆',
            todo:false,
            edit:false
        }

    ];
    let content= document.querySelector(".content");

    // 没有完成的事件
    let undone = (arr)=>{
        /** reduce((n1,n2)=>{},args)
         * 当args赋值,n1的值就等于args,
         * n2:可以代表遍历数组的元素
         * 返回值的结果 永远是e1也就是args
         * 返回值坐累加处理
         * **/
        return arr.reduce((el1,el2)=>{
            return el2.todo?el1:el1+1;
        },0);
    }
    // 通过id查找数组元素
    let findEleById =(id)=>{
        return data.filter( item =>item.id==id)[0];
    } 
    // 渲染完成项
    let renderDone = ()=>{
        return`<span class="todo-clear">
                  <a href="#">Clear <span>${data.length-undone(data)}</span>已完成事项</a>
               </span>`;
    }
    // 渲染未完成项
    let renderUndone = ()=>{
        return `<span class="todo-count">
                    <span class="number">${undone(data)}</span> 
                    <span class="word">项待完成</span>
                </span>`;
    }
    // 退出编辑状态的准备工作,改变值会触发change事件,事件委托一定要进行处理
    let toBlur = (e)=>{
        let {target} = e;
        let {id} = target.parentNode.parentNode.dataset;
        data.forEach(item=>{
           if(target.value.trim()){
                if(item.id == id){
                    item.title = target.value;
                    item.edit = false;
                }
           }
        });
        render(data);
        console.log(data);
        e.stopPropagation();
    }
    let undoneLe = undone(data);

    // 参数必须是个数组
    let render = (arr)=>{
        content.innerHTML = 
        `<ul id="todo-list">
            ${arr.length?renderLi(arr):""}
        </ul>
        <div id="todo-stats">
                ${undoneLe?renderUndone():""}
                ${data.length-undoneLe?renderDone():""}     
        </div>`;
        let list =  document.querySelectorAll(".edit input");
        list.forEach((item,index)=>{
            // 只能显示一个编辑状态
            if(data[index].edit){
                item.select();
            }
            item.addEventListener("blur",toBlur);
        });
        
    }
    // 渲染li
    let renderLi = (arr)=>{
        return arr.map((item) => {
            // return 后面的语句不能换行
            return item = `<li class="${item.edit?"editing":""}">
                            <div class="todo ${item.todo?'done':''}" data-id="${item.id}">
                                <div class="display">
                                    <input class="check" type="checkbox"${item.todo?'checked':""}>
                                    <div class="todo-content">${item.title}</div>
                                    <span class="todo-destroy"></span>
                                </div>
                                <div class="edit">
                                    <input class="todo-input" type="text" value="${item.title}">
                                </div>
                            </div>
                        </li>`;
        }).join("");

    }
    render(data);
    /***
     * 
     * 多个input添加autofocus会走最后一个
     */
    // 添加checkbox状态:改变todo状态,事件委托
    content.addEventListener("change",({target})=>{
        // 编辑状态不触发父控件的change事件
        if(target.className!="check"){
            return;
        }
        if(target.tagName=="INPUT"){
            let parent =target.parentNode.parentNode;
            let pid = parent.dataset.id;
            let item = findEleById(pid);
            // checkbox 一定要跟 数据进行双向绑定
            item.todo = target.checked;
            render(data);

        }  
    });
    // 添加计划
    let newTodo = document.querySelector("#new-todo");
    window.addEventListener("keydown",({keyCode})=>{
        if(keyCode==13){
            if(newTodo.value.trim()){
                let text = newTodo.value;
                data.push({
                    id: Date.now(),
                    title:text,
                    todo:false,
                    edit:false
                });
                render(data);
                newTodo.value="";
            }else{
                alert("请输入计划!!!")
            }
        }
    });
    // 删除一项计划
    content.addEventListener("click",({target})=>{
        if(target.className=="todo-destroy"){
            let {id} = target.parentNode.parentNode.dataset;
            data = data.filter(item=>item.id!=id);
            render(data);
        }
    });
    // 清空已完成计划
    content.addEventListener("click",(e)=>{
        let {target} = e;
        if(target.tagName=="A"||target.parentNode.tagName=="A"){
            data = data.filter(item=>item.todo==false);
            render(data);
            // 清空a的默认行为
            e.preventDefault();
        }
    });
    // 编辑计划
    content.addEventListener("dblclick",(e)=>{
        let {target} = e;
        if(target.className=="todo-content"){
            let {id} = target.parentNode.parentNode.dataset;
            data.forEach(item=>{
                if(item.id==id){
                    item.edit= true;
                }
            });
            render(data);
            
            
        }
    });
    

}