9 Stimmen

Eine Zeichenkette so abschneiden, dass sie in eine bestimmte Pixelbreite passt

Manchmal gibt es Zeichenketten, die in eine bestimmte Pixelbreite passen müssen. Diese Funktion versucht, dies effizient zu tun. Bitte posten Sie Ihre Vorschläge oder Refactorings unten :)

function fitStringToSize(str,len) {
    var shortStr = str;
    var f = document.createElement("span");
    f.style.display = 'hidden';
    f.style.padding = '0px';
    document.body.appendChild(f);

    // on first run, check if string fits into the length already.
    f.innerHTML = str;
    diff = f.offsetWidth - len;

    // if string is too long, shorten it by the approximate 
    // difference in characters (to make for fewer iterations). 
    while(diff > 0)
    {
        shortStr = substring(str,0,(str.length - Math.ceil(diff / 5))) + '…';
        f.innerHTML = shortStr;
        diff = f.offsetWidth - len;
    }

    while(f.lastChild) {
        f.removeChild(f.lastChild);
    }
    document.body.removeChild(f);

    // if the string was too long, put the original string 
    // in the title element of the abbr, and append an ellipsis
    if(shortStr.length < str.length)
    {
        return '<abbr title="' + str + '">' + shortStr + '</abbr>';
    }
    // if the string was short enough in the first place, just return it.
    else
    {
        return str;
    }
}

UPDATE: Die Lösung von @some unten ist viel besser; bitte verwenden Sie diese.

Aktualisierung 2: Der Code ist jetzt als . ; Forken und Patches können gerne eingereicht werden :)

22voto

some Punkte 45857

Es gibt ein paar Probleme mit Ihrem Code.

  • Warum / 5 ? Die Breite der Zeichen hängt ab von font-family y font-size .
  • Sie müssen entkommen str in der Kurzbezeichnung (andernfalls wird der Code durch ein " ungültig).
  • diff wird nicht deklariert und landet im globalen Bereich
  • Le site substring sollte so nicht funktionieren. Welchen Browser verwenden Sie?
  • hidden ist kein gültiger Wert von style.display . Um sie auszublenden, sollten Sie den Wert none aber dann berechnet der Browser nicht die offsetWidth . Verwenden Sie style.visibility="hidden" stattdessen.
  • Die Suche nach der richtigen Länge ist sehr ineffizient.
  • Muss entkommen &lt;/abbr&gt; "

Ich habe ihn für Sie umgeschrieben und Folgendes hinzugefügt className Sie können also einen Stil verwenden, um die font-family y font-size . Herr Fooz schlug vor, die gesamte Zeichenfolge mit einem Mouseover anzuzeigen. Das ist nicht notwendig, da moderne Browser dies für Sie tun (getestet mit FF, IE, Opera und Chrome)

    function fitStringToSize(str,len,className) {
    var result = str; // set the result to the whole string as default
    var span = document.createElement("span");
    span.className=className; //Allow a classname to be set to get the right font-size.
    span.style.visibility = 'hidden';
    span.style.padding = '0px';
    document.body.appendChild(span);

    // check if the string don't fit 
    span.innerHTML = result;
    if (span.offsetWidth > len) {
        var posStart = 0, posMid, posEnd = str.length;
        while (true) {
            // Calculate the middle position
            posMid = posStart + Math.ceil((posEnd - posStart) / 2);
            // Break the loop if this is the last round
            if (posMid==posEnd || posMid==posStart) break;

            span.innerHTML = str.substring(0,posMid) + '&hellip;';

            // Test if the width at the middle position is
            // too wide (set new end) or too narrow (set new start).
            if ( span.offsetWidth > len ) posEnd = posMid; else posStart=posMid;
        }
        //Escape
        var title = str.replace("\"","&#34;");
        //Escape < and >
        var body = str.substring(0,posStart).replace("<","&lt;").replace(">","&gt;");
        result = '<abbr title="' + title + '">' + body + '&hellip;<\/abbr>';
    }
    document.body.removeChild(span);
    return result;
    }

Bearbeiten: Bei weiteren Tests habe ich ein paar Fehler gefunden.

  • Ich habe Math.ceil anstelle der vorgesehenen Math.floor (Ich mache dafür Folgendes verantwortlich dass Englisch nicht meine Muttersprache ist Sprache ist)

  • Wenn der Eingabe-String html-Tags enthielt hätte, wäre das Ergebnis undefiniert (es ist nicht gut, ein Tag in der Mitte abzuschneiden der Mitte abzuschneiden oder offene Tags zu lassen)

Verbesserungen:

  • Die Zeichenkette, die an allen Stellen in den Span kopiert wird, muss entschlüsselt werden. Sie können weiterhin html-Einträge verwenden, aber es sind keine Tags erlaubt ( < y > wird angezeigt)
  • Umgeschrieben wurde die while -Anweisung (es ist eine etwas schneller, aber der Hauptgrund war es, den Fehler zu beseitigen, der der zusätzliche Runden verursachte und um die die Break-Anweisung loszuwerden)
  • Umbenennung der Funktion in fitStringToWidth

Version 2:

function fitStringToWidth(str,width,className) {
  // str    A string where html-entities are allowed but no tags.
  // width  The maximum allowed width in pixels
  // className  A CSS class name with the desired font-name and font-size. (optional)
  // ----
  // _escTag is a helper to escape 'less than' and 'greater than'
  function _escTag(s){ return s.replace("<","&lt;").replace(">","&gt;");}

  //Create a span element that will be used to get the width
  var span = document.createElement("span");
  //Allow a classname to be set to get the right font-size.
  if (className) span.className=className;
  span.style.display='inline';
  span.style.visibility = 'hidden';
  span.style.padding = '0px';
  document.body.appendChild(span);

  var result = _escTag(str); // default to the whole string
  span.innerHTML = result;
  // Check if the string will fit in the allowed width. NOTE: if the width
  // can't be determined (offsetWidth==0) the whole string will be returned.
  if (span.offsetWidth > width) {
    var posStart = 0, posMid, posEnd = str.length, posLength;
    // Calculate (posEnd - posStart) integer division by 2 and
    // assign it to posLength. Repeat until posLength is zero.
    while (posLength = (posEnd - posStart) >> 1) {
      posMid = posStart + posLength;
      //Get the string from the beginning up to posMid;
      span.innerHTML = _escTag(str.substring(0,posMid)) + '&hellip;';

      // Check if the current width is too wide (set new end)
      // or too narrow (set new start)
      if ( span.offsetWidth > width ) posEnd = posMid; else posStart=posMid;
    }

    result = '<abbr title="' +
      str.replace("\"","&quot;") + '">' +
      _escTag(str.substring(0,posStart)) +
      '&hellip;<\/abbr>';
  }
  document.body.removeChild(span);
  return result;
}

0 Stimmen

Sehr schön, vielen Dank. /5 wurde auf der Grundlage von Eyeballing es in meiner Anwendung (m ist 10px, f ist 3px) gewählt. Es ist eigentlich eine Art von Mist, weil die Schriftgröße abhängig von der Gestaltung der div ändern wird, dass die Zeichenfolge in platziert werden, so dass wir idealerweise nicht an Körper, sondern an diese div anhängen würde.

0 Stimmen

Substring: gah, ich glaube das war ein Tippfehler, ich habe den Bereichsanfangsoperator vergessen.

0 Stimmen

Wenn das Element, in das Sie den Sting einfügen wollen, bereits im Dom existiert, können Sie die obige Funktion ändern, um ihn dort einzufügen. Aber wenn dieses Element style.display="none" hat, erhält man keine Breite... Die Verwendung von body und einem Klassennamen ist also gar keine schlechte Idee.

3voto

Mr Fooz Punkte 102791

Auf den ersten Blick sieht es für mich gut aus. Hier sind einige kleinere Vorschläge:

  • Verwenden Sie eine binäre Suche, um die optimale Größe zu finden, anstatt einer linearen Suche.

  • (optional) einen Mouseover hinzufügen, so dass ein Tooltip die vollständige Zeichenfolge anzeigt.

0 Stimmen

Die <abbr> title-Eigenschaft gibt in allen modernen Browsern einen Mouseover-Tooltip :) Was meinen Sie mit "binärer Suche"? Im Moment versucht es, die Zeichenfolge kürzer durch die geschätzte Anzahl von Zeichen zu machen, dass es überlang ist, so sollte es nur 1-3 Iterationen, egal wie lang die Zeichenfolge haben

