一、鼠標進入容器方向的判定
判斷鼠標從哪個方向進入元素容器是一個經常碰到的問題,如何來判斷呢?
首先想到的是:獲取鼠標的位置,然后經過一大堆的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(" 。
如何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.; } } }; 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回調中新窗口被攔截的問題。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。
新聞熱點
疑難解答