# 基础知识点

# web apis和js基础关联性

# js的组成

  • JavaScript
    • ECMAscript javascript语法 JavaScript基础
    • DOM 页面 文档对象模型 web apis
    • BOM 浏览器对象模型 web apis

# 获取元素

# 根据id名获取元素

document.getElementById('time');

  • 参数 字符串id名
  • 返回 对应dom节点
  • get 获得 element 元素 by 通过 驼峰命名法
  • 参数 id是大小写敏感的字符串

console.dir(timer)

  • 打印我们返回的元素对象 更好的查看里面的属性和方法

# 根据标签名获取

document.getElementsByTagName('li');

  • 参数 字符串标签名
  • 返回 伪数组
// 1. 通过标签名获取节点 : 返回伪数组
// document.getElementsByTagName(字符串类型的标签名)
var inps = document.getElementsByTagName('input');
// console.log(inps);

# 获取父元素指定标签名

获取某个元素(父元素)内部所有指定标签名的子元素 注意:父元素必须是单个对象(必须指明是哪一个元素对象).获取的时候不包括父元素自己 获取ol里面的li

var ol=document.getElementById('ol');
        console.log(ol.getElementsByTagName('li'));

# 通过html5新增的方法获取

ie9+支持

# 1.根据类名返回元素对象 box是对象

document.getElementsByClassName('box')

  • 参数 字符串类名
  • 返回 伪数组
// 2. 通过类名获取节点: 返回伪数组
// document.getElementsByClassName(字符串类名的类名)
var btns = document.getElementsByClassName("btn");

# 2. 直接写选择器 根据指定选择器返回第一个元素对象

切记 里面的选择器需要加符号 .box #nav
        var  firstbox=document.querySelector('.box')
        返回一个节点,如果页面中有多个标签使用了这个选择器 只返回第一个 没有这个节点返回null

# 3.返回指定选择器的所有元素对象集合

      //参数  字符串类型的css选择器, 多个选择器逗号隔开  
var allBox = document.querySelectorAll('.box');
	 document.querySelectorAll('.box,.father')
返回伪数组						"参数1,参数2"

# 特殊元素获取

# 1.获取body 元素

var bodyEle = document.body;  

# 2.获取html 元素

  // var htmlEle = document.html;
        var htmlEle = document.documentElement;   

# dom节点属性

# 行内样式 style

# className

  • // className
    // 1. 如果是控制单个类名, 没有影响
    // 2. 如果要是控制多个类名: 添加可以多次添加; 思考: 删除比较麻烦
    

# classList

  • 伪数组: 有索引, 有数据, 可遍历
    // add() : 添加类名
    btn1.onclick = function() {
      box.classList.add("aa");
    }
    
    // remove(): 移除类名
    btn2.onclick = function() {
      box.classList.remove("dd");
    }
    
    // toggle(): 切换
    btn3.onclick = function() {
      box.classList.toggle("daqiu");
    }
    

标准属性 与html属性写法一致 class除外

  • src
  • value
  • checked true false

# 自定义属性

  • //如果保存自己业务方面需要的数据, 可以自定义HTML属性保存自己任何想要的数据
    // 自定义HTML属性也要满足HTML标准属性的语法 k="v" , 工作中可以: data-xx="xx";
    // **** js如何获取自定义属性值  dataset
    var inps = document.getElementsByTagName("input");
    // console.log(inps[0].dataset.guanxi); // dataset属性返回一个对象
    
    // ****** 需求: 按钮单击, 修改img的src , 对应的按钮的data-xx自定义HTML属性的值
    var img = document.getElementById("img");
    inps[0].onclick = function() {
      img.src = inps[0].dataset.guanxi;
    }
    inps[1].onclick = function() {
      img.src = inps[1].dataset.guanxi;
    }
    
  • 节点方法 设置不带格式的自定义HTML的获取和设置方法

  •      //回顾 :自定义html k="v" data-guanxi=""js:dataset.guanxi
        var box = document.querySelector("#box");
        // console.log(box.dataset.zhangsan);
        // 不带个格式的自定义html的属性获取方法
        console.log(box.dataset.abc);   //undefined
    // 1.获取
        // box.getAttribute(字符串类型的属性名)
        console.log(box.getAttribute("abc"));
        // 2.设置
        // box.setAttribute("字符串类型的属性名","属性值")
        box.setAttribute("abc", "rrr")
    

# innerHTML

操作节点内的HTML,包含标签, 属性及文本内容

# innerText

操作节点内的文本内容

# 类属性的操作及html的

  • 行内样式 style
  • 类样式class className
  • 类样式 classList
    • 添加类名 add()
    • 移除类名 remove()
    • 切换类名 toggle()
  • 标准属性 与html属性写法一致 class除外
    • src
    • value
    • checked
      • true
      • false
  • 自定义属性
    • 设置 data-xx="值"
    • 获取 dom节点.dataset.xx

# 获取元素在页面中的位置

  • offsetLeft
  • offsetTop

# 根据已有节点获取节点

DOM节点.children 返回该节点所有子节点, 伪数组
DOM节点.parentNode 返回该节点的父节点

# 添加节点

1. 创建节点 createElement("字符串类型的标签名")
2. 添加节点 结尾追加 appendChild()
某个节点前追加 insertBefore(追加的节点, 位置节点)
3. 移除节点 removeChild()

# 节点.offsetWidth

返回该节点的实际宽度 = width + border + padding

# 节点.offsetHeight

返回该节点的实际高度

# dom节点方法事件类型

# 点击事件 onclick

  •  btn.onclick = function () {
            alert("btn");
        }
    

# 获得焦点 onfocus 失去焦点 onblur

# 操作自定义属性

  • 获取 getAttribute()
    • 参数: 字符串类型的属性名
    • 返回: 属性值
  • 设置 setAttribute()
    • 参数1 : 字符串类型的属性名
    • 参数2: 属性值

# 鼠标事件类型

鼠标按下 mousedown
鼠标移动 mousemove
鼠标弹起 mouseup

# 键盘鼠标事件类型

键盘按下 keydown
键盘弹起 keyup
鼠标移入 mouseover
鼠标离开 mouseout

# 阻止事件冒泡

    // 事件冒泡: 父子级标签都绑定相同的事件: 先执行子DOM的事件; 再执行父DOM的事件
    // div 和 button绑定  click -- alert(1)  div(alert(2))
    var div = document.querySelector("div");
    var btn = document.querySelector("button");
    // 如果想要阻止事件冒泡, 必须借助事件对象
    btn.onclick = function(e) {
        // e表示事件对象
        // 阻止事件冒泡: 只执行自己的事件, 阻止的是事件逐层向父辈元素传递
        e.stopPropagation();
        alert(1);
    }
    div.onclick = function() {
        alert(2);
    }

# 新的注册事件方式

    // 事件源.addEventListener(事件类型,function(e){});
    // 执行函数可以是匿名函数也可以是函数(如果多个相同的事件的执行函数不想被覆盖, 执行函数必须有名字)
    btn.addEventListener("click", function fn1() {
        alert(1);
    })
    btn.addEventListener("click", function fn2() {
        alert(2);
    })

