【譯】用 JavaScript 和 Emoji 做位址列動畫

W、peach發表於2019-01-24

你可以在位址列使用 emoji(和其它圖形 unicode 字元),這看著很棒,但是好像沒人這麼做,為什麼呢?也許 emoji 對於正常的網路平臺來說太過異國情調了?或許是他們因為害怕不利於SEO?

不管什麼原因,維恩圖中的合理性觀點“沒人這麼做,但這是可能的”是讓我興奮的點。所以我決定花費一些時間研究在位址列中圖形字元的可能性,特別是通過 JavaScript 給這些字元加上動畫。

迴圈動畫

首先,確保你頁面的 JavaScript 程式碼是 UTF-8 編碼,否則無法在你的程式碼中顯示 emoji,這可以通過設定 HTTP 頭部或頁面的 META 標籤來實現。你很可能不用擔心這個,但你可以在這裡找到更多資訊:Unicode in Javascript by Flavio

為了達到我們想要的效果,讓 emoji 像小仙女一樣在位址列裡偏偏起舞,我們需要一個迴圈,實際上,我們所需要的只是一個迴圈,我們啟動這個迴圈,它不斷迴圈,我們的目的就達到了。這是我們的第一個迴圈動畫,一個旋轉的emoji 月亮。我猜當他們新增這個 emoji 序列時,也有這個想法吧?

moon.gif

    var f = ['?', '?', '?', '?', '?', '?', '?', '?'];

    function loop() {
        location.hash = f[Math.floor((Date.now()/100)%f.length)];

        setTimeout(loop, 50);
    }

    loop();
複製程式碼

執行程式碼,你可以在位址列看到此迴圈的結果。

如果你不喜歡旋轉的月亮,你可以選擇任何你喜歡的 emoji 來替換這個陣列,比如一個時鐘:

clock.gif

var f = ['?','?','?','?','?','?','?','?','?','?','?','?'];
複製程式碼

這是一個非常簡單的例子,真的非常簡單,所以我們來升級一下迴圈,讓它顯示一串 emoji ! 這次我們使用 emoji 的skin tone modifiers膚色調節屬性來製作一些變色寶寶:

babies2.gif

    var e = ['?', '?', '?', '?', '?'];

    function loop() {
        var s = '',
            i, m;

        for (i = 0; i < 10; i ++) {
            m = Math.floor(e.length * ((Math.sin((Date.now()/100) + i)+1)/2));
            s += '?' + e[m];
        }

        location.hash = s;

        setTimeout(loop, 50);
    }

    loop(); 
複製程式碼

我們可以使用時間和位置控制的正弦波來選擇我們想要的顏色,這給了我們一個很好的顏色變幻效果!

比如我們再來一次月亮旋轉,使它展開,製作一個類似於載入條的動畫?好的,開始實現:

moons.gif

    var f = ['?', '?', '?', '?', '?', '?', '?', '?'],
        d = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        m = 0;

    function loop() {
        var s = '', x = 0;

        if (!m) {
            while (d[x] == 4) {
                x ++;
            }

            if (x >= d.length) m = 1;
            else {
                d[x] ++;
            }
        }
        else {
            while (d[x] == 0) {
                x ++;
            }

            if (x >= d.length) m = 0;
            else {
                d[x] ++;

                if (d[x] == 8) d[x] = 0;
            }
        }

        d.forEach(function (n) {
            s += f[n];
        });

        location.hash = s;

        setTimeout(loop, 50);
    }

    loop();
複製程式碼

探索其它字元

不止是 emoji 給我們提供了一種在位址列顯示圖形的方法,我們的目標中也有一些 unicode 字元。

特別有趣的是 框線字元:

box-characters.png

它們中很多更適合二維輸出,但它們在一維輸出也很棒,例如,我們可以建立一個多個高度變化的塊字串,並構造一個漂亮的小波浪動畫:

wavy.gif

    function loop() {
        var i, n, s = '';

        for (i = 0; i < 10; i++) {
            n = Math.floor(Math.sin((Date.now()/200) + (i/2)) * 4) + 4;

            s += String.fromCharCode(0x2581 + n);
        }

        window.location.hash = s;

        setTimeout(loop, 50);
    }

    loop();
複製程式碼

我非常喜歡它的效果,我把它永久放在了 wavyurl.com 上。

使用可變寬度字元,我們甚至在水平方向上擺動,建立類似於進度條的東西:

progress.gif

    function loop() {
        var s = '',
            p;

        p = Math.floor(((Math.sin(Date.now()/300)+1)/2) * 100);

        while (p >= 8) {
            s += '█';
            p -= 8;
        }
        s += ['⠀','▏','▎','▍','▌','▋','▊','▉'][p];

        location.hash = s;
        setTimeout(loop, 50);
    }
複製程式碼

進度條?這看起來,還是有用的,這讓我想到了……

在位址列顯示視訊進度

為了增加我們小實驗的可能性,我提出了在位址列中顯示網路視訊進度的想法。我只需附加一個函式,將我們的進度字串定義在視訊的timeupdate事件中,瞧!位址列中的視訊進度條包含時間和持續時間!

video-progress.gif

    var video;

    function formatTime(seconds) {
        var minutes = Math.floor(seconds/60),
            seconds = Math.floor(seconds - (minutes*60));

        return ('0'+minutes).substr(-2) + ':' + ('0'+seconds).substr(-2);
    }

    function renderProgressBar() {
        var s = '',
            l = 15,
            p = Math.floor(video.currentTime / video.duration * (l-1)),
            i;

        for (i = 0; i < l; i ++) {
            if (i == p) s +='◯';
            else if (i < p) s += '─';
            else s += '┄';
        }

        location.hash = '╭'+s+'╮'+formatTime(video.currentTime)+'╱'+formatTime(video.duration);
    }

    video = document.getElementById('video');
    video.addEventListener('timeupdate', renderProgressBar);
複製程式碼

我比較喜歡這個線條和圓組成的進度條,如果你喜歡別的 emoji 比如月亮,我也能讓你滿意:

video-moons.gif

    var e = ['?', '?', '?', '?', '?'],
        video;

    function formatTime(seconds) {
        var minutes = Math.floor(seconds/60),
            seconds = Math.floor(seconds - (minutes*60));

        return ('0'+minutes).substr(-2) + ':' + ('0'+seconds).substr(-2);
    }

    function renderProgressBar() {
        var s = '',
            c = 0,
            l = 10,
            p = Math.floor(video.currentTime / video.duration * ((l*5)-1)),
            i;

        while (p >= 5) {
            s += e[4];
            c ++;
            p -= 5;
        }
        s += e[p];
        c ++;

        while (c < l) {
            s += e[0];
            c ++;
        }

        location.hash = s+formatTime(video.currentTime)+'╱'+formatTime(video.duration);
    }

    video = document.getElementById('video');
    video.addEventListener('timeupdate', renderProgressBar);
複製程式碼

好的,將此進度條稱為“有用”的延伸。 只瞄一眼,我也可以看到在視訊分享 URL 中的進度。 與YouTube一樣,你可以選擇在特定時間建立指向視訊的連結,新增視覺指示是不是很酷?嗯?

也許我還沒有提出一些更有用的“技術”實現,我會繼續思考這個問題。 嘿,也許你可以嘗試一些東西?

最後

你可能想知道為什麼我使用location.hash =,而不是新且酷的HTML5 History API。 有兩個原因:

第一個問題是 History API有一個特點:它實際上更改了整個 URL 路徑,而不僅僅是 hash。 因此,如果我使用 History API 並將頁面更改為/?????,它看起來會比新增 # 更好。 但這也意味著我的 Web 伺服器必須能夠響應/?????,否則如果使用者重新整理或以其他方式導航到修改後的 URL 將會失敗。 這是可行的,但比使用location.hash =更復雜,需要我修改伺服器配置。

第二個問題有些出乎意料。 實際上,在我測試的3個瀏覽器中,有2個歷史API被限制的。 如果我以極快的速度將我的波形網址推送到位址列,我最終會在 Chrome 中收到以下錯誤:

Throttling history state changes to prevent the browser from hanging.

Safari 給我們提供了更詳細的資訊:

SecurityError: Attempt to use history.pushState() more than 100 times per 30.000000 seconds

現在,如果讓我保持在這個限制下也行,但是每秒3幀只是不會影響我目前的動畫效果。

好孩子 Firefox 似乎並不在乎我推送新歷史的次數和速度,這真是想得太周到了。但是,兩個主要的瀏覽器受到影響,加上需要web伺服器配置來修復第一個問題,使我更願意忍受 URL 中的 #。

結語

我就講到這裡。但我要告訴你,我還有一些想法,讓小遊戲顯示在位址列。特別是考慮到盲文字元我們還沒有探索,所以請繼續關注。

如果你有任何問題、評論,或者只是想了解我的最新進展,請在 Twitter 上關注我: @MatthewRayfield。或者點這裡訂閱我的幾乎從未被打擾過的電子郵件。

哦,如果你想要以上示例的原始碼,點這下載

相關文章