JavaScript事件委托案例(可以删除的表格)阻止默认右键菜单和自定义右键菜单

选项卡(tab 切换)
分析效果
ul 下 有三个 li => 当作按钮使用
ol 下 有三个 li => 当作展示内容的盒子使用
按钮li点击, 对应切换 盒子li 显示
怎么切换 ?
当你点击第一个 按钮li 的时候
只有第一个 按钮li 有 active 类名
其他的 按钮li 没有 active 类名
所有的 盒子li 都没有 active 类名
只有第一个 盒子li 有 active 类名
当你点击第二个 按钮li 的时候
只有第二个 按钮li 有 active 类名
其他的 按钮li 没有 active 类名
所有的 盒子li 都没有 active 类名
只有第二个 盒子li 有 active 类名
代码思路:
1. 需要获取元素
1-1. 获取所有 ul 下面的 li
因为要给每一个 li 添加一个点击事件
我要在点击事件里面进行一些操作
1-2. 获取所有 ol 下面的 li
因为要对每一个 li 进行操作
需要添加 active 类名或者删除 active 类名
2. 添加点击事件
2-1. 要给每一个 ul 下面的 li 添加点击事件
因为每一个 li 都有点击效果
btns 这个伪数组里面存的就是 ul 下面的所有 li
一个 for 循环, 遍历 btns 这个伪数组, 给每一个添加点击事件
2-2. 我要知道我点的 li 是索引为几的 li
因为我点击索引为 0 的 li 的时候
要让 tabs 里面对应索引为 0 的有 active 类名
我点击索引为 1 的 li 的时候
要让 tabs 里面对应索引为 1 的有 active 类名
再循环的时候, 给每一个 btns 的 li 身上添加一个自定义属性
这个自定义属性用来记录索引值
3. 点击事件里面的操作
3-1. 再点击事件里面
我点击索引为 0 的按钮的时候
让所有的按钮都没有 active 类名
单独给自己加上一个 active 类名
3-2. 在点击事件里面
让 tabs 里面的所有 li 都没有里面
让 tabs 里面索引和我点击的 li 的索引一样的那一个有类名
// 1. 获取元素
var btns = document.querySelectorAll(‘ul > li’)
var tabs = document.querySelectorAll(‘ol > li’)
// 2. 循环添加点击事件
for (var i = 0; i < btns.length; i++) {
// 2-1. 添加点击事件
btns[i].addEventListener(‘click’, function () {
// 3-1. 给所有的 li 去掉类名
for (var j = 0; j < btns.length; j++) {
btns[j].className = ‘’
tabs[j].className = ‘’
}
// 3-2. 给自己和 tabs 里面索引配套的添加类名
this.className = ‘active’
// this 是你点击的这个元素, 你点击的这个元素的索引是 几, 我们不知道
// this.getAttribute(‘index’) 是获取到你点击的这个元素身上的自定义属性 index
// 因为这个 index 自定义属性记录着这个元素的索引呢
tabs[this.getAttribute(‘index’) - 0].className = ‘active’
})
// 2-2. 添加自定义属性 index
// 在点击事件之前的循环里面, 给每一个元素添加了一个自定义属性
// 把这个元素的索引记录在了元素身上
btns[i].setAttribute(‘index’, i)
}
因为你点击的时候循环已经结束了
当 i === 3 的时候, 也就是 i === btns.length 的时候循环结束
所以你在点击事件里面使用 i 一定是 3
你写的 btns[i] 就是 btns[3] 压根没有这个元素
选项卡(tab 切换)
分析效果
ul 下 有三个 li => 当作按钮使用
ol 下 有三个 li => 当作展示内容的盒子使用
按钮li点击, 对应切换 盒子li 显示
怎么切换 ?
当你点击第一个 按钮li 的时候
只有第一个 按钮li 有 active 类名
其他的 按钮li 没有 active 类名
所有的 盒子li 都没有 active 类名
只有第一个 盒子li 有 active 类名
当你点击第二个 按钮li 的时候
只有第二个 按钮li 有 active 类名
其他的 按钮li 没有 active 类名
所有的 盒子li 都没有 active 类名
只有第二个 盒子li 有 active 类名
代码思路:
1. 需要获取元素
1-1. 获取所有 ul 下面的 li
因为要给每一个 li 添加一个点击事件
我要在点击事件里面进行一些操作
1-2. 获取所有 ol 下面的 li
因为要对每一个 li 进行操作
需要添加 active 类名或者删除 active 类名
2. 添加点击事件
2-1. 要给每一个 ul 下面的 li 添加点击事件
因为每一个 li 都有点击效果
btns 这个伪数组里面存的就是 ul 下面的所有 li
一个 for 循环, 遍历 btns 这个伪数组, 给每一个添加点击事件
2-2. 我要知道我点的 li 是索引为几的 li
因为我点击索引为 0 的 li 的时候
要让 tabs 里面对应索引为 0 的有 active 类名
我点击索引为 1 的 li 的时候
要让 tabs 里面对应索引为 1 的有 active 类名
再循环的时候, 给每一个 btns 的 li 身上添加一个自定义属性
这个自定义属性用来记录索引值
3. 点击事件里面的操作
3-1. 再点击事件里面
我点击索引为 0 的按钮的时候
让所有的按钮都没有 active 类名
单独给自己加上一个 active 类名
3-2. 在点击事件里面
让 tabs 里面的所有 li 都没有里面
让 tabs 里面索引和我点击的 li 的索引一样的那一个有类名
// 1. 获取元素
var btns = document.querySelectorAll(‘ul > li’)
var tabs = document.querySelectorAll(‘ol > li’)
// 2. 循环添加点击事件
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener(‘click’, function () {
for (var j = 0; j < btns.length; j++) {
btns[j].className = ‘’
tabs[j].className = ‘’
}
this.className = ‘active’
tabs[this.getAttribute(‘index’) - 0].className = ‘active’
})
btns[i].setAttribute(‘index’, i)
}
选项卡(tab 切换)
分析效果
ul 下 有三个 li => 当作按钮使用
ol 下 有三个 li => 当作展示内容的盒子使用
按钮li点击, 对应切换 盒子li 显示
怎么切换 ?
当你点击第一个 按钮li 的时候
只有第一个 按钮li 有 active 类名
其他的 按钮li 没有 active 类名
所有的 盒子li 都没有 active 类名
只有第一个 盒子li 有 active 类名
当你点击第二个 按钮li 的时候
只有第二个 按钮li 有 active 类名
其他的 按钮li 没有 active 类名
所有的 盒子li 都没有 active 类名
只有第二个 盒子li 有 active 类名
代码思路:
1. 需要获取元素
1-1. 获取所有 ul 下面的 li
因为要给每一个 li 添加一个点击事件
我要在点击事件里面进行一些操作
1-2. 获取所有 ol 下面的 li
因为要对每一个 li 进行操作
需要添加 active 类名或者删除 active 类名
2. 添加点击事件
2-1. 要给每一个 ul 下面的 li 添加点击事件
因为每一个 li 都有点击效果
btns 这个伪数组里面存的就是 ul 下面的所有 li
一个 for 循环, 遍历 btns 这个伪数组, 给每一个添加点击事件
2-2. 我要知道我点的 li 是索引为几的 li
因为我点击索引为 0 的 li 的时候
要让 tabs 里面对应索引为 0 的有 active 类名
我点击索引为 1 的 li 的时候
要让 tabs 里面对应索引为 1 的有 active 类名
再循环的时候, 给每一个 btns 的 li 身上添加一个自定义属性
这个自定义属性用来记录索引值
3. 点击事件里面的操作
3-1. 再点击事件里面
我点击索引为 0 的按钮的时候
让所有的按钮都没有 active 类名
单独给自己加上一个 active 类名
3-2. 在点击事件里面
让 tabs 里面的所有 li 都没有里面
让 tabs 里面索引和我点击的 li 的索引一样的那一个有类名
// 1. 获取元素
// 所有 ul 下面的 li 当作 按钮使用, 所以起名叫做 btns
var btns = document.querySelectorAll(‘ul > li’)
// 所有 ol 下面的 li 当作 切换盒子使用, 所以起名叫做 tabs
var tabs = document.querySelectorAll(‘ol > li’)
2. 给 btns 里面的每一个添加点击事件
for (var i = 0; i < btns.length; i++) {
// 2-1. 给每一个 btns 里面的 li 添加点击事件
btns[i].addEventListener(‘click’, function () {
// 3-1. 让所有的 btns 里面的 li 都没有类名 - 又需要一个循环
for (var j = 0; j < btns.length; j++) {
btns[j].className = ‘’
}
// 让我点击的这一个, 有 active 类名
// this 就是我点击的这个 li
this.className = ‘active’
3-2. 让所有 tabs 里面的 li 都没有类名 - 又需要一个循环
for (var k = 0; k < tabs.length; k++) {
tabs[k].className = ‘’
}
// 让索引和点击的这个 li 一样的那个 tabs里的li 有 active 类名
// 获取到你点击的 li 的索引
var index = this.getAttribute(‘index’) - 0
tabs[index].className = ‘active’
})
2-2. 给每一个 li 身上添加一个自定义属性, 用来记录索引值
btns[i].setAttribute(‘index’, i)
}
this 是一个在函数里面使用的关键字
不同的函数 this 指向不一样, 在事件处理函数里面
this 就是事件源, 绑定在谁身上的事件, this 就是谁
你点击哪一个按钮的时候, 执行的是哪一个按钮身上的点击事件, this 就是哪一个按钮
选项卡(tab 切换)
分析效果
ul 下 有三个 li => 当作按钮使用
ol 下 有三个 li => 当作展示内容的盒子使用
按钮li点击, 对应切换 盒子li 显示
怎么切换 ?
当你点击第一个 按钮li 的时候
只有第一个 按钮li 有 active 类名
其他的 按钮li 没有 active 类名
所有的 盒子li 都没有 active 类名
只有第一个 盒子li 有 active 类名
当你点击第二个 按钮li 的时候
只有第二个 按钮li 有 active 类名
其他的 按钮li 没有 active 类名
所有的 盒子li 都没有 active 类名
只有第二个 盒子li 有 active 类名
代码思路:
1. 需要获取元素
1-1. 获取所有 ul 下面的 li
因为要给每一个 li 添加一个点击事件
我要在点击事件里面进行一些操作
1-2. 获取所有 ol 下面的 li
因为要对每一个 li 进行操作
需要添加 active 类名或者删除 active 类名
2. 添加点击事件
2-1. 要给每一个 ul 下面的 li 添加点击事件
因为每一个 li 都有点击效果
btns 这个伪数组里面存的就是 ul 下面的所有 li
一个 for 循环, 遍历 btns 这个伪数组, 给每一个添加点击事件
2-2. 我要知道我点的 li 是索引为几的 li
因为我点击索引为 0 的 li 的时候
要让 tabs 里面对应索引为 0 的有 active 类名
我点击索引为 1 的 li 的时候
要让 tabs 里面对应索引为 1 的有 active 类名
再循环的时候, 给每一个 btns 的 li 身上添加一个自定义属性
这个自定义属性用来记录索引值
3. 点击事件里面的操作
3-1. 再点击事件里面
我点击索引为 0 的按钮的时候
让所有的按钮都没有 active 类名
单独给自己加上一个 active 类名
3-2. 在点击事件里面
让 tabs 里面的所有 li 都没有里面
让 tabs 里面索引和我点击的 li 的索引一样的那一个有类名
// 1. 获取元素
// 所有 ul 下面的 li 当作 按钮使用, 所以起名叫做 btns
var btns = document.querySelectorAll(‘ul > li’)
// 所有 ol 下面的 li 当作 切换盒子使用, 所以起名叫做 tabs
var tabs = document.querySelectorAll(‘ol > li’)
// 2. 给 btns 里面的每一个添加点击事件
for (var i = 0; i < btns.length; i++) {
// 2-1. 给每一个 btns 里面的 li 添加点击事件
btns[i].addEventListener(‘click’, function () {
// btns.length === tabs.length
// 因为有几个按钮就有几个盒子
// 我可以把两个事情放在一个循环里面做
// 3-1. 让所有的 btns 里面的 li 都没有类名 - 又需要一个循环
// 3-2. 让所有 tabs 里面的 li 都没有类名 - 又需要一个循环
for (var j = 0; j < btns.length; j++) {
// j === 0 1 2
btns[j].className = ‘’
tabs[j].className = ‘’
}
// 让我点击的这一个, 有 active 类名
this.className = ‘active’
// 让索引和点击的这个 li 一样的那个 tabs里的li 有 active 类名
var index = this.getAttribute(‘index’) - 0
tabs[index].className = ‘active’
})
// 2-2. 给每一个 li 身上添加一个自定义属性, 用来记录索引值
btns[i].setAttribute(‘index’, i)
}
外层循环
当 i === 0 的时候
给 btns[0] 添加点击事件
给 btns[0] 添加自定义属性 index=“0”
当 i === 1 的时候
给 btns[1] 添加点击事件
给 btns[1] 添加自定义属性 index=“1”
当 i === 2 的时候
给 btns[2] 添加点击事件
给 btns[2] 添加自定义属性 index=“2”
等你能点击的时候, 循环已经结束了
你触发点击事件的时候
因为循环已经结束了
每一个 li 身上都已经有了自定义属性了
for (var j = 0; j < btns.length; j++) {
btns[j].className = ‘’
tabs[j].className = ‘’
}
for 循环之所以能循环数组或者伪数组
是因为 for 循环能给我们提供一组有规律的数字
条件写的 btns.length 只是为了得到一个数字
来作循环停止的条件
btns === [ li, li, li ]
tabs === [ li, li, li ]
btns.length === 3
tabs.length === 3
在循环里面的时候 j 分别等于 0 1 2
tabs[j] => btns[0] btns[1] btns[2]
btns[j] => tabs[0] tabs[1] tabs[2]
分析效果
1. 可以拖着跑, 我们需要文字不能选中
当你不小心选中文字的时候, 那么就不能拖着盒子跑了
所以我们需要文字不能选中
2. 鼠标按下可以拖着跑
鼠标抬起不能拖着跑
鼠标脱手不能继续拖着跑了
3. 鼠标抬起的时候
如果没有接触的元素, 那么就回归原位
如果有接触的元素, 那么和谁接触面积大, 就和谁交换位置
4. 鼠标脱手的时候
直接回归原位
5. 鼠标移动
如果是按下状态, 那么就带着盒子一起走
如果是抬起或者脱手状态, 那么就不带着盒子一起走
6. li 的移动不能超出 ul 的范围
代码思路

  1. 获取元素
    1-1. 获取 ul
    因为我需要他的尺寸
    li 不能超出 ul 的范围
    1-2. 获取 ul 下面所有的 li
    因为每一个都可以拖走
    需要绑定很多事件
  2. 绑定事件
    1-1. 拖着走就是 mousemove 事件
    1-2. 按下能拖着走 mousedown 事件
    1-3. 抬起不能拖着走 mouseup 事件
    1-4. 脱手回归原位, 也不能拖着走 mouseout 事件
    我们需要给每一个 li 都绑定这四个事件
    循环 lis 这个伪数组, 给里面的每一个元素绑定四个事件
    因为在事件里面写的代码比较多
    所以把四个事件处理函数单独书写在外面
  3. 取消文本选中效果
    因为文本一旦框选了, 那么拖着走的时候
    就是在拖着文本内容移动, 就不能拖着盒子走了
    需要给 document 绑定一个 selectstart 事件
    在这个事件里面阻止一下浏览器默认行为
  4. 确定什么时候可以触发移动事件(移动事件触发的目的就是拖着盒子跑)
    按下以后, 移动事件 可以 触发
    抬起以后, 移动事件 不能 触发
    脱手以后, 移动事件 不能 触发
    提前定义一个变量, 用于确定移动事件能不能触发
    初始默认是 false
    按下以后赋值为 true
    不管是抬起还是脱手都赋值为 false
    在移动事件里面判断, 如果是 true 就继续执行, 如果是 false 就 return
    变量需要定义在全局
    因为四个事件处理函数里面都需要用到这个变量
    有的是赋值有的是获取
    如果定义为某一个函数里面的私有变量
    那么其他函数里面就使用不了了
    所以定义为全局变量, 那么所有的函数里面都可以使用
  5. 获取元素
    1-1. 获取 ul
    var ul = document.querySelector(‘ul’)
    1-2. 获取 ul 下面的每一个 li
    var lis = ul.children // children 获取的是某一个节点下的所有 子元素节点
  6. 循环 lis 绑定事件
    for (var i = 0; i < lis.length; i++) {
    // 2-1. 给每一个 li 绑定 mousedown 事件
    lis[i].addEventListener(‘mousedown’, downHandler)
    // 2-2. 给每一个 li 绑定 mouseup 事件
    lis[i].addEventListener(‘mouseup’, upHandler)
    // 2-3. 给每一个 li 绑定 mousemove 事件
    lis[i].addEventListener(‘mousemove’, moveHandler)
    // 2-4. 给每一个 li 绑定 mouseout 事件
    lis[i].addEventListener(‘mouseout’, outHandler)
    }
  7. 取消文本选中效果
    document.addEventListener(‘selectstart’, function (e) {
    // 阻止默认行为
    e.preventDefault()
    })
  8. 判断移动事件能不能触发
    var moveState = false // 表示 mousemove 函数不能继续执行
    // 准备四个事件处理函数
    // 按下的事件处理函数
    function downHandler() {
    // 鼠标按下的时候, 可以跟着跑
    // 我们就把 moveState 变量设置为 true
    moveState = true
    console.log(‘鼠标按下’)
    }
    // 抬起的事件处理函数
    function upHandler() {
    // 鼠标抬起以后, 不可以跟着跑
    // 我们就把 moveState 变量设置为 false
    moveState = false
    console.log(‘鼠标抬起’)
    }
    // 移动的事件处理函数
    function moveHandler() {
    // if (moveState === false) {
    // return
    // }
    // 如果 if 只有一句话, 可以省略 {} 不写
    // if (moveState === false) return
    // 如果 if 后面的 return 可以执行, 说明 !moveState === true
    // 说明 moveState 一定是 false, 因为只有 false 取反以后才是 true
    if (!moveState) return
    console.log(‘盒子跟着跑’)
    }
    // 脱手的事件处理函数
    function outHandler() {
    // 鼠标脱手以后, 不能跟着跑
    // 我们就把 moveState 设置为 false
    moveState = false
    console.log(‘鼠标脱手’)
    }
    分析效果
    1. 可以拖着跑, 我们需要文字不能选中
      当你不小心选中文字的时候, 那么就不能拖着盒子跑了
      所以我们需要文字不能选中
    2. 鼠标按下可以拖着跑
      鼠标抬起不能拖着跑
      鼠标脱手不能继续拖着跑了
    3. 鼠标抬起的时候
      如果没有接触的元素, 那么就回归原位
      如果有接触的元素, 那么和谁接触面积大, 就和谁交换位置
    4. 鼠标脱手的时候
      直接回归原位
    5. 鼠标移动
      如果是按下状态, 那么就带着盒子一起走
      如果是抬起或者脱手状态, 那么就不带着盒子一起走
    6. li 的移动不能超出 ul 的范围
      代码思路
  9. 获取元素
    1-1. 获取 ul
    因为我需要他的尺寸
    li 不能超出 ul 的范围
    1-2. 获取 ul 下面所有的 li
    因为每一个都可以拖走
    需要绑定很多事件
  10. 绑定事件
    1-1. 拖着走就是 mousemove 事件
    1-2. 按下能拖着走 mousedown 事件
    1-3. 抬起不能拖着走 mouseup 事件
    1-4. 脱手回归原位, 也不能拖着走 mouseout 事件
    我们需要给每一个 li 都绑定这四个事件
    循环 lis 这个伪数组, 给里面的每一个元素绑定四个事件
    因为在事件里面写的代码比较多
    所以把四个事件处理函数单独书写在外面
  11. 取消文本选中效果
    因为文本一旦框选了, 那么拖着走的时候
    就是在拖着文本内容移动, 就不能拖着盒子走了
    需要给 document 绑定一个 selectstart 事件
    在这个事件里面阻止一下浏览器默认行为
  12. 确定什么时候可以触发移动事件(移动事件触发的目的就是拖着盒子跑)
    按下以后, 移动事件 可以 触发
    抬起以后, 移动事件 不能 触发
    脱手以后, 移动事件 不能 触发
    提前定义一个变量, 用于确定移动事件能不能触发
    初始默认是 false
    按下以后赋值为 true
    不管是抬起还是脱手都赋值为 false
    在移动事件里面判断, 如果是 true 就继续执行, 如果是 false 就 return
    变量需要定义在全局
    因为四个事件处理函数里面都需要用到这个变量
    有的是赋值有的是获取
    如果定义为某一个函数里面的私有变量
    那么其他函数里面就使用不了了
    所以定义为全局变量, 那么所有的函数里面都可以使用
  13. 确定什么时候可以触发脱手事件(脱手事件触发的目的是让元素回归原位)
    按下以后, 脱手事件 可以 触发
    抬起以后, 因为元素交换位置了, 那么不能再触发 脱手 事件了
    脱手以后, 因为元素回归原为了, 那么不能再触发 脱手 事件了
    提前定义一个变量, 用于确定脱手事件能不能触发
    初始默认值是 false
    按下以后赋值为 true
    不管是抬起还是脱手, 都赋值为 false
    在脱手事件里面判断, 如果是 true 就继续执行, 如果是 false 就 return
    和 moveState 一样, 需要定义在全局
  14. 获取元素
    1-1. 获取 ul
    var ul = document.querySelector(‘ul’)
    1-2. 获取 ul 下面的每一个 li
    var lis = ul.children // children 获取的是某一个节点下的所有 子元素节点
  15. 循环 lis 绑定事件
    for (var i = 0; i < lis.length; i++) {
    // 2-1. 给每一个 li 绑定 mousedown 事件
    lis[i].addEventListener(‘mousedown’, downHandler)
    // 2-2. 给每一个 li 绑定 mouseup 事件
    lis[i].addEventListener(‘mouseup’, upHandler)
    // 2-3. 给每一个 li 绑定 mousemove 事件
    lis[i].addEventListener(‘mousemove’, moveHandler)
    // 2-4. 给每一个 li 绑定 mouseout 事件
    lis[i].addEventListener(‘mouseout’, outHandler)
    }
    // 3. 取消文本选中效果
    document.addEventListener(‘selectstart’, function (e) {
    // 阻止默认行为
    e.preventDefault()
    })
  16. 判断移动事件能不能触发
    var moveState = false // 表示 mousemove 函数不能继续执行
  17. 判断脱手事件能不能触发
    var outState = false // 表示 mouseout 函数不能继续执行
    // 准备四个事件处理函数
    // 按下的事件处理函数
    function downHandler() {
    // 鼠标按下的时候, 可以跟着跑
    moveState = true
    // 鼠标按下的时候, 可以有脱手效果
    outState = true
    console.log(‘鼠标按下’)
    }
    // 抬起的事件处理函数
    function upHandler() {
    // 鼠标抬起以后, 不可以跟着跑
    moveState = false
    // 鼠标抬起以后, 不能再触发脱手效果了, 因为要触发交换效果
    outState = false
    console.log(‘鼠标抬起’)
    }
    // 移动的事件处理函数
    function moveHandler() {
    // 判断 moveState 为 false 的时候, 不让这个函数继续执行了
    if (!moveState) return
    console.log(‘盒子跟着跑’)
    }
    // 脱手的事件处理函数
    function outHandler() {
    // 鼠标脱手以后, 不能跟着跑
    moveState = false
    // outHandler 会在鼠标移出元素的时候触发, 也就是脱手时候触发
    // 脱手就应该触发回归原位的操作
    // outState 再 按下 的时候给赋值为 true
    // outState 再 抬起 的时候给赋值为 false
    if (outState === false) { return } // 表示抬起以后, 不再执行脱手操作
    // 当你执行完毕一次脱手以后, 我马上把 outState 改变为 false
    // 之后你就不能再次执行 脱手效果了
    // 如果你需要回归原位操作, 那么你需要再次按下一个元素
    // 如果你不安下元素, 那么就不要再继续回归原位了
    outState = false
    console.log(‘元素回归原位’)
    }
    分析效果
    1. 可以拖着跑, 我们需要文字不能选中
      当你不小心选中文字的时候, 那么就不能拖着盒子跑了
      所以我们需要文字不能选中
    2. 鼠标按下可以拖着跑
      鼠标抬起不能拖着跑
      鼠标脱手不能继续拖着跑了
    3. 鼠标抬起的时候
      如果移动的元素没有接触的元素, 那么就回归原位
      如果移动的元素有接触的元素, 那么和谁接触面积大, 就和谁交换位置
    4. 鼠标脱手的时候
      再移动的过程中, 光标离开了移动元素
      直接回归原位
    5. 鼠标移动
      如果是按下状态, 那么就带着盒子一起走
      如果是抬起或者脱手状态, 那么就不带着盒子一起走
    6. li 的移动不能超出 ul 的范围
      代码思路
  18. 获取元素
    1-1. 获取 ul
    因为我需要他的尺寸
    li 不能超出 ul 的范围
    1-2. 获取 ul 下面所有的 li
    因为每一个都可以拖走
    需要绑定很多事件
  19. 绑定事件
    1-1. 拖着走就是 mousemove 事件
    1-2. 按下能拖着走 mousedown 事件
    1-3. 抬起不能拖着走 mouseup 事件
    1-4. 脱手回归原位, 也不能拖着走 mouseout 事件
    我们需要给每一个 li 都绑定这四个事件
    循环 lis 这个伪数组, 给里面的每一个元素绑定四个事件
    因为在事件里面写的代码比较多
    所以把四个事件处理函数单独书写在外面
  20. 取消文本选中效果
    因为文本一旦框选了, 那么拖着走的时候
    就是在拖着文本内容移动, 就不能拖着盒子走了
    需要给 document 绑定一个 selectstart 事件
    在这个事件里面阻止一下浏览器默认行为
  21. 确定什么时候可以触发移动事件(移动事件触发的目的就是拖着盒子跑)
    按下以后, 移动事件 可以 触发
    抬起以后, 移动事件 不能 触发
    脱手以后, 移动事件 不能 触发
    提前定义一个变量, 用于确定移动事件能不能触发
    初始默认是 false
    按下以后赋值为 true
    不管是抬起还是脱手都赋值为 false
    在移动事件里面判断, 如果是 true 就继续执行, 如果是 false 就 return
    变量需要定义在全局
    因为四个事件处理函数里面都需要用到这个变量
    有的是赋值有的是获取
    如果定义为某一个函数里面的私有变量
    那么其他函数里面就使用不了了
    所以定义为全局变量, 那么所有的函数里面都可以使用
  22. 确定什么时候可以触发脱手事件(脱手事件触发的目的是让元素回归原位)
    按下以后, 脱手事件 可以 触发
    抬起以后, 因为元素交换位置了, 那么不能再触发 脱手 事件了
    脱手以后, 因为元素回归原为了, 那么不能再触发 脱手 事件了
    提前定义一个变量, 用于确定脱手事件能不能触发
    初始默认值是 false
    按下以后赋值为 true
    不管是抬起还是脱手, 都赋值为 false
    在脱手事件里面判断, 如果是 true 就继续执行, 如果是 false 就 return
    和 moveState 一样, 需要定义在全局
  23. 拖着元素跑
    6-1. 需要在鼠标按下的时候记录一个开始的鼠标 client 位置
    变量需要定义在全局, 因为需要在 mousedown 下面赋值, 需要在 mousemove 里面使用
    6-2. 在移动的时候随时获取光标的 client 坐标位置
    和 startX 和 startY 进行相减
    6-3. 在鼠标按下的时候, 记录一开始的左边的距离和上边的距离
    因为移动的时候, 要在最初是的基础上进行移动
    需要两边给变量定义在全局, 因为 mousedown 里面赋值, mousemove 里面使用
    6-4. 边界值判断
    左边: 当移动距离 <= 0 的时候, 强行让移动距离 = 0
    上边: 当移动距离 <= 0 的时候, 强行让移动距离 = 0
    右边: 当移动距离 >= ul 的宽度 - li 的宽度
    强行让移动距离 = ul 的宽度 - li 的宽度
    下边: 当移动距离 >= ul 的高度 - li 的高度
    强行让移动距离 = ul 的高度 - li 的高度
    注意: ul 不能使用 offsetWidth 和 offsetHeight
    因为 offset 一套是带有边框的
    li 移动到边框里面就到极限了, 所以我们使用 client 一套
    6-5. 给元素的 left 和 top 属性赋值
    一旦赋值了 left 和 top 属性, 元素就移动起来了
    不要忘记加 px 这个单位
    在移动的时候, 需要给元素加一个 z-index 属性, 让他在最上面
    当你每一个元素都移动一遍以后, 他们的 z-index 就全都一样了
    当全都一样的时候, 又成为了后面的压住前面的
    在移动结束, 也就是 抬起 或者 脱手的时候都表示移动结束
    在移动结束的时候再把它回归到 1 的位置
    移动哪一个哪一个最高, 移动完毕还是正常显示
  24. 获取元素
    1-1. 获取 ul
    var ul = document.querySelector(‘ul’)
    1-2. 获取 ul 下面的每一个 li
    var lis = ul.children // children 获取的是某一个节点下的所有 子元素节点
  25. 循环 lis 绑定事件
    for (var i = 0; i < lis.length; i++) {
    2-1. 给每一个 li 绑定 mousedown 事件
    lis[i].addEventListener(‘mousedown’, downHandler)
    2-2. 给每一个 li 绑定 mouseup 事件
    lis[i].addEventListener(‘mouseup’, upHandler)
    2-3. 给每一个 li 绑定 mousemove 事件
    lis[i].addEventListener(‘mousemove’, moveHandler)
    2-4. 给每一个 li 绑定 mouseout 事件
    lis[i].addEventListener(‘mouseout’, outHandler)
    }
  26. 取消文本选中效果
    document.addEventListener(‘selectstart’, function (e) {
    // 阻止默认行为
    e.preventDefault()
    })
  27. 判断移动事件能不能触发
    var moveState = false // 表示 mousemove 函数不能继续执行
  28. 判断脱手事件能不能触发
    var outState = false // 表示 mouseout 函数不能继续执行
    6-1. 准备两个变量记录按下时的鼠标坐标
    var startX = 0, startY = 0
    6-3. 准备两个变量, 记录初始的 left 和 top 值
    var startLeft = 0, startTop = 0
    // 准备四个事件处理函数
    // 按下的事件处理函数
    function downHandler(e) {
    // 鼠标按下的时候, 可以跟着跑
    moveState = true
    // 鼠标按下的时候, 可以有脱手效果
    outState = true
    // 这里开始下按下的业务逻辑
    6-1. 在按下的时候给 startX 和 startY 赋值
    startX = e.clientX
    startY = e.clientY
    6-3. 记录移动的这个元素初始的 left 和 top 值
    // this 就是我按下的这个元素
    startLeft = this.offsetLeft // offsetLeft 就是获取元素左侧偏移量
    startTop = this.offsetTop // offsetTop 就是获取元素上方的偏移量
    }
    // 抬起的事件处理函数
    function upHandler() {
    // 鼠标抬起以后, 不可以跟着跑
    moveState = false
    // 鼠标抬起以后, 不能再触发脱手效果了, 因为要触发交换效果
    outState = false
    // 这里开始写抬起的业务逻辑
    6-5. 还原 z-index
    this.style.zIndex = 1
    console.log(‘判断元素和谁交换’)
    }
    // 移动的事件处理函数
    function moveHandler(e) {
    // 判断 moveState 为 false 的时候, 不让这个函数继续执行了
    // if (!moveState) return
    if (moveState === false) { return }
    // 这里开始也移动的业务逻辑
    6-2. 随时获取 client 一套信息, 和 startX 和 startY 相减
    // 因为要在原始偏移量的基础上加上光标移动距离
    // 所以我们最后加一个 startLeft 和 startTop
    var moveX = e.clientX - startX + startLeft
    var moveY = e.clientY - startY + startTop
    6-4. 边界值判断
    // 左边
    if (moveX <= 0) moveX = 0
    // 上边
    if (moveY <= 0) moveY = 0
    // 右边
    if (moveX >= ul.clientWidth - this.offsetWidth) moveX = ul.clientWidth - this.offsetWidth
    // 下面
    // offsetHeight 是元素的 内容 + padding + border 的尺寸
    if (moveY >= ul.clientHeight - this.offsetHeight) moveY = ul.clientHeight - this.offsetHeight
    6-5. 给元素赋值 left 和 top
    // 给我拖动这的这个元素赋值
    // this 就是我拖动的这个元素
    this.style.left = moveX + ‘px’
    this.style.top = moveY + ‘px’
    // 在加一个 zIndex 属性, 让他比别的元素大一些
    this.style.zIndex = 999
    }
    // 脱手的事件处理函数
    function outHandler() {
    // 鼠标脱手以后, 不能跟着跑
    moveState = false
    // 鼠标脱手以后, 需要先触发一次, 不能再继续触发脱手效果了
    // if (!outState) return
    if (outState === false) { return }
    outState = false
    // 这里开始也脱手的业务逻辑
    // 6-5. 还原 z-index
    this.style.zIndex = 1
    console.log(‘元素回归原位’)
    }
    handler 处理程序
    moveState 移动状态
    outState 移出状态
    offsetWidth 和 offsetHeight
    => 获取元素的 内容 + padding + border 的尺寸
    => width : 宽
    => height : 高
    offsetLeft 和 offsetTop
    => 获取元素的 上边和左边 的偏移量
    => left : 左
    => top : 上
    clientWidth 和 clientHeight
    => 获取元素的 内容 + padding 的尺寸
    clientX 和 clientY
    => 实在鼠标的事件对象里面找到的
    => 光标相对于浏览器可视窗口左上角的距离
    分析效果
    1. 可以拖着跑, 我们需要文字不能选中
      当你不小心选中文字的时候, 那么就不能拖着盒子跑了
      所以我们需要文字不能选中
    2. 鼠标按下可以拖着跑
      鼠标抬起不能拖着跑
      鼠标脱手不能继续拖着跑了
    3. 鼠标抬起的时候
      如果移动的元素没有接触的元素, 那么就回归原位
      如果移动的元素有接触的元素, 那么和谁接触面积大, 就和谁交换位置
    4. 鼠标脱手的时候
      再移动的过程中, 光标离开了移动元素
      直接回归原位
    5. 鼠标移动
      如果是按下状态, 那么就带着盒子一起走
      如果是抬起或者脱手状态, 那么就不带着盒子一起走
    6. li 的移动不能超出 ul 的范围
      代码思路
  29. 获取元素
    1-1. 获取 ul
    因为我需要他的尺寸
    li 不能超出 ul 的范围
    1-2. 获取 ul 下面所有的 li
    因为每一个都可以拖走
    需要绑定很多事件
  30. 绑定事件
    1-1. 拖着走就是 mousemove 事件
    1-2. 按下能拖着走 mousedown 事件
    1-3. 抬起不能拖着走 mouseup 事件
    1-4. 脱手回归原位, 也不能拖着走 mouseout 事件
    我们需要给每一个 li 都绑定这四个事件
    循环 lis 这个伪数组, 给里面的每一个元素绑定四个事件
    因为在事件里面写的代码比较多
    所以把四个事件处理函数单独书写在外面
  31. 取消文本选中效果
    因为文本一旦框选了, 那么拖着走的时候
    就是在拖着文本内容移动, 就不能拖着盒子走了
    需要给 document 绑定一个 selectstart 事件
    在这个事件里面阻止一下浏览器默认行为
  32. 确定什么时候可以触发移动事件(移动事件触发的目的就是拖着盒子跑)
    按下以后, 移动事件 可以 触发
    抬起以后, 移动事件 不能 触发
    脱手以后, 移动事件 不能 触发
    提前定义一个变量, 用于确定移动事件能不能触发
    初始默认是 false
    按下以后赋值为 true
    不管是抬起还是脱手都赋值为 false
    在移动事件里面判断, 如果是 true 就继续执行, 如果是 false 就 return
    变量需要定义在全局
    因为四个事件处理函数里面都需要用到这个变量
    有的是赋值有的是获取
    如果定义为某一个函数里面的私有变量
    那么其他函数里面就使用不了了
    所以定义为全局变量, 那么所有的函数里面都可以使用
  33. 确定什么时候可以触发脱手事件(脱手事件触发的目的是让元素回归原位)
    按下以后, 脱手事件 可以 触发
    抬起以后, 因为元素交换位置了, 那么不能再触发 脱手 事件了
    脱手以后, 因为元素回归原为了, 那么不能再触发 脱手 事件了
    提前定义一个变量, 用于确定脱手事件能不能触发
    初始默认值是 false
    按下以后赋值为 true
    不管是抬起还是脱手, 都赋值为 false
    在脱手事件里面判断, 如果是 true 就继续执行, 如果是 false 就 return
    和 moveState 一样, 需要定义在全局
  34. 拖着元素跑
    6-1. 需要在鼠标按下的时候记录一个开始的鼠标 client 位置
    变量需要定义在全局, 因为需要在 mousedown 下面赋值, 需要在 mousemove 里面使用
    6-2. 在移动的时候随时获取光标的 client 坐标位置
    和 startX 和 startY 进行相减
    6-3. 在鼠标按下的时候, 记录一开始的左边的距离和上边的距离
    因为移动的时候, 要在最初是的基础上进行移动
    需要两边给变量定义在全局, 因为 mousedown 里面赋值, mousemove 里面使用
    6-4. 边界值判断
    左边: 当移动距离 <= 0 的时候, 强行让移动距离 = 0
    上边: 当移动距离 <= 0 的时候, 强行让移动距离 = 0
    右边: 当移动距离 >= ul 的宽度 - li 的宽度
    强行让移动距离 = ul 的宽度 - li 的宽度
    下边: 当移动距离 >= ul 的高度 - li 的高度
    强行让移动距离 = ul 的高度 - li 的高度
    注意: ul 不能使用 offsetWidth 和 offsetHeight
    因为 offset 一套是带有边框的
    li 移动到边框里面就到极限了, 所以我们使用 client 一套
    6-5. 给元素的 left 和 top 属性赋值
    一旦赋值了 left 和 top 属性, 元素就移动起来了
    不要忘记加 px 这个单位
    在移动的时候, 需要给元素加一个 z-index 属性, 让他在最上面
    当你每一个元素都移动一遍以后, 他们的 z-index 就全都一样了
    当全都一样的时候, 又成为了后面的压住前面的
    在移动结束, 也就是 抬起 或者 脱手的时候都表示移动结束
    在移动结束的时候再把它回归到 1 的位置
    移动哪一个哪一个最高, 移动完毕还是正常显示
  35. 脱手回归原位
    7-1. 当触发脱手的时候, 直接给元素的 left 和 top 赋值为初始值
    我们之前第 6 步的时候, 我们在鼠标按下的时候, 就已经记录了元素 left 和 top
    当我们脱手的时候, 只要拿到一开始记录的内容
    直接给 left 和 top 赋值就好了
    7-2. 回去的太快了
    我想让他慢一点, 加一个 transition 属性就 ok 了
    7-3. 脱手回归以后
    因为拖手的时候加上了一个 transition 属性
    那么这个属性就会一直存在在元素身上了
    当你下次拖着跑的时候, 每移动 1px 都要经历 transition
    我们要在鼠标按下去的时候, 再把 transition 赋值为 none
    拖着跑的时候没有 transition, 只有脱手或者交换的时候才有 transition
  36. 抬起的时候交换位置
  37. 获取元素
    1-1. 获取 ul
    var ul = document.querySelector(‘ul’)
    // 1-2. 获取 ul 下面的每一个 li
    var lis = ul.children // children 获取的是某一个节点下的所有 子元素节点
  38. 循环 lis 绑定事件
    for (var i = 0; i < lis.length; i++) {
    // 2-1. 给每一个 li 绑定 mousedown 事件
    lis[i].addEventListener(‘mousedown’, downHandler)
    // 2-2. 给每一个 li 绑定 mouseup 事件
    lis[i].addEventListener(‘mouseup’, upHandler)
    // 2-3. 给每一个 li 绑定 mousemove 事件
    lis[i].addEventListener(‘mousemove’, moveHandler)
    // 2-4. 给每一个 li 绑定 mouseout 事件
    lis[i].addEventListener(‘mouseout’, outHandler)
    }
  39. 取消文本选中效果
    document.addEventListener(‘selectstart’, function (e) {
    // 阻止默认行为
    e.preventDefault()
    })
  40. 判断移动事件能不能触发
    var moveState = false // 表示 mousemove 函数不能继续执行
  41. 判断脱手事件能不能触发
    var outState = false // 表示 mouseout 函数不能继续执行
    6-1. 准备两个变量记录按下时的鼠标坐标
    var startX = 0, startY = 0
    6-3. 准备两个变量, 记录初始的 left 和 top 值
    var startLeft = 0, startTop = 0
    // 准备四个事件处理函数
    // 按下的事件处理函数
    function downHandler(e) {
    // 鼠标按下的时候, 可以跟着跑
    moveState = true
    // 鼠标按下的时候, 可以有脱手效果
    outState = true
    // 这里开始下按下的业务逻辑
    6-1. 在按下的时候给 startX 和 startY 赋值
    startX = e.clientX
    startY = e.clientY
    6-3. 记录移动的这个元素初始的 left 和 top 值
    // this 就是我按下的这个元素
    startLeft = this.offsetLeft // offsetLeft 就是获取元素左侧偏移量
    startTop = this.offsetTop // offsetTop 就是获取元素上方的偏移量
    7-3. 按下的时候, 把 transition 赋值为 none
    this.style.transition = ‘none’
    }
    // 抬起的事件处理函数
    function upHandler() {
    // 鼠标抬起以后, 不可以跟着跑
    moveState = false
    // 鼠标抬起以后, 不能再触发脱手效果了, 因为要触发交换效果
    outState = false
    // 这里开始写抬起的业务逻辑
    6-5. 还原 z-index
    this.style.zIndex = 1
    console.log(‘判断元素和谁交换’)
    }
    // 移动的事件处理函数
    function moveHandler(e) {
    // 判断 moveState 为 false 的时候, 不让这个函数继续执行了
    // if (!moveState) return
    if (moveState === false) { return }
    6-2. 随时获取 client 一套信息, 和 startX 和 startY 相减
    var moveX = e.clientX - startX + startLeft
    var moveY = e.clientY - startY + startTop
    6-4. 边界值判断
    // 左边
    if (moveX <= 0) moveX = 0
    // 上边
    if (moveY <= 0) moveY = 0
    // 右边
    if (moveX >= ul.clientWidth - this.offsetWidth) moveX = ul.clientWidth - this.offsetWidth
    // 下面
    if (moveY >= ul.clientHeight - this.offsetHeight) moveY = ul.clientHeight - this.offsetHeight
    6-5. 给元素赋值 left 和 top
    this.style.left = moveX + ‘px’
    this.style.top = moveY + ‘px’
    this.style.zIndex = 999
    }
    // 脱手的事件处理函数
    function outHandler() {
    // 鼠标脱手以后, 不能跟着跑
    moveState = false
    // 鼠标脱手以后, 需要先触发一次, 不能再继续触发脱手效果了
    // if (!outState) return
    if (outState === false) { return }
    outState = false
    // 这里开始也脱手的业务逻辑
    // 6-5. 还原 z-index
    this.style.zIndex = 1
    7-1. 直接拿到按下的时候记录的 left 和 top 继续赋值
    this.style.left = startLeft + ‘px’
    this.style.top = startTop + ‘px’
    7-2. 加一个 transition 属性
    this.style.transition = ‘all .4s linear’
    }
    handler 处理程序
    moveState 移动状态
    outState 移出状态
    offsetWidth 和 offsetHeight
    => 获取元素的 内容 + padding + border 的尺寸
    => width : 宽
    => height : 高
    offsetLeft 和 offsetTop
    => 获取元素的 上边和左边 的偏移量
    => left : 左
    => top : 上
    clientWidth 和 clientHeight
    => 获取元素的 内容 + padding 的尺寸
    clientX 和 clientY
    => 实在鼠标的事件对象里面找到的
    => 光标相对于浏览器可视窗口左上角的距离
    transition 属性
    => 运动的属性 all 表示所有属性都参与过渡
    => 运动的时间 .4s 表示 0.4s 完成运动
    => 运动的延迟 不写默认是 0 没有延迟
    => 运动的曲线 linear 表示匀速运动
    分析效果
    1. 可以拖着跑, 我们需要文字不能选中
      当你不小心选中文字的时候, 那么就不能拖着盒子跑了
      所以我们需要文字不能选中
    2. 鼠标按下可以拖着跑
      鼠标抬起不能拖着跑
      鼠标脱手不能继续拖着跑了
    3. 鼠标抬起的时候
      如果移动的元素没有接触的元素, 那么就回归原位
      如果移动的元素有接触的元素, 那么和谁接触面积大, 就和谁交换位置
    4. 鼠标脱手的时候
      再移动的过程中, 光标离开了移动元素
      直接回归原位
    5. 鼠标移动
      如果是按下状态, 那么就带着盒子一起走
      如果是抬起或者脱手状态, 那么就不带着盒子一起走
    6. li 的移动不能超出 ul 的范围
      代码思路
  42. 获取元素
    1-1. 获取 ul
    因为我需要他的尺寸
    li 不能超出 ul 的范围
    1-2. 获取 ul 下面所有的 li
    因为每一个都可以拖走
    需要绑定很多事件
  43. 绑定事件
    1-1. 拖着走就是 mousemove 事件
    1-2. 按下能拖着走 mousedown 事件
    1-3. 抬起不能拖着走 mouseup 事件
    1-4. 脱手回归原位, 也不能拖着走 mouseout 事件
    我们需要给每一个 li 都绑定这四个事件
    循环 lis 这个伪数组, 给里面的每一个元素绑定四个事件
    因为在事件里面写的代码比较多
    所以把四个事件处理函数单独书写在外面
  44. 取消文本选中效果
    因为文本一旦框选了, 那么拖着走的时候
    就是在拖着文本内容移动, 就不能拖着盒子走了
    需要给 document 绑定一个 selectstart 事件
    在这个事件里面阻止一下浏览器默认行为
  45. 确定什么时候可以触发移动事件(移动事件触发的目的就是拖着盒子跑)
    按下以后, 移动事件 可以 触发
    抬起以后, 移动事件 不能 触发
    脱手以后, 移动事件 不能 触发
    提前定义一个变量, 用于确定移动事件能不能触发
    初始默认是 false
    按下以后赋值为 true
    不管是抬起还是脱手都赋值为 false
    在移动事件里面判断, 如果是 true 就继续执行, 如果是 false 就 return
    变量需要定义在全局
    因为四个事件处理函数里面都需要用到这个变量
    有的是赋值有的是获取
    如果定义为某一个函数里面的私有变量
    那么其他函数里面就使用不了了
    所以定义为全局变量, 那么所有的函数里面都可以使用
  46. 确定什么时候可以触发脱手事件(脱手事件触发的目的是让元素回归原位)
    按下以后, 脱手事件 可以 触发
    抬起以后, 因为元素交换位置了, 那么不能再触发 脱手 事件了
    脱手以后, 因为元素回归原为了, 那么不能再触发 脱手 事件了
    提前定义一个变量, 用于确定脱手事件能不能触发
    初始默认值是 false
    按下以后赋值为 true
    不管是抬起还是脱手, 都赋值为 false
    在脱手事件里面判断, 如果是 true 就继续执行, 如果是 false 就 return
    和 moveState 一样, 需要定义在全局
  47. 拖着元素跑
    6-1. 需要在鼠标按下的时候记录一个开始的鼠标 client 位置
    变量需要定义在全局, 因为需要在 mousedown 下面赋值, 需要在 mousemove 里面使用
    6-2. 在移动的时候随时获取光标的 client 坐标位置
    和 startX 和 startY 进行相减
    6-3. 在鼠标按下的时候, 记录一开始的左边的距离和上边的距离
    因为移动的时候, 要在最初是的基础上进行移动
    需要两边给变量定义在全局, 因为 mousedown 里面赋值, mousemove 里面使用
    6-4. 边界值判断
    左边: 当移动距离 <= 0 的时候, 强行让移动距离 = 0
    上边: 当移动距离 <= 0 的时候, 强行让移动距离 = 0
    右边: 当移动距离 >= ul 的宽度 - li 的宽度
    强行让移动距离 = ul 的宽度 - li 的宽度
    下边: 当移动距离 >= ul 的高度 - li 的高度
    强行让移动距离 = ul 的高度 - li 的高度
    注意: ul 不能使用 offsetWidth 和 offsetHeight
    因为 offset 一套是带有边框的
    li 移动到边框里面就到极限了, 所以我们使用 client 一套
    6-5. 给元素的 left 和 top 属性赋值
    一旦赋值了 left 和 top 属性, 元素就移动起来了
    不要忘记加 px 这个单位
    在移动的时候, 需要给元素加一个 z-index 属性, 让他在最上面
    当你每一个元素都移动一遍以后, 他们的 z-index 就全都一样了
    当全都一样的时候, 又成为了后面的压住前面的
    在移动结束, 也就是 抬起 或者 脱手的时候都表示移动结束
    在移动结束的时候再把它回归到 1 的位置
    移动哪一个哪一个最高, 移动完毕还是正常显示
  48. 脱手回归原位
    7-1. 当触发脱手的时候, 直接给元素的 left 和 top 赋值为初始值
    我们之前第 6 步的时候, 我们在鼠标按下的时候, 就已经记录了元素 left 和 top
    当我们脱手的时候, 只要拿到一开始记录的内容
    直接给 left 和 top 赋值就好了
    7-2. 回去的太快了
    我想让他慢一点, 加一个 transition 属性就 ok 了
    7-3. 脱手回归以后
    因为拖手的时候加上了一个 transition 属性
    那么这个属性就会一直存在在元素身上了
    当你下次拖着跑的时候, 每移动 1px 都要经历 transition
    我们要在鼠标按下去的时候, 再把 transition 赋值为 none
    拖着跑的时候没有 transition, 只有脱手或者交换的时候才有 transition
  49. 抬起的时候交换位置
    8-1. 获取到和哪些元素有接触
    准备一个空数组, 循环遍历每一个 li
    看谁和移动的这个 li 有接触面积
    谁有就把谁放到这个数组里面
    循环结束, 数组里面就都是有接触面积的元素了
    8-2. 找到有接触的元素
    判断如果 areaArr 是一个空数组
    表示没有接触的元素, 那么应该让移动的这个 li 回归原位
    如果 areaArr 里面有内容, 那么我在进行下一步判断
    8-3. areaArr 数组里面有成员
    我就要和 areaArr 数组里面的每一个成员进行比较
    找到和谁的接触面积大, 和谁的接触面积大, 就和谁交换
    循环 areaArr 这个数组, 分别判断每一个的接触面积
    找到接触面积最大的那个元素
    8-4. 让 this 的 left 和 top 值和 areaEle 元素的 left top 值交换
    this 的 left 和 top 就是鼠标按下的时候记录的 startLeft 和 startTop
    我们先把 areaEle 元素的 left 值赋值给 this 的 left 值
    我们先把 areaEle 元素的 top 值赋值给 this 的 top 值
    把 startLeft 赋值给 areaEle 元素的 left 值
    把 startTop 赋值给 areaEle 元素的 top 值
  50. 获取元素
    1-1. 获取 ul
    var ul = document.querySelector(‘ul’)
    1-2. 获取 ul 下面的每一个 li
    var lis = ul.children // children 获取的是某一个节点下的所有 子元素节点
  51. 循环 lis 绑定事件
    for (var i = 0; i < lis.length; i++) {
    2-1. 给每一个 li 绑定 mousedown 事件
    lis[i].addEventListener(‘mousedown’, downHandler)
    2-2. 给每一个 li 绑定 mouseup 事件
    lis[i].addEventListener(‘mouseup’, upHandler)
    2-3. 给每一个 li 绑定 mousemove 事件
    lis[i].addEventListener(‘mousemove’, moveHandler)
    2-4. 给每一个 li 绑定 mouseout 事件
    lis[i].addEventListener(‘mouseout’, outHandler)
    }
  52. 取消文本选中效果
    document.addEventListener(‘selectstart’, function (e) {
    // 阻止默认行为
    e.preventDefault()
    })
  53. 判断移动事件能不能触发
    var moveState = false // 表示 mousemove 函数不能继续执行
  54. 判断脱手事件能不能触发
    var outState = false // 表示 mouseout 函数不能继续执行
    6-1. 准备两个变量记录按下时的鼠标坐标
    var startX = 0, startY = 0
    6-3. 准备两个变量, 记录初始的 left 和 top 值
    var startLeft = 0, startTop = 0
    // 准备四个事件处理函数
    // 按下的事件处理函数
    function downHandler(e) {
    // 鼠标按下的时候, 可以跟着跑
    moveState = true
    // 鼠标按下的时候, 可以有脱手效果
    outState = true
    // 这里开始下按下的业务逻辑
    // 6-1. 在按下的时候给 startX 和 startY 赋值
    startX = e.clientX
    startY = e.clientY
    6-3. 记录移动的这个元素初始的 left 和 top 值
    // this 就是我按下的这个元素
    startLeft = this.offsetLeft // offsetLeft 就是获取元素左侧偏移量
    startTop = this.offsetTop // offsetTop 就是获取元素上方的偏移量
    7-3. 按下的时候, 把 transition 赋值为 none
    this.style.transition = ‘none’
    }
    // 抬起的事件处理函数
    function upHandler() {
    // 鼠标抬起以后, 不可以跟着跑
    moveState = false
    // 鼠标抬起以后, 不能再触发脱手效果了, 因为要触发交换效果
    outState = false
    // 这里开始写抬起的业务逻辑
    6-5. 还原 z-index
    this.style.zIndex = 1
    8-1. 获取到有接触面积的元素
    // 先准备一个变量
    var areaArr = []
    // 循环遍历 li, 看谁和 this 有接触
    // this 就是当前移动的这个元素
    for (var i = 0; i < lis.length; i++) {
    // lis 里面包含了九个元素, 有其他八个, 也有当前移动的这一个
    // 自己和自己不用比, 因为没有元素比我自己和自己的接触面积大
    if (lis[i] === this) continue
    // 比较一下看看有没有面积接触的, 有的话就放在数组里面
    // 没有面积接触就继续下一个
    // 判断 (this.offsetLeft 和 lis[i].offsetLeft 相减) 绝对值 < this.offsetWidth
    // 判断 (this.offsetTop 和 lis[i].offsetTop 相减) 绝对值 < this.offsetHeight
    if (
    Math.abs(this.offsetLeft - lis[i].offsetLeft) < this.offsetWidth &&
    Math.abs(this.offsetTop - lis[i].offsetTop) < this.offsetHeight
    ) {
    // 表示两个元素有接触
    // 把这个 lis[i] 元素加到 areaArr 这个数组里面
    areaArr.push(lis[i])
    }
    }
    // 循环结束以后, areaArr 里面就是所有有接触的元素
    8-2. 判断是不是一个空数组, 判断数组的 length 是不是 0
    // 如果是空数组, 表示没有接触的, 直接回归原位
    if (areaArr.length === 0) {
    // 回归原位
    // 直接拿到原始的 left 和 top 赋值给 this 这个元素就可以了
    this.style.left = startLeft + ‘px’
    this.style.top = startTop + ‘px’
    return
    }
    8-3. 找到和谁的接触面积大
    // 准备两个变量, 一个记录接触面积, 一个记录接触面积大的元素
    var areaMax = 0 // 记录接触面积
    var areaEle = null // 记录接触面积大的元素
    // 循环遍历 areaArr
    for (var j = 0; j < areaArr.length; j++) {
    // areaArr[i] 表示的是每一个有接触面积的元素
    // 自身元素的宽度 - (自身元素的左侧偏移量 - areaArr[j]的左侧偏移量 取绝对值)
    // 接触面积的宽度
    var x = this.offsetWidth - Math.abs(this.offsetLeft - areaArr[j].offsetLeft)
    // 接触面积的高度
    var y = this.offsetHeight - Math.abs(this.offsetTop - areaArr[j].offsetTop)
    // 接触面积就是 x * y
    // 对接触面积进行比较
    if (x * y > areaMax) {
    areaMax = x * y
    areaEle = areaArr[j]
    }
    }
    // 循环结束的时候, areaEle 就是接触面积最大的那个元素
    // console.log('接触面积最大的元素是 : ', areaEle)
    8-4. 和接触面积最大的元素交换位置
    this.style.left = areaEle.offsetLeft + ‘px’
    this.style.top = areaEle.offsetTop + ‘px’
    this.style.transition = ‘all .4s linear’
    areaEle.style.left = startLeft + ‘px’
    areaEle.style.top = startTop + ‘px’
    areaEle.style.transition = ‘all .4s linear’
    }
    // 移动的事件处理函数
    function moveHandler(e) {
    // 判断 moveState 为 false 的时候, 不让这个函数继续执行了
    // if (!moveState) return
    if (moveState === false) { return }
    6-2. 随时获取 client 一套信息, 和 startX 和 startY 相减
    var moveX = e.clientX - startX + startLeft
    var moveY = e.clientY - startY + startTop
    6-4. 边界值判断
    // 左边
    if (moveX <= 0) moveX = 0
    // 上边
    if (moveY <= 0) moveY = 0
    // 右边
    if (moveX >= ul.clientWidth - this.offsetWidth) moveX = ul.clientWidth - this.offsetWidth
    // 下面
    if (moveY >= ul.clientHeight - this.offsetHeight) moveY = ul.clientHeight - this.offsetHeight
    6-5. 给元素赋值 left 和 top
    this.style.left = moveX + ‘px’
    this.style.top = moveY + ‘px’
    this.style.zIndex = 999
    }
    // 脱手的事件处理函数
    function outHandler() {
    // 鼠标脱手以后, 不能跟着跑
    moveState = false
    // 鼠标脱手以后, 需要先触发一次, 不能再继续触发脱手效果了
    // if (!outState) return
    if (outState === false) { return }
    outState = false
    // 这里开始也脱手的业务逻辑
    6-5. 还原 z-index
    this.style.zIndex = 1
    7-1. 直接拿到按下的时候记录的 left 和 top 继续赋值
    this.style.left = startLeft + ‘px’
    this.style.top = startTop + ‘px’
    7-2. 加一个 transition 属性
    this.style.transition = ‘all .4s linear’
    }
    handler 处理程序
    moveState 移动状态
    outState 移出状态
    area 面积
    offsetWidth 和 offsetHeight
    => 获取元素的 内容 + padding + border 的尺寸
    => width : 宽
    => height : 高
    offsetLeft 和 offsetTop
    => 获取元素的 上边和左边 的偏移量
    => left : 左
    => top : 上
    clientWidth 和 clientHeight
    => 获取元素的 内容 + padding 的尺寸
    clientX 和 clientY
    => 实在鼠标的事件对象里面找到的
    => 光标相对于浏览器可视窗口左上角的距离
    transition 属性
    => 运动的属性 all 表示所有属性都参与过渡
    => 运动的时间 .4s 表示 0.4s 完成运动
    => 运动的延迟 不写默认是 0 没有延迟
    => 运动的曲线 linear 表示匀速运动
    continue 关键字
    => 在循环里面使用, 结束循环中的本次, 直接 i++ 进行循环的下一次
    数组 数据类型
    => length 表示数组里面有多少个元素
    => 索引是从 0 开始, 表示第多少个元素
    => 当 length === 0 的时候, 表示数组里面没有元素
    push 数组常用方法
    => 语法: 数组.push(要追加到数组里面的内容)
    => 作用: 向数组里面追加内容
    面积比较
    areaArr === [ 2号li, 4号li, 5号li ]
    areaMax = 21000
    areaEle = 4号li
    循环遍历
    当 j === 0 的时候
    areaArr[0] === 2号li
    x 就是 this 和 2号li 接触的宽度 50
    y 就是 this 和 2号li 接触的高度 40
    判断 x * y > areaMax 结果为 true
    areaMax = 50 * 40 赋值为 2000
    areaEle = 2号li
    当 j === 1 的时候
    areaArr[1] === 4号li
    x 就是 this 和 4号li 接触的宽度 140
    y 就是 this 和 4号li 接触的高度 150
    判断 x * y > areaMax 结果为 true
    areaMax = 140 * 150 赋值为 21000
    areaEle = 4号li
    当 j === 2 的时候
    areaArr[2] === 5号li
    x 就是 this 和 5号li 接触的宽度 50
    y 就是 this 和 5号li 接触的高度 150
    判断 x * y > areaMax 比较的是 7500 > 21000 结果为 false
    当 j === 3
    循环结束
    循环结束以后, areaEle 就是和 this 接触面积最大的那个元素
    分析效果
    1. 可以拖着跑, 我们需要文字不能选中
      当你不小心选中文字的时候, 那么就不能拖着盒子跑了
      所以我们需要文字不能选中
    2. 鼠标按下可以拖着跑
      鼠标抬起不能拖着跑
      鼠标脱手不能继续拖着跑了
    3. 鼠标抬起的时候
      如果移动的元素没有接触的元素, 那么就回归原位
      如果移动的元素有接触的元素, 那么和谁接触面积大, 就和谁交换位置
    4. 鼠标脱手的时候
      再移动的过程中, 光标离开了移动元素
      直接回归原位
    5. 鼠标移动
      如果是按下状态, 那么就带着盒子一起走
      如果是抬起或者脱手状态, 那么就不带着盒子一起走
    6. li 的移动不能超出 ul 的范围
      代码思路
  55. 获取元素
    1-1. 获取 ul
    因为我需要他的尺寸
    li 不能超出 ul 的范围
    1-2. 获取 ul 下面所有的 li
    因为每一个都可以拖走
    需要绑定很多事件
  56. 绑定事件
    1-1. 拖着走就是 mousemove 事件
    1-2. 按下能拖着走 mousedown 事件
    1-3. 抬起不能拖着走 mouseup 事件
    1-4. 脱手回归原位, 也不能拖着走 mouseout 事件
    我们需要给每一个 li 都绑定这四个事件
    循环 lis 这个伪数组, 给里面的每一个元素绑定四个事件
    因为在事件里面写的代码比较多
    所以把四个事件处理函数单独书写在外面
  57. 取消文本选中效果
    因为文本一旦框选了, 那么拖着走的时候
    就是在拖着文本内容移动, 就不能拖着盒子走了
    需要给 document 绑定一个 selectstart 事件
    在这个事件里面阻止一下浏览器默认行为
  58. 确定什么时候可以触发移动事件(移动事件触发的目的就是拖着盒子跑)
    按下以后, 移动事件 可以 触发
    抬起以后, 移动事件 不能 触发
    脱手以后, 移动事件 不能 触发
    提前定义一个变量, 用于确定移动事件能不能触发
    初始默认是 false
    按下以后赋值为 true
    不管是抬起还是脱手都赋值为 false
    在移动事件里面判断, 如果是 true 就继续执行, 如果是 false 就 return
    变量需要定义在全局
    因为四个事件处理函数里面都需要用到这个变量
    有的是赋值有的是获取
    如果定义为某一个函数里面的私有变量
    那么其他函数里面就使用不了了
    所以定义为全局变量, 那么所有的函数里面都可以使用
  59. 确定什么时候可以触发脱手事件(脱手事件触发的目的是让元素回归原位)
    按下以后, 脱手事件 可以 触发
    抬起以后, 因为元素交换位置了, 那么不能再触发 脱手 事件了
    脱手以后, 因为元素回归原位了, 那么不要多次触发 脱手 事件了
    提前定义一个变量, 用于确定脱手事件能不能触发
    初始默认值是 false
    按下以后赋值为 true
    不管是抬起还是脱手, 都赋值为 false
    在脱手事件里面判断, 如果是 true 就继续执行, 如果是 false 就 return
    和 moveState 一样, 需要定义在全局
  60. 拖着元素跑
    6-1. 需要在鼠标按下的时候记录一个开始的鼠标 client 位置
    变量需要定义在全局, 因为需要在 mousedown 下面赋值, 需要在 mousemove 里面使用
    6-2. 在移动的时候随时获取光标的 client 坐标位置
    和 startX 和 startY 进行相减
    6-3. 在鼠标按下的时候, 记录一开始的左边的距离和上边的距离
    因为移动的时候, 要在最初是的基础上进行移动
    需要两边给变量定义在全局, 因为 mousedown 里面赋值, mousemove 里面使用
    6-4. 边界值判断
    左边: 当移动距离 <= 0 的时候, 强行让移动距离 = 0
    上边: 当移动距离 <= 0 的时候, 强行让移动距离 = 0
    右边: 当移动距离 >= ul 的宽度 - li 的宽度
    强行让移动距离 = ul 的宽度 - li 的宽度
    下边: 当移动距离 >= ul 的高度 - li 的高度
    强行让移动距离 = ul 的高度 - li 的高度
    注意: ul 不能使用 offsetWidth 和 offsetHeight
    因为 offset 一套是带有边框的
    li 移动到边框里面就到极限了, 所以我们使用 client 一套
    6-5. 给元素的 left 和 top 属性赋值
    一旦赋值了 left 和 top 属性, 元素就移动起来了
    不要忘记加 px 这个单位
    在移动的时候, 需要给元素加一个 z-index 属性, 让他在最上面
    当你每一个元素都移动一遍以后, 他们的 z-index 就全都一样了
    当全都一样的时候, 又成为了后面的压住前面的
    在移动结束, 也就是 抬起 或者 脱手的时候都表示移动结束
    在移动结束的时候再把它回归到 1 的位置
    移动哪一个哪一个最高, 移动完毕还是正常显示
  61. 脱手回归原位
    7-1. 当触发脱手的时候, 直接给元素的 left 和 top 赋值为初始值
    我们之前第 6 步的时候, 我们在鼠标按下的时候, 就已经记录了元素 left 和 top
    当我们脱手的时候, 只要拿到一开始记录的内容
    直接给 left 和 top 赋值就好了
    7-2. 回去的太快了
    我想让他慢一点, 加一个 transition 属性就 ok 了
    7-3. 脱手回归以后
    因为拖手的时候加上了一个 transition 属性
    那么这个属性就会一直存在在元素身上了
    当你下次拖着跑的时候, 每移动 1px 都要经历 transition
    我们要在 鼠标按下 去的时候, 再把 transition 赋值为 none
    拖着跑的时候没有 transition, 只有脱手或者交换的时候才有 transition
  62. 抬起的时候交换位置
    8-1. 获取到和哪些元素有接触
    准备一个空数组, 循环遍历每一个 li
    看谁和移动的这个 li 有接触面积
    谁有就把谁放到这个数组里面
    循环结束, 数组里面就都是有接触面积的元素了
    8-2. 判断没有接触的元素
    判断如果 areaArr 是一个空数组
    表示没有接触的元素, 那么应该让移动的这个 li 回归原位
    如果 areaArr 里面有内容, 那么我在进行下一步判断
    8-3. areaArr 数组里面有成员
    我就要和 areaArr 数组里面的每一个成员进行比较
    找到和谁的接触面积大, 和谁的接触面积大, 就和谁交换
    循环 areaArr 这个数组, 分别判断每一个的接触面积
    找到接触面积最大的那个元素
    8-4. 让 this(移动的元素) 的 left 和 top 值和 areaEle(接触面积最大) 元素的 left top 值交换
    this 的 left 和 top 就是鼠标按下的时候记录的 startLeft 和 startTop
    我们先把 areaEle 元素的 left 值赋值给 this 的 left 值
    我们先把 areaEle 元素的 top 值赋值给 this 的 top 值
    把 startLeft 赋值给 areaEle 元素的 left 值
    把 startTop 赋值给 areaEle 元素的 top 值
  63. 获取元素
    1-1. 获取 ul
    var ul = document.querySelector(‘ul’)
    1-2. 获取 ul 下面的每一个 li
    var lis = ul.children // children 获取的是某一个节点下的所有 子元素节点
  64. 循环 lis 绑定事件
    for (var i = 0; i < lis.length; i++) {
    2-1. 给每一个 li 绑定 mousedown 事件
    lis[i].addEventListener(‘mousedown’, downHandler)
    2-2. 给每一个 li 绑定 mouseup 事件
    lis[i].addEventListener(‘mouseup’, upHandler)
    2-3. 给每一个 li 绑定 mousemove 事件
    lis[i].addEventListener(‘mousemove’, moveHandler)
    2-4. 给每一个 li 绑定 mouseout 事件
    lis[i].addEventListener(‘mouseout’, outHandler)
    }
  65. 取消文本选中效果
    document.addEventListener(‘selectstart’, function (e) {
    // 阻止默认行为
    e.preventDefault()
    })
  66. 判断移动事件能不能触发
    var moveState = false // 表示 mousemove 函数不能继续执行
  67. 判断脱手事件能不能触发
    var outState = false // 表示 mouseout 函数不能继续执行
    6-1. 准备两个变量记录按下时的鼠标坐标
    var startX = 0, startY = 0
    6-3. 准备两个变量, 记录初始的 left 和 top 值
    var startLeft = 0, startTop = 0
    // 准备四个事件处理函数
    // 按下的事件处理函数
    function downHandler(e) {
    // 鼠标按下的时候, 可以跟着跑
    moveState = true
    // 鼠标按下的时候, 可以有脱手效果
    outState = true
    // 这里开始下按下的业务逻辑
    6-1. 在按下的时候给 startX 和 startY 赋值
    startX = e.clientX
    startY = e.clientY
    6-3. 记录移动的这个元素初始的 left 和 top 值
    // this 就是我按下的这个元素
    startLeft = this.offsetLeft // offsetLeft 就是获取元素左侧偏移量
    startTop = this.offsetTop // offsetTop 就是获取元素上方的偏移量
    7-3. 按下的时候, 把 transition 赋值为 none
    this.style.transition = ‘none’
    }
    // 抬起的事件处理函数
    function upHandler() {
    // 鼠标抬起以后, 不可以跟着跑
    moveState = false
    // 鼠标抬起以后, 不能再触发脱手效果了, 因为要触发交换效果
    outState = false
    6-5. 还原 z-index
    this.style.zIndex = 1
    8-1. 获取到有接触面积的元素
    var areaArr = []
    // 循环遍历 li, 看谁和 this 有接触
    for (var i = 0; i < lis.length; i++) {
    // lis 里面包含了九个元素, 有其他八个, 也有当前移动的这一个
    // 自己和自己不用比, 因为没有元素比我自己和自己的接触面积大
    if (lis[i] === this) continue
    // 比较一下看看有没有面积接触的, 有的话就放在数组里面
    // 没有面积接触就继续下一个
    // 判断 (this.offsetLeft 和 lis[i].offsetLeft 相减) 绝对值 < this.offsetWidth
    // 判断 (this.offsetTop 和 lis[i].offsetTop 相减) 绝对值 < this.offsetHeight
    if (
    Math.abs(this.offsetLeft - lis[i].offsetLeft) < this.offsetWidth &&
    Math.abs(this.offsetTop - lis[i].offsetTop) < this.offsetHeight
    ) {
    // 表示两个元素有接触
    // 把这个 lis[i] 元素加到 areaArr 这个数组里面
    areaArr.push(lis[i])
    }
    }
    // 循环结束以后, areaArr 里面就是所有有接触的元素
    8-2. 判断是不是一个空数组, 判断数组的 length 是不是 0
    if (areaArr.length === 0) {
    // 回归原位
    this.style.left = startLeft + ‘px’
    this.style.top = startTop + ‘px’
    return
    }
    8-3. 找到和谁的接触面积大
    var areaMax = 0 // 记录接触面积
    var areaEle = null // 记录接触面积大的元素
    // 循环遍历 areaArr
    for (var j = 0; j < areaArr.length; j++) {
    // 接触面积的宽度
    var x = this.offsetWidth - Math.abs(this.offsetLeft - areaArr[j].offsetLeft)
    // 接触面积的高度
    var y = this.offsetHeight - Math.abs(this.offsetTop - areaArr[j].offsetTop)
    if (x * y > areaMax) {
    areaMax = x * y
    areaEle = areaArr[j]
    }
    }
    // 循环结束的时候, areaEle 就是接触面积最大的那个元素
    8-4. 和接触面积最大的元素交换位置
    this.style.left = areaEle.offsetLeft + ‘px’
    this.style.top = areaEle.offsetTop + ‘px’
    this.style.transition = ‘all .4s linear’
    areaEle.style.left = startLeft + ‘px’
    areaEle.style.top = startTop + ‘px’
    areaEle.style.transition = ‘all .4s linear’
    }
    // 移动的事件处理函数
    function moveHandler(e) {
    // 判断 moveState 为 false 的时候, 不让这个函数继续执行了
    // if (!moveState) return
    if (moveState === false) { return }
    6-2. 随时获取 client 一套信息, 和 startX 和 startY 相减
    var moveX = e.clientX - startX + startLeft
    var moveY = e.clientY - startY + startTop
    6-4. 边界值判断
    // 左边
    if (moveX <= 0) moveX = 0
    // 上边
    if (moveY <= 0) moveY = 0
    // 右边
    if (moveX >= ul.clientWidth - this.offsetWidth) moveX = ul.clientWidth - this.offsetWidth
    // 下面
    if (moveY >= ul.clientHeight - this.offsetHeight) moveY = ul.clientHeight - this.offsetHeight
    6-5. 给元素赋值 left 和 top
    this.style.left = moveX + ‘px’
    this.style.top = moveY + ‘px’
    this.style.zIndex = 999
    }
    // 脱手的事件处理函数
    function outHandler() {
    // 鼠标脱手以后, 不能跟着跑
    moveState = false
    // 鼠标脱手以后, 需要先触发一次, 不能再继续触发脱手效果了
    // if (!outState) return
    if (outState === false) { return }
    outState = false
    // 这里开始也脱手的业务逻辑
    6-5. 还原 z-index
    this.style.zIndex = 1
    7-1. 直接拿到按下的时候记录的 left 和 top 继续赋值
    this.style.left = startLeft + ‘px’
    this.style.top = startTop + ‘px’
    7-2. 加一个 transition 属性
    this.style.transition = ‘all .4s linear’
    }