# 事件委托

  // 优化: 如果很多节点都绑定相同的事件, 计算机存储多个执行函数, 占用内存
    // 方案: js事件委托
    // 把子级的事件委托给父级, 只给父级绑定一次单击事件, 事件内部: 判断用户单击的到底是哪个子级节点
    var father = document.querySelector(".father");
    father.addEventListener("click", function(e) {
        // 如果用户单击的是left,弹窗left.....
        // e.target 返回用户单击的真正的事件的元素对象: DOM节点 -- 说明之前所学的所有属性和方法都能使用
        // console.log(e.target);  // -- DOM节点
        // 访问DOM节点的class属性值 : className  classList
        // console.log(e.target.className); // -- DOM节点
        // 如果单击的DOM节点的类名==left, 表示是left标签弹窗left...
        if (e.target.className == "left") {
            alert("left");
        } else if (e.target.className == "right") {
            alert("right");
        }

    });

# 事件基础

事件是有三部分组成 事件源 事件类型 事件处理程序 我们也称为事件三要素

  1. 事件源 事件被触发的对象 谁 按钮
  2. 事件类型 如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
  3. 事件处理程序 通过一个函数赋值的方式 完成

# 执行事件步骤

  // 1. 获取事件源
        var div = document.querySelector('div');
        // 2.绑定事件 注册事件
        // div.onclick 
        // 3.添加事件处理程序 
        div.onclick = function() {
            console.log('我被选中了');
        }

# 添加事件监听

  • 语法 dom节点.DOM节点.addEventListener(事件类型, 执行函数,事件执行阶段)
    • true : 事件在捕获阶段执行
    • false : 事件在冒泡阶段执行
  • 优点: 多个注册不同函数, 不会被覆盖

# 事件执行流程

  • 捕获阶段
  • 到达目标
  • 冒泡阶段 事件默认在冒泡阶段执行

# 阻止事件冒泡

  • e.stopPropagation();

# 事件委托

  • 优点
    • 减少事件绑定次数, 优化代码
    • 可以给程序添加的节点绑定事件
  • 步骤
      1. 事件只注册一次, 只给父节点注册事件
      2. 需要知道事件操作的真正DOM:e.target

# 事件对象

# e.target

1.返回时间对应的真正的DOM 2.e.target.nodeName 返回字符串型的DOM标签名(大写)

# e.currentTarget

返回事件源节点

# 坐标系

  • 可视区坐标系配合固定定位的盒子使用
    1. e.clientX
    2. e.clientY
  • 页面坐标系配合绝对定位的盒子使用
    1. e.pageX
    2. e.pageY

# 阻止默认行为

  • e.preventDefault();
  • a的默认行为
    1. href="javascript:void(0);"
    2. e.preventDefault();
    3. return false
  • 禁止浏览器右键
    • document.oncontextmenu = function(e) { e.preventDefault(); }

# 事件解绑

  • DOM节点.on事件类型 = null
  • DOM节点.removeEventListener(事件类型, 执行函数名);

# 事件对象.keyCode

  • 作用: 判断按下的是哪个键
  • 回车键: 13

# 事件对象.ctrlKey

  • 如果按下的是ctrl键, 返回true

# 操作元素

// innerText 和 innerHTML的区别 
        // 1. innerText 不识别html标签 非标准  去除空格和换行
        var div = document.querySelector('div');
        // div.innerText = '<strong>今天是:</strong> 2019';
        // 2. innerHTML 识别html标签 W3C标准 保留空格和换行的
        div.innerHTML = '<strong>今天是:</strong> 2019';
        // 这两个属性是可读写的  可以获取元素里面的内容
        var p = document.querySelector('p');
        console.log(p.innerText);
        console.log(p.innerHTML);

# this规则

  • this 规则:谁调⽤函数,this就指向谁。
var inps = document.getElementsByTagName("input");

var img = document.getElementById("img");
// this : 表示的是注册事件的标签 / 指向当前发生事件的标签
inps[0].onclick = function() {
  img.src = this.dataset.guanxi;
}
inps[1].onclick = function() {
  img.src = this.dataset.guanxi;
}
inps[2].onclick = function() {
  img.src = this.dataset.guanxi;
}

# 本地存储

  • 注意: 存储的key必须是字符串

    • 简单类型 直接存储
    • 复杂类型 JSON
      1. JSON.stringify() 复杂数据类型转换成json格式字符串
      2. JSON.parse() json格式字符串转换成复杂数据类型 数组 对象
  • localstorage

  • 存储 setItem(key, vlaue)
    读取 getItem(key)
    移除 removeItem(key)
    清除 clear()

# BOM

  • 浏览器对象模型 window window对象的属性和方法, 大部分都可以省略window

  • 方法

    1. onload()

      • 当页面加载完毕(包含静态资源必须书写)
      • window.onload = function(){}
    2. 定时器

      • 单次定时器

      • 设置 var timer = setTimeout(执行函数, 延迟时间)
        清除 clearTimeout(timer)
      • 多次定时器

      • 设置 var timer = setInterval(执行函数, 延迟时间)
        清除 clearInterval(timer)
    3. 属性

      • location.href 设置或获取浏览器地址栏内容
      • getComputedStyle(节点) 返回值: 该节点的所有css属性的集合的对象

# 基础一

# 一. 课程介绍

学习DOM+BOM的属性和方法,并使用它们实现页面上的效果;

# 1.1 DOM

image-20201127185337344

  • DOM - document object model - 文档对象模型:document上方法
  • DOM树:一个 形结构 ,把整个树状的模型,这个对象称为文档对象模型
  • 节点:树形结构里面的每个交叉点(HTML标签),在JS被称为 节点 ,也叫DOM节点
  • 我们现在认知的节点包括: 标签本身、标签上的属性(src、id、class、style等)、标签内文本;

# 二. 案例开灯关灯

# 2.1 DOM-获取ById-注册click-属性style

  • 获取元素: getElementById("id名");
  • 事件: 节点.onclick= function(){}
  • 控制节点的行内css样式 : 节点.style
  // 一 获取节点
    // document.getElementById(字符串类型的id名):返回对应的DOM节点
    // 文档      获取     id 
    var btn = document.getElementById('btn');
    // console.log(btn);
    // 二.单击事件: btn 加一个单击事件:弹窗1
    btn.onclick = function () {
        alert(1);
    }
    // 三个问题
    // 1.事件添加(注册给谁)
    // 2.用户触发方式是什么
    // 3.触发之后发生什么事情
    // 三. js属性控制css属性 节点属性style  只能获取和修改行内样式css样式
    console.log(btn.style.width);
    console.log(btn.style.height);
    btn.style.backgroundColor = "red";
    // 四. 拓展: html属性写法绝大多数和js节点属性写法一致的(标准属性: html标签出厂自带的属性). class属性除外
    // img的src
    var img = document.getElementById("img");
    console.log(img.src);

# 2.2. DOM-案例-两个按钮开关灯

image-20201213101356484

// 需求: 关灯按钮单击: body变黑色; 开灯按钮单击: body变白色
// 给谁添加事件? 触发方式是什么click? 触发之后发生什么事情
var close = document.getElementById("close");
var open = document.getElementById("open");
// 关灯按钮单击
close.onclick = function() {
  document.body.style.backgroundColor = "#000";
}
// 开灯按钮单击
open.onclick = function() {
  document.body.style.backgroundColor = "#fff";
}

