HTML - làm cách nào tôi có thể hiển thị tooltip CHỈ khi dấu chấm lửng được kích hoạt


205

Tôi đã có một khoảng với dữ liệu động trong trang của mình, với ellipsisphong cách.

.my-class
{
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;  
  width: 71px;
}
<span id="myId" class="my-class"></span>
document.getElementById('myId').innerText = "...";

Tôi muốn thêm vào tooltip phần tử này với cùng một nội dung, nhưng tôi muốn nó chỉ xuất hiện khi nội dung dài và dấu chấm lửng xuất hiện trên màn hình.

Có cách nào để làm điều đó?
Trình duyệt có ném một sự kiện khi ellipsisđược kích hoạt không?

* Trình duyệt: Internet Explorer


1
Hãy nhớ rằng text-overflow:ellipsis;hoàn toàn không hoạt động trong Firefox - xem thêm câu hỏi này: stackoverflow.com/questions/4927257/
Kẻ

2
Tôi chỉ phải làm một cái gì đó tương tự. Kiểm tra xem element.offsetWidth < element.scrollWidththeo câu trả lời này dường như làm việc cho đến nay.
Martin Smith

Phát hiện dấu chấm lửng: stackoverflow.com/questions/7738117/ từ
Adrien Be

7
Lưu ý cho hậu thế: text-overflow:ellipsis;hiện hoạt động trong Firefox; nó đã được thêm vào Firefox 7 (phát hành tháng 9 năm 2011).
sleske

Câu trả lời:


161

Đây là một cách sử dụng cài đặt dấu chấm lửng tích hợp và thêm titlethuộc tính theo yêu cầu (với jQuery) dựa trên nhận xét của Martin Smith:

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

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

4
Cảm ơn, làm việc như một nét duyên dáng! Tuy nhiên, nếu bạn muốn làm cho nó hiệu quả hơn, bạn có thể cân nhắc thay thế bind () bằng on () như vậy: $ (document) .on ('mouseenter', '.mightOverflow', function () {...});
Ziad

17
Nếu bạn muốn xóa chú giải công cụ nếu văn bản không còn tràn sửa đổi thành: $ (tài liệu) .on ('mouseenter', '.mightOverflow', function () {var $ t = $ (this); var title = $ t.attr ('title'); if (! title) {if (this.offsetWidth <this.scrollWidth) $ t.attr ('title', $ t.text ())}} {if (this.offsetWidth> = this.scrollWidth && title == $ t.text ()) $ t.removeAttr ('title')}});
Chris Janssen

1
mouseenter là sự kiện chúng tôi liên kết hoặc lắng nghe. Chúng tôi thực sự không phải thêm tooltip vào các yếu tố cho đến khi có ai đó thực sự bắt chước chúng. Vì vậy, chúng tôi trì hoãn việc bổ sung cho đến thời điểm đó của mouseenter trên bất kỳ một trong các thành phần DOM nào với lớp "mightoverflow". Just-In-Time-Tooltips
Jason Kleban

2
"As of jQuery 1.7, the .on() method is the preferred method for attaching event handlers to a document"để biết thêm thông tin, hãy xem api.jquery.com/bindapi.jquery.com/on
Adrien Be

2
Nó không hoạt động trên IE10 - offsetWidth giống hệt với scrollWidth, cả hai đều cho tôi chiều rộng bị cắt ngắn.
SsjCosty

59

Đây là một giải pháp CSS thuần túy. Không cần jQuery. Nó sẽ không hiển thị một chú giải công cụ, thay vào đó, nó sẽ chỉ mở rộng nội dung đến toàn bộ thời gian di chuột.

Hoạt động tuyệt vời nếu bạn có nội dung được thay thế. Sau đó, bạn không phải chạy một hàm jQuery mỗi lần.

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

.might-overflow:hover {
    text-overflow: clip;
    white-space: normal;
    word-break: break-all;
}

18
Nó không tốt như tooltip, vì nó có thể phá vỡ bố cục.
Alexander

2
Vấn đề với chú giải công cụ là chúng không hoạt động trên thiết bị di động, ít nhất là bây giờ. Câu trả lời này có thể (đọc: có thể sẽ) phá vỡ bố cục, nhưng nó có thể được điều chỉnh để, ví dụ, có màu nền khác cho phần tử được di chuột. Điều này vẫn không hoạt động trên thiết bị di động, nhưng nó là một tùy chọn khác cho máy tính để bàn.
phân tích

1
Cảm ơn câu trả lời tuyệt vời này hoàn toàn đáp ứng nhu cầu của tôi. Sử dụng một số JavaScript, chúng ta có thể tưởng tượng làm cho khối được định vị hoàn toàn để nó không phá vỡ bố cục.
Niavlys

2
Đó là một câu trả lời hay, tốt hơn so với việc viết javascript về vấn đề css. Rõ ràng dấu chấm lửng NÊN có một tùy chọn tiêu đề tự động, cách nó được thực hiện tại thời điểm này là thiếu ý nghĩa. Quá xấu css không cho phép chỉ: di chuột nếu các ký tự cuối cùng là '...'
John

32

Câu trả lời của uosɐſ về cơ bản là chính xác, nhưng có lẽ bạn không muốn làm điều đó trong sự kiện mouseenter. Điều đó sẽ khiến nó thực hiện phép tính để xác định xem có cần thiết không, mỗi lần bạn di chuột qua phần tử. Trừ khi kích thước của phần tử đang thay đổi, không có lý do để làm điều đó.

Sẽ tốt hơn nếu chỉ gọi mã này ngay lập tức sau khi phần tử được thêm vào DOM:

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

Hoặc, nếu bạn không biết chính xác khi nào nó được thêm vào, thì hãy gọi mã đó sau khi tải xong trang.

nếu bạn có nhiều hơn một phần tử mà bạn cần thực hiện điều này, thì bạn có thể cung cấp cho chúng tất cả cùng một lớp (chẳng hạn như "mightOverflow") và sử dụng mã này để cập nhật tất cả:

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

+1, thực hiện khi tải trang có vẻ đơn giản hơn nhưng cũng cung cấp nhiều khả năng hơn. I E. bạn có thể muốn tạo kiểu cho phần tử này có một chú giải công cụ với phần gạch chân được chấm chấm để "báo hiệu" cho chú giải công cụ. chẳng hạn như$(".mightOverflow").each(function() { if( $(this).offsetWidth < $(this).scrollWidth && !$(this).attr('title')){ $(this).attr('title', $(this).text()); $(this).css('border-bottom', '1px dotted #A8A8A8'); } });
Adrien Be

'mỗi lần bạn di chuột qua' đều sai (ít nhất là bây giờ - tôi không biết câu trả lời đã được cập nhật chưa) Nó sẽ kiểm tra xem nó có được tính toán trước đó không '&&! $ this.attr (' title ')'
Rune Jeppesen

Không, điều đó chỉ khiến nó không thêm thuộc tính tiêu đề nữa. Việc tính toán để xác định xem có cần thiết hay không. this.offsetWidth < this.scrollWidthvà thậm chí có thể kiểm tra !$this.attr('title')sẽ được thực hiện mỗi khi bạn di chuột qua phần tử.
Elezar

9
Vấn đề với phương pháp này là tất cả các yếu tố được kiểm tra cùng một lúc (tác động hiệu suất tiềm năng) và nó chỉ tính toán một lần, do đó, nếu người dùng thu nhỏ trình duyệt khiến mọi thứ bị cắt ngắn hoặc mở rộng, khiến chúng không còn bị cắt cụt nữa cập nhật sự hiện diện của một tooltip. Việc gắn mã của bạn vào cửa sổ thay đổi kích thước một lần nữa sẽ có vấn đề về hiệu năng vì mọi mục đều kiểm tra kích thước của nó. Bằng cách sử dụng phân quyền sự kiện "$ (tài liệu) .on ('mouseenter', '.mightOverflow', ..." và trì hoãn việc kiểm tra cho đến khi bạn di chuột qua phần tử, bạn có thể cập nhật nhanh chóng và chỉ kiểm tra 1 phần tử @ một lần
Chris Janssen

Nó không hoạt động trên IE10 - offsetWidth giống hệt với scrollWidth, cả hai đều cho tôi chiều rộng bị cắt ngắn.
SsjCosty

18

Đây là hai giải pháp CSS thuần túy khác:

  1. Hiển thị văn bản cắt ngắn tại chỗ:

.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. Hiển thị một "tooltip" tùy ý :

.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>


Điều này thật đúng với gì mà tôi đã tìm kiếm!
Praneet Nadkar

Giải pháp tuyệt vời, chính xác những gì tôi cần. Cảm ơn bạn !
Agu V

17

Đây là plugin jQuery của tôi:

(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);

Sử dụng:

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

Biên tập:

Tôi đã thực hiện một ý chính cho plugin này. https://gist.github.com/UziTech/d45102cdffb1039d4415


1
Nó không hoạt động trên IE10 - offsetWidth giống hệt với scrollWidth, cả hai đều cho tôi chiều rộng bị cắt ngắn.
SsjCosty

@SsjCosty tại sao bạn thử nghiệm trên IE 10? Không nên có ai sử dụng IE 10 vào thời điểm này, vì bất kỳ ai có thể cài đặt IE 10 đều có thể cài đặt IE 11.
Tony Brix

À, chúng tôi có một chính sách công ty mà phiên bản IE tối thiểu của chúng tôi hỗ trợ là 10. Ngoài ra vì rất nhiều khách hàng của chúng tôi (một số ngân hàng và các tổ chức khác nhau) vẫn sử dụng IE10. Ồ tốt
SsjCosty

12

Chúng ta cần phát hiện xem dấu chấm lửng có thực sự được áp dụng hay không, sau đó hiển thị một chú giải công cụ để hiển thị toàn văn. Sẽ không đủ nếu chỉ so sánh " this.offsetWidth < this.scrollWidth" khi phần tử gần như giữ nội dung của nó mà chỉ thiếu một hoặc hai pixel chiều rộng, đặc biệt là đối với văn bản của các ký tự Trung Quốc / Nhật Bản / Hàn Quốc có chiều rộng đầy đủ.

Dưới đây là một ví dụ: http://jsfiddle.net/28r5D/5/

Tôi tìm thấy một cách để cải thiện phát hiện dấu chấm lửng:

  1. So sánh " this.offsetWidth < this.scrollWidth" trước, tiếp tục bước # 2 nếu thất bại.
  2. Chuyển kiểu css tạm thời thành {'tràn': 'hiển thị', 'khoảng trắng': 'bình thường', 'ngắt từ': 'break-all'}.
  3. Hãy để trình duyệt thực hiện chuyển tiếp. Nếu xảy ra hiện tượng ngắt từ, phần tử sẽ mở rộng chiều cao của nó, điều đó cũng có nghĩa là cần có dấu chấm lửng.
  4. Khôi phục kiểu css.

Đây là sự cải tiến của tôi: http://jsfiddle.net/28r5D/6/


10

Tôi đã tạo một plugin jQuery sử dụng tooltip của Bootstrap thay vì tooltip tích hợp của trình duyệt. Xin lưu ý rằng điều này chưa được thử nghiệm với trình duyệt cũ hơn.

JSFiddle: https://jsfiddle.net/0bhsoirl/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");
      }
    }
  });
};

Đơn giản và rực rỡ. Cảm ơn bạn!
GumZ

3

Đây là những gì tôi đã làm. Hầu hết các tập lệnh tooltip yêu cầu bạn thực thi một chức năng lưu trữ các chú giải công cụ. Đây là một ví dụ về 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();
});

Nếu bạn không muốn kiểm tra dấu chấm lửng, bạn có thể đơn giản hóa như sau:

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

Tôi có "khi" xung quanh nó, để chức năng "setupTooltip" không thực thi cho đến khi tất cả các tiêu đề đã được cập nhật. Thay thế "setupTooltip", bằng chức năng tooltip của bạn và * bằng các yếu tố bạn muốn kiểm tra. * sẽ đi qua tất cả nếu bạn rời khỏi nó.

Nếu bạn chỉ muốn cập nhật các thuộc tính tiêu đề bằng công cụ trình duyệt, bạn có thể đơn giản hóa như sau:

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

Hoặc không kiểm tra dấu chấm lửng:

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

Tại sao các downvote? Hãy bình luận nếu bạn đang làm điều đó để mọi người biết vấn đề là gì. Cảm ơn.
fanfavorite

2

Nếu bạn muốn làm điều này chỉ bằng cách sử dụng javascript, tôi sẽ làm như sau. Cung cấp cho span một thuộc tính id (để có thể dễ dàng truy xuất từ ​​DOM) và đặt tất cả nội dung trong một thuộc tính có tên 'content':

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

Sau đó, trong javascript của bạn, bạn có thể thực hiện các thao tác sau sau khi phần tử được chèn vào 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); 
}

Tất nhiên, nếu bạn đang sử dụng javascript để chèn khoảng thời gian vào DOM, bạn chỉ có thể giữ nội dung trong một biến trước khi chèn nó. Bằng cách này, bạn không cần một thuộc tính nội dung trên nhịp.

Có nhiều giải pháp thanh lịch hơn thế này nếu bạn muốn sử dụng jQuery.


Đẹp. Vì tôi đang sử dụng JQuery trong phần khác của trang này - giải pháp tao nhã của JQuery là gì ??
Người nhện

$("#myDataId").attr("title", function() { var innerText = $(this).text(); var content = $(this).attr("content"); if (innerText.length <= content.length) { return content; } return null; });
Đánh dấu Costello

1
Tôi đã thử đề xuất đầu tiên của bạn với javascript thuần túy - nó không hoạt động. thuộc tính 'InternalText' lưu toàn bộ chiều dài của văn bản ngay cả khi nó không hiển thị hoàn toàn trên màn hình vì vậy luôn luôn: elemInnerText.length == elemContent.length !!
Người nhện

Kiểu nhịp của bạn là chiều rộng 71. Tại sao không kiểm tra xem độ rộng của chuỗi có dài hơn không? Nếu bạn muốn làm một cái gì đó thực sự thú vị, bạn có thể thêm một yếu tố ẩn mà không cần tràn văn bản: dấu chấm lửng và so sánh độ rộng của cả hai. Nếu cái ẩn rộng hơn cái không ẩn, hãy thêm thuộc tính title vào cái nhìn thấy được.
Đánh dấu Costello

2

Tôi có lớp CSS, xác định nơi đặt dấu chấm lửng. Dựa vào đó, tôi làm như sau (bộ phần tử có thể khác, tôi viết chúng, trong đó sử dụng dấu chấm lửng, tất nhiên nó có thể là một bộ chọn lớp riêng biệt):

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

1
i trường hợp của tôi thislà một anchorvì vậy tôi đã sử dụng this.text()thay vìval()
Basheer AL-MOMani

2

Đây là một giải pháp JavaScript của Vanilla:

(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>


1

Đây là giải pháp của tôi, hoạt động như một cơ duyên!

    $(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');
      }
  });

Xin chào @FarukT giải pháp của bạn đang hoạt động tốt cho tôi, cảm ơn bạn rất nhiều. Tôi muốn hỏi liệu tôi có hai thẻ html giả sử đầu vào & span không và tôi muốn tính toán offsetWidth của cả hai thẻ này cùng một lúc để thực hiện một số phép tính Số học bằng cách sử dụng offsetWidth. Làm thế nào tôi có thể làm điều đó?
Kunal Tyagi

Xin chào @KunalTyagi, bạn có thể sử dụng nó với 2 chức năng riêng biệt, tôi chỉ được viết một chức năng với đầu vào và khoảng thời gian nhưng bạn có thể sao chép chức năng này 2 lần, ví dụ chức năng đầu tiên chỉ với đầu vào và chỉ trong chức năng thứ hai. như thế này: $ (tài liệu) .on ('mouseover', 'input', function () {...}); và thứ hai $ (tài liệu) .on ('mouseover', 'span', function () {...});
FarukT

0

Không có giải pháp nào ở trên làm việc cho tôi, nhưng tôi đã tìm ra một giải pháp tuyệt vời. Sai lầm lớn nhất mà mọi người đang mắc phải là có tất cả 3 thuộc tính CSS được khai báo trên phần tử khi tải trang. Bạn phải thêm các kiểu + tooltip đó một cách linh hoạt NẾU và CHỈ NẾU khoảng thời gian bạn muốn một hình elip trên rộng hơn cha mẹ của nó.

    $('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

Bạn có thể bao quanh nhịp với một nhịp khác, sau đó chỉ cần kiểm tra xem độ rộng của nhịp ban đầu / bên trong có lớn hơn nhịp mới / nhịp ngoài hay không. Lưu ý rằng tôi có thể nói - đó là dựa trên tình huống của tôi khi tôi có một spanbên trong tdvì vậy tôi thực sự không biết rằng nếu nó sẽ hoạt động với spanbên trong của một span.

Mặc dù đây là mã của tôi cho những người khác có thể thấy mình ở một vị trí tương tự như của tôi; Tôi đang sao chép / dán nó mà không sửa đổi mặc dù nó ở trong bối cảnh Angular, tôi không nghĩ rằng điều đó làm giảm khả năng đọc và khái niệm thiết yếu. Tôi đã mã hóa nó như một phương thức dịch vụ vì tôi cần áp dụng nó ở nhiều nơi. Bộ chọn mà tôi đã chuyển qua là một bộ chọn lớp sẽ khớp với nhiều trường hợp.

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());
            }
        }
    });
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.