《從案例中學習JavaScript》之實現對話效果(3)

上一節傳送門:《從案例中學習JavaScript》之實現對話效果(2)-- 附超簡單函數封裝技巧

本節涉及的知識點:

  • div元素的 scrollHeight 和 clientHeight
  • 開關變量的使用技巧

先聲明一下,這個案例是我臨時想出來的,當時覺得挺好玩的,所以開始做。算是一次嘗試吧,這不是講解真正的游戲開發,雖然H5是可以做游戲開發的,不過我還沒有去深入研究過。更何況這個案例比較基礎,還沒有用h5。

本案例的目的還是借由一個例子來講解JavaScript的知識點,沒別的意思。

繼續上一節的內容,本節實現效果:文字填滿對話框的時候,自動停住,需要用戶手動去點擊一下,然后進行下一段對話。

上一節的代碼中,我們將實現邏輯封裝成一個方法

var gameDialog = function(id,text,speed){
    var innerBox = document.getElementById(id);
    var text = text;
    var len = text.length;
    var timer = null;
    var index = 0;
    
    timer = setInterval(function(){
        if(index == len){
            clearInterval(timer);
        }
        innerBox.innerHTML += text.charAt(index++);
    },speed);
}

函數的封裝極大地實現了代碼的復用,調用方法后,就可以執行我們的動畫效果了。但是,上一節中遺留了一個問題,比如我們傳入了過多的文字,就會出現這樣的情況:

gameDialog('content',
    " 簡書客戶端中包含雜文時政、小說詩歌、電影評論、科技新聞,無論你的興趣如何構成,總能在這里找到志趣相投的作者與內容。"+
    " 簡書始終致力于做中文世界最好的寫作與閱讀平臺,集結最優秀的創作者與文字愛好者,在嘈雜喧囂的網絡時代,重新沉淀并喚醒文字的力量。" +
    " 簡書客戶端中包含雜文時政、小說詩歌、電影評論、科技新聞,無論你的興趣如何構成,總能在這里找到志趣相投的作者與內容。"+
    " 簡書始終致力于做中文世界最好的寫作與閱讀平臺,集結最優秀的創作者與文字愛好者,在嘈雜喧囂的網絡時代,重新沉淀并喚醒文字的力量。" 
,38);

我們輸入了這么長一段字符,原本的div肯定是裝不下的,但是因為我們給content部分的css樣式中添加了overflow : hidden,所以溢出的文字沒有顯示出來,但實際上它已經溢出了。

如圖:


Paste_Image.png

在rpg游戲中,一般都是對話框被占滿后就停在那里了,然后需要玩家進行某些操作,比如按一個空格鍵,或者鼠標點擊一下,就清空掉當前的對話框,打印接下來的文字。

那么,如何判斷文字是否溢出了呢?這正是我們下一步要做的。

1. 判斷文字是否溢出

我們先把 overflow : hidden 這個屬性給去掉,看一下是什么效果。

Paste_Image.png

可見,多出來的文字被擠下來了!

我們可以通過dom元素的scrollHeight屬性來獲取當前盒子的完整高度(包括溢出部分),于是在輪詢中動態打印出文字區域的scrollHeight。

代碼:

timer = setInterval(function(){
    console.log(innerBox.scrollHeight);
    if(index == len){
        clearInterval(timer);
    }
    innerBox.innerHTML += text.charAt(index++);
},speed);
Paste_Image.png

如圖,每溢出一行,scrollHeight就增加25px,也就是我們設定的行高。

回顧css文件:

.dialog .innerBox #content {
    /*background: #E10482;*/
    margin:2px 10px 10px 10px;
    width:95%;
    height:99%;
    line-height:25px;
    /*overflow: hidden;*/
    font-size: 20px;
    text-align:justify;
}

行高正好是25px。你可能會問,為什么第一次是從79到100,是21px而不是25px呢?

我們將圖放大:

Paste_Image.png

content盒子的可見高度未必是文字行高的整數倍,這也就導致了第一次溢出是會有偏差的,如圖,第一次溢出部分的行高并沒有完全脫離content盒子,對不對?

這樣好理解了吧。

繼續。

我們已經可以動態獲取div盒子的完整高度了,那么是不是也可以獲取可視區域的高度呢?

當然可以啦,clientHeight就可以辦到!

console.log('文字可視區域的高度為:' + innerBox.clientHeight);
Paste_Image.png

