Quel est le moyen le plus élégant de montrer un texte HTML lettre par lettre (comme les légendes de jeux vidéo) à l'aide de CSS et de JavaScript?
Bien que je sois sûr que son problème puisse être résolu en utilisant une approche de force brute (disons, en scindant les caractères et en les imprimant un à un en utilisant jQuery.append()
), j'espère qu'il y aura des CSS3 (pseudo-éléments?) Ou la magie JQuery à faire. cela plus élégamment.
Points supplémentaires si la solution prend en compte le contenu HTML interne.
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);
}
}
Appeler avec:
$(function () {
showText("#msg", "Hello, World!", 0, 500);
});
Si une révélation en douceur est raisonnable, alors je pense que cela devrait être assez simple. Non testé, mais voici comment 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 );
D'accord, je n'ai pas pu résister et j'ai fait du violon. Une petite erreur de code que j'ai corrigée. Cela me semble bien!
Vous devriez vraiment juste append
, ou afficher/masquer.
Toutefois, si, pour une raison quelconque, vous ne souhaitez pas modifier votre texte, vous pouvez utiliser ce morceau de code excessivement compliqué:
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, n'utilisez pas ça ...
100% javascript vanille, 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);
J'ai fait un petit plugin JQuery pour cela. Tout d’abord, vous devez vous assurer que le texte sera visible si javascript est désactivé, sinon, réaffichez 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 cela:
$('h1').retype();
Lorsque j’ai fait cela, j’ai rencontré le problème d’un mot sautant de la fin d’une ligne à la mendicité de la suivante. les autres lettres visibles et simplement déplacées une par une de la portée invisible à la 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)
Rendez votre code plus élégant en préparant des promesses pour chaque itération, puis exécutez-les dans un deuxième temps, où vous pourrez 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>
Ceci est basé sur armen.shimoon's:
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 - je devais le changer en substr. De plus, mon texte d'origine utilise HTML et le texte saisi utilise le formatage HTML (br, b, etc.). J'ai aussi la fonction qui s'arrête si la cible a été cachée.
Vanille
(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 le el qu'une fois car il faut un peu de ressources pour modifier le DOM.
Vous devez envelopper chaque lettre dans une balise span, car les éléments HTML anonymes ne peuvent pas être stylés. Puis révélez une durée à la fois. Cela évite certains problèmes innerText/innerHTML (pas de refusion DOM?), Mais peut être excessif dans votre cas.
il y a une bonne réponse comment le faire ici : C'est une façon de manipuler chaque lettre avec n'importe quelle propriété .animate () disponible, pas avec des hacks comme si on couvrait le texte avec s etc.
J'essayais de résoudre le même problème et j'ai proposé 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);
});