-3 WebAPI

WebAPI

  1. WebAPI

  2. API: Application programming Interface,应用程序编程接口

  3. Web API 提供的一套操作浏览器功能和页面元素的API

  4. 通过DOM接口可以改变网页的内容、解构和样式

  5. DOM

    -1 创建元素

    1. document.write
    2. innerHTML 常用
    3. createElement

    -2 增加元素

    1. appendChild
    2. insertBefore

    -3 删除元素

    1. removeChild

    -4 修改元素

    1. 修改属性: src href title
    2. 修改普通元素内容: innerHTML innerText
    3. 修改表单元素: value type disabled
    4. 修改元素样式: style className

    -5 查找元素

    1. DOM提供的API方法: getElementById getElementsByTagName
    2. H5提供的新方法: querySelector querySelectorAll 常用
    3. 利用节点操作获取元素: (父)parentNode (子)children previousElementSibling
      nextElementSibling

    -6 属性操作

    1. setAttribute 设置DOM属性
    2. getAttribute 得到DOM属性
    3. removeAttribute 移除属性

    -7. 事件操作
    - onclick
    - onmouseover
    - onmouseout
    - onfocus
    - onblur
    - onmousemove
    - onmouseup
    - onmousedown

1.1 获取标签

1 web_API

#1_ DOM:Document Object Model
 - 文档:一个页面就是一个文档,DOM中使用 document 表示
 - 元素(element):页面中的所有的标签都是元素,元素可以看成是对象
 - 节点(node):页面中所有的内容都是节点:标签,属性,文本
 - 树状图(DOM树):由文档及文档中的所有的元素(标签)组成的一个树形结构图

 --- #1 获取标签
 	-- document.getElementById("btn")
 	-- document.getElementsByTagName("p")   //根据标签名字获取元素,返回的是一个伪数组
    -- document.getElementsByTagName("a")[0]

  -- document.getElementsByName("name属性的值")  //根据name属性的值获取元素,返回来的是一个伪数组
  -- document.getElementsByClassName("cls")
  -- document.querySelector("#btn")   //根据选择器获取元素,可以使用它们的 id, 类, 类型, 属性, 属性值等来选取元素
  -- document.querySelector(".box")  //万用属性获取元素,较常用
  -- document.querySelector("li")
  
  -- document.querySelectorAll(".cls")   //根据选择器获取元素,返回来的是一个伪数组,里面保存了多个的DOM对象
  
  -- var bodyEle = document.body   // 返回body元素对象
  -- var htmlEle = document.documentElement   //返回html元素对象

  -- #2节点操作,利用节点层次关系获取元素
    - nodeType: 节点的类型,1---标签节点,2----属性节点,3---文本节点
    - nodeName: 标签节点--大写的标签名字,属性节点---小写的属性名字,文本节点---#text
    - nodeValue: 标签---null,属性---属性的值,文本---文本内容

    - ulObj.parentNode.nodeType 
    - ulObj.parentNode.nodeName
    - ulObj.parentNode.nodeValue

	- dvObj.childNodes   //获取子节点,包括元素节点,文本节点等
    - var nodes=dvObj.childNodes[i];   //获取里面的每个子节点,返回一个集合
	- if (nodes[i].nodeType == 1 && nodes[i].nodeName == "P")  //判断这个子节点是不是p标签

    - dvObj.children     //只获取子元素节点,常用
    - ulObj.children[0]  //获取第一个子元素节点,常用
    - ulObj.children[ul.children.length -1]  //获取最后一个子元素节点,常用
   
    - ulObj.firstElementChild  //获取第一个子元素节点
	- ulObj.lastElementChild	
	 
	- .nextSibling   //某个元素的后一个兄弟节点,包含文本节点,元素节点等等
	- .previousSibling 
    - .nextElementSibling  //后一个兄弟元素节点,常用
    - .previousElementSibling
    
	- 获取元素/节点操作对比
    - ulObj.parentNode  - ulObj.parentElement  //父级节点  //父级元素
    - ulObj.childNodes  - ulObj.children
    - ulObj.firstChild  - ulObj.firstElementChild
    - ulObj.lastChild   - ulObj.lastElementChild
    - .previousSibling  - .previousElementSibling  //某个元素的前一个兄弟节点;某个元素的前一个兄弟元素
    - .nextSibling    - .nextElementSibling//某个元素的后一个兄弟节点;某个元素的后一个兄弟元素
    
    - 节点选择比元素选择多一个中间空白#text

    - var node=dvObj.getAttributeNode("id");   //获取的是属性的节点

1.2 元素的样式操作

 --- #2 元素的样式操作
   -- JS 修改的 style 样式,产生的是行内样式,CSS 权重比较高
   -- src,title,alt,href,id   //操作基本标签的属性
   -- name,value,type,checked,selected,disabled,readonly //操作表单标签的属性
   -- .style.属性=值;    //元素的样式操作
   -- .className=值;
   -- element.style   行内样式类操作
   -- element.className  类名样式类操作,会覆盖原先类名,可以写多个保留原来的类名

   -- img
   	- imObj.src="images/liuyan.jpg";  //设置图片的大小
    - imObj.width="300";
    - imObj.height="400";
    - imObj.style.width = "300px";
    - imObj.style.backgroundColor = "pink";

   -- btn/a
    - btnObj.innerText="设置文字";
    - btnObj.href = "http://www.itcast.cn";
    - btnObj.checked=true;
    - this.src=document.getElementById("ak").href;
    - this.value.length

   -- div 
    - dvObj.style.width = "300px";
    - dvObj.style.backgroundColor = "yellow";
    - dvObj.style.border = "10px solid red";
    - dvObj.style.display="none";
    - dvObj.display="block";
    - dvObj.className="cls";   //设置类样式
    
   -- 表单
    - inputObJ.value = '设置输入框内的文字'

   -- 伪数组
    - 循环遍历这个数组, 
    - imgObjs[0].alt = "改了";  
    - imgObjs[0].title = "现实吧";
    - inputs[i].value = "设置文字";
    - inputs[i].type != "button";//判断
    - imgObjs[i].onclick;
    -inputs[i].value

1.3 元素内容操作

 --- #3 元素内容操作  
     - pObjs[i].innerText="设置文字";  //直接显示,不识别html标签
     - document.getElementsByTagName("p")[0].innerText   //获取文本框的值
       - textContent
     - .innerHTML="<p>这是一个p</p>"  //设置新的html标签内容,识别html标签。常用

   -- 函数操作。常用
    - imgObjs[i].onclick  //注册点击事件
    - list[i].onmouseover  //注册事件
    - list[i].onmouseout
    - .onblur       //注册失去焦点的事件
    - .onfocus      //注册获取焦点的事件
    - return false   //阻止超链接默认的跳转事件
   
  -- 获取属性值
    - element.属性    获取属性值,获取的是本身自带的属性值
    - element.getAttribute('属性')  获取的是自定义的属性值

  -- 设置属性值
    - element.属性= '值'     获取属性值,获取的是本身自带的属性值
    - element.setAttribute('属性','值')     获取的是自定义的属性值
     
  -- 自定义属性
   - list[i].setAttribute("score",(i+1)*10);    /setAttribute("属性的名字","属性的值");
   - this.getAttribute("score")                 /getAttribute("属性的名字")
   - my$("dv").removeAttribute("score")     / 移除自定义属性:removeAttribute("属性的名字")
   - my$("dv").removeAttribute("class")         /移除元素自带的样式属性
 
  --H5自定义属性
   - 为了保存并使用数据,data-开头作为属性并且赋值 
   -  <div data-index= '1'></div>
   -  element.setAttribute('data-index',2)   //设置属性
   -  element.getAttribute('data-index')   //获取属性值
					  //dataset 是一个集合里面存放了所有以data开头的自定义属性,只能获取data-开头
   -  element.dataset.index  //获取属性值
   -  element.dataset[ 'index' ]    //获取属性值

1.4 元素的创建和移除

--- #4 元素的创建
  -- document.write("标签代码及内容");  
    //如果在页面加载完毕后创建元素.页面中的内容会被干掉,会导致页面重绘

   - document.write("<p>这是一个p</p>");

  -- 父级对象.innerHTML="标签代码及内容";   //创建并插入
   - my$("dv").innerHTML="<p>窗前明月光,疑是地上霜,举头望明月,低头思故乡</p>";
	 // 拼接字符串较耗时,数组方式可提高效率
	
  -- document.createElement("标签名字");  //创建元素节点,常用
	- var pObj = document.createElement("p");  //先创建,再插入
	- divObj.appendChild(pObj)
    - setInnnerText(元素对象,"元素内容");  //插入内容
	- setInnnerText(pObj, "这是一个标签p");

    - 父级元素.appendChild(子级元素对象);  //添加节点,后面追加元素
     - my$("dv").appendChild(obj)
									//添加节点,选择位置追加元素
    - 父级元素.inerstBefore(新的子级对象,参照的子级对象); 
     - my$("dv").insertBefore(obj,my$("dv").firstElementChild)

    - 父级元素.removeChild(要干掉的子级元素对象);  //删除节点
     - my$("dv").removeChild(my$("dv").firstElementChild)
	
 -- node.cloneNode()   //克隆节点,默认只复制标签,不复制内容
  -- var li = ul.children[0].cloneNode(true);   
     ul.appendChild(li);//括号内为true,为深拷贝,会复制节点本身以及里面所有的子节点

