无法为容器所有子元素实现3D旋转hover效果,for循环实现异常
问题根源
这是典型的循环内闭包变量共享问题,具体原因如下:
- 你用
var声明的循环变量i属于函数作用域,整个循环全程只会创建一个i变量,所有绑定的事件回调都共享这同一个i的引用。等循环跑完的时候,i的值已经变成了rotate.length,超出了数组的下标范围,事件触发时读取rotate[i]会返回undefined,自然不会有任何效果。 - 另外你把事件处理函数定义在循环内部,每次迭代都会重复创建新的函数,属于不必要的性能开销。
修复方案
方案1:替换变量声明(改动最小)
把循环的var i改为let i即可,let是块级作用域声明,每次循环迭代都会生成独立的i绑定到当前块,每个回调拿到的都是对应迭代的独立i值。另外建议直接用this代替rotate[i],事件回调中的this默认指向当前绑定事件的DOM元素,逻辑更稳妥,完全不需要依赖循环变量。
修复后代码:
let rotate = document.getElementsByClassName("group")[0].getElementsByTagName("a"); // 仅把var替换为let即可解决变量共享问题 for (let i=0; i<rotate.length; i++) { const height = rotate[i].clientHeight; const width = rotate[i].clientWidth; rotate[i].addEventListener('mousemove', handleMove) function handleMove(e) { const xVal = e.layerX; const yVal = e.layerY; const yRotation = 20 * ((xVal - width / 2) / width); const xRotation = -20 * ((yVal - height / 2) / height); const string = 'perspective(500px) scale(1.1) rotateX(' + xRotation + 'deg) rotateY(' + yRotation + 'deg)'; this.style.transform = string; } rotate[i].addEventListener('mouseout', function() { this.style.transform = 'perspective(500px) scale(1) rotateX(0) rotateY(0)' }) rotate[i].addEventListener('mousedown', function() { this.style.transform = 'perspective(500px) scale(0.9) rotateX(0) rotateY(0)' }) rotate[i].addEventListener('mouseup', function() { this.style.transform = 'perspective(500px) scale(1.1) rotateX(0) rotateY(0)' }) }
方案2:用forEach遍历(更易维护)
把DOM集合转成数组后用forEach遍历,天然避免循环变量共享问题,代码可读性更高:
const rotate = Array.from(document.querySelector(".group").getElementsByTagName("a")); rotate.forEach(el => { const height = el.clientHeight; const width = el.clientWidth; el.addEventListener('mousemove', e => { const xVal = e.layerX; const yVal = e.layerY; const yRotation = 20 * ((xVal - width / 2) / width); const xRotation = -20 * ((yVal - height / 2) / height); const string = `perspective(500px) scale(1.1) rotateX(${xRotation}deg) rotateY(${yRotation}deg)`; el.style.transform = string; }) el.addEventListener('mouseout', () => { el.style.transform = 'perspective(500px) scale(1) rotateX(0) rotateY(0)' }) el.addEventListener('mousedown', () => { el.style.transform = 'perspective(500px) scale(0.9) rotateX(0) rotateY(0)' }) el.addEventListener('mouseup', () => { el.style.transform = 'perspective(500px) scale(1.1) rotateX(0) rotateY(0)' }) })
内容的提问来源于stack exchange,提问作者tez
相关产品推荐
相关产品推荐