# 2.3 DOM-案例-一个按钮开关灯

// 需求: 一个按钮开关灯
// 如果是关灯:执行关灯的代码; 如果是开灯:执行开灯的代码
var btn = document.getElementById("btn");
btn.onclick = function() {
  // 如果btn的文字是关灯 -- 获取到value属性值 判断是否是关灯
  // console.log(btn.value);
  if (btn.value == "关灯") {
    // 背景色变黑色
    document.body.style.backgroundColor = "#000";
    // 文字变开灯-控制value
    btn.value = "开灯";
  } else {
    // body背景色变白
    document.body.style.backgroundColor = "#fff";
    // value - 关灯
    btn.value = "关灯";
  }
}

# 三. 案例-搜索案例

# 3.1 DOM-注册focus和blur

事件类型:

  • 获得焦点: focus
  • 失去焦点:blur
var search = document.getElementById("search");
var list = document.getElementById("list");
// 1. 文本框获得焦点: 菜单显示display:block
search.onfocus = function() {
  // console.log(1);
  list.style.display = "block";
}

// 2. 文本框失去焦点: 菜单隐藏display:none
search.onblur = function() {
  list.style.display = "none";
}

# 3.2 DOM-类样式-className

// 需求: 按钮单击: 给box添加类名bgc_2
var btn = document.getElementById("btn");
var box = document.getElementById("box");
btn.onclick = function() {
  // console.log(box.className);
  // 添加类名
  // box.className = "bgc_2";  // 覆盖
  box.className += " bgc_2";
}

// className
// 1. 如果是控制单个类名, 没有影响
// 2. 如果要是控制多个类名: 添加可以多次添加; 思考: 删除比较麻烦

# 3.3 DOM-类样式对象-classList-语法

  • 添加类: add()
  • 移除类: remove()
  • 切换类: toggle()
// 手动书写一个数组
var arr = [1, 2, 3, 4];
console.log(arr);
var btn1 = document.getElementById("btn1");
var btn2 = document.getElementById("btn2");
var btn3 = document.getElementById("btn3");
var box = document.getElementById("box");
console.log(box.classList); //  ?? 返回的是什么? 伪数组: 有索引, 有数据, 可遍历

// add() : 添加类名
btn1.onclick = function() {
  box.classList.add("aa");
}

// remove(): 移除类名
btn2.onclick = function() {
  box.classList.remove("dd");
}

// toggle(): 切换
btn3.onclick = function() {
  box.classList.toggle("daqiu");
}

# 3.4 DOM-类样式对象-classList-搜索案例

var search = document.getElementById("search");
var list = document.getElementById("list");
// 1. 文本框获得焦点: 菜单显示: 给菜单添加show类
search.onfocus = function() {
  // list.classList.add("show");
  list.classList.toggle("show");
}
// 2. 文本框失去焦点: 菜单隐藏: 给菜单移除show类
search.onblur = function() {
  // list.classList.remove("show");
  list.classList.toggle("show");
}

# 四. 案例-美女相册

# 4.1 DOM-获取ByTagName和ByClassName

// 1. 通过标签名获取节点 : 返回伪数组
// document.getElementsByTagName(字符串类型的标签名)
var inps = document.getElementsByTagName('input');
// console.log(inps);

// 2. 通过类名获取节点: 返回伪数组
// document.getElementsByClassName(字符串类名的类名)
var btns = document.getElementsByClassName("btn");
// console.log(btns);
console.log(inps[0] == btns[0]);

# 4.2 DOM-案例-点击按钮切换图

var img = document.getElementById("img");
var inps = document.getElementsByTagName("input"); // 伪数组
// 单击按钮1, 把img的src属性值修改01.jpg
inps[0].onclick = function() {
  img.src = "./images/01.jpg";
}
// 单击按钮2, 把img的src属性值修改02.jpg
inps[1].onclick = function() {
  img.src = "./images/02.jpg";
}

# 4.3 DOM-案例-点击按钮切换图-自定义属性

  • 属性: data-xx
  • 获取:dataset.xx
// 如果保存自己业务方面需要的数据, 可以自定义HTML属性保存自己任何想要的数据
// 自定义HTML属性也要满足HTML标准属性的语法 k="v" , 工作中可以: data-xx="xx";
// **** js如何获取自定义属性值  dataset
var inps = document.getElementsByTagName("input");
// console.log(inps[0].dataset.guanxi); // dataset属性返回一个对象

// ****** 需求: 按钮单击, 修改img的src , 对应的按钮的data-xx自定义HTML属性的值
var img = document.getElementById("img");
inps[0].onclick = function() {
  img.src = inps[0].dataset.guanxi;
}
inps[1].onclick = function() {
  img.src = inps[1].dataset.guanxi;
}

# 4.4 DOM-案例-点击按钮切换图-this

var inps = document.getElementsByTagName("input");

var img = document.getElementById("img");
// this : 表示的是注册事件的标签 / 指向当前发生事件的标签
inps[0].onclick = function() {
  img.src = this.dataset.guanxi;
}
inps[1].onclick = function() {
  img.src = this.dataset.guanxi;
}
inps[2].onclick = function() {
  img.src = this.dataset.guanxi;
}

# 4.5 DOM-案例-点击按钮切换图-遍历循环

var inps = document.getElementsByTagName("input");
var img = document.getElementById("img");
// 遍历inps, 修改img的src = 当前这个按钮的guanxi属性值
// for (var i = 0; i < inps.length; i++) {
//     inps[i].onclick = function() {
//         // img.src = this.dataset.guanxi;
//         img.src = inps[i].dataset.guanxi;  // i = 3
//     }
// }
// console.log(i);
// let: 每次循环生成一个独立的块作用域 {i = 0}
// let: 每次循环生成一个独立的块作用域 {i = 1}
// let: 每次循环生成一个独立的块作用域 {i = 2}
for (let i = 0; i < inps.length; i++) {
  inps[i].onclick = function() {
    // img.src = this.dataset.guanxi;
    img.src = inps[i].dataset.guanxi;
  }
}
// const 常量

# 五. 案例-选选与反选

# 5.1 DOM-属性checked

// 如果是复选框, 是否勾选, checked的值是true还是false
// var ck = document.getElementById("ck");
// console.log(ck.checked);

// 按钮禁用disalbed
var btn = document.getElementById("btn");
btn.disabled = true;

# 5.2 DOM-案例-全选与反选

var checkAll = document.getElementById("checkAll");
var cks = document.getElementsByClassName("ck"); // 伪数组
// 1. 全选绑定单击事件
checkAll.onclick = function() {
  // 设置子选项的选中状态 = checkAll的选中状态
  // 子选项的checked = checkAll的checked的值
  // console.log(checkAll.checked);
  for (var i = 0; i < cks.length; i++) {
    cks[i].checked = checkAll.checked;
  }
}

// 2. 子选项绑定单击事件: 如果子选项的3个都选中了, 设置全选也是选中的; 否则全选不能选中
for (var i = 0; i < cks.length; i++) {
  cks[i].onclick = function() {
    // 看子选项中是否有某个是未选中, j不可能=3
    for (var j = 0; j < cks.length; j++) {
      // 如果有某个子选项是false值,说明未选中, break退出循环, j不可能=3
      // 如果循环完成都没有进入到下面的分支, j从0,1,2,3 最终j的值是3
      if (cks[j].checked == false) {
        break;
      }
    }
    if (j == 3) {
      // 设置全选也是选中的
      checkAll.checked = true;
    } else {
      checkAll.checked = false;
    }
  }
}

