用`visibilitychange`事件實現吸睛的十八禁

不愛吃蕃茄的魚發表於2016-11-17

用`visibilitychange`事件實現吸睛的十八禁
18禁

我知道你們都是看這圖進來的,但是這個圖跟下面的內容沒有必然聯絡。

前不久在網上找資料的時候突然發現某個頁面的 title 是啥※18♥禁★電影【線上觀看】☆...,突然就心頭一緊,是哪個頁面咋還自動彈廣告頁,還是新標籤頁面開啟的。當時我的表情就是這樣。

用`visibilitychange`事件實現吸睛的十八禁

懷著就像你們看我題圖就點進來的心情點開了那個頁面,耶,正常的內容啊!剛剛那個18禁呢?!

用`visibilitychange`事件實現吸睛的十八禁

冷靜了一下,就想這是個trick啊,然後我就自己動手實現了一個。
效果就像這個樣子。

這本來是個動態圖,看這裡

用`visibilitychange`事件實現吸睛的十八禁

實際上,這部分程式碼我已經作為一個模組開源在我的部落格裡了,沒單獨分離出來。 interesting-title.js
這個檔案的歷史commits資訊中暴露了一些奇奇怪怪的連結,老司機開車就是開的這麼觸不及防。不要問我要邀請碼,我也沒種子。

用`visibilitychange`事件實現吸睛的十八禁

下面,我就來教你手把手實現這個trick。

首先,我們先分析需求。

基本功能是在頁面被隱藏的時候顯示一些勁爆的title,開個小玩笑;
當使用者點選進來的時候(也就是頁面正常顯示的時候)顯示正常的title。

接著,分析下技術要點。

  • document.title 修改標題
  • visibilitychange 事件來監聽頁面是否隱藏

挺簡單的嘛,我們們開幹!

動態的修改title

  function interesting(title) {
    // origin info
    let originTitle = document.title;

    // interesting info
    title = title || '※18♥禁★電影【線上觀看】☆...';

    // get prefix support for ...
    let hidden, visibilityChange;
    ['', 'o', 'ms', 'moz', 'webkit'].forEach(prefix => {
      let supportHidden = prefix + (prefix ? 'Hidden' : 'hidden');
      if (typeof document[supportHidden] === 'undefined') return;
      hidden = supportHidden;
      visibilityChange = prefix + 'visibilitychange';
    });

    // not support for return
    if (typeof document.addEventListener === 'undefined' || typeof document[hidden] === 'undefined') return;

    // start interesting
    document.addEventListener(visibilityChange, function() {
      document.title = document[hidden] ? title : originTitle;
    }, false);
  }複製程式碼

很完美啊,根本攔不到我們這種老司機。

看我這結構,多優雅,還支援自定義 title 呢。

用`visibilitychange`事件實現吸睛的十八禁

“喲,小安啊,這能幹咋不上天呢”

好吧,上天我們是不行的,但我們還得繼續優化使用者體驗,要給使用者那種突然發現這個頁面的心頭一震!然後又會心一笑的美妙落差啊。

既然是18禁,當然要裝的像的一點。那哪兒不像呢?

隔壁桌的小草同志看了看說:“一般這種網站的標題不總是動來動去的麼”

很有經驗啊,我的小草。

用`visibilitychange`事件實現吸睛的十八禁

來,給標題加個跑馬燈。

  // start interesting
  document.addEventListener(visibilityChange, horseRaceLamp, false);

  let timer;
  function horseRaceLamp() {
    if (document[hidden]) {
      document.title = title;
      if (!noRunTitle) timer = setInterval(() => {
        let str = document.title;
        document.title = str.substr(1, str.length - 1) + str[0];
      }, 50);
    } else {
      document.title = originTitle;
      if (timer || timer === 0) clearInterval(timer);
    }
  }複製程式碼

“這麼[遮蔽字]真!”

咳咳,請注意措辭,不要講髒話!

本著使用者體驗的角度,總感覺哪兒不對啊,還有哪兒可以改改呢?