1.5 事件

--- #5 事件的绑定和解绑
   -- 1. 对象.on事件名字=事件处理函数  /如果是多个相同事件注册用这种方式,最后一个执行,之前的被覆盖了 
   		 事件源.事件类型 = 事件处理程序
   		 
     - my$("btn").onclick=function(){};
     - onclick
     - onmousenter  
     - onmouseover
     - onmouseout
     - onfocus
     - onblur
     - onmousemove
     - onmouseup
     - onmousedown
    

   -- 为同一个元素绑定多个相同的事件
   -- 2. 对象.addEventListener("没有on的事件名字",事件处理函数,false);
     - my$("btn").addEventListener("click",function(){},false);  
     - my$("btn").addEventListener("click",f1,false);
     - my$("btn").removeEventListener("click",f1,false); //解绑
   	 - divs[0].onclick = null;   //解绑

   -- 3. 对象.attachEvent("有on的事件名字",事件处理函数);  /仅IE8支持
     - my$("btn").attachEvent("onclick",function(){});
     - my$("btn").attachEvent("onclick",f1);
     -- my$("btn").detachEvent("onclick",f1);

   -- 事件对象
	- event 是一个事件对象,是事件的一系列相关数据的集合
	- div.addEventListener('click',function(event){
       consoel.log(event);
   })
     
    - e.target  返回触发事件的对象
    - e.currentTarget  返回触发事件的对象, ie6-8不兼容
    - e.srcElement  返回触发事件的对象, ie6-8使用
    - e.type  返回事件的类型,如 click mouseover 不带on
    - e.cancelBubble  该属性阻止冒泡, ie6-8使用
	- e.returnValue  该属性阻止默认事件,如不让链接跳转, ie6-8使用
	- e.preventDefault()  该方法阻止默认事件,如不让链接跳转
	- e.stopPropagation()  阻止冒泡,标准
    
  -- 鼠标事件 mouseEvent -mousemove
     - e.clientX  返回鼠标相对于浏览器窗口可视区域的X
     - e.clientY  返回鼠标相对于浏览器窗口可视区域的Y
     - e.pageX    返回鼠标相对于文档页面的 X 坐标,IE9+ 常用
     - e.pageY    返回鼠标相对于文档页面的 Y 坐标,IE9+ 常用
     - e.screenX  返回鼠标相对于电脑屏幕的 X 坐标
     - e.screenY  返回鼠标相对于电脑屏幕的 Y 坐标
     
     -mouseenter  mouseenter不会冒泡,只会经过自身盒子触发
     -mouseleave

	 -mouseover  会冒泡
	 -mouseout
   
   -- 键盘事件 
   	- onkeyup     某个键盘按键被松开时触发,不区分字母大小写
    - onkeydown   某个键盘按键被按下时触发,不区分字母大小写
    - onkeypress  某个键盘按键被按下时触发,不能识别功能键,区分字母大小写
    - 执行顺序 keydown -- keypress --  keyup
    
    - e.keyCode  相应键的ASCII值
	- 
    
   -- 事件委托
    - 不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
    - 案例: 给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,因为点击li,事件会冒泡到ul上,ul有注册事件,就会触发事件监听器
       
   -- 为同一个元素绑定多个不同的事件,指向相同的事件处理函数
    - switch(e.type)-case  

--- #6 事件冒泡
   -- 多个元素嵌套,有层次关系,这些元素都注册了相同的事件,如果里面的元素的事件触发了,外面的元素的该事件自动的触发了.
   -- document > html > body > div
   -- e.stopPropagation();  // 谷歌和火狐支持
   -- window.event.cancelBubble=true;  // IE特有的

#3_ 思维

  -- 动态选择效果   先设置好静态效果,再循环遍历注册元素点击事件,在点击时去清除样式和添加样式。
  -- 排他功能    循环遍历每次点击设置一次属性值的初始化
  -- 命名函数  如果是循环的方式添加事件,推荐用命名函数
  -- 匿名函数  如果不是循环的方式添加事件,推荐使用匿名函数

--- #7 动画函数封装
  -核心原理:通过定时器 setInterval() 不断移动盒子位置

1.5 事件实例代码

//1 阻止默认事件,让链接不跳转,或让提交按钮不提交
var a = document.querySelector('a');
a.addEventListener('click', function(e){
    e.preventDefault();
})

//传统写法
a.onclick = function(e){
    e.preventDefault();  //普通浏览器
    e.returnValue;  // 低版本浏览器 ie6~8
    return false;  // 但是return 后面的代码不执行
}

//2 阻止冒泡兼容方案
if (e && e.stopPropagation){
    e.stopPropagation();
} else {
   window.event.cancelBubble = true; 
}

//3 事件监听
<ul>
	<li>点击弹框</li>    
	<li>点击弹框</li>    
	<li>点击弹框</li>    
	<li>点击弹框</li>    
	<li>点击弹框</li>    
</ul>
//事件委托核心原理:给父节点添加侦听器,利用事件冒泡影响每一个子节点
var ul = document.querySelector('ul');
ul.addEventListener('click',function(){
    // alert('点击弹框');
    // e.target 可以得到点击对象
    e.target.style.backgroundColor = 'black';
})

//4 禁止复制页面中的文字
  //1 contextmenu 禁止右键菜单
document.addEventListener('contextmenu', function(e) {
    e.preventDefault();
})

  //2 selectstart禁止选中文字
document.addEventListener('selectstart', function(e){
    e.preventDefault();
})

//5 跟随鼠标移动的图标
//每次移动鼠标,能获取最新的鼠标坐标,把这个x和y坐标作为图片的top和left值就可以移动图片
//图片要移动距离,且不占位置,需使用绝对定位

<img src="images/angel.gif" alt="">
<script>
var pic = document.querySelector('img');
document.addEventListener('mousemove', function(e){
    //1. mousemove 只要鼠标移动1px,就会触发事件
    var x = e.pageX;
    var y = e.pageY;
    console.log('X坐标是' + x, 'Y坐标是' + Y);
    pic.style.left = x - 50 + 'px';  // 坐标需要加 px 单位
    pic.style.top = y - 40 + 'px';
})  
</script>


//6 常用键盘事件

document.onkeyup = functon(){
    console.log('keyup');
}

document.addEventListener('keyup', function(){
    console.log('keyup');
})

document.addEventListener('keydown', function(){
    console.log('keydown');
})

document.addEventListener('keypress', function(){
    console.log('keypress');
})


//7 按下s键自动定位搜索框
//检测到用户按下了s键,就把光标定位到搜索框里面

<input type="text">

var search = document.querySelector('input');
document.addEventListener('keyup', function(e){
    if(e.keyCode === 83){
        search.focus();
    }
})
    
//8 输入框上方显示放大内容
//给表单添加键盘事件,把表单内容值 value 获取过来赋值给放大盒子
    <style>
        /* 放大框下方小三角 */
        
        .con::before {
            content: '';
            width: 0;
            height: 0;
            position: absolute;
            top: 28px;
            left: 18px;
            border: 8px solid #000;
            border-style: solid dashed dashed;
            border-color: #fff transparent transparent;
        }
    </style>
<body>
    <div class="search">
        <div class="con">123</div>
        <input type="text" placeholder="请输入快递单号" class="jd">
    </div>
</body>
<script>
    //1 获取元素
    var con = document.querySelector('.con');
    var jd_input = document.querySelector('.jd');
	//2 注册按键up事件,将值给 con
    jd_input.addEventListener('keyup', function() {
        if (this.value == '') {
            con.style.display = 'none';
        } else {
            con.style.display = 'block';
            con.innerText = this.value;
        }
    })
	//3 失去焦点时,就隐藏con盒子
	jd_input.addeventListener('blur',function(){
        con.style.display = 'none';
    })
	//4 得到焦点时,就显示con盒子
	jd_input.addeventListener('focus',function(){
        if(this.value !== ''){
            con.style.display = 'block';
        }
    })
</script>

1.6 元素实例代码

//1分时显示不同图片