# 基础二

# 一. 获取-css选择器

image-20201214091428294

// document.getElementById("box")
// document.querySelector(字符串类型的css选择器)
// 返回一个节点, 如果页面中有多个标签使用了这个选择器, 只返回第一个; 没有这个节点, 返回null
var father = document.querySelector(".father");
// console.log(father);
var fuqin = document.querySelectorAll(".father, li"); // 返回伪数组
console.log(fuqin);

# 二. 操作属性

// 回顾: 自定义HTML k="v"  data-guanxi=""  js: dataset.guanxi
var box = document.querySelector("#box");
// console.log(box.dataset.zhangsan);

// 不带格式的自定义HTML属性的获取和设置方法
// console.log(box.dataset.abc);  // undefined
// 1. 获取
// box.getAttribute(字符串类型的属性名)
// console.log(box.getAttribute("abc"));

// 2. 设置
// box.setAttribute(字符串类型的属性名, 属性值)
box.setAttribute("abc", "daqiu");

# 三. 添加事件监听addEventListener

// 节点.on事件类型 = function(){}
// 1. 什么样的情况是on注册事件的方式无法解决
// A: 按钮注册单击 - alert(1); B添加功能: 单击按钮-alert(2) : 后边的覆盖前面的
var btn = document.querySelector("#btn");
// btn.onclick = function() {
//     alert(1);
// }
// btn.onclick = function() {
//     alert(2);
// }

// 2. 学新的注册事件的方式 : 添加事件监听
// btn.addEventListener(事件类型, 执行函数);
btn.addEventListener("click", function fn1() {
  alert(1);
})
btn.addEventListener("click", function fn1() {
  alert(2);
})

# 四. 事件冒泡与捕获-基础

image-20201214110208662

// 看 : 事件在冒泡节点执行 , 如果父子级节点都注册了相同的单击事件  出现什么现象
// 冒泡现象: 事件默认在冒泡阶段执行: 从触发事件的节点, 逐层向父级传递
var div = document.querySelector('div');
var btn = document.querySelector('button');
btn.onclick = function() {
  alert("btn");
}
div.onclick = function() {
  alert("div");
}

# 五. 事件冒泡与捕获-多级注册

// 1.注册事件: 添加事件监听; 2. 看事件在冒泡阶段执行; 3. 改变事件在捕获阶段执行 addEventListener()参数3:布尔型 , 默认是false在冒泡阶段执行; true在捕获阶段执行
var box_1 = document.querySelector(".box_1")
box_1.addEventListener("click", function() {
  alert("box_1");
}, true)
var box_2 = document.querySelector(".box_2")
box_2.addEventListener("click", function() {
  alert("box_2");
}, true)
var box_3 = document.querySelector(".box_3")
box_3.addEventListener("click", function() {
  alert("box_3");
}, true)

# 六. 阻止冒泡

// 看 : 事件在冒泡节点执行 , 如果父子级节点都注册了相同的单击事件  出现什么现象
// 冒泡现象: 事件默认在冒泡阶段执行: 从触发事件的节点, 逐层向父级传递
var div = document.querySelector('div');
var btn = document.querySelector('button');
// 阻止事件冒泡, 借助事件对象, 一个方法
btn.onclick = function(e) {
  // e.stopPropagation(); 阻止事件冒泡 : 阻止事件逐层向父级传递
  e.stopPropagation();
  alert("btn");

}
div.onclick = function() {
  alert("div");
}

# 七. 事件委托使用场景

var father = document.querySelector(".father");
var left = document.querySelector(".left");
var right = document.querySelector(".right");
left.onclick = function(e) {
  alert("个人信息");
  e.stopPropagation();

}
right.onclick = function(e) {
  alert("配置信息");
  e.stopPropagation();
}
father.onclick = function() {
  alert(Math.random());
}

# 八. 事件委托

// 目标: 事件委托: 有5个子级节点, 都有相同的事件, 为了减小事件绑定的次数, 把事件委托给父级节点
var father = document.querySelector(".father");
father.addEventListener("click", function(e) {
  // console.log(1);
  // **** 将来用户单击不同的子级, 触发不同的代码
  // 判断: 用户到底单击的是哪个子级节点: 如果单击的标签的类名是left, 表示单击到了left节点, 执行left的相关需求代码
  // ?? 获取类名 className  classList
  // 目标: 新的知识: 确定用户单击的标签的className值
  // e.target 返回用户单击的节点
  // console.log(e.target.className);
  var lei_name = e.target.className;
  if (lei_name == "left") {
    alert("left");
  } else if (lei_name == "right") {
    alert("right");
  }
})

# 九. 事件对象的属性和方法

// 一. 事件对象的属性
    // 1. e.target ,  e.currentTarget
    var parent = document.querySelector("#parent");
    parent.onclick = function(e) {
        // console.log(e.target); // 用户单击的节点,用户触发事件的节点
        // console.log(e.currentTarget); // 返回注册事件的节点
    }

    // 2.鼠标坐标系 - 不要加给节点,加给body
    document.body.onclick = function(e) {
        // 2.1 浏览器可视区原点的距离 - 配合固定定位的盒子使用
        // console.log(e.clientX, e.clientY);

        // 2.2 页面左上角的距离 - 配合绝对定位的盒子使用
        console.log(e.pageX, e.pageY);
    }


    // 二. 事件对象方法: 阻止默认行为
//javascript:void(0)
    // var aa = document.querySelector("a");
    // aa.onclick = function(e) {
    //     // e.preventDefault();
    //     return false;

    // }
    // 浏览器右键弹菜单
    document.oncontextmenu = function(e) {
        e.preventDefault();
    }

# 十. 事件委托

# 10.1 新增标签

// 单击按钮, ul里面新增li
var btn = document.querySelector("#btn");
var ul = document.querySelector("ul");
btn.onclick = function() {
  // 节点属性 节点.innerHTML: 获取和设置某个节点内的节点
  // console.log(ul.innerHTML); 

  // 节点.innerText: 节点内的文本内容
  // console.log(ul.innerText);

  // 新增li
  // ul.innerHTML += '<li class="son">新的li</li>'
  ul.innerText += '<li class="son">新的li</li>'
}

# 10.2 所有标签注册事件

var btn = document.querySelector("#btn");
var ul = document.querySelector("ul");
// 1. 按钮单击新增li
btn.onclick = function() {
  ul.innerHTML += '<li class="son">我是新的li</li>';
  // 2. li单击,弹窗1
  var lis = document.querySelectorAll("ul li");
  // console.log(lis);
  // lis.onclick = function() {
  //     alert(1);
  // }
  for (var i = 0; i < lis.length; i++) {
    lis[i].onclick = function() {
      alert(1);
    }
  }
}

// 2. li单击,弹窗1
var lis = document.querySelectorAll("ul li");
// console.log(lis);
// lis.onclick = function() {
//     alert(1);
// }
for (var i = 0; i < lis.length; i++) {
  lis[i].onclick = function() {
    alert(1);
  }
}

