在这里,鼠标移入dom元素用mouseenter事件监听,移出dom元素用mouseleave事件监听。

二、判断鼠标的位置

我们知道,上面两个鼠标事件中,有个属性叫e.clientx和e.clientY,分别代表鼠标以文档窗口左上角为坐标原点,往右为x轴正方向,往下为y轴正方向的距离。
同时,dom元素有两个属性offsetTop和offsetLeft,分别代表元素(不包含transform的平移效果)上边界距离文档窗口上边缘、左边界距离文档窗口左边缘的距离,如图:

三、坐标系的平移

假设,我们将上述的坐标系进行平移,使它的坐标原点处于dom元素的中心点,那么x、y方向分别要减去宽高一半即width/2,height/2的距离。
dx = clientX - offsetLeft - width/2
dy = clientY - offfsetTop - height/2
那么(dx, dy)就相当于鼠标移入事件触发的点,在以元素中心点为原点的新坐标系下的坐标值。如图:

鼠标移入移出方向判断-方向与角度值对应.jpg

在js中,Math.atan2(y, x)方法可返回从x轴到点(x, y)之间的角度(弧度为单位),返回值 -Π 到 Π(Math.PI)。
1、θ = Math.atan2(dy, dx) * 180 / Math.PI 则返回了以角度为单位的值。
此时四边分别对应的角度为:
上边:θ = [-135°, -45°]
右边:θ = [-45°, 45°]
下边:θ = [45°, 135°]
左边:θ = [-180°, -135°] [135°, 180°]
2、θ范围为-180到180间,将它转化为0到360间,加上180
即θ = Math.atan2(dy, dx) * 180 / Math.PI + 180,此时四边分别对应角度为:
上边:θ = [45°, 135°]
右边:θ = [135°, 225°]
下边:θ = [225°, 315°]
左边:θ = [0°, 45°] [315°, 360°]
3、θ的结果如果同时除以90,并且四舍五入,即
θ = Math.round((Math.atan2(dy, dx) * 180 / Math.PI + 180) / 90),此时四边分别对应的值为:
上边:θ = 1
右边:θ = 2
下边:θ = 3
左边:θ = 0 | 4
4、上面的结果再次加3,即
θ = Math.round((Math.atan2(dy, dx) * 180 / Math.PI + 180) / 90) + 3,此时四边分别对应的值为:
上边:θ = 4
右边:θ = 5
下边:θ = 6
左边:θ = 3 | 7
5、最后,θ结果再次对4取余,即
θ = (Math.round((Math.atan2(dy, dx) * 180 / Math.PI + 180) / 90) + 3) % 4,此时四边分别对应的值为:
上边:θ = 0
右边:θ = 1
下边:θ = 2
左边:θ = 3
至此,完成了鼠标移入的坐标点,通过一系列计算步骤,一一对应到四个方向的过程。

五、若是dom元素不是正方形

以上的判断和计算,都是假设如果dom元素是正方形的情况下,如果dom元素不是正方形,那么dx、dy的计算应为:
dx = (clientX - offsetLeft - width / 2) * (width > height ? (height / width ) : 1);
dy = (clientY - offfsetTop - height / 2) * (height > width ? (width /height ) : 1);

判断方向的核心代码
* 根据鼠标移入移出事件中鼠标的位置,来判断它是在元素的哪个方向移入移出 * 返回值 0 代表从上方移入移出,1 代表从右侧移入移出,2 代表从下方移入移出,3 代表从左侧移入移出 function getDirection(event) { let d; let w = dom.offsetWidth; let h = dom.offsetHeight; let l = dom.offsetLeft; let t = dom.offsetTop; let dx = (event.clientX - l - w / 2) * (w > h ? (h / w) : 1); let dy = (event.clientY - t - h / 2) * (h > w ? (w / h) : 1); d = (Math.round((Math.atan2(dy, dx) * 180 / Math.PI + 180) / 90) + 3) % 4; return d;

以下是测试代码:

let dom = document.getElementById('test');
function bindEvent() {
    dom.onmouseenter = function(e) {
        get(e, 'in');
    dom.onmouseleave = function(e) {
        get(e, 'out');
function get(e, state) {
    let d = getDirection(e);
    let dir = '';
    switch (d) {
        case 0: {
            dir = '-top';
            break;
        case 1: {
            dir = '-right';
            break;
        case 2: {
            dir = '-bottom';
            break;
        case 3: {
            dir = '-left';
            break;
    console.log(state + dir);
* 根据鼠标移入移出事件中鼠标的位置,来判断它是在元素的哪个方向移入移出
* 返回值 0 代表从上方移入移出,1 代表从右侧移入移出,2 代表从下方移入移出,3 代表从左侧移入移出
function getDirection(event) {
    let d;
    let w = dom.offsetWidth;
    let h = dom.offsetHeight;
    let l = dom.offsetLeft;
    let t = dom.offsetTop;
    let dx = (event.clientX - l - w / 2) * (w > h ? (h / w) : 1);
    let dy = (event.clientY - t - h / 2) * (h > w ? (w / h) : 1);
    d = (Math.round((Math.atan2(dy, dx) * 180 / Math.PI + 180) / 90) + 3) % 4;