먼저 렌더링(직접 녹음한 gif, 좀 못생겼음, 미안, 도구 licicecap)
구현 아이디어
HTML 구조
<ul> <li> <div class="bg"> <p>JS</p> </div> </li> ..... </ul>
li는 mouseenter와 mouseleave의 캐리어 역할을 합니다.
div는 애니메이션 실행의 전달자 역할을 합니다.
CSS
div는 절대 위치 지정을 사용하고 위쪽과 왼쪽을 통해 위치를 변경합니다.
div의 상단과 왼쪽이 li 크기를 초과할 수 있으므로 li의 Overflow:hidden 설정이 필요합니다.
JS
1. JS를 사용하여 CSS3 전환 애니메이션 조작
2. 마우스 움직임의 안팎 방향 판단 방법
마우스 좌표 관련 지식
MouseEvent 객체
다음은 MouseEvent의 좌표에 대한 몇 가지 관련 지식을 소개합니다.
(clientX, clientY): 시각적 영역을 참조 시스템으로 좌표합니다.
(pageX, pageY): 참조 시스템인 전체 페이지(스크롤 막대에 의해 펼쳐진 영역 포함)의 좌표입니다.
(screenX, screenY): 컴퓨터 화면을 기준 시스템으로 사용하는 좌표입니다.
요소 내부의 좌표 가져오기
function pointTo(element, e) { var elementBox = element.getBoundingClientRect(); return { x: e.clientX - elementBox.left, y: e.clientY - elementBox.top }; }
요소의 왼쪽 상단 좌표 계산
function startPoint(element){ var x = 0,y = 0; while(element != null) { x += element.offsetLeft; y += element.offsetTop; element = element.offsetParent; } return { x: x, y: y } }
요소의 너비와 높이를 가져옵니다. (너비와 높이로 생각하지 마세요. 초보자는 특히 실수하기 쉽습니다.)
offsetHeight与offsetWidth
CSS3 전환 애니메이션을 간단히 캡슐화
/* options参数: obj: 运动的对象 speed: 运动的持续时间(可选) changeStyle: 改变的属性,这里可能多个,所以采用函数的方式(可选) callback: 回调函数(可选) */ function animation(options){ if(!options.obj) { return false; } //设置默认持续时间 options.speed = options.speed || '.5s'; options.obj.style.transition = "all " + options.speed + " ease-in-out"; options.changeStyle.call(options.obj); var flag = false; options.obj.addEventListener('transitionend',function(){ //这里主要由于transitionend在每个属性的动画执行完多会走一遍,所以我们要让它只执行一次。 if(!flag) { options.callback && options.callback(); } },false); }
방향을 결정하는 방법
접선과 관련된 개념 여기서는 수학에서 직접 그림을 그렸는데, 확실히 이해가 되실지 궁금합니다
요소의 운동방향을 알아보세요
function getDirection(element,startPoint,pagePoint){ var halfWidth = element.offsetWidth / 2,halfHeight = element.offsetHeight / 2; //得到中心点 var center = { x: startPoint.x + halfWidth, y: startPoint.y + halfHeight } //得到鼠标偏离中心点的距离 var disX = pagePoint.x - center.x; var disY = pagePoint.y - center.y; if(disY < 0 && Math.abs(disY / disX) >= 1) { //上方 return 1; } else if(disY > 0 && Math.abs(disY / disX) >= 1) { //下 return 2; } else if(disX < 0 && Math.abs(disY / disX) < 1) { //左 return 3; } else { //右 return 4; } }
이벤트를 시작하는 코드에 댓글이 있습니다
/* options中的参数: 触发事件的载体: targetElement 执行动画的载体: animationElement */ function HoverAction(options) { if(!options.targetElement || !options.animationElement) { return false; } this.targetElement = options.targetElement; this.animationElement = options.animationElement; this.timeId = null; this.speed = "0.3s"; } HoverAction.prototype.addEvent = function() { //保存this的指向 var _this = this; _this.targetElement.addEventListener('mouseenter',function(e){ //得到鼠标的坐标 var point = { x: e.pageX, y: e.pageY } console.log(point); //获得方向 var dir = getDirection(_this.targetElement,startPoint(_this.targetElement),point); clearTimeout(_this.timeId); //取消过渡动画(防止重置动画载体位置时触发过渡效果) _this.animationElement.style.transition = ""; //得到运动的方向,要确定动画载体的开始位置 switch(dir){ case 1: _this.animationElement.style.top = "-100%"; _this.animationElement.style.left = "0"; break; case 2: _this.animationElement.style.top = "100%"; _this.animationElement.style.left = "0"; break; case 3: _this.animationElement.style.top = "0"; _this.animationElement.style.left = "-100%"; break; case 4: _this.animationElement.style.top = "0"; _this.animationElement.style.left = "100%"; break; } //异步执行 _this.timeId = setTimeout(function(){ animation({ obj: _this.animationElement, speed: _this.speed, changeStyle: function(){ this.style.top = "0"; this.style.left = "0"; } }); },20); },false); _this.targetElement.addEventListener('mouseleave',function(e){ var left,top; var point = { x: e.pageX, y: e.pageY } clearTimeout(_this.timeId); _this.animationElement.style.transition = ""; var dir = getDirection(_this.targetElement,startPoint(_this.targetElement),point); switch(dir) { case 1: top = '-100%'; left = '0'; break; case 2: top = '100%'; left = "0"; break; case 3: left = "-100%"; top = "0"; break; case 4: left = "100%"; top = "0"; break; } _this.timeId = setTimeout(function(){ animation({ obj: _this.animationElement, speed: _this.speed, changeStyle: function(){ this.style.top = top; this.style.left = left; } }); },20); },false); }