<body>
	<img src='images/a.gif' alt="">
	<div>上午好</div>
	<script>
		//1.获取元素
        var img = document.querySelector('img');
        var div = document.querySelector('div');
        //2.得到当前的小时数
		var date = new Date();
		var h = date.getHours();
		//3. 判断小时数改变图片和文字信息
		if(h < 12){
            img.src = 'images/s.gif';
            div.innerHTML = '上午好!';
        } else if(h < 18){
            img.src = 'images/x.gif';
            div.innerHTML = '下午好!';
        } else {
            img.src = 'images/w.gif';
            div.innerHTML = '晚上好!'
        }
    </script>
</body>

//2用户登录框,切换登录框
//一个按钮两个状态,点击一次切换为文本框继续点击一次切换为密码框

<div class="box">
	<label for="">
    	<img src="image/close.png" alt="" id='eye'> 
    </label>
    <input type="password" name="" id="pwd">    
</div>
<script>
//1. 获取元素
var eye = document.getElementById('eye');
var pwd = document.getElementById('pwd');
//2. 注册事件处理程序
var flag = 0;
eye.onclick = function(){
    if (flag == 0){
        pwd.type = 'text';
        eye.src = 'images/open.png';
        flag = 1;
    } else {
        pwd.type = 'password';
        flag = 0;
    }   
}
</script>

//3点击关闭二维码图片
<div>
	<img src="images/tao.png" alt="">
    <i class="close-btn">X</i>
</div>
//1. 获取元素
var btn = document.querySelector('.close-btn');
var box = document.querySelector('.box');
//2. 注册事件,程序处理
btn.onclick = function(){
    box.style.display = 'none';   //改变属性,隐藏
} 

//4循环精灵图背景
//背景图为竖向排列的一个精灵图,让循环里边的i索引号*44就是每个图片的y坐标
//1.获取元素,所有的小 li
var lis = document.querySelectorAll('li');
for(var i = 0;i < lis.length;i++){
    //让索引号乘以44,就是每个人 li 的背景y坐标
    var index = i * 44;
    lis[i].style.backgroundPosition = '0 -'+index+ 'px';  //(x y) (0 -44px)
}

//5显示隐藏文本框内容
//当鼠标点击文本框时,里面的文字隐藏,当鼠标离开文本框时,里面的文字显示 
<input type="text" value="手机">

// 1. 获取元素
var text = document.querySelector('input');
// 2. 注册事件,获取焦点事件 onfocus
text.onfocus = function(){
    if(this.value ==== '手机'){
        this.value = '';
    }
    // 获得焦点时需要把文本框里面的文字颜色变黑
    this.style.color = '#333';
}

//3. 注册事件,失去焦点事件 onblur
text.onblur = function(){
    if(this.value === ''){
        this.value = '手机'
    }
    // 失去焦点时需要把文本框里面的文字颜色变黑
    this.style.color = '#999'
}

//6密码提示框显示
<div class="register">
	<input type="password" class="ipt">		
	<p class="message">请输入6~16位密码</p>
</div>
//1. 获取元素
var pit = document.querySelector('.ipt');
var message = document.querySeletor('.message');
//2. 注册事件 失去焦点
ipt.onblur = function(){
    // 根据表单里面值的长度 ipt.value.length
    if (this.value.length <6 || this.value.length > 16){
        message.className =  'messaga wrong';
        message.innerHTML = '输入的位数要求是6~16位';
    } else {
        message.className = 'message right';
        message.innerHTML = '您输入的正确!';
    }
}

//7排他思路
//1. 获取所有的6个按钮标签
var btns = document.getElementsByTagName('button');
// btns 得到的是伪数组,
for(var i = 0; i< btns.length;i++){
    btn[i].onclick = function(){
        // 先把所有的按钮的背景色都去掉
        for(var i = 0;i < btns.length;i++){
            btns[i].style.backgroundColor = '';
        }
        // 然后设置当前点击的元素背景颜色
        this.style.backgroundColor = 'pink';
    }
}

//8点击切换背景图片
// 1. 获取元素
var imgs = document.querySelector('.baidu').querySelectorAll('img');
//2. 循环注册事件
for(var i = 0; i< imgs.length;i++){
    imgs[i].onclick = function(){
        // this.src 是点击图片的路径,把这个路径给 body
        document.body.style.backgroundImage = 'url(' +this.src+ ')';
    }
}

//9 hover表格行高亮
// 1.获取元素,获取 tbody 里面所有的行
var trs = document.querySelector('tbody').querySelectorAll('tr');
// 2. 利用循环绑定注册事件
for(var i = 0;i< trs.length;i++){
    // 3.鼠标经过事件 onmouseover 
    trs[i].onmouseover = function(){
        this.className = 'bg';
    }
    // 4.鼠标离开事件 onmuseout
    trs[i].onmouseout = function(){
        this.className = '';
    }
}

//10 全选按钮
//1. 获取元素
var j_cbALL = document.getELememtById('j_cbAll');
var j_tbs = document.getELementById('j_tb').getElementByTagName('input');

//2. 注册事件 
j_cbAll.onclick = function(){
    for(var i =0;i< j_tbs.length; i++){
        j_tbs[i].checked = this.checked;  //this.checked获取当前复选框的选中状态
    }
}

//3. 下面复选框需要全部选中,上面全选按钮才选中
//给下面每个复选框注册点击时事件,每次点击都循环判断4个小按钮是否全部选中
for(var i = 0; i < j_tbs.length;i++){
    j_tbs[i].onclick = function(){
        var flag = true; //flag 控制全选按钮是否选中
        for(var i=0; i< j_tbs.length; i++){
            // 每次点击下面的复选框都要循环检查4个小按钮是否全部被选中
            if(!j_tbs[i].checked){
                flag = false;
                break     //只要有一个没有选中,就退出for循环
            }
        }
        j_cbAll.checked = flag;
    }
}

//11 点击tab切换对应的内容

<body>
  <div class="tab">
    <div class="tab_list">
      <ul>
        <li class="current">商品介绍</li>
        <li>规格与包装</li>
        <li>售后保障</li>
        <li>商品评价</li>
        <li>手机社区</li>
      </ul>
    </div>
    <div class="tab_con">
      <div class="item" style="display: block;">内容1</div>
      <div class="item">内容2</div>
      <div class="item">内容3</div>
      <div class="item">内容4</div>
      <div class="item">内容5</div>
    </div>
  </div>
</body>
<script>
  // 获取元素
  var tab_list = document.querySelector('.tab_list');
  var lis = tab_list.querySelectorAll('li');
  var items = document.querySelectorAll('.item');
  // for 循环绑定点击事件
  for (var i = 0; i < lis.length; i++) {
    // 给5个小li设置索引号
    lis[i].setAttribute('index', i);
    lis[i].onclick() = function () {
      for (var i = 0; i < lis.length; i++) {
        lis[i].className = ''
      }
      this.className = 'current';

      // 下面的显示内容模块
      var index = this.getAttribute('index');
      // 先让所有的div隐藏
      for (var i = 0; i < items.length; i++) {
        items[i].style.display = 'none';
      }
      //留下对应index的item显示出来
      items[index].style.display = 'block';
    }
  }
</script>

//12 下拉菜单 
<ul class="nav">
    <!-- ul元素中包含4个li  -->
    <li>
      <!-- 每个li元素中包含a和ul  -->
      <a href="#">微博</a>
      <ul>
        <li>
          <a href="#">私信</a>
        </li>
        <li>
          <a href="#">评论</a>
        </li>
        <li>
          <a href="#">@我</a>
        </li>
      </ul>
    </li>
  </ul>
//鼠标经过li,里面的第二个孩子ul显示,鼠标离开,则ul隐藏
  //1. 获取元素
  var nav = document.querySelector('.nav');
  var lis = nav.children; //得到4个小li
  //2. 循环注册事件
  for (var i = 0; i < lis.length; i++) {
    lis[i].onmouseover = function () {
      //获取第二个子元素节点
      this.children[1].style.display = 'block';
    }
    lis[i].onmouseout = function () {
      this.children[1].style.display = 'none';
    }
  }

//13 简单版发布留言案例
//点击按钮,动态创建一个li,添加到ul里面
 <textarea name="" id="" cols="30" rows="10">评论内容</textarea>
  <button></button>
  <ul></ul>

//1.获取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
//2.注册事件
 btn.onclick = function () {
    if (text.value == '') {
      alert('请输入内容!');
      return false;
    } else {
      //-1.创建元素
      var li = document.createElement('li');
      // 先有li 才能赋值,添加一个a标签
      li.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
      //-2.添加元素
      //ul.appendChild(li); 添加到后面
      ul.insertBefore(li, ul.children[0]);  //添加到最前面
      //-3.删除元素,删除的是当前的链接的父元素li
      var as = document.querySelectorAll('a')
      for (var i = 0; i > as.length; i++) {
        as[i].onclick = function () {
          //node.removeChild(child)
          ul.removeChild(this.parentNode);
        }
      }
    }
  }


//14 依次删除元素
<body>
  <ul class="nav">
    <ul>
      <li>元素1</li>
      <li>元素2</li>
      <li>元素3</li>
      <li>元素4</li>
    </ul>
</body>
<script>
  // 1. 获取元素
  var ul = document.querySelector('ul');
  var btn = document.querySelector('button');
  // 2. 删除元素
  // ul.removeChild(ul.children[0]);
  // 3. 点击按钮依次删除里面的子元素
  btn.onclick = function () {
    if (ul.children.length == 0) {
      this.disabled = true;
    } else {
      ul.removeChild(ul.children[0]);
    }
  } 
</script>

//15 动态表格
<body>
  <table cellspacing="0" border>
    <thead>
      <tr>
        <th>姓名</th>
        <th>科目</th>
        <th>成绩</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <!-- 动态创建 -->
      <!-- <tr>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr> -->
    </tbody>
  </table>


</body>
<script>
  //1. 先准备好数据
  var datas = [{
    name: 'AAA',
    subject: 'JavaScript',
    score: 100
  }, {
    name: 'BBB',
    subject: 'JavaScript',
    score: 80
  }, {
    name: 'CCC',
    subject: 'JavaScript',
    score: 90
  }, {
    name: 'DDD',
    subject: 'JavaScript',
    score: 60
  }];

  //1.向tbody中创建行,根据数组长度创建行数
  var tbody = document.querySelector('tbody');
  for (var i = 0; i < datas.length; i++) {
    //创建tr行
    var tr = document.createElement('tr');
    tbody.appendChild(tr);
    //2.行内创建单元格 td td的个数取决于每个对象里面的属性个数
    for (var k in datas[i]) {
      //创建单元格
      var td = document.createElement('td');
      // 把对象里面的属性值 datas[i][k] 给 td
      td.innerHTML = datas[i][k];   //obj[k] 得到的是属性值
      tr.appendChild(td);
    }
    //3. 创建有删除2个字的单元格
    var td = document.createElement('td');;
    td.innerHTML = '<a href="javascript:;">删除</a>';
    tr.appendChild(td);
  }

  //4. 删除操作
  var as = document.querySelectorAll('a');
  for (var i = 0; i < as.length; i++) {
    as[i].onclick = function () {
      // 点击a 删除当前a 所在的行,a链接的父元素的父元素
      tbody.removeChild(this.parentNode.parentNode)
    }
  }
</script>

