如何使用JavaScript在文本上实现删除线动画效果?

7
我希望尝试创建这样一种效果:当我触发一个事件时,一条动画线会穿过一段文本。这个效果应该用Java Script完成。
有人能提供一些实现方法吗?我已经在页面上有了文本,我想让文本从左到右被划掉,就像正在绘制一条线一样。

你使用的是哪种标记语言?原生JavaScript,还是使用了一些库(jQuery,MooTools,Glow,Scriptaculous等)? - David Thomas
目前没有承诺使用任何框架。不过最好能够与dojo一起使用。 - thiswayup
7个回答

4

使用jQuery稍加修改即可实现:http://jsfiddle.net/yahavbr/EbNh7/

使用的JS代码:

var _text = "";
$(document).ready(function() {
    _text = $("#myDiv").text();
    StrikeThrough(0);
});

function StrikeThrough(index) {
    if (index >= _text.length)
        return false;
    var sToStrike = _text.substr(0, index + 1);
    var sAfter = (index < (_text.length - 1)) ? _text.substr(index + 1, _text.length - index) : "";
    $("#myDiv").html("<strike>" + sToStrike + "</strike>" + sAfter);
    window.setTimeout(function() {
        StrikeThrough(index + 1);
    }, 100);
}

这将会通过动画效果在myDiv文本上添加删除线。

由于它不使用任何重型的jQuery插件,因此可以很容易地转换为纯JavaScript代码,所以如果您不想使用jQuery,我将编辑我的答案。


这很酷,但最好不要使用html()序列化HTML,因为它会删除所有其他附加的事件。 - alex
@alex 我假设没有这样的事件,只是举了一个快速的例子.. 你认为有什么更好的替代方案? - Shadow The Spring Wizard
我自己添加了一个答案 - alex

4
var findText = function(element, pattern, callback) {

    if ( ! element.childNodes) {
      return;   
    }
    for (var childi = element.childNodes.length; childi-- > 0;) {
        var child = element.childNodes[childi];
        if (child.nodeType == 1) {
            findText(child, pattern, callback);
        } else if (child.nodeType == 3) {
            var matches = [];
            var match;
            while (match = pattern.exec(child.data))
            matches.push(match);
            for (var i = matches.length; i-- > 0;)
            callback.call(window, child, matches[i]);
        }
    }
}


findText(document.body, /./g, function(node, match) {
    var element = document.createElement('span');
    node.splitText(match.index + 1);
    element.appendChild(node.splitText(match.index));
    node.parentNode.insertBefore(element, node.nextSibling);
});

var spans = document.getElementsByTagName('span'),
    spansLength = spans.length,
    currentSpan = 0,
    interval = setInterval(function() {
        if (currentSpan == spansLength) {
            clearInterval(interval);
        }
        spans[currentSpan++].style.textDecoration = 'line-through';

    }, 100);

jsFiddle

  • 使用正则表达式遍历每个字符(除了\n),并递归应用带有回调函数的函数,将每个匹配的字符用span包装起来。
  • 选择所有这些span元素,然后使用setInterval()遍历它们,通过spanstyle对象添加style="text-decoration: line-through"
  • 当我们遍历完每个span时停止。

使用innerHTML的缺点是在序列化HTML时,您会失去所有事件等。在上面的fiddle中,strong元素仍然可点击(您将单击span,它将冒泡到父元素)。


1
当然可以加上 +1,但我怀疑楼主并不想让整个文档的文本都被划掉吧? :) - Shadow The Spring Wizard
@Shadow,原帖作者可以将 document.body 更改为他们想要的任何元素,非常感谢。 - alex
1
当然,我知道.. :) 另外,你正在使用 document.getElementsByTagName('span'),因此这也需要更改以支持特定元素。 - Shadow The Spring Wizard
@alex 这不是有点过度吗?请告诉我你对此的看法:
  1. 在文本节点之前创建一个带有删除线的 span。
  2. 循环遍历文本,并按间隔将每个字符移动到新的 span 中。
  3. 如果原始元素是 span,则给它添加删除线并将所有文本移回其中(以维护事件),然后删除新的 span。否则就这样!
- pilau

