Afficher le texte lettre par lettre
Quelle est la façon la plus élégante de montrer un texte html lettre par lettre (comme les légendes de jeux vidéo) en utilisant CSS et JavaScript?
Bien que je sois sûr que son peut être résolu en utilisant une approche de force brute (disons, diviser les caractères et les imprimer un par un en utilisant jQuery.append()
), j'espère qu'il y a quelques CSS3 (pseudo-éléments?) ou jQuery magic pour le faire plus élégamment.
Points supplémentaires si la solution considère le contenu HTML interne.
13 réponses
HTML
<div id="msg"/>
Javascript
var showText = function (target, message, index, interval) {
if (index < message.length) {
$(target).append(message[index++]);
setTimeout(function () { showText(target, message, index, interval); }, interval);
}
}
Appelez avec:
$(function () {
showText("#msg", "Hello, World!", 0, 500);
});
Si une révélation lisse est raisonnable, je pense que cela devrait être assez simple. Non testé, mais c'est ainsi que j'imagine que cela fonctionnerait
Html
<div id="text"><span>The intergalactic space agency</span></div>
Css
div#text { width: 0px; height: 2em; white-space: nowrap; overflow: hidden; }
JQuery
var spanWidth = $('#test span').width();
$('#text').animate( { width: spanWidth }, 1000 );
Ok, je n'ai pas pu résister et j'ai fait un violon. Une petite erreur de code que j'ai corrigée. Semble bon pour moi si!
, Vous devriez vraiment juste append
, ou afficher/masquer.
Cependant, si pour une raison étrange vous ne voulez pas modifier votre texte, vous pouvez utiliser ce morceau de code trop compliqué pour aucune bonne raison:
HTML:
<p>I'm moving slowly...<span class="cover"></span></p>
CSS:
p {
font-family: monospace;
float: left;
padding: 0;
position: relative;
}
.cover {
height: 100%;
width: 100%;
background: #fff;
position: absolute;
top: 0;
right: 0;
}
JQuery:
var $p = $('p'),
$cover = $('.cover'),
width = $p.width(),
decrement = width / $p.text().length;
function addChar()
{
$cover.css('width', '-=' + decrement);
if ( parseInt( $cover.css('width') ) < width )
{
setTimeout(addChar, 300);
}
}
addChar();
Et enfin, voici le violon: http://jsfiddle.net/dDGVH/236/
Mais, sérieusement, ne l'utilisez pas...
100% vanille javascript, mode strict, HTML discret,
function printLetterByLetter(destination, message, speed){
var i = 0;
var interval = setInterval(function(){
document.getElementById(destination).innerHTML += message.charAt(i);
i++;
if (i > message.length){
clearInterval(interval);
}
}, speed);
}
printLetterByLetter("someElement", "Hello world, bonjour le monde.", 100);
Quand j'ai fait cela, j'ai rencontré le problème d'un mot sautant de la fin d'une ligne à la mendicité de l'autre comme les lettres semblaient contourner cela, j'avais l'habitude de passer côte à côte, l'un dont le texte était transparent, l'autre visible et simplement déplacé les lettres une par une de la portée invisible au visible. Voici un violon.
HTML
<div class='wrapper'>
<span class='visible'></span><span class='invisible'></span>
</div>
CSS
.visible {
color: black;
}
.invisible {
color: transparent;
}
JS
var text = "Whatever you want your text to be here",
soFar = "";
var visible = document.querySelector(".visible"),
invisible = document.querySelector(".invisible");
invisible.innerHTML = text;
var t = setInterval(function(){
soFar += text.substr(0, 1),
text = text.substr(1);
visible.innerHTML = soFar;
invisible.innerHTML = text;
if (text.length === 0) clearInterval(t);
}, 100)
J'ai fait un petit plugin jquery pour cela. Vous devez d'abord vous assurer que le texte sera visible si javascript est désactivé, et sinon, réafficher le texte lettre par lettre.
$.fn.retype = function(delay) {
var el = this,
t = el.text(),
c = t.split(''),
l = c.length,
i = 0;
delay = delay || 100;
el.empty();
var interval = setInterval(function(){
if(i < l) el.text(el.text() + c[i++]);
else clearInterval(interval);
}, delay);
};
L'utilisation sera aussi simple que celle-ci:
$('h1').retype();
Ceci est basé sur armen.shimoon:
var showText = function (target, message, index, interval) {
if (index <= message.length && $(target).is(':visible')) {
$(target).html(message.substr(0, index++));
setTimeout(function () { showText(target, message, index, interval); }, interval);
}
}
Message [index++] ne fonctionnait pas dans ma page Web jquery-j'ai dû le changer en substr. De plus, mon texte original utilise du HTML et le texte tapé utilise le formatage HTML (br, b, etc.). J'ai également la fonction s'arrêtant si la cible a été cachée.
Vous devez envelopper chaque lettre dans la balise span, car les éléments HTML anonymes ne peuvent pas être stylés. Puis révéler une portée à la fois. Cela évite certains problèmes innerText / innerHTML (pas de rediffusion DOM?), mais peut-être exagéré dans votre cas.
Vanillla
(function () {
var showText = function(target, msg, index, interval){
var el = document.getElementById(target);
if(index < msg.length){
el.innerHTML = el.innerHTML + msg.charAt(index);
index = index + 1;
setTimeout(function(){
showText(target,msg,index,interval);
},interval);
}
};
showText("id", "Hello, World!", 0, 50);
})();
Vous pouvez améliorer ce code en le changeant de sorte que vous n'obtenez l'el qu'une seule fois en raison du fait qu'il faut un peu de ressources pour modifier le DOM.
Il y a une bonne réponse à comment le faire ici: c'est une façon que vous pouvez manipuler chaque lettre avec tout .animate () propriété Disponible, pas avec des hacks comme couvrir le texte avec s etc.
J'ai essayé de résoudre le même problème et j'ai trouvé cette solution qui semble fonctionner.
HTML
<div id='target'></div>
JQuery
$(function() {
var message = 'Hello world';
var index = 0;
function displayLetter() {
if (index < message.length) {
$('#target').append(message[index++]);
}
else{
clearInterval(repeat);
}
}
var repeat = setInterval(displayLetter, 100);
});
Rendez votre code plus élégant en préparant des promesses pour chaque itération, puis exécutez-les comme deuxième étape où vous pouvez injecter la logique DOM.
const message = 'Solution using Promises';
const typingPromises = (message, timeout) =>
[...message].map(
(ch, i) =>
new Promise(resolve => {
setTimeout(() => {
resolve(message.substring(0, i + 1));
}, timeout * i);
})
);
typingPromises(message, 140).forEach(promise => {
promise.then(portion => {
document.querySelector('p').innerHTML = portion;
});
});
<div ><p></p></div>
Il y a quelques bibliothèques pour cela. Il y a TypeItJs et TypedJS les deux permettent au html d'être dans la chose que vous tapez ainsi que de nombreuses autres méthodes qui aident à animer les effets de la machine à écrire.