//16 innerHTML 数组方式创建大量元素,提高效率
// innerHTML 采用数组形式拼接,创建多个元素时效率更高
var inner = document.querySelector('.inner');
var arr = [];
for (var i=0;i<=100; i++){
    arr.push('<a href="#">百度</a>')
}
inner.innerHTML = arr.join('')  //把数组转换为字符串给inner
  1. BOM

    #2_ BOM:Browser Object Model 即浏览器对象模型,与浏览器窗口进行交互的对象

    window
    |
    — document
    |
    — location
    |
    — navigation
    |
    — screen
    |
    — history

    — #1 系统对话框

    • window.alert(“您好啊”);
    • window.prompt(“请输入帐号”); //有返回值

    — #2 窗口加载事件

    • window.onload // 页面加载完毕执行
    • window.onunload // 页面关闭后才触发的事件
    • window.onbeforeunload // 页面关闭之前触发的
    • window.onresize // 调整窗口大小加载事件

    — #3 location对象中的属性和方法,获取或设置窗体的URL

    • window.location.hash //返回片段,地址栏上#及后面的内容,锚点

    • window.location.host //返回主机名及端口号

    • window.location.hostname //返回主机名

    • window.location.pathname //返回文件的路径—相对路径

    • window.location.port //返回端口号

    • window.location.protocol //返回协议

    • window.location.search //返回参数,搜索的内容

    • 地址栏上的地址的操作

    • location.href=“http://www.jd.com”; //设置跳转的页面的地址

    • location.assign(“http://www.jd.com”); //记录浏览历史,可以实现后退功能

    • location.reload(); //重新加载–刷新

    • location.replace(“http://www.jd.com”); //没有历史记录

    • window.history.forward(); //历史记录的后退和前进

    • window.history.back();

    • window.navigator.userAgent /判断用户浏览器的类型

    • window.navigator.platform /判断浏览器所在的系统平台类型

    — #4 API

    • 定时器

    • setInterval(fn,time); clearInterval(timeId);

    • var timeId=window.setInterval(函数,间隔时间毫秒);

    • setTimeout(fn,time);

    • var timeId=window.setTimeout(fn,3000);

    • clearTimeout(timeId);

    • 区别

    • setInterval(fn,time) 方法重复调用一个函数,每间隔这个时间,就去调用一次回调函数

    • 随机数

    • var x = parseInt(Math.random() * 100 + 1);(0~99 1-100)

    • 获取当前时间

    • var dt = new Date();
      var hour = dt.getHours();
      var second = dt.getSeconds();

    • this的指向问题

    • this的指向在函数定义时确定不了,一般情况下this最终指向的是那个调用它的对象

    — #5 三组属性 offset scroll client
    – offset系列:动态获取该元素的位置、大小。获得元素距离带有定位父元素的位置

    • element.offsetParent:返回作为该元素带有定位的父级元素,如果父级元素没有定位则返回body

    • element.offsetWidth:返回 自身 包括padding、边框、内容区的宽度,返回数值不带单位

    • element.offsetHeight:返回 自身包括padding、边框、内容区的高度,返回数值不带单位

    • element.offsetLeft:返回元素相对带有定位父元素左边框的偏移

    • element.offsetTop:返回元素相对带有定位父元素上方的偏移

    • 没有脱离文档流:

    • element.offsetLeft:父级元素margin+父级元素padding+父级元素的border+自己的margin

    • 脱离文档流

    • 是自己的left和自己的margin

    – scroll系列:卷曲 -onscroll事件

    • element.scrollWidth: 返回元素中 内容的 实际的宽(没有边框),如果没有内容就是元素的宽
    • .scrollHeight: 返回元素中 内容的 实际的高(没有边框),如果没有内容就是元素的高
    • element.scrollTop ;返回元素被向上卷曲出去的距离,数值不包含单位
    • element.scrollLeft :返回元素向左卷曲出去的距离,数值不包含单位
    • window.pageYOffset :页面被卷曲的距离 IE9+ //获取页面的滚动距离
    • window.pageXOffset

    – client系列:可视区域

    • clientWidth:返回 自身 包括padding,内容区的宽度,不含边框,返回数值不带单位,常用
    • clientHeight:返回 自身 包括padding,内容区的高度,不含边框,返回数值不带单位,常用
    • clientLeft:左边边框的宽度
    • clientTop :返回上面的边框的宽度

    –总结
    -返回 自身 的宽度
    element.offsetWidth 内容区+padding+border
    clientWidth 内容区+padding
    element.scrollWidth 实际的宽度

    -- offset 常用于获取元素位置  offsetLeft offsetTop
    -- client 常用于获取元素大小  clientWidth clientHeight
    -- scroll 常用于获取滚动的距离 scrollTop scrollLeft
    

    — #6 JS执行机制

    1. 先执行执行栈中的同步任务。
    2. 异步任务(回调函数)先放入任务队列中。
    3. 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。

    — #7 立即执行函数

    • 不需要调用,立马能够自己执行的函数
    • 作用:独立创建一个作用域,里面的变量都是局部变量,不会有命名冲突
      -1. 第二个小括号可以看作是调用函数
      ()()
      (function(a,b){
      console.log(a)
      })(1,2)

    -2. (fn()())
    (function sum(a,b){
    console.log(a +b);
    }(2,3));

2.1 实例代码

//1 5秒之后关闭广告
<img src="images/ad.jpg" alt="" class="ad">
var ad = document.querySelector('.ad');
setTimeout(function(){
	ad.style.display = 'none';
}, 5000)

//2 倒计时效果
//倒计时不断变化,使用setInterval使其自动变化
<body>
    <div class="search">
        <span class="day">0</span>
        <span class="hour">0</span>
        <span class="minute">0</span>
        <span class="second">0</span>
    </div>
</body>
<script>
    //1 获取元素 
    var day = document.querySelector('.day');
    var hour = document.querySelector('.hour');
    var minute = document.querySelector('.minute');
    var second = document.querySelector('.second');
    // 获取的是用户输入时间的总的毫秒数
    var inputTime = +new Date('2020-3-5 16:40:00');
    countDown(); //先调用一次,去掉开启空白
    //2 开启定时器
    setInterval(countDown, 1000);

    function countDown(time) {
        var nowTime = +new Date(); //返回的是当前时间的总的毫秒数
        //var inputTime = +new(time); //返回的是用户输入时间的总的毫秒数
        var times = (inputTime - nowTime) / 1000; //times 是剩余时间总的秒数
        var d = parseInt(times / 60 / 60 / 24); //天
        d = d < 10 ? '0' + d : d;
        var h = parseInt(times / 60 / 60 % 24); //时
        h = h < 10 ? '0' + h : h;
        var m = parseInt(times / 60 % 60); //分
        m = m < 10 ? '0' + m : m;
        var s = parseInt(times % 60); // 当前的秒
        s = s < 10 ? '0' + s : s;

        day.innerHTML = d;
        hour.innerHTML = h;
        minute.innerHTML = m;
        second.innerHTML = s;
        //return d + '天' + h + '时' + m + '分' + s + '秒';
    }
    //console.log(countDown('2019-5-1 18:00:00'));
</script>

//3 开启和关闭定时器
<button class="begin">开启定时器</button>
<button class="stop">关闭定时器</button>

var begin = document.querySelector('.begin');
var stop = document.querySelector('.stop');
var timer = null;  //全局变量,null 是一个空对对象
begin.addEventListener('click',function(){
	timer = setInterval(function(){
		console.log('定时器已开启');
	}, 1000);
})
stop.addEventListener('click', function(){
	clearInterval(timer);
})

//4 定时控制输入框
//点击按钮,禁用按钮,显示倒计时
<body>
    手机号码: <input type="tel"> <button>发送</button>
</body>
<script>
    var btn = document.querySelector('button');
    var time = 3; //定义剩下的秒数
    //1点击按钮,禁用disabled
    btn.addEventListener('click', function() {
        btn.disabled = true;
        //添加定时器,在定时器内修改按钮内容
        var timer = setInterval(function() {
            //3如果变量为0,停止定时器,复原按钮
            if (time == 0) {
                //4清除定时器和复原按钮
                clearInterval(timer);
                btn.disabled = false;
                btn.innerHTML = '发送';
                time = 3;
            } else {
                //2按钮内的内容发生变化
                btn.innerHTML = '还剩下' + time + '秒';
                time--;
            }
        }, 1000);
    })
</script>

//5 使用URL传递参数
//第一个登陆页面,里面有提交表单,action提交到 index.html页面
//第二个页面使用第一个页面的参数,实现数据在不同页面之间传递

-login.html
<body>
    <form action="index.html">
        用户名:<input type="text" name="uname">
        <input type="submit" value="登陆">
    </form>
</body>

-index.html
<script>
	console.log(location.search);// ?uname=andy
	//1 先去掉? substr('起始的位置',截取几个字符串)
	var params = location.search.substr(1);
	//2 利用=把字符串分割为数组 split('=')
	var arr = params.split('=');   //['uname','andy']
	//3 把数据写入div
	var div = document.querySelector('div');
	div.innerHTML = arr[1] + '欢迎您';
</script>

//6 计算鼠标在盒子内的坐标
//在盒子内点击,想要得到鼠标距离盒子左右的距离
//鼠标在页面中的坐标 (e.pageX, e.pageY)
//得到盒子在页面中距离 (box.offsetLeft, box.offsetTop)
var box = document.querySelctor('.box');
box.addEventListener('click', function(e){
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
    this.innerHTML = 'x坐标是' + x + 'y坐标是' +y;
})


//7 模态框拖拽
//页面中的弹出框随鼠标拖拽
//鼠标的坐标减去鼠标在盒子内的坐标,才是模态框真正的位置
<script>
    // 1. 获取元素
    var login = document.querySelector('.login');
    var mask = document.querySelector('.login-bg');
    var link = document.querySelector('#link');
    var closeBtn = document.querySelector('#closeBtn');
    // 2. 点击弹出层这个链接,让 mask 和 login显示出来
    link.addEventListener('click', function() {
        mask.style.display = 'block';
        login.style.display = 'block';
    });
    // 3. 点击 closeBtn 就隐藏 mask 和 login
    closeBtn.addEventListener('click', function() {
            mask.style.display = 'none';
            login.style.display = 'none';
        })
        // 4. 开始拖拽
        //-1 当鼠标按下,就获得鼠标在盒子内的坐标
    title.addEventListener('mousedown', move);

    function move(e) {
        var x = e.pageX - login.offsetLeft;
        var y = e.pageY - login.offsetTop;
        //-2 鼠标移动的时候,把鼠标在页面中的坐标,减去鼠标在盒子内的坐标就是模态框的left和top
        document.addEventListener('mousemove', function(e) {
            login.style.left = e.pageX - x + 'px';
            login.style.top = e.pageY - y + 'px';
        });
        //-4 鼠标弹起,移除鼠标移动事件
        document.addEventListener('mouseup', function() {
            document.removeEventListener('mouseover', move);
        })

    }
</script>


//8 放大镜效果
//-1.鼠标经过小图片盒子,黄色的遮挡快和大盒子显示,离开隐藏2个盒子功能
//-2.黄色的遮挡层跟随鼠标移动
//-3.移动黄色遮挡层,大图片跟随移动功能
<body>
    <div class="preview_wrap">
        <img src="upload/s3.png" alt="">
        <div class="mask" style: "display: none"></div>
        <div class="big" style: "display: none">
            <img src="upload/big.jpg" alt="" class="bigImg">
        </div>
    </div>

</body>
<script>
    //0. 页面加载完后执行
    window.addEventListener('load', function() {
        var preview_img = document.querySelector('.preview_img');
        var mask = document.querySelector('.mask');
        var big = document.querySelector('.big');
        //1. 当鼠标经过 preview_img 就显示和隐藏 mask遮挡层 和 big 大盒子
        preview_img.addEventListener('mouseover', function() {
            mask.style.display = 'block';
            big.style.display = 'block';
        })
        preview_img.addEventListener('mouseout', function() {
                mask.style.display = 'none';
                big.style.display = 'none';
            })
            //2. 鼠标移动的时候,让黄色的盒子跟着鼠标来走
        preview_img.addEventListener('mousemove', function(e) {
            //2.1 先计算出鼠标在盒子内的坐标
            var x = e.pageX - this.offsetLeft;
            var y = e.pageY - this.offsetTop;
            //2.2让鼠标处于mask的中间, 鼠标的坐标减去mask值的一半
            //mask.style.left = x - mask.offsetWidth / 2 + 'px';
            //mask.style.top = y - mask.offsetHeight / 2 + 'px';
            //2.3 抽取判断
            var maskX = x - mask.offsetWidth / 2
            var maskY = y - mask.offsetHeight / 2 + 'px';
            //2.4 如果小于零,把坐标设置为0,如果大于遮挡层最大的移动距离,就把坐标设为最大的移动距离
            var maskMax = preview_img.offsetHeight - mask.offsetHeight;;
            if (maskX <= 0) {
                maskX = 0;
            } else if (maskX >= preview_img.offsetWidth - mask.offsetWidth) {
                maskX = preview_img.offsetWidth - mask.offsetWidth;
            }
            if (maskY <= 0) {
                maskY = 0;
            } else if (maskY >= preview_img.offsetHeight - mask.offsetHeight) {
                maskY = preview_img.offsetHeight - mask.offsetHeight;
            }
            mask.style.left = maskX + 'px';
            mask.style.top = maskY + 'px';
            // mask 移动距离/mask 最大移动距离 = 大图片移动距离/大图片最大移动距离
            //3.大图片移动距离 = mask 移动距离*大图片移动距离/mask 最大移动距离
            var bigImg = document.querySelector('.bigImg');
            //大图片最大移动距离
            var bigMax = bigImg.offsetWidth - big.offsetWidth;
            //大图片移动距离
            var bigX = maskX * bigMax / maskMax;
            var bigY = maskY * bigMax / maskMax;
            bigImg.style.left = -bigX + 'px';
            bigImg.style.top = -bigY + 'px';
        })

    })
</script>

//9 flexible 分析
(function flexible(window, document) {
    // 获取HTML根元素
    var docEl = document.documentElement
        // dpr 物理像素比
    var dpr = window.devicePixelRatio || 1

    // adjust body font size
    // 设置body的字体大小
    function setBodyFontSize() {
        //如果页面有body这个元素,就设置body的字体大小
        if (document.body) {
            document.body.style.fontSize = (12 * dpr) + 'px'
        } else {
            //如果没有body,则等着页面主要的DOM元素加载完毕再去设置body的字体大小
            document.addEventListener('DOMContentLoaded', setBodyFontSize)
        }
    }
    setBodyFontSize();

    // set 1rem = viewWidth / 10
    // 设置 html 元素的大小
    function setRemUnit() {
        var rem = docEl.clientWidth / 10
        docEl.style.fontSize = rem + 'px'
    }

    setRemUnit()

    // reset rem unit on page resize
    // 当页面尺寸大小发生变化的时候,要重新设置 rem的大小
    window.addEventListener('resize', setRemUnit)
        // pageshow 事件,页面重新加载事件
    window.addEventListener('pageshow', function(e) {
        if (e.persisted) {
            setRemUnit()
        }
    })

    // detect 0.5px supports
    //有的移动端的浏览器不支持0.5像素的写法
    if (dpr >= 2) {
        var fakeBody = document.createElement('body')
        var testElement = document.createElement('div')
        testElement.style.border = '.5px solid transparent'
        fakeBody.appendChild(testElement)
        docEl.appendChild(fakeBody)
        if (testElement.offsetHeight === 1) {
            docEl.classList.add('hairlines')
        }
        docEl.removeChild(fakeBody)
    }
}(window, document))

//10 仿淘宝固定右侧边栏
// 原先是绝对定位,当页面滚动到一定位置,侧边栏改为固定定位,页面继续滚动,显示返回顶部按钮
// 需要用到页面滚动事件 scroll 因为是页面滚动,所以事件源是 document,滚动到某个位置,就去判断页面被卷去的上部值
// 元素被卷去的头部是 element.scrollTop, 页面被卷去的头部则是 window.pageYOffset
<body>
    <div class="slider-bar">
        <span class="goBack" style: "display: none">返回顶部</span>
    </div>
    <div class="header">头部区域</div>
    <div class="banner">banner区域</div>
    <div class="main">主体部分</div>

</body>
<script>
    // 1. 获取元素
    var sliderbar = document.querySelector('.slider-bar');
    var banner = document.querySelector('.banner');
    var main = document.querySelector('.main');
    var goBack = document.querySelector('.goback');


    // 先计算出被卷曲头部的大小
    var bannerTop = banner.offsetTop;
    var mainTop = main.offsetTop;
    // 侧边栏固定定位之后应该变化的数值
    var sliderTop = sliderbar.offsetTop - bannerTop;
    // 2. 页面滚动事件,滚动到banner
    document.addEventListener('scroll', function() {
        if (window.pageYOffset >= bannerTop) {
            sliderbar.style.position = 'fixed';
            sliderbar.style.top = sliderTop + 'px';
        } else {
            sliderbar.style.position = 'absolute';
            sliderbar.style.top = "300px";
        }
        // 页面滚动,滚动到main
        if (window.pageYOffset >= mainTop) {
            goBack.style.display = 'block';
        } else {
            goBack.style.display = 'none';
        }
    })
</script>

//11 简单动画

<div>盒子</div>

div{
    position: absolute;
    left: 0;
    width: 100px;
    height: 100px;
    background-color: black;
}

var div = document.querySelector('div');
var timer = setInterval(function() {
    if (div.offsetLeft >= 400){
        //停止定时器,即停止动画
        clearInterval(timer);
    }
    div.style.left = div.offsetLeft + 1 + 'px';
}, 30);


//12 动画函数封装
<style>
    div {
        position: absolute;
        left: 0;
        width: 100px;
        height: 100px;
        background-color: black;
    }
</style>

<body>
    <div>123</div>
</body>
<script>
    function animate(obj, target) {
        var timer = setInterval(function() {
            if (div.offsetLeft >= target) {    
                clearInterval(timer);
            }
            obj.style.left = obj.offsetLeft + 1 + 'px';
        }, 30);
    }

    var div = document.querySelector('div');
    animate(div, 300);
</script>

//13 动画函数封装优化

 function animate(obj, target) {
     	//让元素只有一个定时器,先清除以前的定时器,只保留当前一个定时器
     	clearInterval(obj.timer);
     	// 将timer添加为对象的属性,节省内存空间
        obj.timer  = setInterval(function() {
            if (obj.offsetLeft >= target) {    
                clearInterval(obj.timer );
            }
            obj.style.left = obj.offsetLeft + 1 + 'px';
        }, 30);
    }

    var div = document.querySelector('div');
    animate(div, 300);

//14 缓动动画封装
//让盒子每次移动的距离慢慢变小,速度就会慢慢落下来
//核心算法: (目标值 - 现在的位置) / 10  做为每次移动的距离步长 
<script>
    function animate(obj, target) {
        //让元素只有一个定时器,先清除以前的定时器,只保留当前一个定时器
        clearInterval(obj.timer);
        // 将timer添加为对象的属性,节省内存空间
        obj.timer = setInterval(function() {
            // 步长值写到定时器里面,并取整数.判断正负数,正则取大,负则取小
            //var step =Math.ceil() 
            var step = (target - obj.offsetLeft) / 10;
            step = step > 0 ? Math.ceil(step) : Math.floor(step);
            if (obj.offsetLeft == target) {
                clearInterval(obj.timer);
            }
            obj.style.left = obj.offsetLeft + step + 'px';
        }, 15);
    }
    var div = document.querySelector('div');
    animate(div, 500);
</script>

//15 动画封装添加回调函数
<script>
    function animate(obj, target, callback) {
        //让元素只有一个定时器,先清除以前的定时器,只保留当前一个定时器
        clearInterval(obj.timer);
        // 将timer添加为对象的属性,节省内存空间
        obj.timer = setInterval(function() {
            // 步长值写到定时器里面,并取整数.判断正负数,正则取大,负则取小
            //var step =Math.ceil() 
            var step = (target - obj.offsetLeft) / 10;
            step = step > 0 ? Math.ceil(step) : Math.floor(step);
            if (obj.offsetLeft == target) {
                clearInterval(obj.timer);
                //回调函数写到定时器结束里面
                //if (callback) {
                //    callback();
                // }
                callback && callback();
            }
            obj.style.left = obj.offsetLeft + step + 'px';
        }, 15);
    }
    var div = document.querySelector('div');
    var btn = document.querySelector('button');
    animate(div, 500);
    btn800.addEventListener('click', function() {
        animate(div, 800, function() {
            alert('结束了!');
            div.style.backgroundColor = 'red';
        });
    })
</script>

3 PC网页特效

  • 节流阀
    • 防止轮播图按钮连续点击造成播放过快
    • 目的: 让上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发
    • 思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数
      开始设置一个变量 var flag = true;
      if (flag){ flag=false; do something} 关闭水龙头
      利用回调函数,动画执行完毕, flag=true 打开水龙头

3.1 实例代码

//1 鼠标经过 silderbar 让con盒子滑动出来
<body>
    <div class="sliderbar">
        <span>⬅</span>
        <div class='con'>问题反馈</div>
    </div>
</body>
<script>
    //1. 获取元素
    var sliderbar = document.querySelector('.sliderbar');
    var con = document.querySelector('.con');
    sliderbar.addEventListener('mouseenter', function() {
        animate(con, -160, function() {
            sliderbar.children[0].innerHTML = '→';
        });
    })
    sliderbar.addEventListener('mouseleave', function() {
        animate(con, 0, function() {
            sliderbar.children[0].innerHTML = '⬅';
        })
    })
</script>

//2 网页轮播图-综合案例
<body>
  <div class="w">
    <div class="main">
      <div class="focus fl">
        <!-- 左侧按钮 -->
        <a href="javascript:;" class="arrow-l"></a>
        <!-- 右侧按钮 -->
        <a href="javascript:;" class="arrow-r"></a>
        <!-- 核心滚动区域 ul宽度为600%,子绝对定位,父overflowhiden-->
        <ul>
          <li>
            <a href="#"><img src="upload/focus1.jpg" alt=""></a>
          </li>
          <li>
            <a href="#"><img src="upload/focus2.jpg" alt=""></a>
          </li>
          <li>
            <a href="#"><img src="upload/focus3.jpg" alt=""></a>
          </li>

        </ul>
        <!-- 小圆圈 -->
        <ol class="circle">
          <li></li>
          <li class="current"></li>
          <li></li>
        </ol>
      </div>
    </div>
  </div>
</body>
<script>
  window.addEventListener('load', function () {
    //1 获取元素
    var arrow_l = document.querySelector('.arrow-l');
    var arrow_r = document.querySelector('.arrow-r');
    var focus = document.querySelector('.focus');
    //2 鼠标经过 focus 就显示隐藏左右按钮
    focus.addEventListener('mouseenter', function () {
      arrow_l.style.display = 'block';
      arrow_r.style.display = 'block';
      //11.1 鼠标经过时定时器清除
      clearInterval(timer);
      timer = null; //清除定时器变量
    })
    focus.addEventListener('mouseleave', function () {
      arrow_l.style.display = 'none';
      arrow_r.style.display = 'none';
    });
    //3 动态生成小圆圈,有几张图片,就生成几个小圆圈
    var ul = focus.querySelector('ul');
    for (var i = 0; i < ul.children.length; i++) {
      var li = document.createElement('li');
      //5.1 记录当前小圆圈的索引号,通过自定义属性来做
      li.setAttribute('index', i);
      ol.appendChild(li);
      //4 排他思想,绑定点击事件
      li.addEventListener('click', function () {
        // 清除所有的小li的类名
        for (var i = 0; i < ol.children.length; i++) {
          ol.children[i].className = '';
        }
        // 当前的li 设置 current 类名
        this.className = 'current';
        //5 点击小圆圈,移动图片。移动距离为索引号乘以图片的宽度
        //5.2 点击时拿到当前li 的index;
        var index = this.getAttribute('index');
        //9.1 点击某个li,要把li的左引号给 num
        num = index;
        //9.2 点击某个li,要把li的索引号给 circle
        circle = index;
        var focusWidth = focus.offsetWidth;
        animate(ul, -index * focusWidth);
      })
    }
    //3.1 把ol中的第一个li设置类名为 current
    ol.children[0].className = 'current';
    //6 克隆第一张图片li 放到ul 后面
    var first = ul.children[0].cloneNode(true);
    ul.appendChild(first);
    //7 点击右侧按钮,图片滚动一张
    var num = 0;
    // 8.1 circle 控制小圆圈的播放
    var circle = 0;
    //12 添加节流阀
    var flag = true;
    arrow_r.addEventListener('click', function () {
      if (flag) {
        flag = false; //关闭节流阀
        //7.1 在最后添加第一张图片,如果走到了最后复制的一张图片
        //ul快速复原 left 改为 0;
        if (num == ul.children.length - 1) {
          ul.style.left = 0;
          num = 0;
        }
        num++;
        animate(ul, -num * focusWidth, function () {
          flag = true; //动画播放完毕关闭节流阀
        });
        // 8. 点击右侧按钮,小圆圈跟随一起变化
        circle++;
        // 如果 cirle=4,说明走到了最后克隆的这张图片,就复原
        if (circle == ol.children.length) {
          circle = 0;
        }
        circleChange();
        // //8.2 先清除其余小圆圈的current 类名
        // for (var i = 0; i < ol.children.length; i++) {
        //     ol.children[i].className = '';
        // }
        // //8.3 留下当前的小圆圈的currnet类名
        // ol.children[circle].className = 'current';
      }

    });
    //10.
    arrow_l.addEventListener('click', function () {
      if (flag) {
        flag = false; //关闭节流阀
        //7.1 在最后添加第一张图片,如果走到了最后复制的一张图片
        //ul快速复原 left 改为 0;
        if (num == 0) {
          // ul.style.left = (ul.children.length - 1) * focusWidth + 'px';
          // num = ul.children.length - 1;
          num = ul.children.length - 1;
          ul.style.left = -num * focusWidth + 'px';

        }
        num--;
        animate(ul, -num * focusWisdth, function () {
          flag = true; //动画播放完毕关闭节流阀
        });
        // 8. 点击右侧按钮,小圆圈跟随一起变化
        circle--;
        // 如果circle<0 说明走到了第一张图片,则小圆圈要改为第4个
        // if (circle < 0) {
        //     circle = ol.children.length - 1;
        // }
        circle = circle < 0 ? ol.children.length - 1 : circle;

        circleChange();
      }

    });

    // 重复代码,抽离出来
    function circleChange() {
      //8.2 先清除其余小圆圈的current 类名
      for (var i = 0; i < ol.children.length; i++) {
        ol.children[i].className = '';
      }
      //8.3 留下当前的小圆圈的currnet类名
      ol.children[circle].className = 'current';
    }
    //11 自动播放功能
    var timer = setInterval(function () {
      //手动调用点击事件
      arrow_r.click();
    }, 2000);
  })
</script>

//3 返回顶部
// 滚动窗口文档中的特定位置,window.scroll(x,y)
// 当点击了返回顶部模块,就让窗口滚动到页面的最上方
goBack.addEventListener('click', function(){
    // x y 不跟单位,直接写数字
    window.scroll(0,0);
    //窗口滚动,对象是window
    animate(window,0);
})
//改为上下滚动函数
 function animate(obj, target, callback) {
        //让元素只有一个定时器,先清除以前的定时器,只保留当前一个定时器
        clearInterval(obj.timer);
        // 将timer添加为对象的属性,节省内存空间
        obj.timer = setInterval(function() {
            // 步长值写到定时器里面,并取整数.判断正负数,正则取大,负则取小
            //var step =Math.ceil() 
            var step = (target - window.pageYOffset) / 10;
            step = step > 0 ? Math.ceil(step) : Math.floor(step);
            if (window.pageYOffset == target) {
                clearInterval(obj.timer);
                //回调函数写到定时器结束里面
                //if (callback) {
                //    callback();
                // }
                callback && callback();
            }
            //obj.style.left = window.pageYOffset + step + 'px';
            window.scroll(0, window.pageYOffset + step);
        }, 15);
    }

//4 筋斗云特效
// 鼠标进过某个小li,筋斗云会飞到当前小li的位置,鼠标离开,筋斗云复原
// 鼠标点击某个小li,筋斗云就会留在点击的这个小li的位置
<body>
    <div id="c_nav" class="c-nav">
        <span class="cloud"></span>
        <ul>
            <li class="current"><a href="#">首页新闻</a></li>
            <li>
                <a href="#">师资力量</a>
            </li>
            <li>
                <a href="#">活动策划</a>
            </li>
            <li>
                <a href="#">企业文化</a>
            </li>
            <li>
                <a href="#">招聘信息</a>
            </li>
            <li>
                <a href="#">公司介绍</a>
            </li>
            <li>
                <a href="#">小猪佩奇</a>
            </li>
        </ul>
    </div>
</body>
<script>
    window.addEventListener('load', function() {
        //1. 获取元素
        var cloud = document.querySelector('.cloud');
        var c_nav = document.querySelector('.c-nav');
        var lis = document.querySelector('.li');
        //2. 给所有的小 li 绑定事件
        // 这个 current 作为筋斗云的起始位置
        var current = 0;
        for (var i = 0; i < lis.length; i++) {
            // 鼠标经过当前li的位置作为目标值
            lis[i].addEventListener('mouseenter', function() {
                animate(cloud, this.offsetLeft);
            });
            // 鼠标离开,复原为0/curent
            lis[i].addEventListener('mouseleave', function() {
                animate(cloud, current);
            });
            //当鼠标点击,把当前位置作为目标值
            lis[i].addEventListener('click', function() {
                current = this.offsetLeft;
            })
        }
    })
</script>

4 移动端网页特效

  1. 触屏事件 -touch
    -touchstart 手指触摸到一个元素时触发
    -touchmove 手指从一个DOM元素上滑动时触发
    -touchend 手指从一个DOM元素上移开时触发

  2. 触摸事件对象 TouchEvent
    -touches 手指触摸屏幕的所有的手指的一个列表
    -targetTouches 正在触摸当前 DOM 元素上的手指的一个列表
    -changedTouches 手指状态发生了改变的列表,从无到有变化

  3. H5新属性 — classList
    -返回元素的类名,可以用来在元素中添加,移除,切换CSS类

  4. 移动端 click 事件会有 300ms 的延时,因为移动端屏幕双击会缩放(double tap to zoom)页面
    解决方案:

    1. 禁用缩放
    ``` 2. 利用 touch 事件封装函数解决 300 ms 延迟。 - 当手指触摸屏幕,记录当前的触摸时间 - 当手指离开屏幕,用离开的时间减去触摸的时间 - 如果时间小于150ms,且没有滑动过屏幕,那么定义为点击 //封装tap, 解决click 300ms 延时问题 function tap (obj,callback){ var isMove = false; var startTime = 0; // 记录触摸时候的时间变量 obj.addEventListener('touchstart',function(e) { startTime = Date.now(); //记录触摸时间 }); obj.addEventListener('touchmove',function(e){ isMove = true; // 看看是否有滑动,有滑动算拖拽,无则为点击 }); obj.addEventListener('touchend',function(e){ //如果手指触摸和离开时间小于 150 ms 算点击 if (!isMove && (Date.now() - startTime) < 150){ callback && callback(); //执行回调函数 } isMove = false; // 取反 重置 startTime = 0; }); } //调用 tap(div,functon(){})
    1. 插件
      ----fastclick插件解决 300 ms延迟

      if (‘addEventListener’ in document) {
      document.addEventListener(‘DOMContentLoaded’, function() {
      FastClick.attach(document.body);
      }, false);
      }

      ----Swiper 插件
      ----superslide 插件
      ----isscroll 插件
      ----zy.media.js 视频插件

  5. 移动端常用开发框架

  6. 本地存储
    ```javascript
    -1
    window.sessionStorage

    • 生命周期为关闭浏览器窗口,关闭窗口就删除
    • 在同一个窗口下数据可以共享
    • 以键值对的形式储存使用
      //示例
      var ipt = document.querySelector(‘input’);
      var set = document.querySelector(’.set’);
      var get = document.querySelector(’.get’);
      var remove = document.querySelector(’.remove’);
      set.addEventListener(‘click’ function(){
      var val = ipt.value;
      sessionStorage.setItem(‘uname’,val);
      })
      get.addEventListener(‘click’ function(){
      consoel.log(sessionStorage.getItem(‘uname’));
      })
      remove.addEventListener(‘click’ function(){
      sessionStorage.removeItem(‘uname’);
      })
      //清除所有sessionStorage
      del.addEventListener(‘click’ function(){
      sessionStorage.clear();
      })
      -2
      window.localStorage
    • 生命周期永久生效,除非手动删除,即使页面关闭也会存在
    • 同一浏览器可以多窗口页面共享
    • 以键值对的形式储存使用
      //示例
      //示例
      var ipt = document.querySelector(‘input’);
      var set = document.querySelector(’.set’);
      var get = document.querySelector(’.get’);
      var remove = document.querySelector(’.remove’);
      set.addEventListener(‘click’ function(){
      var val = ipt.value;
      localStorage.setItem(‘uname’,val);
      })
      get.addEventListener(‘click’ function(){
      consoel.log(localStorage.getItem(‘uname’));
      })
      remove.addEventListener(‘click’ function(){
      localStorage.removeItem(‘uname’);
      })
      //清除所有sessionStorage
      del.addEventListener(‘click’ function(){
      localStorage.clear();
      })
      
      
      
      
      
      

4.1实例代码

1 触摸事件示例
//获取元素
var div = document.querySelector('div');
// 手指触摸DOM元素事件
div.addEventListener('touchstart', function() {
    console.log('触摸事件触发')
})
// 手指在DOM元素上移动事件
div.addEventListener('touchmove', function(){
    console.log('触摸事件持续')
})
// 手指在离开DOM元素事件
div.addEventListener('touchend', function(){
    console.log('触摸事件结束')
})

//classList示例
var div = document.querySelector('div');
//1.添加类名
div.classList.add('three');
//2.删除类名
div.classList('one');
//3.切换类名
var btn = document.querySelector('button');
btn.addEventListener('click', function(){
    document.body.classList.toggle('bg');
})



2. div随手指移动
// 手指移动中,计算出手指移动的距离。然后用盒子原来的位置+手指移动的距离
//手指移动距离,手指滑动中的位置减去手指刚开始触摸的位置

var div = document.querySelector('div');
var startX = 0;   //获取手指初始坐标
var startY = 0;
var x = 0;  //获得盒子原来的位置
var y = 0;
div.addEventListener('touchstart', function(e){
    startX = e.targetTouches[0].pageX;
    startY = e.targetTouches[0].pageY;
    x = ths.offsetLeft;
    y = this.offsetTop;
});

div.addEventListener('touchmove', function(e){
    // 计算手指的移动距离: 手指移动之后的坐标减去手指初始的坐标
    var moveX = e.targetTouches[0].pageX - startX;
    var moveY = e.targetTouches[0].pageY - startY;
    this.style.left = x + moveX + 'px';
    this.style.top = y + moveY + 'px';
    e.preventDedault(); //阻止屏幕滚动的默认行为
})

3. 移动端轮播图
<body>
  <div class="focus">
    <ul>
      <!-- 31231 -->
      <li><img src="upload/focus1.jpg" alt=""></li>
      <li><img src="upload/focus2.jpg" alt=""></li>
      <li><img src="upload/focus3.jpg" alt=""></li>
    </ul>
    <ol>
      <li></li>
      <li></li>
      <li></li>
    </ol>
  </div>
</body>
<script>
  window.addEventListener('load', function () {
    // 1.获取元素
    var focus = document.querySelector('.focus');
    var ul = focus.children[0];
    // 获得focus的宽度
    var w = focus.offsetWidth;
    // 2. 利用定时器自动轮播图片
    var index = 0;
    var timer = setInterval(function () {
      index++;
      var translatex = -index * w;
      ul.style.transition = 'all .3s';
      ul.style.transform = 'translateX(' + translatex + ' + "px")';
    }, 2000);

    // 3.过渡完成后再去判断,监听过渡完成的事件 transitionend
    ul.addEventListener('transitionend', function () {
      // 无缝滚动
      if (index >= 3) {
        index = 0;
        //去掉过渡效果,让 ul 快速的跳到目标位置
        ul.style.transition = 'none';
        // 利用最新的索引号乘以宽度去滚动图片
        var translatex = -index * w;
        ul.style.transform = 'translateX(' + translatex + ' + "px")';
      } else if (index < 0) {
        index = 2;
        //去掉过渡效果,让 ul 快速的跳到目标位置
        ul.style.transition = 'none';
        // 利用最新的索引号乘以宽度去滚动图片
        var translatex = -index * w;
        ul.style.transform = 'translateX(' + translatex + ' + "px")';
      }
      // 4. 小圆点跟随变化
      // 把ol里面的li带有current类名的选出来去掉类名
      ol.querySelector('.current').classList.remove('.current');
      // 让当前索引号的小 li 加上 current
      ol.children[index].classList.add('.current');
    });
    //5 手指滑动轮播图
    // 触摸元素 touchstart: 获取手指初始坐标
    var startX = 0;
    var moveX = 0;
    var flag = false;
    ul.addEventListener('touchstart', function (e) {
      startX = e.targetTouches[0].pageX;
      //手指触摸的时候就停止定时器
      clearInterval(timer);
    });
    //6 移动手指 touchmove: 计算手指的滑动距离,并且移动盒子
    ul.addEventListener('touchmove', function (e) {
      // 计算移动距离
      moveX = e.targetTouches[0].pageX - startX;
      // 移动盒子: 盒子原来的位置 + 手指移动的距离
      var translateX = -index * w + moveX;
      ul.style.transition = 'none';
      ul.style.transform = 'translateX(' + translatex + ' + "px")';
      flag = true; // 如果用户手指移动过再去判断,否则不做判断效果
      e.preventDefault(); // 阻止屏幕移动事件
    });
    //手指离开,根据移动距离去判断是回弹还是播放上一张下一张
    ul.addEventListener('touchend', function (e) {
      if (flag) {
        //-1 如果移动距离大于50就播放上一张或下一张
        if (Math.abs(moveX) > 50) {
          if (moveX > 0) {
            index--;
          } else {
            index++;
          }
          var translatex = -index * w;
          ul.style.transition = 'all .3s';
          ul.style.transform = 'translateX(' + translatex + 'px)'
        } else {
          //小于50,返回原来的位置
          var translatex = -index * w;
          ul.style.transition = 'all .1s';
          ul.style.transform = 'translateX(' + translatex + 'px)'
        }
      }
      //手指离开重新开启定时器
      clearInterval(timer);
      var timer = setInterval(function () {
        index++;
        var translatex = -index * w;
        ul.style.transition = 'all .3s';
        ul.style.transform = 'translateX(' + translatex + ' + "px")';
      }, 2000);
    });
  })
</script>

4. 点击按钮返回顶部
<style>
    .goBack {
        display: none;
        position: fixed;
        bottom: 50px;
        right: 20px;
        width: 38px;
        height: 38px;
        background: url(../images/back.png) no-repeat;
        background-size: 38px 38px;
    }
</style>

<body>
    <div class="boBack"></div>
</body>
<script>
    var goBack = document.querySelector('.goBack');
    var nav = document.querySelector('nav');
    window.addEventListener('scroll', function() {
        if (window.pageYOffset >= nav.offsetTop) {
            goBack.style.display = 'block';
        } else {
            goBack.style.display = 'none';
        }
    });
    goBack.addEventListener('click', function() {
        window.scroll(0, 0);
    })
</script>

5. 记住用户名
//永久储存 使用localStorage

<body>
    <div>
        <input type="text" id="username"><input type="checkbox" name="" id="remember">记住用户名
    </div>
</body>
<script>
    var username = document.querySelector('#username');
    var remember = document.querySelector('#remember');
    if (localStorage.getItem('username')) {
        username.value = localStorage.getItem('username');
        remember.checked = true;
    }
    //复选框发生改变时判断
    remember.addEventListener('change', function() {
        if (this.checked) {
            localStorage.setItem('username', username.value);
        } else {
            localStorage.removeItem('username');
        }
    })
</script>

5.底部线

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值