简体   繁体   English

HTML - 如何仅在激活省略号时显示工具提示

[英]HTML - how can I show tooltip ONLY when ellipsis is activated

I have got a span with dynamic data in my page, with ellipsis style.我的页面中有一个包含动态数据的跨度,带有ellipsis样式。

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

I'd like to add to this element tooltip with the same content, but I want it to appear only when the content is long and the ellipsis appear on screen.我想添加具有相同内容的元素工具提示,但我希望它仅在内容很长且省略号出现在屏幕上时才出现。

Is there any way to do it?有什么办法吗?
Does the browser throw an event when ellipsis is activated?激活ellipsis时浏览器是否会抛出事件?

*Browser: Internet Explorer *浏览器:Internet Explorer

Here's a way that does it using the built-in ellipsis setting, and adds the title attribute on-demand (with jQuery) building on Martin Smith's comment:这是一种使用内置省略号设置的方法,并根据 Martin Smith 的评论按需添加title属性(使用 jQuery):

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

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

Here's a pure CSS solution.这是一个纯 CSS 解决方案。 No need for jQuery.不需要 jQuery。 It won't show a tooltip, instead it'll just expand the content to its full length on mouseover.它不会显示工具提示,而是会在鼠标悬停时将内容扩展到其全长。

Works great if you have content that gets replaced.如果您的内容被替换,效果会很好。 Then you don't have to run a jQuery function every time.这样您就不必每次都运行 jQuery 函数。

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

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

Here are two other pure CSS solutions:这是另外两个纯 CSS 解决方案:

  1. Show the truncated text in 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. Show an arbitrary "tooltip" : 显示任意的“工具提示”

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

uosɐſ's answer is fundamentally correct, but you probably don't want to do it in the mouseenter event. uosɐſ 的回答从根本上是正确的,但您可能不想在 mouseenter 事件中这样做。 That's going to cause it to do the calculation to determine if it's needed, each time you mouse over the element.每次您将鼠标悬停在元素上时,这将导致它进行计算以确定是否需要它。 Unless the size of the element is changing, there's no reason to do that.除非元素的大小发生变化,否则没有理由这样做。

It would be better to just call this code immediately after the element is added to the DOM:最好在将元素添加到 DOM 后立即调用此代码:

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

Or, if you don't know when exactly it's added, then call that code after the page is finished loading.或者,如果您不知道它是何时添加的,则在页面加载完成后调用该代码。

if you have more than a single element that you need to do this with, then you can give them all the same class (such as "mightOverflow"), and use this code to update them all:如果您需要使用多个元素来执行此操作,那么您可以为它们提供所有相同的类(例如“mightOverflow”),并使用此代码来更新它们:

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

Here is my jQuery 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();

Edit:编辑:

I have made a gist for this plugin.我已经为这个插件做了一个要点。 https://gist.github.com/UziTech/d45102cdffb1039d4415 https://gist.github.com/UziTech/d45102cdffb1039d4415

We need to detect whether ellipsis is really applied, then to show a tooltip to reveal full text.我们需要检测是否真的应用了省略号,然后显示工具提示以显示全文。 It is not enough by only comparing " this.offsetWidth < this.scrollWidth " when the element nearly holding its content but only lacking one or two more pixels in width, especially for the text of full-width Chinese/Japanese/Korean characters.当元素几乎包含其内容但宽度仅缺少一两个像素时,仅比较“ this.offsetWidth < this.scrollWidth ”是不够的,特别是对于全角中文/日文/韩文字符的文本。

Here is an example: http://jsfiddle.net/28r5D/5/这是一个例子: http : //jsfiddle.net/28r5D/5/

I found a way to improve ellipsis detection:我找到了一种改进省略号检测的方法:

  1. Compare " this.offsetWidth < this.scrollWidth " first, continue step #2 if failed.首先比较“ this.offsetWidth < this.scrollWidth ”,如果失败则继续步骤#2。
  2. Switch css style temporally to {'overflow': 'visible', 'white-space': 'normal', 'word-break': 'break-all'}.暂时将 css 样式切换为 {'overflow': 'visible', 'white-space': 'normal', 'word-break': 'break-all'}。
  3. Let browser do relayout.让浏览器重新布局。 If word-wrap happening, the element will expands its height which also means ellipsis is required.如果发生自动换行,元素将扩展其高度,这也意味着需要省略号。
  4. Restore css style.恢复css样式。

Here is my improvement: http://jsfiddle.net/28r5D/6/这是我的改进: http : //jsfiddle.net/28r5D/6/

I created a jQuery plugin that uses Bootstrap's tooltip instead of the browser's build-in tooltip.我创建了一个 jQuery 插件,它使用 Bootstrap 的工具提示而不是浏览器的内置工具提示。 Please note that this has not been tested with older browser.请注意,这尚未在较旧的浏览器上进行测试。

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

