web-dev-qa-db-fra.com

détecter les sauts de ligne avec jQuery?

est-il possible que jQuery/javascript détecte où une chaîne est cassée (afin de tenir dans les contraintes de largeur CSS) afin d'insérer des éléments DOM avant le début d'une nouvelle ligne?

24
Mild Fuzz

Je suis venu avec une approche, mais il pourrait être exagéré pour vos objectifs, alors prenez cela en compte.

Vous devez créer un clone de l'élément, vider l'original, puis replacer chaque mot dans l'élément d'origine. Si la hauteur change en tout point, il y a un saut de ligne avant ce mot. Ce serait assez simple à faire avec $(el).text(), mais cela devient plus compliqué s'il peut y avoir d'autres balises à l'intérieur, pas seulement du texte. J'ai essayé d'expliquer comment le décomposer par nœud dans cette boîte de réponse, mais j'ai trouvé plus facile de créer un plugin jQuery dans un jsFiddle. Lien ici: http://jsfiddle.net/nathan/qkmse/ ( Gist ).

Il ne supportera pas très bien les éléments flottants, et il y a quelques autres situations où il va tomber. Faites-moi savoir si vous souhaitez plus d'options, ou si cela ne fonctionne pas tout à fait pour vos besoins, ou si vous ne savez pas comment l'appliquer et je vais essayer de vous aider.

37
Nathan MacInnes

Voici une approche. Remarque: je ne vois pas de solution idéale sans utiliser des polices monospaces. L'égalité avec les personnages facilite beaucoup cette tâche.

  1. Caractères de largeur égale
  2. Calculer la taille d'un caractère
  3. Calculer la taille du conteneur
  4. Trouver des personnages par ligne
  5. Trouvez l'endroit où la ligne sera brisée (c.-à-d. Espaces, tirets, etc.)
  6. Obtenez tous les index de rupture.

Regardez le jsfiddle pour le code HTML associé. Je n'ai pas terminé cette fonction. Davantage de contrôles doivent être mis en place lors du calcul de l'indice de rupture. À l'heure actuelle, il utilise lastIndexOf (''), mais cela ignore que l'index suivant pourrait être un espace, ou le courant. De plus, je ne comptabilise pas d'autres caractères de rupture de ligne. Cependant, cela devrait être un excellent point de départ.

var text = $('#text').text(),                   // "lorem ipsum ... "
    len = text.length,                          // total chars
    width = $('#text').width(),                 // container width
    span = $('<span />').append('a').appendTo('#sandbox'),
    charWidth = span.width(),                  // add single character to span and test width
    charsPerRow = Math.floor(width/charWidth); // total characters that can fit in one row

var breakingIndexes = [], // will contain indexes of all soft-breaks
    gRowStart = 0,        // global row start index
    gRowEnd = charsPerRow;// global row end index

while(gRowEnd < len){
    var rowEnd = text.substring(gRowStart, gRowEnd).lastIndexOf(' '); // add more checks for break conditions here
    breakingIndexes.Push(gRowStart + rowEnd); // add breaking index to array
    gRowStart = gRowStart + rowEnd + 1; // next start is the next char
    gRowEnd = gRowStart + charsPerRow;  // global end inxex is start + charsperrow
}

var text2 = $('#text2').text();           // "lorem ipsum ... " now not width bound
var start = 0, newText = '';
for(var i=0; i < breakingIndexes.length; i++){
    newText += text2.substring(start, breakingIndexes[i]) + '<br />'; // add hard breaks
    start = breakingIndexes[i]; // update start
}

$('#text2').html(newText); // output with breaks

http://jsfiddle.net/Y5Ftn/1/

6
Josiah Ruddell

ceci est mon script, qui prend du texte, puis fait de chaque ligne une durée

CSS:

    margin: 0;
        padding: 0;
    }

    .title{
        width: 300px;
        background-color: rgba(233,233,233,0.5);
        line-height: 20px;
    }

    span{
        color: white;
        background-color: red;
        display: inline-block;
        font-size: 30px;
    }

    a{
        text-decoration: none;
        color: black;
    }

html

<div class="title">
        <a href="">SOME TEXT LONG TEXT ANDTHISISLONG AND THIS OTHER TEXT</a>
    </div>

JS

$(function(){

        $(".title").find("a").each(function(){

            var $this = $(this);
            var originalText = $this.text();
            $this.empty();

            var sections = [];

            $.each( originalText.split(" "), function(){
                var $span = $("<span>" + this + "</span>");
                $this.append($span);

                var index = $span.position().top;

                if( sections[index] === undefined ){
                    sections[index] = "";
                }

                sections[index] += $span.text() + " ";
            });

            $this.empty();

            for(var i = 0; i< sections.length; i++){
                if( sections[i] !== undefined ){
                    var spanText = $.trim(sections[i]);                     
                    $this.append("<span>" + spanText + "</span>");
                }
            }

        });

    });

Vous devez avoir jQuery inclus. 

Je ne connais pas de fonction javascript intégrée à jQuery pour le faire. Vous pouvez toutefois le faire vous-même, mais ce serait potentiellement lent si vous avez beaucoup de texte. 

En théorie, vous pouvez vous assurer que la hauteur est définie sur auto, supprimez le texte, puis Word par Word, puis réinsérez-le. Lors d'un changement de hauteur, vous supprimez le dernier mot et insérez votre élément dom. Encore une fois, cela sera lent s'il y a beaucoup de texte, et le meilleur moyen de le faire serait de ne pas changer l'élément d'origine, mais de le faire dans un autre élément pouvant être masqué, puis de remplacer l'élément d'origine à la fin. De cette façon, votre utilisateur ne verrait pas le contenu disparaître, puis reviendrait mot par mot.

Une autre méthode consisterait à utiliser un principe similaire et à commencer par un élément vide de même taille avec height auto, puis à insérer un nouveau caractère et un espace jusqu'à obtenir une nouvelle ligne. À partir de là, vous pouvez utiliser ceci comme approximation de la technologie ci-dessus ou vous pouvez ajouter aveuglément la longueur de chaque chaîne jusqu'à ce que vous trouviez une nouvelle ligne, en tenant compte de la largeur de votre élément dom. Cependant, cette technique fonctionne mieux avec les polices à espacement fixe. C’est pourquoi l’utiliser uniquement à titre approximatif.

Cela dit, il existe un moyen de mesurer le texte à l’aide de canvas, mais cela peut être extrême. En théorie, créer un élément de structure, obtenir le contexte, définir toutes les propriétés de la police, puis utiliser la méthode context.measureText(). Un exemple d'utilisation peut être trouvé here .

0
Ktash

Vous pouvez également comparer la largeur du bloc de texte à la largeur de son parent. Si le bloc mesure au moins 98% de la largeur de son parent, il est presque certain qu'il casse

0
Harijs Deksnis

Je pense qu'il serait plus facile de détecter en utilisant une regex - beaucoup moins de code tout en conservant l'efficacité.

Voici quelque chose qui a fonctionné pour moi:

if ((/(\r\n|\n|\r)/.test($(this).val()))) {
    alert('there are line breaks here')
}

Je ne sais pas si cela fonctionnera avec vos chaînes cassées, mais cela fonctionne pour détecter les sauts de ligne avec jQuery.

0
streetlight

Vous ne savez pas exactement quel est votre cas d'utilisation, mais http://code.google.com/p/hyphenator/ peut être une solution à votre problème ou si vous creusez dans le code source de hyphenator.js, vous pourrez peut-être pour trouver le code que vous recherchez. 

0
Josh Schumacher