對了,剛才我們看到的79px正是該區域文字部分的可見高度。

那么顯而易見的,如何判斷文字是否溢出呢?

對,就是將兩個寬度進行比較,一旦發現scrollHeight超過了clientHeight,我們就認為文字溢出了。

上代碼:

timer = setInterval(function(){
    console.log(box.scrollHeight + '=========' + box.clientHeight);
    if(box.scrollHeight > box.clientHeight){
        console.log('文字溢出啦!');
        clearInterval(timer);//清除定時器
                return; //返回
    }
    if(index == len){
        clearInterval(timer);
    }
    box.innerHTML += text.charAt(index++);
},speed);

(為了避免和html中的innerBox混淆,我們將gameDialog方法里面的innerBox改為box。)

Paste_Image.png

OK,我們再把溢出隱藏的屬性加上:

.dialog .innerBox #content {
    margin:2px 10px 10px 10px;
    width:95%;
    height:99%;
    line-height:25px;
    overflow: hidden;
    font-size: 20px;
    text-align:justify;
}

2. 怎么少了一個字?

然后,我們將輪詢的代碼封裝起來,作為一個start函數存在,同時,給文字區域添加一個點擊事件來觸發下一段文字,代碼就成了這樣:

var gameDialog = function(id,text,speed){
    var box = document.getElementById(id);
    var text = text;
    var len = text.length;
    var timer = null;
    var index = 0;
    
    function start(){
        box.innerHTML = '';
        timer = setInterval(function(){
            if(box.scrollHeight > box.clientHeight){
                clearInterval(timer);
                return;
            }
            if(index == len){
                clearInterval(timer);
            }
            box.innerHTML += text.charAt(index++);
        },speed);
}
    
start();

box.onclick = function(){
    start();
}

細心的你也許已經發現了,這個代碼是有問題的。

看圖,第一段文字的末尾是這樣:

Paste_Image.png

而第二段文字的開頭卻是這樣的:

Paste_Image.png

沒錯,少了一個構成的“構”字。(不同電腦可能分辨率不同,在你的電腦上不一定是這個字)

這是為什么呢?

原來,我們在判斷溢出的時候,是用scrollHeight和clientHeight進行比較的,而要使scrollHeight > clientHeight,必然是在文字已經溢出的時候。

也就是說,

if(box.scrollHeight > box.clientHeight){
    clearInterval(timer);
    return;
}

當程序進入這一段邏輯的時候,文字就已經溢出了,不多不少,正好溢出一個字。

解決方法很簡單,我們只需要將這個多出來的字符保存下來,下一次執行start方法的時候,補上去就OK了。

var gameDialog = function(id,text,speed){
    var box = document.getElementById(id);
    var text = text;
    var len = text.length;
    var timer = null;
    var index = 0;
    var character = '';
    
    function start(){
        box.innerHTML = '';
        timer = setInterval(function(){
            if(box.scrollHeight > box.clientHeight){
                //將溢出的那個字保存在下來
                character = text.charAt(index - 1); //因為上一次已經 ++了,所以這里要減一
                clearInterval(timer);
                return;
            }
            if(index == len){
                clearInterval(timer);
            }
            
            if(character){
                box.innerHTML += character;
                character = '';//重置該字符
            }else{
                box.innerHTML += text.charAt(index++);
            }
            
        },speed);
}
    
start();

box.onclick = function(){
    start();
}

這樣就解決少一個字符的問題了。

1.gif

3. 利用開關變量boolean值來判斷是否可以點擊

到目前為止,程序還存在一個bug,就是文字區域的點擊事件一直存在,也就是說,即便當前文字還在打印中,我們也可以觸發點擊事件,而事實上,我們希望在一段動畫結束后才允許我們點擊。

這時候就需要用到boolean值了,boolean就兩個狀態 true或者false,所以我習慣上把它稱為開關變量。

上代碼:

Paste_Image.png
Paste_Image.png
Paste_Image.png

附上資源帖地址:http://www.lxweimin.com/p/19a7a16d66b4

本章結束 ...

剽悍一小兔,電氣自動化畢業。
參加工作后對計算機感興趣,深知初學編程之艱辛。
希望將自己所學記錄下來,給初學者一點幫助。

免責聲明: 博客中所有的圖片素材均來自百度搜索,僅供學習交流,如有問題請聯系我,侵立刪,謝謝。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容