# 10.3 事件委托

var btn = document.querySelector("#btn");
var ul = document.querySelector("ul");
// 1. 按钮单击, ul新增li
btn.onclick = function() {
  ul.innerHTML += '<li class="son">新的li</li>'
}

// 2. 所有li注册单击事件alert(1) -- 事件委托
ul.onclick = function(e) {
  // 判断单击的标签如果是li弹窗
  // 如果类名是son表示单击li, 弹窗  单击的节点.className
  // console.log(e.target);
  // if (e.target.className == "son") {
  //     alert(1);
  // }

  //拓展: 判断是哪个标签的方法
  // console.log(e.target.nodeName); // 返回当前触发事件的大写的标签
  if (e.target.nodeName == "LI") {
    alert(2);
  }
}

# 十一. 事件类型

var box = document.querySelector(".box");
// mousedown: 鼠标按下
box.onmousedown = function() {
  console.log("down");
}

// mousemove: 鼠标移动
box.addEventListener("mousemove", function() {
  console.log("move");
})

// mouseup: 鼠标松开/弹起
box.onmouseup = function() {
  console.log("up");
}

# 十二. 案例: 鼠标跟随小天使

// 鼠标在body移动, 图片跟随: position: fixed;, 获取鼠标的位置, 设置img的left/top就是鼠标的位置的值
var img = document.querySelector("#img");
document.body.onmousemove = function(e) {
  // 1. 获取鼠标坐标点 - 固定定位: 事件对象.client/Y
  var x = e.clientX;
  var y = e.clientY;
  // console.log(x, y);

  // 2. 设置img的left=鼠标水平坐标; img的top=鼠标垂直坐标
  // left: 50px;
  img.style.left = x + 'px';
  img.style.top = y + 'px';
}

# 基础三

# 一. 获取元素对象在页面中的位置

// style: 行内
var son = document.querySelector(".son");
// console.log(son.style.left);
// offsetLeft: 获取盒子相对自己的offsetParent的水平距离
// offsetTop: 获取盒子相对自己的offsetParent的垂直距离

// 1. offsetParent: 返回定位的父节点, 没有这样的父节点, 逐层向上查找, 直到body
// console.log(son.offsetParent);
// 2. 节点属性
console.log(son.offsetLeft, son.offsetTop);

# 二. 事件解绑

var btn = document.querySelector("button");
// 注册onclick
// 解绑: 触发一次事件之后, 不能再继续触发
// btn.onclick = function() {
//     alert(1);
//     btn.onclick = null;
// }

// 注册: 添加事件监听: 如果事件需要解绑的话, 执行函数需要有名字
btn.addEventListener("click", function fn1() {
  alert(2);
  btn.removeEventListener("click", fn1);
})
//  注意: 两种事件注册方式和解绑方式不能交叉混用

# 三. 案例:鼠标拖动盒子

var box = document.querySelector(".box");
// 1. 鼠标按下box
box.onmousedown = function(e) {
  // alert(1);
  // 1.1 计算鼠标在盒子里面的距离(鼠标按下和鼠标移动的时候这段距离不变)
  // 鼠标在盒子的水平位置 = e.pageX-盒子在页面的水平位置
  var mouseLeft = e.pageX - box.offsetLeft;
  var mouseTop = e.pageY - box.offsetTop;

  // 2. 鼠标移动body: 盒子跟随鼠标
  document.body.onmousemove = function(e) {
    // console.log(1);
    // 设置box盒子的left和top值. pageX/Y获取鼠标的位置
    // 2.1 鼠标移动的时候计算盒子的left和top = 鼠标坐标点e.pageX - 鼠标在盒子里面的位置
    var x = e.pageX - mouseLeft;
    var y = e.pageY - mouseTop;
    box.style.left = x + 'px';
    box.style.top = y + 'px';
  }
}

// 3. 鼠标松开: 取消盒子跟随鼠标 - 把鼠标移动事件解绑
box.onmouseup = function() {
  document.body.onmousemove = null;
}

# 四. 操作节点

注意: 方法追加节点: 1.创建节点; 2.使用对应的方法追加

// 按钮单击, 实现用js方法新增节点
var btn = document.querySelector("#btn");
var ul = document.querySelector("ul");
btn.onclick = function() {

  // 如果使用js的方法新增节点, ***** 步骤:1. 创建节点, 2.新增
  // document.createElement(字符串类型的标签名) -- 实现创建一个空的标签
  var li = document.createElement("li");
  // console.log(li);
  // 往空节点里面放点内容
  li.innerText = "我是新的节点";
  // console.log(li);
  // 1. appendChild(目标)  -- 结尾新增节点
  // ul.appendChild(li);

  // 2. inserBefore(新增的节点, 追加的位置): 在任意位置新增节点
  // 目标: ul的开头追加li
  var first = document.querySelector("ul li:first-child");
  ul.insertBefore(li, first);
}

# 五. 发布微博

// 发布按钮单击, 发布内容
// 发布按钮注册单击事件: 把用户输入的内容放到li的p标签, 把这个li放到ul里面开头位置
var text = document.querySelector(".weibo-text");
var btn = document.querySelector(".weibo-btn");
var ul = document.querySelector(".weibo-list");
btn.onclick = function() {
  // 1. 获取用户输入内容: 如果表单控制, 获取用户输入的数据, 用到的都是value属性
  // console.log(text.value);
  var val = text.value;
  // 2. 把用户输入的内容放到li的p里面(创建节点, 放内容)
  var li = document.createElement('li'); // 空节点
  // li.innerHTML = '<p>' + val + '</p><span>删除</span>';
  li.innerHTML = `<p>${val}</p><span>删除</span>`
  // console.log(li);
  // 3. 把li添加到ul的开头 
  var first = document.querySelector(".weibo-list li:first-child");
  ul.insertBefore(li, first)
  // 4. 优化: 清空文本域
  text.value = '';
}

# 六. 获取节点

var btn = document.querySelector("#btn");
var ul = document.querySelector("ul");
btn.onclick = function() {
  // children: 获取所有子节点, 返回伪数组
  // console.log(ul.children[0]);
  // parentNode: 获取父节点: 直接父级, 和定位无关
  // console.log(ul.parentNode);
  // 测试parentNode是否和父级定位有关
  var li_2 = document.querySelector(".li_2")
  // console.log(li_2.parentNode);

  // 兄弟节点
  // console.log(li_2.nextElementSibling);
  console.log(li_2.previousElementSibling);
}

# 七. 发布微博-优化

根据已获取的DOM节点查询第一个子节点li

var text = document.querySelector(".weibo-text");
var btn = document.querySelector(".weibo-btn");
var ul = document.querySelector(".weibo-list");
// 按钮单击: 获取用户输入的数据, 放到li的p里面, 把ul的开头追加li
btn.onclick = function() {
  var val = text.value;
  var li = document.createElement("li");
  li.innerHTML = `<p>${val}</p><span>删除</span>`;
  // 获取ul节点的里面的第一个子节点
  var first = ul.children[0];
  ul.insertBefore(li, first);
  text.value = null;
}

# 八. 删除节点