Here's a Vanilla JavaScript solution:这是一个香草 JavaScript 解决方案:

 var cells = document.getElementsByClassName("cell"); for(const cell of cells) { 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>

If you want to do this solely using javascript, I would do the following.如果您想仅使用 javascript 执行此操作,我将执行以下操作。 Give the span an id attribute (so that it can easily be retrieved from the DOM) and place all the content in an attribute named 'content':给 span 一个 id 属性(以便它可以很容易地从 DOM 中检索)并将所有内容放在一个名为“content”的属性中:

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

Then, in your javascript, you can do the following after the element has been inserted into the DOM.然后,在您的 javascript 中,您可以在将元素插入 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); 
}

Of course, if you're using javascript to insert the span into the DOM, you could just keep the content in a variable before inserting it.当然,如果您使用 javascript 将 span 插入到 DOM 中,您可以在插入之前将内容保存在变量中。 This way you don't need a content attribute on the span.这样你就不需要跨度上的内容属性。

There are more elegant solutions than this if you want to use jQuery.如果您想使用 jQuery,还有比这更优雅的解决方案。

This was my solution, works as a charm!这是我的解决方案,很有魅力!

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

This is what I did.这就是我所做的。 Most tooltip scripts require you to execute a function that stores the tooltips.大多数工具提示脚本要求您执行一个存储工具提示的函数。 This is a jQuery example:这是一个 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();
});

If you didn't want to check for ellipsis css, you could simplify like:如果您不想检查省略号 css,您可以简化如下:

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

I have the "when" around it, so that the "setupTooltip" function doesn't execute until all titles have been updated.我在它周围有“when”,因此“setupTooltip”函数在所有标题都更新之前不会执行。 Replace the "setupTooltip", with your tooltip function and the * with the elements you want to check.将“setupTooltip”替换为您的工具提示功能,将 * 替换为您要检查的元素。 * will go through them all if you leave it. * 如果你离开它,它们会全部通过。

If you simply want to just update the title attributes with the browsers tooltip, you can simplify like:如果您只想使用浏览器工具提示更新标题属性,您可以简化如下:

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

Or without check for ellipsis:或者不检查省略号:

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

This is what I ended up doing based on https://stackoverflow.com/a/13259660/1714951 and adding the removal of the title attribute when the element doesn't overflow anymore.这就是我最终基于https://stackoverflow.com/a/13259660/1714951所做的,并在元素不再溢出时添加了 title 属性的删除。 This is pure JS (ES6), uses event delegation for performance (when using several elements with the same class) and guard clauses for readability:这是纯 JS (ES6),使用事件委托来提高性能(当使用具有相同类的多个元素时)并使用保护子句来提高可读性:

// You may want to change document by an element closer to your target
// so that the handler is not executed as much
document.addEventListener( 'mouseenter', event => {
    let eventTarget = event.target;
    // This could be easily applied to text-truncate instead of my-class if you use bootstrap
    if ( !eventTarget.classList?.contains( 'my-class' ) ) {
        return;
    }
    if ( eventTarget.offsetWidth < eventTarget.scrollWidth ) {
        eventTarget.setAttribute( 'title', eventTarget.innerText );
        return;
    }
    eventTarget.removeAttribute( 'title' );
}, true );

I have CSS class, which determines where to put ellipsis.我有 CSS 类,它决定了在哪里放置省略号。 Based on that, I do the following (element set could be different, i write those, where ellipsis is used, of course it could be a separate class selector):基于此,我执行以下操作(元素集可能不同,我写了那些使用省略号的地方,当然它可能是一个单独的类选择器):

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

None of the solutions above worked for me, but I figured out a great solution.上面的解决方案都不适合我,但我想出了一个很好的解决方案。 The biggest mistake people are making is having all the 3 CSS properties declared on the element upon pageload.人们犯的最大错误是在页面加载时在元素上声明了所有 3 个 CSS 属性。 You have to add those styles+tooltip dynamically IF and ONLY IF the span you want an ellipses on is wider than its 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'
            });
        }
    });

You could possibly surround the span with another span, then simply test if the width of the original/inner span is greater than that of the new/outer span.您可以用另一个跨度包围跨度,然后简单地测试原始/内部跨度的宽度是否大于新/外跨度的宽度。 Note that I say possibly -- it is roughly based on my situation where I had a span inside of a td so I don't actually know that if it will work with a span inside of a span .请注意,我说可能 - 它大致基于我在td内部有一个span情况,所以我实际上不知道它是否可以在span内部使用span

Here though is my code for others who may find themselves in a position similar to mine;不过,这里是我的代码,适用于可能发现自己处于与我类似的位置的其他人; I'm copying/pasting it without modification even though it is in an Angular context, I don't think that detracts from the readability and the essential concept.即使它是在 Angular 上下文中,我也没有修改地复制/粘贴它,我认为这不会降低可读性和基本概念。 I coded it as a service method because I needed to apply it in more than one place.我将它编码为一种服务方法,因为我需要在多个地方应用它。 The selector I've been passing in has been a class selector that will match multiple 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());
            }
        }
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM