web-dev-qa-db-fra.com

HTML - Comment afficher l'infobulle UNIQUEMENT lorsque Ellipsis est activé

J'ai une durée avec des données dynamiques dans ma page qui contiennent des Ellipsis. Sens:

<span style='text-overflow: Ellipsis; overflow : hidden; white-space: nowrap;  
 width: 71;'>${myData}</span>

et j'aimerais ajouter à cette info-bulle d'élément le même contenu (title = '$ {myData}'), mais je souhaite qu'il n'apparaisse que lorsque le contenu est long et que les ellipses apparaissent à l'écran.
Y a-t-il un moyen de le faire?

une direction - lorsque le navigateur (IE dans mon cas) dessine Ellipsis- lance-t-il un événement à ce sujet?

175
Spiderman

Voici une méthode qui utilise le paramètre Ellipsis intégré et ajoute l'attribut title à la demande (avec jQuery) à partir du commentaire de Martin Smith:

$('.mightOverflow').bind('mouseenter', function(){
    var $this = $(this);

    if(this.offsetWidth < this.scrollWidth && !$this.attr('title')){
        $this.attr('title', $this.text());
    }
});
156
Jason Kleban

Voici une solution CSS pure. Pas besoin de jQuery. Aucune info-bulle ne sera affichée, mais le contenu du fichier sera agrandi au passage de la souris.

Fonctionne très bien si le contenu est remplacé. Ensuite, vous ne devez pas exécuter une fonction jQuery à chaque fois.

.might-overflow {
    text-overflow: Ellipsis;
    overflow : hidden;
    white-space: nowrap;
}

.might-overflow:hover {
    text-overflow: clip;
    white-space: normal;
    Word-break: break-all;
}
45
Snæbjørn

la réponse de uosɐſ est fondamentalement correcte, mais vous ne voulez probablement pas le faire dans l'événement mouseenter. Cela va faire faire le calcul pour déterminer si c'est nécessaire, chaque fois que vous survolez l'élément. À moins que la taille de l'élément change, il n'y a aucune raison de le faire.

Il serait préférable d'appeler ce code immédiatement après l'ajout de l'élément au DOM:

var $ele = $('#mightOverflow');
var ele = $ele.eq(0);
if (ele.offsetWidth < ele.scrollWidth)
    $ele.attr('title', $ele.text());

Ou, si vous ne savez pas exactement quand il est ajouté, appelez ce code une fois le chargement de la page terminé.

si vous avez besoin de plus d'un élément pour le faire, vous pouvez leur donner la même classe (telle que "mightOverflow") et utiliser ce code pour les mettre à jour tous:

$('.mightOverflow').each(function() {
    var $ele = $(this);
    if (this.offsetWidth < this.scrollWidth)
        $ele.attr('title', $ele.text());
});
32
Elezar

Voici mon plugin jQuery:

(function($) {
    'use strict';
    $.fn.tooltipOnOverflow = function() {
        $(this).on("mouseenter", function() {
            if (this.offsetWidth < this.scrollWidth) {
                $(this).attr('title', $(this).text());
            } else {
                $(this).removeAttr("title");
            }
        });
    };
})(jQuery);

Usage:

$("td, th").tooltipOnOverflow();

Modifier:

J'ai fait un Gist pour ce plugin. https://Gist.github.com/UziTech/d45102cdffb1039d4415

17
Tony Brix

Nous devons détecter si Ellipsis est vraiment appliqué, puis afficher une info-bulle pour révéler le texte intégral. Il ne suffit pas de comparer "this.offsetWidth < this.scrollWidth" lorsque l'élément contient presque tout son contenu, mais il ne manque que la largeur d'un ou deux pixels, en particulier pour le texte composé de caractères chinois/japonais/coréen pleine largeur.

Voici un exemple: http://jsfiddle.net/28r5D/5/

J'ai trouvé un moyen d'améliorer la détection des ellipses:

  1. Comparez d'abord "this.offsetWidth < this.scrollWidth", passez à l'étape 2 en cas d'échec.
  2. Basculez temporairement le style css en {'overflow': 'visible', 'espace-blanc': 'normal', 'Word-break': 'break-all'}.
  3. Laissez le navigateur faire le relais. Si Word-wrap se produit, l'élément augmentera sa hauteur, ce qui signifie également qu'ellipsis est requis.
  4. Restaurez le style css.

Voici mon amélioration: http://jsfiddle.net/28r5D/6/

12
Feng Dihai

J'ai créé un plugin jQuery qui utilise l'info-bulle de Bootstrap au lieu de l'info-bulle intégrée du navigateur. Veuillez noter que cela n'a pas été testé avec un navigateur plus ancien.

JSFiddle: https://jsfiddle.net/0bhsoavy/4/

$.fn.tooltipOnOverflow = function(options) {
    $(this).on("mouseenter", function() {
    if (this.offsetWidth < this.scrollWidth) {
        options = options || { placement: "auto"}
        options.title = $(this).text();
      $(this).tooltip(options);
      $(this).tooltip("show");
    } else {
      if ($(this).data("bs.tooltip")) {
        $tooltip.tooltip("hide");
        $tooltip.removeData("bs.tooltip");
      }
    }
  });
};
10
Steven

Voici deux autres solutions CSS pures:

  1. Afficher le texte tronqué en place:
.overflow {
  overflow: hidden;
  -ms-text-overflow: Ellipsis;
  text-overflow: Ellipsis;
  white-space: nowrap;
}

.overflow:hover {
  overflow: visible;
}

.overflow:hover span {
  position: relative;
  background-color: white;

  box-shadow: 0 0 4px 0 black;
  border-radius: 1px;
}
<div>
  <span class="overflow" style="float: left; width: 50px">
    <span>Long text that might overflow.</span>
  </span>
  Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad recusandae perspiciatis accusantium quas aut explicabo ab. Doloremque quam eos, alias dolore, iusto pariatur earum, ullam, quidem dolores deleniti perspiciatis omnis.
</div>
  1. Afficher une "info-bulle" arbitraire :
.wrap {
  position: relative;
}

.overflow {
  white-space: nowrap; 
  overflow: hidden;
  text-overflow: Ellipsis;
  
  pointer-events:none;
}

.overflow:after {
  content:"";
  display: block;
  position: absolute;
  top: 0;
  right: 0;
  width: 20px;
  height: 15px;
  z-index: 1;
  border: 1px solid red; /* for visualization only */
  pointer-events:initial;

}

.overflow:hover:after{
  cursor: pointer;
}

.tooltip {
  /* visibility: hidden; */
  display: none;
  position: absolute;
  top: 10;
  left: 0;
  background-color: #fff;
  padding: 10px;
  -webkit-box-shadow: 0 0 50px 0 rgba(0,0,0,0.3);
  opacity: 0;
  transition: opacity 0.5s ease;
}


.overflow:hover + .tooltip {
  /*visibility: visible; */
  display: initial;
  transition: opacity 0.5s ease;
  opacity: 1;
}
<div>
  <span class="wrap">
    <span class="overflow" style="float: left; width: 50px">Long text that might overflow</span>
    <span class='tooltip'>Long text that might overflow.</span>
  </span>
  Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad recusandae perspiciatis accusantium quas aut explicabo ab. Doloremque quam eos, alias dolore, iusto pariatur earum, ullam, quidem dolores deleniti perspiciatis omnis.
</div>
5
Hannes

C'est ce que j'ai fait. La plupart des scripts d'info-bulle nécessitent l'exécution d'une fonction qui stocke les info-bulles. Voici un exemple jQuery:

$.when($('*').filter(function() {
   return $(this).css('text-overflow') == 'Ellipsis';
}).each(function() {
   if (this.offsetWidth < this.scrollWidth && !$(this).attr('title')) {
      $(this).attr('title', $(this).text());
   }
})).done(function(){ 
   setupTooltip();
});

Si vous ne voulez pas vérifier Ellipsis css, simplifiez-vous comme ceci:

$.when($('*').filter(function() {
   return (this.offsetWidth < this.scrollWidth && !$(this).attr('title'));
}).each(function() {
   $(this).attr('title', $(this).text());
})).done(function(){ 
   setupTooltip();
});

J'ai le "quand" autour, de sorte que la fonction "setupTooltip" ne s'exécute pas tant que tous les titres n'ont pas été mis à jour. Remplacez le "setupTooltip", par la fonction info-bulle et le * par les éléments à vérifier. * passera par tous si vous le laissez.

Si vous voulez simplement mettre à jour les attributs de titre avec l'info-bulle du navigateur, vous pouvez simplifier comme ceci:

$('*').filter(function() {
   return $(this).css('text-overflow') == 'Ellipsis';
}).each(function() {
   if (this.offsetWidth < this.scrollWidth && !$(this).attr('title')) {
      $(this).attr('title', $(this).text());
   }
});

Ou sans chèque pour Ellipsis:

$.when($('*').filter(function() {
   return (this.offsetWidth < this.scrollWidth && !$(this).attr('title'));
}).each(function() {
   $(this).attr('title', $(this).text());
});
3
fanfavorite

Si vous voulez faire cela uniquement en utilisant javascript, je voudrais faire ce qui suit. Attribuez à l'attribut span un identifiant (afin qu'il puisse être facilement extrait du DOM) et placez tout le contenu dans un attribut nommé 'contenu':

<span id='myDataId' style='text-overflow: Ellipsis; overflow : hidden;
 white-space: nowrap; width: 71;' content='{$myData}'>${myData}</span>

Ensuite, dans votre javascript, vous pouvez effectuer les opérations suivantes une fois l’élément inséré dans le DOM.

var elemInnerText, elemContent;
elemInnerText = document.getElementById("myDataId").innerText;
elemContent = document.getElementById("myDataId").getAttribute('content')
if(elemInnerText.length <= elemContent.length)
{
   document.getElementById("myDataId").setAttribute('title', elemContent); 
}

Bien entendu, si vous utilisez du javascript pour insérer la plage dans le DOM, vous pouvez simplement conserver le contenu dans une variable avant de l'insérer. De cette façon, vous n'avez pas besoin d'un attribut de contenu sur la durée.

Il existe des solutions plus élégantes que cela si vous souhaitez utiliser jQuery.

2
Mark Costello

J'ai la classe CSS, qui détermine où mettre Ellipsis. En fonction de cela, je fais ce qui suit (le jeu d’éléments peut être différent, j’écris ceux dans lesquels Ellipsis est utilisé, bien sûr il pourrait s’agir d’un sélecteur de classe séparé):

$(document).on('mouseover', 'input, td, th', function() {
    if ($(this).css('text-overflow') && typeof $(this).attr('title') === 'undefined') {
        $(this).attr('title', $(this).val());
    }
});
1
Alexander

C'était ma solution, fonctionne comme un charme!

    $(document).on('mouseover', 'input, span', function() {
      var needEllipsis = $(this).css('text-overflow') && (this.offsetWidth < this.scrollWidth);
      var hasNotTitleAttr = typeof $(this).attr('title') === 'undefined';
      if (needEllipsis === true) {
          if(hasNotTitleAttr === true){
            $(this).attr('title', $(this).val());
          }
      }
      if(needEllipsis === false && hasNotTitleAttr == false){
        $(this).removeAttr('title');
      }
  });
0
FarukT

Vous pouvez éventuellement entourer l'envergure d'une autre étendue, puis simplement tester si la largeur de l'envergure d'origine/intérieure est supérieure à celle de la nouvelle étendue/extérieure. Notez que je dis éventuellement - c'est en gros basé sur ma situation où j'avais un span à l'intérieur d'un td alors je ne sais pas vraiment si cela fonctionnera avec un span à l'intérieur d'un span.

Voici cependant mon code pour les autres qui pourraient se retrouver dans une position similaire à la mienne; Je le copie/le colle sans le modifier même s’il se trouve dans un contexte Angular, je ne pense pas que cela nuise à la lisibilité et au concept essentiel. Je l'ai codé en tant que méthode de service car je devais l'appliquer à plusieurs endroits. Le sélecteur que j'ai transmis est un sélecteur de classe qui correspond à plusieurs instances.

CaseService.applyTooltip = function(selector) {
    angular.element(selector).on('mouseenter', function(){
        var td = $(this)
        var span = td.find('span');

        if (!span.attr('tooltip-computed')) {
            //compute just once
            span.attr('tooltip-computed','1');

            if (span.width() > td.width()){
                span.attr('data-toggle','tooltip');
                span.attr('data-placement','right');
                span.attr('title', span.html());
            }
        }
    });
}
0
George Jempty

Aucune des solutions ci-dessus n'a fonctionné pour moi, mais j'ai trouvé une excellente solution. La plus grande erreur que font les gens est d'avoir toutes les 3 propriétés CSS déclarées sur l'élément lors du chargement de page. Vous devez ajouter ces styles + info-bulle de manière dynamique SI et UNIQUEMENT SI la plage sur laquelle vous souhaitez une ellipses est plus large que son parent.

    $('table').each(function(){
        var content = $(this).find('span').text();
        var span = $(this).find('span');
        var td = $(this).find('td');
        var styles = {
            'text-overflow':'Ellipsis',
            'white-space':'nowrap',
            'overflow':'hidden',
            'display':'block',
            'width': 'auto'
        };
        if (span.width() > td.width()){
            span.css(styles)
                .tooltip({
                trigger: 'hover',
                html: true,
                title: content,
                placement: 'bottom'
            });
        }
    });
0
Brian Gabriel

Voici une solution JavaScript Vanille:

(function init() {

  var cells = document.getElementsByClassName("cell");

  for(let index = 0; index < cells.length; ++index) {
    let cell = cells.item(index);
    cell.addEventListener('mouseenter', setTitleIfNecessary, false);
  }

  function setTitleIfNecessary() {
    if(this.offsetWidth < this.scrollWidth) {
      this.setAttribute('title', this.innerHTML);
    }
  }

})();
.cell {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: Ellipsis;
  border: 1px;
  border-style: solid;
  width: 120px; 
}
<div class="cell">hello world!</div>
<div class="cell">hello mars! kind regards, world</div>
0
wuarmin