3
您可以使用jQuery来动画显示一个看起来像删除线的背景图片。也许是这样的:
$(".someclass").animate({backgroundPosition: '0px 0px'})

这种方法可能比涉及<s>标签的方法更加流畅。你的HTML标记会像这样:

<span class="someclass">Lorem ipsum</span>

您需要确保.someclass具有默认的CSS样式,通过使用background-position来隐藏背景图片,即:

.someclass { background-position: -1000px 0px; }

不错的想法。不过,我觉得这在换行时可能行不通。 - Lambda Fairy

1

我刚从谷歌来到这里,最终写了自己的简单小函数。这是我的做法:

function drawLineOnClick() {

    //add or prepend div to the top of the div holding your text
    $("#IdOfElementHoldingTheText").prepend('<div id="lineThrough"></div>');
    var WidthStrikeThrEl = $("#IdOfElementHoldingTheText").width();

    $("#lineThrough").animate({width: WidthStrikeThrEl},1000, function() {

        //when line has been drawn, apply CSS line-through and remove line
        $("#IdOfElementHoldingTheText").attr('class', 'lineThrCssClass');
        $("#lineThrough").remove();
    });
}


#lineThrough {
  position:absolute;
  top:23px; //centering line over text to simulate actual line through
  width:0px;
  height:1px;
  background:#444; //color of line through
}

.lineThrCssClass {
    color:#444;
    text-decoration:line-through;
}

1
我会在有删除线样式的文本前创建一个空的。然后,我会编写一个函数,从文本开头弹出第一个字符并将其附加到您的中。接下来,使用setTimeout()重复调用该函数,直到文本为空为止。
你要求建议 - 编码需要更长的时间 :)

这是我会做的事情,但是使用 setInterval 而不是 setTimeout - pilau

0
你可以在字符串开头添加一个 <s> 标签,并迭代地将关闭的 </s> 标签向字符串末尾移动一个字符,最好使用 setTimeout()
大致如下(未经测试):
STRIKE_POS = 1;
ORIG_STR = '';

function startStrike(str) {
    STRIKE_POS = 1;
    ORIG_STR = str;
    strike();
}

function strike() {
    var str = '<s>' + ORIG_STR.substr(0, STRIKE_POS) + '</s>'
              + ORIG_STR.substr(STRIKE_POS);

    // DO SOMETHING WITH THE STRING, LIKE DISPLAY SOMEWHERE

    STRIKE_POS++;
    if (STRIKE_POS < ORIG_STR.length) {
        window.setTimeout("strike()", 200);    // adjust the timeout
    }
}

0
这是一个基本实现,适用于当前版本的IE、Firefox和Chrome:
<html>
    <head>
        <script type="text/javascript">
            window.gradualStrike = function(spanId, timeMillis) {
                var stepDuration;
                var strikeElem = document.getElementById(spanId);
                var strikeText = strikeElem.innerHTML.replace("<S>", "<s>").replace("</S>", "</s>");  //IE uppercases the tag
                var currentStrikePos = strikeText.indexOf("</s>");
                if (currentStrikePos < 0) {
                    currentStrikePos = 0;
                    stepDuration = timeMillis / strikeText.length;
                }
                else {
                    if (currentStrikePos + 3 == strikeText.length) {
                        //the '</s>' is at the end, we are done
                        return;
                    }
                    currentStrikePos -= 3; //account for the '<s>' tag
                    stepDuration = timeMillis / (strikeText.length - 7);  //account for '<s>' and '</s>'
                    strikeText = strikeText.replace("<s>", "").replace("</s>", ""); //strikeText.replace(/\<s\>/, "").replace(/\<\/s\>/, "");

                }
                currentStrikePos++;
                strikeText = "<s>" + strikeText.substring(0, currentStrikePos) + "</s>" + strikeText.substring(currentStrikePos);
                strikeElem.innerHTML = strikeText;
                setTimeout("gradualStrike('" + spanId + "', " + timeMillis + ");", stepDuration);
            };
        </script>
    </head>
    <body>
        <span id="someText" onclick="gradualStrike('someText', 1000); this.onclick=function(){return;};">Click to strike...</span>
    </body>
</html>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接