// 删除节点  removeChild(目标节点)
// 按钮单击, 删除ul里面的第一个节点
var btn = document.querySelector("#btn");
var ul = document.querySelector("ul");
btn.onclick = function() {
  // 1. 选中目标节点
  var first = ul.children[0];
  // 2. removeChild()
  ul.removeChild(first);
}

# 九. 发布微博-删除

// 二. 删除 - 未来的span和已有的span都有删除功能-事件委托
ul.onclick = function(e) {
  // 判断用户单击的标签 span执行删除的功能 e.target.nodeName
  if (e.target.nodeName == 'SPAN') {
    // console.log("删除功能");
    // 1. 找到要删除的目标单击的span的父级li parentNode
    var del_li = e.target.parentNode;

    // // console.log(del_li);
    // // 2. removeChild
     ul.removeChild(del_li);
    //console.log(this);
  }
}

# 十. 发布微博-删除优化-事件委托


# 十一. 数据本地化-localstorage

image-20201215152522995

// 本地化存储数据 localstorage.方法

// 存储
// ***** 本地化存储数据的value必须是字符串类型
// js中有2种数据类型: 简单(可以直接存储, 自动隐式转换成字符串) 和 复杂(程序员手动书写程序转换成字符串后再存储)
// localStorage.setItem(key, value): 如果key相同,后面的覆盖前面的数据
// localStorage.setItem("a", "daqiu");
// localStorage.setItem("b", 1);
// localStorage.setItem("a", 100);

// 读取
// localStorage.getItem(key)
// console.log(localStorage.getItem("a"));


// 删除
// localStorage.removeItem(key)
// localStorage.removeItem("a");

// 清空
localStorage.clear();

# 十二. *JSON

// 1. 演示直接存储一个复杂数据类型到localstorage
var obj = {
  name: "daqiu",
  age: 18
}
// localStorage.setItem("dd", obj);

// 2. 学习转换方法
// 2.1 把复杂数据类型转成json格式的字符串 :都是双引号 {"name":"daqiu","age":18}
// var str = JSON.stringify(obj);
// console.log(str);
// localStorage.setItem('qq', str)

// 2.2 把json格式的字符串转成复杂数据类型
var str1 = "[1, 2, 3]";
var str2 = '{"name":"daqiu","age":18}';
// JSON.parse(字符串)
var arr1 = JSON.parse(str1);
// console.log(arr1);
var obj2 = JSON.parse(str2)
console.log(obj2);

# 十三. 微博案例-本地化存储

# 13.1 发布

image-20201215165234609


# 13.2 初始化列表

image-20201215175306546


# 基础四

# 一. BOM

  • BOM: browser object model,是把browser 浏览器看成是一个对象,就是学习浏览器对象的各种方法和属性;

  • 浏览器对象:window对象

# 1.1 window 对象

  • 特点:
    • 所有window对象的属性和方法,大部分可以直接省略 window,而直接使用
    • 因为window对象在浏览器中被称为顶级对象;
    • 顶级对象:页面中所有的东西都是依赖于这个对象存在的;
    • 变量与函数:
      • 所有的全局变量和全局函数都是window对象的属性和方法
      • 在js代码里面,不使用var声明的变量,都是隐式全局变量,这个方式是不推荐的,因为如果不使用var声明,是不会变量提升的;

# 1.2 方法: onload

<title>Document</title>
<!-- <script>
  window.onload = function() {
  var box = document.querySelector(".box");
  console.log(box);
}
</script> -->
// 1. window是浏览器的顶级对象, 省略window
// localStorage.setItem("a", 1);
// window.localStorage.setItem("b", "daqiu");
var box = document.querySelector(".box");
// console.log(box);
var w_box = window.document.querySelector(".box");
// console.log(w_box == box);

// 2. 全局变量或函数, window属性或方法
// var a;
// console.log(a);
var a = 1;
// console.log(a);
// console.log(window.a);

// 3. 声明全局变量不加var 的 影响
// console.log(b);  // 因为不能预解析, 报错b未定义
b = 10;
// console.log(window.b);

// 4. window的方法onload
// btn.onclick = function () {  }
// onload 当页面加载完成的时候: 静态资源图片, html, css
// 有一种情况必须写window.onload:  当页面有图片的时候
// 图片: 预加载
window.onload = function() {}

# 1.3 属性: location

作用: 操作浏览器地址栏的信息, 可获取, 可设置

// location : 管理浏览器地址栏信息的属性, 返回对象
// window.location
// console.log(location);
location.href = "http://www.baidu.com"; // 修改浏览器地址栏的地址

# 1.4 方法: 定时器

定时器可设置, 可清除

# 1.4.1 语法-单次定时器

// 定时器window对象的方法, 定时器可开启可(清除: 关闭)
// 单次定时器
// setTimeout(执行函数, 延迟时间以毫秒为单位): 1000毫秒=1秒
// setTimeout 返回值是number类型, 是当前定时器的标识, 用来清除定时器
// var timer1 = setTimeout(function() {
//     alert(1);
// }, 2000)
// var timer2 = setTimeout(function() {
//     alert(1);
// }, 2000)
// console.log(timer1);
// console.log(timer2);
// // 按钮单击, 清除定时器
// btn.onclick = function() {
//     // clearTimeout(定时器的标识)
//     clearTimeout(timer);
// }

# 1.4.2 语法-多次定时器

// 多次定时器: 开启的函数的参数完全相同
var timer = setInterval(function() {
  alert(2);
}, 2000);
btn.onclick = function() {
  clearInterval(timer)
}

# 1.4.3 案例: 验证码

// 需求: 按钮单击: 按钮不能再点, 文字开始倒计时, 当倒计时到0的恢复默认
var btn = document.querySelector("#getCode");
btn.onclick = function() {
  // 1. 按钮功能禁用 disabled:true
  btn.disabled = true;

  // 2. 文字变成 获取验证码(5) -- 开始倒计时
  // 2.1 设置文字(5)
  var num = 5;
  btn.value = `获取验证码(${num})`;

  // 2.2 倒计时
  var timer = setInterval(function() {
    num--;
    btn.value = `获取验证码(${num})`;

    // 2.3 倒计时到0的恢复默认 num=0
    if (num == 0) {
      // 2.3.1 按钮启用
      btn.disabled = false;
      // 2.3.2 定时器清除-不再倒计时
      clearInterval(timer)
      // 2.3.3 value值 获取验证码
      btn.value = "获取验证码";
    }

  }, 1000);
}

# 二. 案例: 微博

# 2.1 事件类型 : keydown、keyup

var text = document.querySelector("#text");
// on... / 添加事件监听
// onkeydown: 键盘按下
text.onkeydown = function(e) {
  // console.log(1);
  // 一定条件判断: 判断用户按下的到底是哪个键: 借助事件对象的属性
  // 事件对象.keyCode: 获取当前按下的键的键码: 回车键的键码是13
  // console.log(e.keyCode);
  // console.log(e.ctrlKey); // true / false
  // ?? 用户同时按下了回车和ctrl键
  // if (e.keyCode == 13 && e.ctrlKey == true) {
  //     console.log("恭喜你, 大哥, 按下ctrl+回车");
  // }
  if (e.keyCode == 13 && e.ctrlKey) {
    console.log("恭喜你, 大哥, 按下ctrl+回车");
  }
}

