Javascript/jQuery文本动画性能缓慢

Slow performance with Javascript/jQuery text animation

本文关键字:性能 缓慢 动画 文本 jQuery Javascript      更新时间:2023-09-26

这是我代码的简化和解释版本:

    var ptext=parr.find('div.ptext');   //Text Container
    var pt=ptext.html();                //Text Container's string
    var pdv=[pt.split(" ")];            //Text Container's array of words
        pdv.push(pdv[0].length);    //Write also the number of words
    var ht=hp.html();               //Text Container's new string
    var hdv=[ht.split(" ")];            //Text Container's new array of words
    hdv.push(hdv[0].length);            //New number of words
    var kakaka=0;                       //If they begin with the same,
    for (var j=0;j<hdv[0].length;j++){  //Animate only from the position
        if (hdv[0][j]==pdv[0][j])   //where they differ
            kakaka+=2;
    }
    window.clearTimeout(ptext.data('curt'));  //Clear current animation's interval
    ptext.data('count',kakaka);      //Set starting position    
    ptext.data('curt',                      //Set interval's var into object
        window.setInterval((function (item,pdv,hdv,text_callback) {
                return function() {       //item = text obj, text_callback= callback function
                        var i=item.data('count');
                            i=(i==undefined)?0:1+i;
                        item.data('count',i);     //increase counter
                                //first phase - remove old text
                        if (i<=pdv[1])       // go on
                        {
                            item.html((pdv[0].slice(0,pdv[1]-i)).join(' '));
                        }       //if reached the position, add new text
                        else if (i<=pdv[1]+hdv[1])
                        {
                            item.html((hdv[0].slice(0,i-pdv[1])).join(' '));
                        }        //if finish clear timeout and call callback
                        else {
                            item.data('count',0);
                            window.clearTimeout(item.data('curt'));
                            text_callback();
                        }
                }
            })(ptext,pdv,hdv,text_callback),8)   //8 = supposed interval
       );

}

从div 中获取单词,快速逐个删除它们,然后用新文本填充它。