2voto

Können Sie dieselbe Funktion schreiben, aber um Breite und Höhe eines Divs anzupassen? Ich habe ein Div mit fester Breite und Höhe, in das ich Text aus der Datenbank einfügen muss. Wenn der Text zu groß für das Div ist, möchte ich ihn abschneiden und am Ende einfügen... Ist das möglich? Vielen Dank!

EDIT: Ich habe die JS-Lösung für meine Frage gefunden:

<p id="truncateMe">Lorem ipsum dolor sit amet, consectetuer adipiscing
elit. Aenean consectetuer. Etiam venenatis. Sed ultricies, pede sit
amet aliquet lobortis, nisi ante sagittis sapien, in rhoncus lectus
mauris quis massa. Integer porttitor, mi sit amet viverra faucibus,
urna libero viverra nibh, sed dictum nisi mi et diam. Nulla nunc eros,
convallis sed, varius ac, commodo et, magna. Proin vel
risus. Vestibulum eu urna. Maecenas lobortis, pede ac dictum pulvinar,
nibh ante vestibulum tortor, eget fermentum urna ipsum ac neque. Nam
urna nulla, mollis blandit, pretium id, tristique vitae, neque. Etiam
id tellus. Sed pharetra enim non nisl.</p>

<script type="text/javascript">

var len = 100;
var p = document.getElementById('truncateMe');
if (p) {

  var trunc = p.innerHTML;
  if (trunc.length > len) {

    /* Truncate the content of the P, then go back to the end of the
       previous word to ensure that we don't truncate in the middle of
       a word */
    trunc = trunc.substring(0, len);
    trunc = trunc.replace(/\w+$/, '');

    /* Add an ellipses to the end and make it a link that expands
       the paragraph back to its original size */
    trunc += '<a href="#" ' +
      'onclick="this.parentNode.innerHTML=' +
      'unescape(\''+escape(p.innerHTML)+'\');return false;">' +
      '...<\/a>';
    p.innerHTML = trunc;
  }
}

</script>

Für meinen Zweck habe ich den Link von ... entfernt, da ich eine andere Registerkarte auf meiner Seite habe, die den kompletten Text enthält.

1voto

Waleed Eissa Punkte 9825

Zum Glück, CSS3 Text-Überlauf sollte das schließlich erledigt sein.

Wenn jemand ASP.NET verwendet und an einer serverseitigen Lösung interessiert ist, sollte er sich diesen Blogbeitrag ansehen:

http://waldev.blogspot.com/2010/09/truncate-text-string-aspnet-fit-width.html

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X