// onkeyup: 键盘按下 -松开
text.onkeyup = function() {
  // console.log(2);
}

# 2.2 微博组合键发布

// ****** 第四天新增功能:ctrl+回车发布
text.onkeydown = function(e) {
  // 如果用户同时按下ctrl+回车
  if (e.ctrlKey && e.keyCode == 13) {
    // console.log(1);
    // btn.onclick = function () {  } // 对象添加一个方法
    // fn = function () {  }
    // btn.xx()
    btn.onclick(); // 调用对象的方法

    // 所有的事件类型本质就是对象的方法
  }
}

# 2.3 微博-删除

数据可能是重复的, 不能直接找数据直接删除, 找到每个数据的唯一的身份标识, 按身份标识去删除

  1. 清空本地存储
  2. 存储数据: [{key:xx, shenfenzheng: xx}], 存储数据之前把对象添加身份证键值对
  3. 让span标签记录当前数据的身份证标识, 找到数据中和span记录的身份标识是一样的这个数据再删除
    1. 创建节点的时候, 把span添加了自定义HTML属性sfz=时间戳变量(span标签记录当前数据的身份证标识)
    2. span单击的地方: 获取span标签的sfz属性值; 遍历数组, 如果数组中对象的shenfenzheng属性值 == span的sfz属性值, log(找到我了)

image-20201217150421681

需求:

  • 删除li标签
  • localstorage中的数据: 删除数组中的对象
// ***** 第四天删除功能: 标签  和  数据
ul.onclick = function(e) {
  if (e.target.nodeName == "SPAN") {
    // 删除li: 找到li, 删除它
    // this.parentNode
    var del_li = e.target.parentNode;
    ul.removeChild(del_li);
    // ------------以下是删除数据
    // 找到数据中和span的sfz属性值相同的数据删除掉
    // 1. 获取span的sfz属性值 -- 节点.getAtrr..()
    var del_sfz = e.target.getAttribute("sfz");
    // console.log(del_sfz);
    // 2. 数据在数组里面, 是多条数据 , 遍历 , 如果找到相同的身份证 删除对象
    for (var i = 0; i < arr.length; i++) {
      if (del_sfz == arr[i].shenfenzheng) {
        // console.log("大哥, 你找到我了");
        // 删除数据: 删除数组中的对象, 删除一个对象
        // arr.pop()  arr.shift()  arr.splice(位置, 个数, 添加的) 
        arr.splice(i, 1);
        // console.log(arr); // arr的数据已经删除了 , 同步localstorage, 再往localstorage存储一遍: 先转成字符串, 再存储
        var str = JSON.stringify(arr);
        localStorage.setItem("aa", str)

      }
    }

  }
}

# 三. tab栏

# 3.1 事件: mouseover 和 mouseout

var box = document.querySelector(".box");
// *** mouseover/mouseout: 当鼠标移入或离开子元素, 也能触发父元素的事件
// mouseover : 鼠标移入
// box.onmouseover = function() {
//     console.log(1);
// }

// // mouseout: 鼠标离开
// box.onmouseout = function() {
//     console.log(2);
// }

// mouseenter 和 mouseleave
box.onmouseenter = function() {
  console.log(1);
}

// mouseout: 鼠标离开
box.onmouseleave = function() {
  console.log(2);
}

# 3.2 案例: tab栏

window.onload = function() {
  var lis = document.querySelectorAll(".tab-item")
  var mains = document.querySelectorAll(".main");
  // 排他思想: 只许州官放火不许百姓点灯: 1. 设置所有li都不能变红:删除类active;2. 设置鼠标移入的li变红
  for (var i = 0; i < lis.length; i++) {
    // 1.0 存储i为索引值(下边代码要用)
    lis[i].setAttribute("index", i);
    lis[i].onmouseover = function() {
      // 1. 所有li移除active
      for (var i = 0; i < lis.length; i++) {
        lis[i].classList.remove("active");
      }
      // 2. 这个li添加active
      this.classList.add("active");

      // _______________ 控制内容显示
      // 鼠标移入第一个li, 内容显示第一个;鼠标移入到第二个li,内容显示第二个
      // 鼠标移入第一个li, 索引值0, 在四个div中找到索引值为0的显示
      // 鼠标移入第二个li, 索引值1, 在四个div中找到索引值为1的显示
      // .....
      // 先获取鼠标移入的li的索引值, 用这个索引值找到对应的div 显示
      // 1. 获取鼠标移入的li this的索引值,保存(并没有索引值属性, 自己自定义一个HTML属性, 去替代索引值) -- 1.0 在遍历的时候给li添加HTML属性存索引值i
      var num = this.getAttribute("index");
      // console.log(num);
      // 3. 排他 - 设置所有div移除类
      for (var i = 0; i < mains.length; i++) {
        mains[i].classList.remove("selected");
      }
      // 2. 用这个索引值筛选对应的div显示,添加class属性值为selected
      mains[num].classList.add("selected");

    }
  }
}

# 基础五

# 一. 轮播图

# 1.1 获取css属性值

# 1.1.1获取DOM节点样式

// window.getComputedStyle(节点)
// 返回的是: 对象 : 当前这个节点的所有css属性
var box = document.querySelector(".box");
var res = getComputedStyle(box);
// console.log(res);
// getComputedStyle返回的对象获取css属性值的时候, 返回的都是字符串
// 注意: *** 返回的只是属性值, 与盒子模型无关   
console.log(res.width);
console.log(res.height);
console.log(res.backgroundColor);

# 1.1.2 获取元素对象的实际宽度和高度

元素的实际宽高 = border+padding+content(width和height)

// 节点属性
var box = document.querySelector(".box");
// 1. offsetWidth/offsetHeight
// console.log(box.offsetWidth); // 620 = width + padding + border
// console.log(box.offsetHeight);

// 2. clientWidth/clientHeight
console.log(box.clientWidth); // 520 = width + padding
console.log(box.clientHeight);

# 1.2 轮播图原理

  • 布局:ul下有很多li标签;浮动在一行;

  • 原理:切换图片的时候,把ul位置修改一下,给ul的父容器,设置一个 overflow:hidden;

  • 功能需求:

    • 左右按钮的轮播
    • 自动轮播
    • 鼠标在轮播图里面的时候,停止自动轮播,离开后继续自动轮播
    • 基础
    
    

# 1.3 左右轮播

