Turbolinks 實例:為什麼 scroll 報錯?來給 jQuery event 取個名稱

紅寶鐵軌客
來關注...
關注/停止關注:紅寶鐵軌客
關注有什麼好處?:當作者有新文章發佈時,「思書」就會自動通知您,讓您更容易與作者互動。
現在就加入《思書》,你就可以關注本作者了!
《思書》是一個每個人的寫作與論壇平台,特有的隱私管理,讓你寫作不再受限,討論更深入真實,而且免費。 趕快來試試!
還未加入《思書》? 現在就登錄! 已經加入《思書》── 登入
寫程式中、折磨中、享受中 ......
868   0  
·
2019/04/15
·
5分鐘


我剛剛碰到了一個有趣的問題,我要用 jQuery 來檢查網頁的位置,當網頁轉到那裡時,就把一個 DOM 顯示出來,很簡單,就給 window 裝上一個 scroll event 吧:

$(window).on( "scroll", function(){
    if ( $(window).scrollTop() > $("#JS-target").offset().top){
      $('#JS-target').find(".#JS-target-overlap").css({
             'visibility' : 'visible',
             'opacity' : '1'
      });
    };
});

如果你是在沒有 Turbolinks 的環境下,就這麼簡單,但是,這樣的一個簡單功能,在 Turbolinks 上,馬上就會有問題了,你第一頁不會有問題,但是點選網頁的連結後,就會一直看到聯覽器的 console 上,不斷的說找不到 #JS-target,你會覺得很奇怪,明明這個連結的網頁並沒有這個 Javascript,為什麼還會執行?

如果你還沒有看過我寫的這篇文章:

Rails Turbolinks™ 5 深度研究 — 不管你是愛、還是恨(說得有點超過),但是真的很多 Rails 人乾脆把 Turbolinks 關掉了。 我還是繼續使用中... 什麼是...
Scrivinor 思書: 紅寶鐵軌客

我建議有空可以看看,只是還蠻長的,如果你很急著要知道答案,我就直接說:問題的根源就是,Turbolinks 已經把你的網頁變成 SPASingle Page Application,單頁式應用網站)了。

在 Turbolinks 使用中,你點選了一個連結,Turbolinks 只是把 <body> 的內容換掉了,<head> 的內容都保留,更重要的是,你曾經掛上的 Javascript event,當然也被保留了,這也就是這個 scroll event 為什麼還會繼續執行的原因。

這 「SPA 單頁式應用網站」的觀念,是在使用 Turbolinks 中,最重要必須要了解的其中一項觀念,不然,你的 BUG 都會在點選網頁連結後發生,很多情況下,甚至不被發現!

那我們實務上要怎麼寫呢?下面是一個解法:

$(document).on('turbolinks:load', function() {
  if ($('#JS-target').length > 0) {
    $(window).on( "scroll.event_target", function(){
        if ( $(window).scrollTop() > $("#JS-target").offset().top){
          $('#JS-target').find(".#JS-target-overlap").css({
                 'visibility' : 'visible',
                 'opacity' : '1'
          });
        };
    });
  }
  else {
    $(window).off( "scroll.event_target" );
  }
});

讓我們來看看這程式的重點:

  1. $(document).on('turbolinks:load', function() 就不在此介紹了,這是一個很標準的 Turbolinks 取代 $(document).ready() 的啟動方式。
  2. if ($('#JS-target').length > 0):先判斷目標 DOM 存不存在,如果存在,才執行需要的 Javascript,我覺得這是一個好習慣,先檢查這頁要不要執行需要的 Javascript,很多人沒寫,我不喜歡,我相信對效率一定有影響,特別是使用者長時間使用不同的網頁。
  3. $(window).on( "scroll.event_target", function():如果存在,就把 event 掛到 on scroll 上,這也是先前的程式,除了多了一個 event_target,這是什麼?我等一下專門說。
  4. $(window).off( "scroll.event_target" ):如果不存在,就把這個 on scoll 的 event 卸載,off 掉,這就是針對 Turbolink 「SPA 單頁式應用網站」特別加上的,因為 Turbolinks 在跳轉到另一頁時,如前所述,你曾經掛上的 Javascript event,都會被保留,如果不把這個 event卸載 off 掉,它就會繼續執行,所以,增加的這一行是針對 Turbolinks 使用上,很重要的 
Event 的 namespace

如果看過我其他文章的人,因該都知道我很喜歡 jQuery,主要是 jQuery 對跨瀏覽器的相容性真是太好用了,電腦跑那麼快,給 jQuery 拖慢一些,我覺得還好啦,我應該是很少數敢公開說 jQuery 好話的人,大家現在談到 jQuery 好像都很不屑,好啦,廢話不多說,我們現在就來談談什麼是那個「event_target」,其實很簡單,就是給這個 event 取個名稱,這也是使用 jQuery 的一個小好處,就直接取名就好,這個 event 就叫做「event_target」,你如果用 Javascript 就要自己寫 namespace 了。

那為什麼要給這個 event 取個名稱呢?因為我們真的可以直接用 $(window).off( ) 卸載 off 掉所有的 event 但是你知道你其他的 Javascript 沒有用到 $(window) 這個物件嗎?$(window).off( "scroll" ) 也一樣,萬一別的地方也用的 scroll event,那你就是把它全關了,這可不行啊,這樣做,你以後只會抓蟲抓到昏倒,所以,你只能卸載 off 掉這一個 event,這一個名叫「event_target」的 event。

jQuery 如何 off 掉指定的 event?

結果,超簡單,只要給它取個名(namespace)就好了,在掛 event 時:

$(window).on( "scroll.myname", function(){... 

把它 off 掉時:

$(window).off( "scroll.myname")

就這樣,超簡單好用!

$(window) 也是一個有趣的東西,它是 jQuery 包裹著 window 的物件,而 window 是一個 global 環境變數,照理,我給 window 加上了一個 event,他就應該是 global 的,這樣,網頁上每一頁都會執行這個 event 了,是這樣嗎?我是沒試過啦,不知道有沒有人試過?

參考:

Namespaced Events in jQuery | CSS-Tricks — It's really easy to add an event listener in jQuery. It's equally easy to remove an event listener. You might want to remove a listener because you don't CSS-Tricks


喜歡作者的文章嗎?馬上按「關注」,當作者發佈新文章時,思書™就會 email 通知您。

思書是公開的寫作平台,創新的多筆名寫作方式,能用不同的筆名探索不同的寫作內容,無限寫作創意,如果您喜歡寫作分享,一定要來試試! 《 加入思書》

思書™是自由寫作平台,本文為作者之個人意見。


文章資訊

本文摘自:
分類於:
標籤:
日期:
創作於:2019/04/15,最後更新於:2019/08/17。
合計:1223字


分享這篇文章:
關於作者

很久以前就是個「寫程式的」,其實,什麼程式都不熟⋯⋯
就,這會一點點,那會一點點⋯⋯




參與討論!
現在就加入《思書》,馬上參與討論!
《思書》是一個每個人的寫作與論壇平台,特有的隱私管理,用筆名來區隔你討論內容,讓你的討論更深入,而且免費。 趕快來試試!
還未加入《思書》? 現在就登錄! 已經加入《思書》── 登入


看看作者的其他文章


看看思書的其他文章



×
登入
申請帳號

需要幫助
關於思書

暗黑模式?
字體大小
成人內容未過濾
更改語言版本?