RavelloH's Blog

LOAD ing ...



Virgule.js现已发布

技术/ 设计 ----字 ---

JAVASCRIPT


前言

22年暑假时,我把博客首页的打字机特效换成了类似于现在这种,但是当时也是随便做出来玩玩的,不仅功能单一,结构臃肿,用了530行js也只能达到让主页有两句循环的轮播,实在太不优雅。
今年十月初我决定重制这个功能将其从530行压缩到370行,并在原有的基础上加入了跳过空格、自定义速度、快捷引用目标等功能,并将其封装为函数,现在想要使用只需一句:

                                    virgule(target,context,speed)
            
太优雅了。
项目现已开源。@Github:RavelloH/virgule.js



效果

升级前后对比

升级前

升级前

升级后

升级后

即时体验

上方左侧填入替换内容,右侧设置速度...



使用

直接引入JavaScript脚本

                                <script src="https://ravelloh.github.io/virgule.js/virgule.js"></script>
            

手动复制源代码

                                // Author:RavelloH
                // LICENCE: MIT
                // Repo src: github.com/RavelloH/virgule.js
                randArrMin = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9"];
                randArr = ["あ","ぃ","い","ぅ","う","ぇ","え","ぉ","お","か","が","き","ぎ","く","ぐ","け","げ","こ","ご","さ","ざ","し","じ","す","ず","せ","ぜ","そ","ぞ","た","だ","ち","ぢ","っ","つ","づ","て","で","と","ど","な","に","ぬ","ね","の","は","ば","ぱ","ひ","び","ぴ","ふ","ぶ","ぷ","へ","べ","ぺ","ほ","ぼ","ぽ","ま","み","む","め","も","ゃ","や","ゅ","ゆ","ょ","よ","ら","り","る","れ","ろ","ゎ","わ","ゐ","ゑ","を","ん","ゔ","ゕ","ゖ","ァ","ア","ィ","イ","ゥ","ウ","ェ","エ","ォ","オ","カ","ガ","キ","ギ","ク","グ","ケ","ゲ","コ","ゴ","サ","ザ","シ","ジ","ス","ズ","セ","ゼ","ソ","ゾ","タ","ダ","チ","ヂ","ッ","ツ","ヅ","テ","デ","ト","ド","ナ","ニ","ヌ","ネ","ノ","ハ","バ","パ","ヒ","ビ","ピ","フ","ブ","プ","ヘ","ベ","ペ","ホ","ボ","ポ","マ","ミ","ム","メ","モ","ャ","ヤ","ュ","ユ","ョ","ヨ","ラ","リ","ル","レ","ロ","ヮ","ワ","ヰ","ヱ","ヲ","ン","ヴ","ヵ","ヶ","ヷ","ヸ","ヹ","ヺ","ー","ヾ","ㄅ","ㄆ","ㄇ","ㄈ","ㄉ","ㄊ","ㄋ","ㄌ","ㄍ","ㄎ","ㄏ","ㄐ","ㄑ","ㄒ","ㄓ","ㄔ","ㄕ","ㄖ","ㄗ","ㄘ","ㄙ","ㄝ","ㄞ","ㄟ","ㄠ","ㄡ","ㄢ","ㄣ","ㄤ","ㄥ","ㄦ","ㄧ","ㄨ","ㄩ","〇","口","甲","乙","丙","丁","戊","己","庚","辛","壬","癸",];
                
                function virgule(target, context, speed = 100) {
                    //context重组
                    contextArr = [];
                    for (var i = 0; i < context.length; i++) {
                        contextArr.push(context[i])
                    }
                    // 添加/
                    target.innerHTML = "";
                    numVirgule = 0
                    var virgulegenerate = setInterval(
                        function() {
                            // 字符划分
                            if (escape(contextArr[numVirgule]).indexOf("%u") < 0) {
                                if (contextArr[numVirgule] == ' ') {
                                    target.innerHTML += ' '
                                } else {
                                    target.innerHTML += '/'
                                }
                            } else {
                                target.innerHTML += '//'
                            }
                            numVirgule += 1
                            if (numVirgule > context.length) {
                                clearInterval(virgulegenerate);
                                target.innerHTML = target.innerHTML.slice(0, target.innerHTML.length-1)
                                setTimeout(function() {
                                    textIn()}, 100)
                            }
                        },
                        1000/speed)
                
                    // 文字进入
                    numIn = 0;
                    numCharacter = 0;
                    function textIn() {
                        originText = target.innerHTML;
                        var virgulereplace = setInterval(
                            function() {
                                numIn += 1
                                if (numIn >= contextArr.length) {
                                    clearInterval(virgulereplace)
                                    textwrite()
                                }
                                cacheText = ''
                                numCharacter = 0
                                for (i = 0; i < numIn; i++) {
                                    if (escape(contextArr[i]).indexOf("%u") < 0) {
                                        if (contextArr[i] == ' ') {
                                            cacheText += ' '
                                            numCharacter += 1
                                        } else {
                                            //单字符
                                            var rand = Math.floor(Math.random() * randArrMin.length);
                                            cacheText += randArrMin[rand]
                                            numCharacter += 1
                                        }
                                    } else {
                                        // 双字符
                                        var rand = Math.floor(Math.random() * randArr.length);
                                        cacheText += randArr[rand]
                                        numCharacter += 2
                                    }
                                }
                                target.innerHTML = cacheText + originText.slice(numCharacter, originText.length)
                            },
                            2000/speed)
                
                        // 原始文字写入
                        numWrite = 0
                        function textwrite() {
                            originText = target.innerHTML;
                            var virgulewrite = setInterval(
                                function() {
                                    numWrite += 1
                                    if (numWrite >= contextArr.length) {
                                        clearInterval(virgulewrite)
                                    }
                                    cacheText = ''
                                    numCharacter = 0
                                    for (i = 0; i < numIn; i++) {
                                        if (escape(contextArr[i]).indexOf("%u") < 0) {
                                            if (contextArr[i] == ' ') {
                                                cacheText += ' '
                                                numCharacter += 1
                                            } else {
                                                //单字符
                                                var rand = Math.floor(Math.random() * randArrMin.length);
                                                cacheText += randArrMin[rand]
                                                numCharacter += 1
                                            }
                                        } else {
                                            // 双字符
                                            var rand = Math.floor(Math.random() * randArr.length);
                                            cacheText += randArr[rand]
                                            numCharacter += 2
                                        }
                                    }
                                    target.innerHTML = context.slice(0, numWrite) + cacheText.slice(numWrite, cacheText.length) + originText.slice(numCharacter, originText.length)
                                },
                                2000/speed)
                
                        }
                    }
                }
            


用以上任意一种方法,获取到JS即可。接下来就是如何使用,也十分方便:

                                                            virgule(target,context,speed) //target context必填,speed可选填,默认100
                //example:
                virgule(document.getElementById('jumping'), 'Place the text you want as the result here',100)
                //对文档中一个id为jumping的元素使用virgule效果,目标文字是"Place the text you want as the result here",速度为100

            
需要注意的是,此项目需搭配等宽字体使用,如自带的Courier New、Terminal等,或者自己引入其他等宽字体。
这里推荐Microsoft Yahei Mono和SF Mono SC。

实现方法

注:下方行数表示以上Js代码所处行数。
4-5:定义了两个列表randArrMin以及randArr,前者用于一个英文字符宽的字符的替换,后者用于一个中文字符宽的替换。
7:定义了virgule的主函数,默认参数中targetcontext必填,speed选填,默认100。
8-12:将context中的内容转换到contextArr中储存。
14-15:重置目标
16-36:创建延迟循环virgulegenerate,间隔1000/speed毫秒。

  • 18-28:判断中英文,中文插入两个/,英文插入一个/,空格插入空格。
  • 29-34:判断何时结束斜杠的插入动作,延迟100ms唤起textIn()
  • 39-40:重置变量
    41-109:textIn()主函数,用于将生成的斜杠替换为context文字。
  • 43:创建定时器virgulereplace,间隔2000/speed毫秒
  • 46-49:终止器,用于在此环节结束后呼出下一个操作函数textWrite()
  • 52-69:二次递归循环,用于按上一级循环进行量将对应数量斜杠替换为随机文字,同样分双字符、单字符、空格三种情况。
  • 70:对应写入,切分随机字符组与斜杠字符组,保证总长度不变。
  • 16-108:textIn()函数下的二级函数textWrite(),用于在将target中所有字符替换为随机字符后,继续将随机字符替换为context()
  • 79-83:在所有过程结束后终止定时器
  • 86-103:同52-69,将contextArr中内容逐个添加进去。
  • 104:重组字符串,酱三个列表中的内容整合写入target中。

  • 关键分析

    其实整个过程中最复杂的是三个插入过程的顺序。这简单来说,分为以下三个阶段:
    1.用斜杠覆盖文本。
    2.逐渐将斜杠替换为随机文字。这一过程中,每将一个斜杠组替换一个新字符,就会重新将它前面的随机字符再随机化。
    3.用target中的文字替换随机文字。这一过程大体与2相反,没将一个随机字符替换为目标字符,就会刷新其后的随机字符。

    以上三个过程顺次进行,每个过程完成后唤起下一个过程。如果还不理解,可以在#效果章节的在线体验中,选择较低的速度运行,以理解这三个过程。

    后言

    上述就是virgule.js现有的功能介绍和使用方法,顺带着也写了大体的实现方法。
    本来打算把virgule效果应用给整个博客的,但碍于实在找不到什么地方再去添加,先鸽了。

    INFO

    00:00


    无正在播放的音乐
    00:00/00:00