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

紅寶鐵軌客
Join to follow...
Follow/Unfollow Writer: 紅寶鐵軌客
By following, you’ll receive notifications when this author publishes new articles.
Don't wait! Sign up to follow this writer.
WriterShelf is a privacy-oriented writing platform. Unleash the power of your voice. It's free!
Sign up. Join WriterShelf now! Already a member. Login to WriterShelf.
寫程式中、折磨中、享受中 ......
868   0  
·
2019/04/15
·
5 mins read


我剛剛碰到了一個有趣的問題,我要用 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


WriterShelf™ is a unique multiple pen name blogging and forum platform. Protect relationships and your privacy. Take your writing in new directions. ** Join WriterShelf**
WriterShelf™ is an open writing platform. The views, information and opinions in this article are those of the author.


Article info

This article is part of:
Categories:
Tags:
Date:
Published: 2019/04/15 - Updated: 2019/08/17
Total: 1223 words


Share this article:
About the Author

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




Join the discussion now!
Don't wait! Sign up to join the discussion.
WriterShelf is a privacy-oriented writing platform. Unleash the power of your voice. It's free!
Sign up. Join WriterShelf now! Already a member. Login to WriterShelf.