JS 飘窗效果

JS 飘窗效果插件

demo

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>JS 飘窗</title>
        <script src="./pWindow.js"></script>
        <style>
            .pWindow {
                width: 100px;
                height: 200px;
                background-color: pink;
            }

            .pWindow::before {
                content: "";
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                height: 35px;
                background-color: #fff;
                border: 1px solid #eee;
            }

            .cancel {
                width: 35px;
                height: 35px;
                position: absolute;
                right: 0;
                top: 0;
                display: flex;
                justify-content: center;
                align-items: center;
            }

            .content {
                position: absolute;
                top: 35px;
                width: 100%;
                height: calc(100% - 35px);
                background-color: orange;
            }
        </style>
    </head>

    <body>
        <div class="pWindow">
            <div class="cancel">×</div>
            <div class="content">
                <a href="https://www.baidu.com" target="_blank">百度一下</a>
            </div>
        </div>
    </body>
    <script>
        pWindow({ bayWindowSelector: ".pWindow", cancelSelector: ".cancel", contentSelector: ".content" })
    </script>

</html>

pWindow.js文件

/**
 *
 * @param {:飘窗元素选择器, 取消飘窗按钮元素选择器,内容区元素选择器,鼠标点击时的位置} bayWindow
 */
function pWindow(
bayWindow = {
    bayWindowSelector,
    cancelSelector,
    contentSelector,
    mouseOnClickSite,
}
) {
    let x = 1,
        y = 1,
        xStatus = generateRandom() > 0.5 ? -1 : 1,
        yStatus = generateRandom() > 0.5 ? -1 : 1,
        dom,
        domBox,
        currentLeft,
        currentTop,
        clientWidth,
        clientHeight,
        animationID,
        cancelBtn,
        content,
        clientX,
        clientY;
    const {
        bayWindowSelector,
        cancelSelector,
        contentSelector,
        mouseOnClickSite,
    } = bayWindow;
    init();
    // 初始化函数,初始化飘窗信息
    function init() {
        dom = document.querySelector(bayWindowSelector);
        domBox = dom.getBoundingClientRect();
        // 初始化时,飘窗距离浏览器窗口左侧距离,随机生成
        const left = generateRandom({
            max: document.documentElement.clientWidth - domBox.width,
            fixed: 0,
        });
        // 初始化时,飘窗距离浏览器窗口顶部距离,随机生成
        const top = generateRandom({
            max: document.documentElement.clientHeight - domBox.height,
            fixed: 0,
        });
        dom.style.cssText = `position:fixed;left:${left}px;top:${top}px;visibility:visible;z-index:99999;`;
        start();
        // 监听鼠标移入飘窗
        dom.addEventListener("mouseenter", mouseenterBayWindow); //已注册在销毁函数中
        // 监听鼠标按下后抬起
        dom.addEventListener("mouseup", mouseupBayWindow); //已注册在销毁函数中
        // 监听鼠标离开飘窗
        dom.addEventListener("mouseleave", mouseleaveBayWindow); //已注册在销毁函数中
        // 监听鼠标离开飘窗
        dom.addEventListener("mouseout", mouseoutBayWindow); //已注册在销毁函数中

        // 飘窗内部其他元素事件
        // 取消按钮
        if (cancelSelector) {
            cancelBtn = document.querySelector(cancelSelector);
            cancelBtn.addEventListener("mousedown", mousedownCancel); //已注册在销毁函数中
        }

        // 内容区
        if (contentSelector) {
            content = document.querySelector(contentSelector);
            content.addEventListener("mousedown", mousedownContent); //已注册在销毁函数中
        }
    }
    /**
   * 飘窗动画
   */
    function start() {
        domBox = dom.getBoundingClientRect();
        currentLeft = domBox.x;
        currentTop = domBox.y;
        clientHeight = document.documentElement.clientHeight;
        clientWidth = document.documentElement.clientWidth;
        if (clientHeight <= currentTop + domBox.height || currentTop < 0) {
            yStatus = -yStatus;
        }
        if (clientWidth <= currentLeft + domBox.width || currentLeft < 0) {
            xStatus = -xStatus;
        }
        // 防止飘窗移动到窗口边界出被吸附开始
        if (domBox.left <= 0) {
            xStatus = 1;
        }
        if (domBox.top <= 0) {
            yStatus = 1;
        }
        if (domBox.right >= document.documentElement.clientWidth) {
            xStatus = -1;
        }
        if (domBox.bottom >= document.documentElement.clientHeight) {
            yStatus = -1;
        }
        // 防止飘窗移动到窗口边界出被吸附结束
        dom.style.top = (currentTop += y * yStatus) + "px";
        dom.style.left = (currentLeft += x * xStatus) + "px";

        animationID = requestAnimationFrame(start);
    }
    /**
   * 生成随机函数,可以用做初始化时飘窗位置与移动速度计算
   * @param {} obj
   * max:最大区间
   * fixed:随机数截取小数点位数
   * @returns
   */
    function generateRandom(obj = { max: 1, fixed: 2 }) {
        return +(Math.random() * obj.max).toFixed(obj.fixed);
    }
    /**
   * 飘窗区鼠标进入回调,事件监听回调函数
   */
    function mouseenterBayWindow() {
        console.log("鼠标进入了");
        cancelAnimationFrame(animationID);
        dom.addEventListener("mousedown", mousedownMousemove); //已注册在销毁函数中
    }
    /**
   * 飘窗区鼠标点击后抬起,取消mousemove监听事件和飘窗跟随事件
   * @param {*} event
   */
    function mouseupBayWindow(event) {
        console.log("鼠标抬起了");
        dom.style.cursor = "default";
        dom.removeEventListener("mousemove", mousemoveBayWindow); //已注册在销毁函数中
    }
    /**
   * 飘窗区鼠标离开后,取消mousemove事件监听和飘窗跟随事件
   */
    function mouseoutBayWindow() {
        console.log("鼠标离开了-事件冒泡");
        dom.style.cursor = "default";
        dom.removeEventListener("mousemove", mousemoveBayWindow); //已注册在销毁函数中
    }
    /**
   * 飘窗区鼠标离开后,飘窗继续移动动画
   * @param {*} event
   */
    function mouseleaveBayWindow(event) {
        console.log("鼠标离开了");
        start();
    }

    /**
   * 取消按钮鼠标点击回调事件,点击后飘窗消失
   * @param {*} event
   */
    function mousedownCancel(event) {
        console.log("点击了取消,鼠标按下了");
        destoryEvent();
        event.stopPropagation();
        // dom.style.cssText = "display:none;";
        dom.remove();
    }
    /**
   * 飘窗内容鼠标点击时回调事件,阻止内容点击时事件冒泡
   * @param {*} event
   */
    function mousedownContent(event) {
        event.stopPropagation();
        console.log("内容去点击");
    }

    /**
   * 飘窗内容去,鼠标按下未抬起时的回调函数
   * @param {*} event
   */
    function mousedownMousemove(event) {
        console.log("鼠标按下了", event.y);
        clientX = event.clientX;
        clientY = event.clientY;
        dom.style.cursor = "move";
        mousemoveBayWindow(event);
        dom.addEventListener("mousemove", mousemoveBayWindow); //已注册在销毁函数中
    }
    /**
   * 飘窗跟随鼠标移动事件
   * @param {*} event
   */
    function mousemoveBayWindow(event) {
        let topDistance, leftDistance, bottomDistance, rightDistance;
        // 点击飘窗时,鼠标自动位移到飘窗的中心
        if (mouseOnClickSite === "center") {
            topDistance = event.y - domBox.height / 2;
            leftDistance = event.x - domBox.width / 2;
            bottomDistance = event.y + domBox.height / 2;
            rightDistance = event.x + domBox.width / 2;
            if (bottomDistance >= document.documentElement.clientHeight) {
                dom.style.top =
                    document.documentElement.clientHeight - domBox.height + "px";
            } else if (topDistance <= 0) {
                dom.style.top = "0px";
            } else {
                dom.style.top = event.y - domBox.height / 2 + "px";
            }
            if (rightDistance >= document.documentElement.clientWidth) {
                dom.style.left =
                    document.documentElement.clientWidth - domBox.width + "px";
            } else if (leftDistance <= 0) {
                dom.style.left = "0px";
            } else {
                dom.style.left = event.x - domBox.width / 2 + "px";
            }
        } else {
            domBox = dom.getBoundingClientRect();
            const x = event.clientX - clientX;
            const y = event.clientY - clientY;
            clientX = event.clientX;
            clientY = event.clientY;
            if (domBox.bottom > document.documentElement.clientHeight) {
                dom.style.top =
                    document.documentElement.clientHeight - domBox.height + "px";
            } else if (domBox.top < 0) {
                dom.style.top = "0px";
            } else {
                dom.style.top = domBox.top + y + "px";
            }
            if (domBox.right > document.documentElement.clientWidth) {
                dom.style.left =
                    document.documentElement.clientWidth - domBox.width + "px";
            } else if (domBox.left < 0) {
                dom.style.left = "0px";
            } else {
                dom.style.left = domBox.left + x + "px";
            }
        }
    }

    // 销毁监听事件函数
    function destoryEvent() {
        dom.removeEventListener("mouseenter", mouseenterBayWindow);
        dom.removeEventListener("mouseup", mouseupBayWindow);
        dom.removeEventListener("mouseleave", mouseleaveBayWindow);
        dom.removeEventListener("mousedown", mousedownMousemove);
        dom.removeEventListener("mousemove", mousemoveBayWindow);
        dom.removeEventListener("mouseout", mouseoutBayWindow);
        cancelBtn.removeEventListener("mousedown", mousedownCancel);
        content.removeEventListener("mousedown", mousedownContent);
    }
}

posted @   走我们钓鱼去  阅读(445)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示