隔壁桌的小林同學聽到小草同志的驚歎也湊過來瞅瞅。好傢伙,才一過來,就說,這不錯啊,就是那個 favicon 看著太不像了啊。

厲害了,我的小林同學,你是怎麼一眼就發現這個核心問題的!

來來來,我們聊聊。

在小林的幫助下,我順利的找到了某榴社群的 favicon ,還不小心把那社群的地址也給提到版本里了 = =、

擼起袖子就是一頓寫。

  const originFavicon = getFaviconEle();
  const originFaviconHref = originFavicon.href;

  const defaultFavicon = 'http://****.****.com/favicon.ico';
  favicon = favicon || defaultFavicon;

  function getFaviconEle(href) {
    let ele = document.querySelector('link[rel="shortcut icon"]') || document.querySelector('link[type*=image]');
    if (ele) return ele;
    href = href || '/favicon.ico';
    ele = document.createElement('link');
    ele.setAttribute('rel', 'shortcut icon');
    ele.setAttribute('href', href);
    document.querySelector('head').appendChild(ele);
    return ele;
  }

  // 更新跑馬燈方法
  function horseRaceLamp() {
    if (document[hidden]) {
      document.title = title;
      if (originFavicon) originFavicon.href = favicon;
      if (!noRunTitle) timer = setInterval(() => {
        let str = document.title;
        document.title = str.substr(1, str.length - 1) + str[0];
      }, 50);
    } else {
      document.title = originTitle;
      if (originFavicon) originFavicon.href = originFaviconHref;
      if (timer || timer === 0) clearInterval(timer);
    }
  }複製程式碼

這下子就看起來萬事大吉了啊。
最後用 base64 轉一下 favico 再合併一下前面的所有程式碼,大概有50多行,再優化一下預設傳參,再加個是否啟動替換 favico 的開關,就齊活了啊,來看一下最終的程式碼。

  const defaultFavicon = 'data:image/vnd.microsoft.icon;base64,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';

  export default function({ title, favicon, noRunTitle, noRunFavicon } = { noRunTitle: false, noRunFavicon: false }) {
    // origin info
    let originTitle = document.title;
    let originFavicon, originFaviconHref;
    if (!noRunFavicon) {
      originFavicon = getFaviconEle();
      originFaviconHref = originFavicon.href;
    }

    // interesting info
    title = title || '※18♥禁★電影【線上觀看】☆...';
    favicon = favicon || defaultFavicon;

    // get prefix support for ...
    let hidden, visibilityChange;
    ['', 'o', 'ms', 'moz', 'webkit'].forEach(prefix => {
      let supportHidden = prefix + (prefix ? 'Hidden' : 'hidden');
      if (typeof document[supportHidden] === 'undefined') return;
      hidden = supportHidden;
      visibilityChange = prefix + 'visibilitychange';
    });

    // not support for return
    if (typeof document.addEventListener === 'undefined' || typeof document[hidden] === 'undefined') return;

    // start interesting
    document.addEventListener(visibilityChange, horseRaceLamp, false);

    let timer;

    function horseRaceLamp() {
      if (document[hidden]) {
        document.title = title;
        if (originFavicon) originFavicon.href = favicon;
        if (!noRunTitle) timer = setInterval(() => {
          let str = document.title;
          document.title = str.substr(1, str.length - 1) + str[0];
        }, 50);
      } else {
        document.title = originTitle;
        if (originFavicon) originFavicon.href = originFaviconHref;
        if (timer || timer === 0) clearInterval(timer);
      }
    }
  }

  function getFaviconEle(href) {
    let ele = document.querySelector('link[rel="shortcut icon"]') || document.querySelector('link[type*=image]');
    if (ele) return ele;
    href = href || '/favicon.ico';
    ele = document.createElement('link');
    ele.setAttribute('rel', 'shortcut icon');
    ele.setAttribute('href', href);
    document.querySelector('head').appendChild(ele);
    return ele;
  }複製程式碼

如果覺得這篇文章不錯,就給我點個star吧,如果想持續關注我的部落格,就點個watch

謝謝! 我的部落格

說了這麼多廢話!

用`visibilitychange`事件實現吸睛的十八禁

相關文章