鼠标跟随、DOM二级事件
一、鼠标跟随
- 实现一个跟随鼠标移动的效果
 - 思路:
 
- 页面中的盒子并不会自己跟着鼠标移动,所谓的鼠标跟随就是在鼠标移动的时候,不断的计算鼠标所处的位置,然后把盒子的位置设置到鼠标所处的位置上即可;
 - 很显然是鼠标移动的时候,所以需要监听鼠标移动事件,因为盒子在整个页面中所以需要监听document的鼠标移动事件;
 - 在事件触发时计算鼠标的位置,把元素设置到鼠标的位置
 
let box = document.querySelector('#box');document.onmousemove = function (e) {// 1. 获取鼠标的位置let {clientX,clientY} = e;console.log('move', clientX, clientY);// 2. 计算盒子的位置,并设置给元素box.style.left = clientX - box.offsetWidth / 2 + 'px';box.style.top = clientY - box.offsetHeight / 2 + 'px';};
二、限制边界的鼠标跟随
- 前面已经实现了鼠标跟随,但是鼠标可以画出屏幕,现在要求限制盒子在屏幕的可是区域内;
 - 思路:
- 盒子的最大边界即盒子的left和top的最大值,left的最大值 = 浏览器可视窗口的宽度 - 盒子的宽度;top的最大值 = 浏览器的可视窗口的高度 - 盒子的高度;
 - 盒子边最小边界即left=0,top=0的位置
 
 
function win(attr) {return document.documentElement[attr] || document.body[attr];}let box = document.querySelector('#box');let minL = 0;let minT = 0;document.onmousemove = function (e) {// 1. 获取鼠标的位置let {clientX,clientY} = e;// 2. 获取盒子的offsetWidth/offsetHeightlet {offsetWidth,offsetHeight} = box;console.log('move', clientX, clientY);// 3. 求盒子的最大边界值let maxL = win('clientWidth') - box.offsetWidth;let maxT = win('clientHeight') - box.offsetHeight;// 4. 根据鼠标位置求得盒子应该所处的位置let l = clientX - offsetWidth / 2;let t = clientY - offsetHeight / 2;// 5. 在设置之前对求出的l和t进行修正// left的边界判断if (l < minL) {l = minL;}if (l > maxL) {l = maxL;}// top的边界判断if (t < minT) {t = minT;}if (t > maxT) {t = maxT;}// 6. 把修正之后的值设置给元素对象box.style.left = l + 'px';box.style.top = t + 'px';};
三、电商放大镜
- 页面中有两个等大的盒子,box1中放着原图和一个可以跟随鼠标移动的小盒子mask,mask相对于box1相对定位;
 - 另一个box2放着大图,大图相对于盒子绝对定位;且大盒子overflow:hidden; 大图片的尺寸等于box1的尺寸乘以想放大的倍数,如本例中放大三倍,box1宽高300,所以大图宽高900;
 - mask 的尺寸 box1的尺寸 = box2的尺寸 大图的尺寸
 - 起初box2和mask都是隐藏的,当鼠标划入box1时,设置mask和box2的display: block;
 - 接着在box1中移动鼠标,实现带边界的鼠标跟随;
 - 因为mask占box1的比例和box2占大图的比例是相同的。但是大图的尺寸是box2的3倍,为了保证看到的是相同的地方,box2中图片的left和top的移动距离,应该是mask在box1中移动的3倍(放大三倍)
 
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title><style>* {margin: 0;padding: 0;}.box1, .box2 {position: relative;float: left;width: 300px;height: 300px;border: 1px solid red;margin: 50px;overflow: hidden;}.box1 img {width: 100%;height: 100%;}.box2 img {position: absolute;left: 0;top: 0;width: 900px;height: 900px;}.mask {display: none;position: absolute;left: 0;top: 0;width: 100px;height: 100px;background: rgba(0, 0, 0, .5);cursor: move;}.box2 {display: none;}</style></head><body><div id="box1" class="box1"><img src="./iphone.jpg" alt=""><div class="mask" id="mask" style="width: 100px;height: 100px"></div></div><div class="box2" id="box2"><img src="./iphone.jpg" alt="" id="bigImg"></div><script src="js/5-放大镜.js"></script></body></html>
let $ = sltcr => document.querySelector(sltcr);// 1. 获取元素对象let box1 = $('#box1');let box2 = $('#box2');let mask = $('#mask');let bigImg = $('#bigImg');// 2. 当鼠标划入时把mask和box2显示出来box1.onmouseenter = function () {box2.style.display = mask.style.display = 'block';};box1.onmouseleave = function () {box2.style.display = mask.style.display = 'none';};// 计算mask能够在box1中移动的边界let {offsetLeft,offsetTop,clientWidth,clientHeight} = box1;let {width,height} = mask.style;let maxL = clientHeight - parseFloat(width);let maxT = clientHeight - parseFloat(height);// 2. 监听box1的鼠标移动事件box1.onmousemove = function (e) {// 2.1 获取现在鼠标的位置并计算盒子应该出现的位置let l = e.clientX - offsetLeft - parseFloat(width) / 2;let t = e.clientY - offsetTop - parseFloat(height) / 2;// 2.2 根据边界修正l和tif (t < 0) {t = 0;}if (t > maxT) {t = maxT;}if (l < 0) {l = 0;}if (l > maxL) {l = maxL;}// 2.3 把l和t设置给mask实现mask鼠标跟随跟随mask.style.left = l + 'px';mask.style.top = t + 'px';// 2.4 设置大图left和top的值为mask移动距离的3倍bigImg.style.left = -l * 3 + 'px';bigImg.style.top = -t * 3 + 'px';};
四、DOM2级事件
- JS中的事件分为DOM0级事件和DOM2级事件;
 
DOM0级事件
- DOM0级事件绑定
 
box.onclick = function () {};box.onclick = function () {console.log('1')};box.onclick = function () {console.log('2');};
- DOM0级事件移除
 
box.onclick = null;
- 用DOM0级事件的方式绑定,只能绑定一个事件,因为DOM0级事件是DOM元素对象的一个属性,多次赋值,这个属性只能保存的是最后一次被赋的值;
 - DOM0级事件都是绑定在冒泡阶段的;
 
DOM2级事件:
- 可以为同一事件绑定多个事件函数;
 - 可以指定绑定的在捕获阶段还是绑定再冒泡阶段;
 
- DOM2级事件绑定:
 
元素.addEventListener('事件名称', 事件函数, false冒泡 | true捕获)box.addEventListener('click', function () {console.log(1)}, true);box.addEventListener('click', function () {console.log(2)}, false);box.addEventListener('click', function () {console.log(3);}, false);
- 移除DOM2级事件
 
元素.removeEventListener('事件名称', 事件函数, false|true);
DOM0级事件和DOM2级事件绑定区别:
- DOM0级事件只有冒泡阶段,DOM2级事件的第三个参数false表示冒泡,true表示捕获
 - DOM0级事件只能为一个事件绑定一个事件函数,而DOM2级事件可以绑定多个事件函数;
 
DOM2事件为啥可以绑定多个事件呢?
DOM2级事件给在绑定的时候是给每个元素的每个事件准备了一个事件池,类似一个数组,每次addEventListener()就是把事件函数放到事件池中,然后等事件触发的时候,再一个一个的把事件函数从事件池中拿出来执行一次;
- IE低版本DOM2级事件:
 - 绑定事件:元素.attachEvent(‘onclick’, callback);
 - 移除事件:元素.detachEvent(‘onclick’, callback);
 - 而且IE的DOM2级事件只能绑定在冒泡阶段,如果绑定多个,事件触发时,事件函数的执行顺序和绑定顺序无关;
 
【发上等愿,结中等缘,享下等福,择高处立,寻平处住,向宽处行】