它使用 .setInterval(( 函数,该函数应该每 8ms 回调一次。这在我的 i5 CPU 上运行良好,但在 i3 笔记本电脑上非常慢。

您能就如何提高性能提供一些建议吗?

你可以

  • 尝试使容器具有设置的宽度和高度,以避免重新绘制和重排文档。 操作后调整元素的大小。
  • 然后,您可以避免数组操作(拆分和连接(,而直接使用字符串操作。
  • 通过在循环操作之外存储引用来避免重复调用同一元素
  • 使用 text() 而不是 html() ,这样,DOM 只会创建文本节点。

这是一个演示,它在我值得信赖的奔腾 4 上运行得非常快

$(function() {
    function clearText(selector, callback) {
        //cache repeatedly used items
        var element = $(selector),
            elementText = element.text() + ' '; 
        //set element dimensions to fixed
        element.width(element.width());    
        element.height(element.height());
        (function erase() {
            if (elementText) {
                //use slice operations instead
                elementText = elementText.slice(elementText.indexOf(' ')+1);
                //use "text()"
                element.text(elementText);
                //loop
                setTimeout(function() {
                    erase();
                }, 8);
            } else {
                //set the dimensions back to auto
                element.width('auto').height('auto');   
                //execute callback returning the jQuery element
                callback.apply(element); 
            }
        }())
    }
    clearText('#foo', function() {
        //"this" is jQuery object "#foo"
        this.text('hello world');
    });
});​

这将完成这项工作,您可能希望更改 setTimeout 调用之间的延迟。它可以变得更加独立,但我现在没有动力:

<script type="text/javascript">
// Some support functions
(function(g) {
  var el = document.createElement('div');
  if (typeof el.textContent == 'string') {
    g.getText = function(el) {return el.textContent};
    g.setText = function(el, text) {el.textContent = text};
  }
  if (typeof el.innerText == 'string') {
    g.getText = function(el) {return el.innerText};
    g.setText = function(el, text) {el.innerText = text};
  }
}(this));
function annoyUser(el, text) {
  var re = /'s+/g;
  var oText = getText(el).split(re);
  if (oText.length == 1) {
    setText(el, text);
  } else {
    oText.pop();
    setText(el, oText.join(' '));
    setTimeout(function(){annoyUser(el, text)}, 100);
  }
}
window.onload = function() {
  setTimeout(function() {
    annoyUser(document.getElementById('d0'), 'hello world')
  }, 1000);
}
</script>
<div id="d0">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
 metus sapien, lobortis non dictum et, mollis vitae lorem. Nulla facilisi. Morbi eget
 ante diam.</div>

这是完美完成的功能,整个想法是将其包装在 SPANS 中,然后对于每个跨度,我们将更改可见性,当它到达反向阶段时,替换为不同的文本包装在跨度中。

我不保证你会明白任何事情,但你肯定知道我是如何解决的。注意,基本上主要输入是pdv,hdv - 是输入文本和输出文本的单词数组。

function letsdance(obj,op,type,text_callback){  //animate text
    if (text_callback==undefined) var text_callback=function(){};
    var parr=obj.parents('.pconter');
    var ptext=parr.find('div.ptext');

    var pt=ptext.html();
    var ppp=ptext.children();
    var pdv=[[]];
    for (var i=0;i<ppp.length;i++)
        pdv[0].push(    ppp[i].outerHTML    );

    if (ppp.length==0){
    var pdv=[pt.split(" ")];
        for (var i=0;i<pdv[0].length;i++)
            pdv[0][i]='<span>'+pdv[0][i]+'</span>';
        ptext.html(pdv[0].join(' '));
    }
    pdv.push(pdv[0].length-1);
    if (op){
        if (type===1)
            {
                var ht=obj.html();
            }
        else if (type==2)
            {
                var ht=ptext.data('orig');  
            }
        else {
        var ide=(obj.attr('id').match(/_['da-zA-Z]*_['da-zA-Z]*$/))[0];
        var hp=parr.find('div.hptext[id$="'+ide+'"]');
        var ht=hp.html();   
        }
        var hdv=[ht.split(" ")];
            hdv.push(hdv[0].length-1);  
    } else {    
        var current_selection=parseInt(ptext.data('current_section'));
        if (current_selection>0){
            var pto=ptext.siblings('.subptext[id$="NN'+current_selection+'"]').html();
            }
        else 
            var pto=ptext.data('orig');
        var hdv=[pto.split(" ")];
            hdv.push(hdv[0].length-1);  
    }
    var kakaka=0;
    var kaka=false;
    for (var i=0;i<=hdv[1];i++){
        if (pdv[0][i]!=undefined&&!kaka&&hdv[0][i]==pdv[0][i].replace(/(<([^>]+)>)/ig,"")&&!/invis/.test(pdv[0][i])){
                        kakaka+=1;  
        }
        else {
            kaka=true;
            hdv[0][i]='<span class="invis">'+hdv[0][i]+'</span>'; 
        }
    }
    var invi_count=pdv[1];
    for (invi_count;invi_count>=0;invi_count--)
        if (!/invis/.test(pdv[0][invi_count])) break;
    window.clearInterval(ptext.data('curt'));
    ptext.data('count',invi_count).data('index',kakaka).data('phase',0)//data('skip',0);            
    ptext.data('curt',
        window.setInterval((function (item,pdv,hdv,text_callback) {
                return function() {
                    var i=item.data('count');      
                    var phase=item.data('phase');      
                    var index=item.data('index');    
                    switch (phase)
                    {
                        case 0:
                                item.children(':eq('+i+')').addClass('invis');
                                if (i>index)    
                                    item.data('count',i-1);
                                else
                                    item.data('count',index).data('phase',1)
                                    .html((pdv[0].slice(0,index)).join(' ')).append(' '+hdv[0].slice(index,hdv[1]).join(' '));
                        break;  
                        case 1:
                                item.children(':eq('+i+')').removeClass('invis');
                                if (i<hdv[1])
                                    item.data('count',i+1);
                                else{
                                    //item.data('count',0).data('phase',0);
                                    window.clearInterval(item.data('curt'));
                                    text_callback();
                                }
                        break;      
                    }
                }
            })(ptext,pdv,hdv,text_callback),4)
       );

}