handler 处理程序
moveState 移动状态
outState 移出状态
area 面积
offsetWidth 和 offsetHeight
=> 获取元素的 内容 + padding + border 的尺寸
=> width : 宽
=> height : 高
offsetLeft 和 offsetTop
=> 获取元素的 上边和左边 的偏移量
=> left : 左
=> top : 上
clientWidth 和 clientHeight
=> 获取元素的 内容 + padding 的尺寸
clientX 和 clientY
=> 实在鼠标的事件对象里面找到的
=> 光标相对于浏览器可视窗口左上角的距离
transition 属性
=> 运动的属性 all 表示所有属性都参与过渡
=> 运动的时间 .4s 表示 0.4s 完成运动
=> 运动的延迟 不写默认是 0 没有延迟
=> 运动的曲线 linear 表示匀速运动
continue 关键字
=> 在循环里面使用, 结束循环中的本次, 直接 i++ 进行循环的下一次
数组 数据类型
=> length 表示数组里面有多少个元素
=> 索引是从 0 开始, 表示第多少个元素
=> 当 length === 0 的时候, 表示数组里面没有元素
push 数组常用方法
=> 语法: 数组.push(要追加到数组里面的内容)
=> 作用: 向数组里面追加内容
面积比较
areaArr === [ 2号li, 4号li, 5号li ]
areaMax = 21000
areaEle = 4号li
循环遍历
当 j === 0 的时候
areaArr[0] === 2号li
x 就是 this 和 2号li 接触的宽度 50
y 就是 this 和 2号li 接触的高度 40
判断 x * y > areaMax 结果为 true
areaMax = 50 * 40 赋值为 2000
areaEle = 2号li
当 j === 1 的时候
areaArr[1] === 4号li
x 就是 this 和 4号li 接触的宽度 140
y 就是 this 和 4号li 接触的高度 150
判断 x * y > areaMax 结果为 true
areaMax = 140 * 150 赋值为 21000
areaEle = 4号li
当 j === 2 的时候
areaArr[2] === 5号li
x 就是 this 和 5号li 接触的宽度 50
y 就是 this 和 5号li 接触的高度 150
判断 x * y > areaMax 比较的是 7500 > 21000 结果为 false
当 j === 3
循环结束
循环结束以后, areaEle 就是和 this 接触面积最大的那个元素

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值