看到這標題,是不是有點逆天的感覺,總感覺好狂拽炫酷,耳邊隱隱約約傳來一個聲音:你這麼叼,你咋不上天呢! ~~ 額,好吧!
話入正題,我為什麼會提出這麼一個問題呢?
阻止浏覽器默認行為,真的能阻止嗎?那到底是什麼樣的方案,我會有這樣的質疑?
那,就是它了,別看,就是你:
//阻止浏覽器默認行為觸發的通用方法 function stopDefault(e){ //防止浏覽器默認行為(W3C) if(e && e.preventDefault){ e.preventDefault(); } //IE中組織浏覽器行為 else{ window.event.returnValue=fale; return false; } }
沒錯,就是你,這個在網上一搜,基本上非常通用的解決方案,以前我也對這種方法深信不疑,覺得這是前輩們的多少次實踐論證出來的東西,應該是精品,但是就在我寫拖拽效果的時候,在阻止浏覽器默認行為時,發現在IE8下,居然嗝屁了,
你不信?那就讓我們一起來看看,上面的解決方案在IE8以下的表現吧!當然,標准浏覽器是沒有問題的啦,畢竟e.preventDefault() 方法還是槓槓的。
首先我們要明確一下,什麼是浏覽器的默認行為,舉個栗子:
頁面上有一行文字,如果我選中,然後拖動文字,那麼文字可以被拖動,拖動後再松手,可能被選中的文字就去搜索了,由於此效果不好截圖,你們自己去玩一下,那這一行為就是浏覽器的默認行為;
再舉個栗子:
頁面上有一張圖片,點擊圖片,然後拖動,圖片會好像是復制了一份,然後也是可以被拖動,這也是浏覽器的默認行為,看看IE下的截圖:
這個樣子的,你們應該司空見慣了吧,那浏覽器廠家做的某些默認行為,我們為什麼要想方設法的去阻止掉呢?因為我們在做某些效果的時候,浏覽器的默認行為會影響我們的效果,比如說表單中的提交按鈕,理論上的默認效果是我一點擊就會將我的表單提交出去,
但現實情況可能並不希望它這樣,所以我們需要阻止一下。
好了,我們來說說我們阻止浏覽器的默認行為的神器吧,還是以圖片和文字為例子,
<img src="1.jpg" id="img1" alt=""> <p id="text">聖誕節開發能順利的煩惱時來得快耐腐蝕的快樂你發了十多年兩三點扣年費是考慮到你發來看你</p>
這是我們頁面上的一張圖和一行文字,隨便打的
window.onload = function(){ var oImg = document.getElementById("img1"); var oText = document.getElementById("text"); oImg.onmousedown = function(e){ stopDefault(e); } oText.onmousedown = function(e){ stopDefault(e); } //阻止浏覽器默認行為觸發的通用方法 function stopDefault(e){ //防止浏覽器默認行為(W3C) if(e && e.preventDefault){ e.preventDefault(); } //IE中組織浏覽器行為 else{ window.event.returnValue=false; //實際上在IE8以下,會報錯 return false; } } }
這是用我們的神器來寫的一個小例子,意思是當鼠標按下去的時候,我們來阻止浏覽器的默認行為,看看都有什麼表現,如果圖片和文字不能被拖動,說明是可以阻止默認行為的,如果不能,呵呵,你就慘了~
在標准浏覽器上,good,沒問題,完美,在IE上,IE9以上good,IE8下,呃呃(此處有音效),嗝屁了,它們依然快樂的到處游走,跟它們就沒什麼關系,由此可見,上面的神器是不足以來滿足我們的要求的(毀三觀啊)~
那現在的問題就變了,怎樣才能全面兼容阻止浏覽器的默認行為呢?這就是標題的後半段要講的內容了(主角來了)!
首先,我們要肯定的是 e.preventDefault() 方法是絕對可以在標准浏覽器下阻止默認行為的,但是(重點來了),我們今天不用這個方法,而是用 return false 這個熟悉的老朋友,當然關於return ,我們又可以講一篇長長的博文,像老太太的裹腳布一樣,
這裡我們不講多麼的詳細,就提幾點:
return 表達式是結束函數執行,返回調用函數,沒有返回結果,舉個栗子:
function adc(){ var a=2; var b=3; var sum = 0; return ; sum = a+b; console.log(sum); } adc();
看上面的這個函數,如果沒有return,那麼console就會打印sum的值5,但是恰恰有個return,讓函數在return後就不往下執行,而是返回到調用函數,所以就沒有值了,
那麼return false呢,一般是返回錯誤的處理結果;終止處理;阻止提交表單;阻止執行默認的行為等等,值得注意的是,執行return false,其實是執行了3個行為:
1、執行event.preventDefault(); 阻止浏覽器的默認行為;
2、event.stopPropagation(); 阻止冒泡行為;
3、停止回調函數執行並立即返回。
所以用此方法的時候,必須要考慮,你是否會有阻止冒泡的需求,如果有,我們就必須要用 event.preventDefault();來阻止浏覽器的默認行為了,我們還是來舉個栗子吧(一向的風格就是例子勝於雄辯):
window.onload = function(){ var oImg = document.getElementById("img1"); var oText = document.getElementById("text"); oImg.onmousedown = function(e){ return false; } oText.onmousedown = function(e){ return false; } }
還是用上面的例子,改寫一下,看看效果如何, 恩,標准浏覽器,槓槓的,再看IE,IE9以上依舊如此完美,IE8以下依舊那麼飄逸,好吧,看來我們要解決的梗就是如何使IE8以下浏覽器能乖一點!
要解決這個問題,我先介紹一個方法(閃亮登場):
setCapture() //意思是在窗口設置鼠標捕獲
額,不懂,好吧,我也不懂,那我們就用例子來描述一下:
<input type="button" value="按鈕一"> <input type="button" value="按鈕二">
頁面上有2個按鈕
window.onload = function(){ var aInput = document.getElementsByTagName("input"); //設置全局捕獲,當我們給一個元素設置全局捕獲後,這個元素就會監聽後續的所有事件,當有事件發生的時候,就會被當前設置了全局捕獲的元素所觸發 /* ie : 有,並且有效果 ff : 有,但沒有效果 chrome : 沒有,會報錯 */ aInput[0].setCapture(); aInput[0].onclick = function(){ alert(1); }; aInput[1].onclick = function(){ alert(2); } }
分別給2個按鈕設點擊事件,並且給按鈕一開一個小灶,給它設一個全局的鼠標捕獲,我們來看看,谷歌下,會報錯,不支持,火狐下,沒有報錯,也沒有別的什麼反應,一切正常,說明火狐是支持的,只是沒反應(因為不報錯),IE下,怪異情況就出現了
無論我的鼠標在哪裡點擊,都會彈出1,就算是點擊按鈕2,也會彈出1,點到窗口外,也會彈出1,這是為什麼呢?我查了一下資料,大概的解釋是:
函數功能:該函數在屬於當前線程的指定窗口裡設置鼠標捕獲。一旦窗口捕獲了鼠標,所有鼠標輸入都針對該窗口,無論光標是否在窗口的邊界內。同一時刻只能有一個窗口捕獲鼠標。如果鼠標光標在另一個線程創建的窗口上,只有當鼠標鍵按下時系統才將鼠標輸入指向指定的窗口。
通俗的意思是:當某個元素設置了全局鼠標捕獲,那個這個元素就會監聽後續發生的所以事件,當有事件發生的時候,就會被當前設置了全局捕獲的元素觸發,
所以,我們看上面例子的怪異表現,當鼠標點擊的時候,就會被綁定了全局捕獲的按鈕一所觸發,那會執行按鈕一的點擊事件,所以會彈出1;
那麼它是怎麼來阻止浏覽器的默認行為的呢?舉個栗子:
window.onload = function(){ var oImg = document.getElementById("img1"); var oText = document.getElementById("text"); oImg.onmousedown = function(e){ oImg.setCapture(); } oText.onmousedown = function(e){ oText.setCapture(); } }
我們都知道這個在標准浏覽器上是不行的,我們暫時不管,只看IE的,你會發現,在IE上,一下子就老實了,再也不到處跑了,這是為什麼呢?用上面的解釋就是,因為此時圖片和文字都設了全局鼠標捕獲,不管頁面上有什麼事件發生,都會轉移到它們身上,我們又
沒有給它們寫move事件,所以就很乖乖的在那裡不動了,明白了嗎?
那我們給圖片加個自定義的move事件,看看會怎樣?(此時這裡的圖片是絕對定位的,樣式我就不寫了)
window.onload = function(){ var oImg = document.getElementById("img1"); oImg.onmousedown = function(ev){ var ev = ev || event; var disX = ev.clientX - this.offsetLeft; var disY = ev.clientY - this.offsetTop; if(oImg.setCapture){ oImg.setCapture(); } document.onmousemove = function(ev){ var ev = ev || event; oImg.style.left = ev.clientX - disX + 'px'; oImg.style.top = ev.clientY - disY + 'px'; }; document.onmouseup = function(ev){ document.onmousemove = document.onmouseup = null; if(oImg.releaseCapture){ //取消全局捕獲 oImg.releaseCapture(); } }; return false; } }
運行一下,感覺整個世界都平靜了,再也沒有紛爭了,所以浏覽器都表現一致,這就是一個簡易的拖拽效果,這就是我給我解決方案,不知道你們是否滿意呢!嘻嘻~~
當然,需要特別注意的是(多啰嗦一句):
1、如果是需要阻止所有的默認事件,那麼我們用return false 和 obj.setCapture() 方法一起用;
2、如果我們僅僅只是想阻止浏覽器的默認行為,可以用event.preventDefault() 與 obj.setCapture()方法一起用,這裡是考慮到冒泡;
好了,基本上就這些了,阻止冒泡方法我也試了一下,還是挺兼容的,代碼我也貼一下,換算優惠大贈送吧!
if ( e.stopPropagation ){ //標准浏覽器 e.stopPropagation(); }else{ //兼容IE的方式來取消事件冒泡 window.event.cancelBubble = true; }
以上方法只是個人意見,如有什麼理解的不對的,或者是有錯誤的地方,歡迎批評指正,也歡迎大家跟我交流技術方面的知識,謝謝大家!
ps:如果你看過我寫的pc拖拽效果,請看的時候參考一下本文,哪裡的阻止默認事件寫錯了,記得修改!