【譯】用 JavaScript 和 Emoji 作地址欄動畫

你能夠在地址欄使用 emoji(和其它圖形 unicode 字符),這看着很棒,可是好像沒人這麼作,爲何呢?也許 emoji 對於正常的網絡平臺來講太過異國情調了?或許是他們由於懼怕不利於SEO?javascript

無論什麼緣由,維恩圖中的合理性觀點「沒人這麼作,但這是可能的」是讓我興奮的點。因此我決定花費一些時間研究在地址欄中圖形字符的可能性,特別是經過 JavaScript 給這些字符加上動畫。java

循環動畫

首先,確保你頁面的 JavaScript 代碼是 UTF-8 編碼,不然沒法在你的代碼中顯示 emoji,這能夠經過設置 HTTP 頭部或頁面的 META 標籤來實現。你極可能不用擔憂這個,但你能夠在這裏找到更多信息:Unicode in Javascript by Flaviogit

爲了達到咱們想要的效果,讓 emoji 像小仙女同樣在地址欄裏恰恰起舞,咱們須要一個循環,實際上,咱們所須要的只是一個循環,咱們啓動這個循環,它不斷循環,咱們的目的就達到了。這是咱們的第一個循環動畫,一個旋轉的emoji 月亮。我猜當他們添加這個 emoji 序列時,也有這個想法吧?github

moon.gif

var f = ['🌑', '🌒', '🌓', '🌔', '🌝', '🌖', '🌗', '🌘'];

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

        setTimeout(loop, 50);
    }

    loop();
複製代碼

運行代碼,你能夠在地址欄看到此循環的結果。web

若是你不喜歡旋轉的月亮,你能夠選擇任何你喜歡的 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 字符。ide

特別有趣的是 框線字符:

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。或者點這裏訂閱個人幾乎從未被打擾過的電子郵件。

哦,若是你想要以上示例的源代碼,點這下載

相關文章
相關標籤/搜索