JS判断鼠标进入容器的方向与window.open新窗口被拦截的问题
发布时间 - 2026-01-10 22:03:23 点击率:次一、鼠标进入容器方向的判定

判断鼠标从哪个方向进入元素容器是一个经常碰到的问题,如何来判断呢?
首先想到的是:获取鼠标的位置,然后经过一大堆的if..else逻辑来确定。这样的做法比较繁琐,下面介绍两种比较方便的方法:
第一种方法,利用圆和反正切三角函数
如下图所示:
以div容器的中心点作为圆心,以高和宽的最小值作为直径画圆,将圆以[π/4,3π/4),[3π/4,5π/4),[5π/4,7π/4),[-π/4,π/4)划分为四个象限。
代码如下:
$(".box").on("mouseenter mouseleave",function(e){
/** 获取容器宽高 **/
var w = $(this).width();
var h = $(this).height();
/** 计算X和Y相对于圆心点的距离,如果不是正方形,按照X,Y谁小按谁进行比例缩放**/
var x = (e.pageX - $(this).offset().left - (w/2)) * ( w > h ? (h/w) : 1 );
var y = (e.pageY - $(this).offset().top - (h/2)) * ( h > w ? (w/h) : 1 );
/** 根据X,Y的值,做反正切atan2计算,返回值在[-π,π]之间 ,这里加上180,剔除负值**/
/** 如果不加180,则0,1,2,3对应下左上右**/
/** 除以90并四舍五入,使得可以以45度为分割线,获取象限**/
/** 加3与4取模,将0,1,2,3对应t,r,b,l既上右下左**/
var direction = Math.round((((Math.atan2(y, x) * (180 / Math.PI)) + 180 ) / 90 )+3)%4;
switch(direction) {
case 0:
/** 上 **/
break;
case 1:
/** 右 **/
break;
case 2:
/** 下 **/
break;
case 3:
/** 左 **/
break;
}});
这个方法中的Math.round((((Math.atan2(y, x) * (180 / Math.PI)) + 180 )/90)+3)% 4公式比较难理解,首先得到鼠标坐标经过换算后的值,然后算出该坐标的弧度,接着换算成度数,加180去掉负数,随后转移象限将0123对应TRBL,如果不加180去掉负数,0123对应BLTR,有点不合CSS的习惯。
第二种方法,利用斜率
如下图所示:
以浏览器左上角做原点,画坐标轴,向下为负,向右为正,和数学坐标系一致。中间的div的左上角坐标(x1,y1),右下角坐标(x2,y2),中心点的坐标(cx,cy)。如图两点的斜率为k(k<0),关于x轴对称的斜率为-k。
需要注意一点的是所有的Y轴坐标都是负数,因为就是将容器置于坐标系的第四象限。
$(".box").on("mouseenter mouseleave", function(e) {
var w = $(this).width();
h = $(this).height(),
x1 = $(this).offset().left,
y1 = -$(this).offset().top,
x2 = x1 + w,
y2 = y1 - h,
cx = (x1 + x2) / 2,
cy = (y1 + y2) / 2,
k = (y2 - y1) / (x2 - x1),
k1 = (-e.pageY - cy) / (e.pageX - cx),
direction = -1;
if ((k1 < -k) && (k < k1)) {
direction = e.pageX > cx?1:3;
} else {
direction = -e.pageY > cy?0:2;//大家理解代码的时候一定记住,Y坐标都是负的
}
//0123对应TRBL
});
如上代码所示:当鼠标的位置与容器中心点所形成的斜率在(k,-K)之间,必然是左右移入或移出,如果鼠标的X坐标大于中心点CX,则是右边进入,否则为左边进入;若斜率不在(k,-k)之间,则是上下进入或出去,只要判断鼠标的Y坐标与中心点CY的大小关系即可,大于则是下边,相反就是上边。
二、window.open新窗口被拦截的问题
当我们使用window.open()方法打开一个窗口时,部分浏览器会检测是否是用户主动行为,若不是,则会阻止窗口的打开,例如在异步Ajax的回调函数中调用。
新窗口被拦截检测
窗口被阻止打开,如不给出提示,用户体验将会很不好,那如何检测窗口被阻止?
如下代码所示:
var newWin = null,
isBlock = !1;
/** 新窗口被某些扩展阻止打开,会抛出错误,因此使用try..catch **/
try {
newWin = window.open('http://www.baidu.com', '_blank');
/** 新窗口被阻止时,返回值是undefined或null**/
(!newWin) && (isBlock = !0);
} catch (ex) {
isBlock = !0;
}
if (isBlock) alert('您阻止了窗口的打开。');
为何新窗口被拦截
浏览器设计者出于安全的考虑,window.open 命令在用户操作(trusted events)时, 才会正常的打开应该页面而不会被浏览器拦截。什么是trusted events?
The isTrusted read-only property of the Event interface is a boolean that is true when the event was generated by a user action, and false when the event was created or modified by a script or dispatched via dispatchEvent.
当前事件是由用户行为触发(例如鼠标点击按钮触发操作),便是trusted events,而用自定义事件dispatchEvent触发的事件则不是trusted events。
因此使用JS代码自动触发window.open() ,第二个参数不为_self,打开新窗口在大部分浏览器中会被拦截。如果第二个参数为_self,则不会被拦截,如window.open("http://www.baidu.com","_self") 。
如何Ajax回调中避免被拦截
很多人的需求是点击按钮发送Ajax请求,请求数据回来后,再使用window.open来打开新的窗口,由于是异步操作,直接window.open ,肯定会被拦截。这时我们可以变通以下,先打开一个空窗口,然后等数据回来后替换为需要的地址
如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>弹窗拦截测试</title>
<style type="text/css">
#btn{ width:100px; height: 30px; line-height: 30px; text-align:center; background-color:#0087dc; transition:all .2s; color:#fff; border-radius:3px;cursor:pointer; }
#btn:hover{ background-color:#0060b2; }
</style>
</head>
<body>
<div id="btn">打开新窗口</div>
<script type="text/javascript">
btn.addEventListener('click',(e)=>{
var xhr = new XMLHttpRequest();
var newWin = window.open('about:blank');
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4){
if(xhr.status == 200){
newWin.location.href="http://www.baidu.com";
}
}
};
xhr.open('post','/dnslookup',!1);//异步方式
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
xhr.send('host=www.baidu.com&rrtype=A');
},!0);
</script>
</body>
</html>
服务端代码如下:
var http = require('http'),
url = require('url'),
dns = require('dns'),
qs = require('querystring'),
fs = require('fs');
function router(req,res,pathname){
switch(pathname){
case '/dnslookup':
lookup(req,res);
break;
default:
showIndex(req,res);
}
}
function showIndex(req,res){
var pagePath = __dirname+'/'+'block.html';
var html = fs.readFileSync(pagePath);
res.end(html);
}
function lookup(req,res){
var postData = '';
req.on('data',function(data){
postData+=data;
});
req.on('end',function(data){
var json = qs.parse(postData);
var hostname = json.host;
var rrtype = json.rrtype;
dns.resolve(hostname,rrtype,function(err,adresses){
if(err){
res.end(JSON.stringify({errcode:1,ips:[]}));
}
res.end(JSON.stringify({errcode:0,ips:adresses}));
});
});
}
http.createServer(function(req,res){
var pathname = url.parse(req.url).pathname;
req.setEncoding("utf8");
res.writeHead(200,{'Content-Type':'text/html'});
router(req,res,pathname);
}).listen(3000);
如上所示便可解决在Ajax回调中新窗口被拦截的问题。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
# window.open
# 拦截
# js判断鼠标进入方向
# js
# 鼠标进入方向
# Ajax请求响应中用window.open打开新窗口被拦截的解决方法
# window.open不被拦截的简单实现代码(推荐)
# window.open打开窗口被拦截的快速解决方法
# js实现window.open不被拦截的解决方法汇总
# ajax请求成功后新开窗口window.open()被拦截解决方法
# window.open关于浏览器拦截问题分析及解决方法
# window.open不被拦截的实现代码
# window.open被浏览器拦截后的自定义提示效果代码
# 解决window.open()被浏览器拦截的问题
# 鼠标
# 中心点
# 所示
# 则是
# 的是
# 都是
# 回调
# 第二个
# 种方法
# 不加
# 如下图
# 返回值
# 是一个
# 将会
# 是由
# 才会
# 两种
# 很多人
# 回来后
# 我们可以
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel如何实现多表关联模型定义_Laravel多对多关系及中间表数据存取【方法】
Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】
logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?
如何用西部建站助手快速创建专业网站?
nginx修改上传文件大小限制的方法
Laravel如何发送邮件和通知_Laravel邮件与通知系统发送步骤
如何在IIS7中新建站点?详细步骤解析
如何获取免费开源的自助建站系统源码?
如何在Windows 2008云服务器安全搭建网站?
高端智能建站公司优选:品牌定制与SEO优化一站式服务
谷歌浏览器下载文件时中断怎么办 Google Chrome下载管理修复
高性能网站服务器部署指南:稳定运行与安全配置优化方案
Laravel如何实现本地化和多语言支持_Laravel多语言配置与翻译文件管理
Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程
如何在HTML表单中获取用户输入并用JavaScript动态控制复利计算循环
如何用JavaScript实现文本编辑器_光标和选区怎么处理
Win11怎么关闭透明效果_Windows11辅助功能视觉效果设置
常州企业网站制作公司,全国继续教育网怎么登录?
如何在自有机房高效搭建专业网站?
Laravel如何实现全文搜索功能?(Scout和Algolia示例)
公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?
如何在云主机上快速搭建网站?
如何在VPS电脑上快速搭建网站?
HTML透明颜色代码怎么让图片透明_给img元素加透明色的技巧【方法】
Win11搜索栏无法输入_解决Win11开始菜单搜索没反应问题【技巧】
Claude怎样写约束型提示词_Claude约束提示词写法【教程】
小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?
如何快速打造个性化非模板自助建站?
再谈Python中的字符串与字符编码(推荐)
新三国志曹操传主线渭水交兵攻略
如何挑选优质建站一级代理提升网站排名?
Laravel怎么做缓存_Laravel Cache系统提升应用速度的策略与技巧
如何在橙子建站中快速调整背景颜色?
php8.4header发送头信息失败怎么办_php8.4header函数问题解决【解答】
HTML 中动态设置元素 name 属性的正确语法详解
深圳网站制作培训,深圳哪些招聘网站比较好?
如何用ChatGPT准备面试 模拟面试问答与职场话术练习教程
高端建站如何打造兼具美学与转化的品牌官网?
Python面向对象测试方法_mock解析【教程】
JavaScript数据类型有哪些_如何准确判断一个变量的类型
laravel服务容器和依赖注入怎么理解_laravel服务容器与依赖注入解析
如何获取PHP WAP自助建站系统源码?
高防网站服务器:DDoS防御与BGP线路的AI智能防护方案
SQL查询语句优化的实用方法总结
javascript日期怎么处理_如何格式化输出
北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?
中山网站制作网页,中山新生登记系统登记流程?
Laravel如何实现数据库事务?(DB Facade示例)
微信小程序制作网站有哪些,微信小程序需要做网站吗?
Laravel路由怎么定义_Laravel核心路由系统完全入门指南