var points = document.querySelectorAll(".list i");
var ul = document.querySelector("#imglist");
// 1. 右侧箭头单击, 图片向左侧移动
var right = document.querySelector(".arrow-right");
// 一个索引值变量, 默认显示第一张图, 索引值为0
var index = 0;
// 获取图片的宽度
var w = document.querySelector("img").offsetWidth;
// console.log(w);
right.onclick = function() {
  // 1. 索引值单击一次+1 
  index++;
  // *** 经验: 先计算,再判断, 最后赋值
  // 如果已经移动到第7张图(没有这个图片), 回到第一张
  if (index == 6) {
    index = 0;
  }
  // 2. 计算距离公式 -- 结果
  var result = index * w;
  // 3. 设置ul的left取值为第二步的结果 730px
  ul.style.left = -result + 'px';

  // *************圆点样式: 显示第几张图片, 这个数字对应的圆点添加current类, 其他的圆点删除current类
  // 1. 排他:所有圆点删除类
  for (var i = 0; i < points.length; i++) {
    points[i].classList.remove("current");
  }
  // 2. 设置和图片索引对应的圆点添加类
  points[index].classList.add("current");
}
// 2. 左侧箭头单击, 图片向右侧移动
var left = document.querySelector(".arrow-left");
left.onclick = function() {
  // 1. 索引值单击一次-1 
  index--;
  // *** 经验: 先计算,再判断, 最后赋值
  // 如果已经移动到索引值取到-1,没有这样的图, 回到最后一张图index=5
  if (index == -1) {
    index = 5;
  }
  // 2. 计算距离公式 -- 结果
  var result = index * w;
  // 3. 设置ul的left取值为第二步的结果 730px
  ul.style.left = -result + 'px';
  // *************圆点样式: 显示第几张图片, 这个数字对应的圆点添加current类, 其他的圆点删除current类
  // 1. 排他:所有圆点删除类
  for (var i = 0; i < points.length; i++) {
    points[i].classList.remove("current");
  }
  // 2. 设置和图片索引对应的圆点添加类
  points[index].classList.add("current");
}

# 1.4 关联圆点

// *************圆点样式: 显示第几张图片, 这个数字对应的圆点添加current类, 其他的圆点删除current类
// 1. 排他:所有圆点删除类
for (var i = 0; i < points.length; i++) {
  points[i].classList.remove("current");
}
// 2. 设置和图片索引对应的圆点添加类
points[index].classList.add("current");

# 1.5 自动轮播

// 3. 图片自动向左侧移动
var timer = setInterval(function() {
  // 和右箭头单击事件是一样的效果
  right.onclick();
}, 2000)

# 1.6 鼠标控制轮播

// 4. 鼠标移入到图片, 停止自动播放; 鼠标离开: 继续播放
// 不要给图片或ul注册事件, 图片是移动; ul范围比较大 -- 注册给显示区域是最合适
var box = document.querySelector("#box");
box.onmouseover = function() {
  // 清除定时器
  clearInterval(timer);
}
box.onmouseout = function() {
  // *** 这里开启定时器不要加var, 因为添加了var导致开启多个定时器, 定时器有累加的问题
  timer = setInterval(function() {
    // 和右箭头单击事件是一样的效果
    right.onclick();
  }, 2000)
}

# 二. 案例: 手风琴

window.onload = function() {
  var lis = document.querySelectorAll("#box li");
  for (var i = 0; i < lis.length; i++) {
    // 1. 鼠标移入: 这个li的宽度是800. 其他的li 的宽度是100
    lis[i].onmouseover = function() {
      // 1.1 控制所有li宽度是100
      for (var i = 0; i < lis.length; i++) {
        lis[i].style.width = '100px';
      }

      // 1.2 控制鼠标移入的li的宽度是800
      this.style.width = "800px";
    }

    // 2. 鼠标离开: 所有li的宽度是240
    lis[i].onmouseout = function() {
      for (var i = 0; i < lis.length; i++) {
        lis[i].style.width = '240px';
      }
    }
  }
}

# 三. 案例: 旋转木马

原理:

  • 按钮单击切换类名(类名存储到数组)
  • 远近虚实效果只是css设置了不同的透明度和位置等

# 3.1 单击按钮切换(基础需求)

// 旋转木马: 用不同的css类名控制了 近实远虚, 单击切换类名
var ps = document.querySelectorAll("p");
var btn = document.querySelector("#btn");
// 把两个类名存到js中, 用js添加给2个p标签
var arr = ['pos_1', 'pos_2'];
// 1. 页面初始化
for (var i = 0; i < ps.length; i++) {
  // 添加类名
  ps[i].className = arr[i];
}

// 2. 按钮单击, 切换类名
btn.onclick = function() {
  // ['pos_1', 'pos_2'];
  // [ 'pos_2',  'pos_1']
  // ['pos_1', 'pos_2'];
  // p1 = pos_2
  // p2 = pos_1
  // 数组后面删除一个数据pop,  删除的这个数据添加到数组的开头unshift
  var del_name = arr.pop();
  arr.unshift(del_name);
  // console.log(arr);
  for (var i = 0; i < ps.length; i++) {
    // 添加类名
    ps[i].className = arr[i];
  }
}

# 3.2 案例: 旋转木马

image-20201206155810513

window.onload = function() {
  // 1. 初始化: 5个li对应5个类名
  var lis = document.querySelectorAll("#slide li");
  var arr = ["left1", "left2", "middle", "right2", "right1"];
  // for (var i = 0; i < lis.length; i++) {
  //     lis[i].className = arr[i];
  // }
  function change() {
    for (var i = 0; i < lis.length; i++) {
      lis[i].className = arr[i];
    }
  }
  change();
  // 2. 左右箭头单击
  var left = document.querySelector("#arrLeft");
  var right = document.querySelector("#arrRight");
  right.onclick = function() {
    // 2.1 改变数组里面类名的顺序 : left1去最后: arr 开头删除一个; 添加到结尾
    var del_name = arr.shift();
    arr.push(del_name);
    // console.log(arr);
    // 2.2 遍历把类名添加到标签li
    // for (var i = 0; i < lis.length; i++) {
    //     lis[i].className = arr[i];
    // }
    change();
  }
  left.onclick = function() {
    // 类名顺序: 结尾删除一个, 添加到开头: 发现最后一个标签的类名不是right1, 编程right2 -- 结尾删除一个类, 发现第一个标签去了最后一个位置right1(第一个标签添加类名right1)
    var del_name = arr.pop();
    arr.unshift(del_name);
    // for (var i = 0; i < lis.length; i++) {
    //     lis[i].className = arr[i];
    // }
    change();
  }
}

# 四. 360开机动画

# 4.1 动画或过渡结束事件

  • 动画或者过渡结束事件:专门是指css3里面的 动画或者过渡 结束会触发的事件,css3动画有两种,结束动画事件也有两个;
  • 特点:不能使用on的方式注册,只能使用addEventListener的方式注册
  • transitionend:元素的过渡动画结束的时候触发;
  • animationend:会在帧动画结束的时候触发,如果帧动画是无限次的,不会触发该事件animationend
// **** 这2组事件只能通过添加事件监听的形式注册
// transitionend:过渡完成之后触发的事件
// animationend: 动画完成之后触发的事件
var box = document.querySelector(".box");
// box.addEventListener("transitionend", function() {
//     console.log(1);
// })

box.addEventListener("animationend", function() {
  console.log(2);
})

# 4.2 案例

// 需求: x号按钮单击: 下半部分变换高度到0; 高度动画完成之后, 上半部width变换到0
var close = document.querySelector("#closeButton");
// 因为html和css是写好的, 观察添加过渡的标签到底是谁: 下半部和最大的box(改变宽度的不是上半部分是box)
var xia = document.querySelector("#bottomPart");
var box = document.querySelector("#box");
close.onclick = function() {
  // 1. 下半部高度=0
  xia.style.height = 0;
  // 2. 下半部分高度为0后立刻触发transitionend: 大盒子box的宽度=0
  // 事件添加给谁xia ; 触发方式; 触发之后发生什么事
  xia.addEventListener("transitionend", function() {
    box.style.width = 0;
  })

}