Multiline content exceeds Show the ultimate solution

Posted by kessels1234 on Fri, 24 Dec 2021 09:50:46 +0100

Recently, I encountered a seemingly simple problem, but it is not easy to write. For multiline text, beyond Display. It can be implemented through css, but limited by browser compatibility, it sometimes needs to rely on JS. Through JS implementation, we need to consider the text size. The byte lengths corresponding to Chinese and English, numeral and punctuation symbols are inconsistent. If we do not consider it comprehensively, there will always be a gap for different text contents.

First of all, we need to understand that the byte length occupied by Chinese characters, English letters, numbers and special symbols is different. If it needs to be calculated accurately, it cannot be intercepted according to the number of elements of the string. They can be intercepted by converting them into the number of bytes, which has higher accuracy. Therefore, we need a method to obtain the length of string bytes:

    function bitCompute(content) {
        var total = 0,
            len = arguments[0].length || 0
        for (var i = 0; i < len; i++) {
            if (content[i].charCodeAt() > 255) {
                total += 2;
            } else {
                total += 1;
            }
        }
        return total
    }

Copy code
For the number of bytes of content to be intercepted, we need to know the ratio of the number of bytes that can be put into the container to the total number of bytes. Show the number of bytes / total bytes = offsetWidth / scrollWidth:

     function complate() {
        var offsetWidth = el.offsetWidth;
        var scrollWidth = el.scrollWidth;
        var gap = scrollWidth - offsetWidth;
        var percent = Math.floor(offsetWidth / scrollWidth * 1e3) / 1e3;
        return {
            gap: gap,
            percent: percent
        }
    }

Copy code
According to the calculated data, we can manipulate the string

    function cut(content) {
        el.innerHTML = content;
        var info = complate(),
            percent = info.percent;
        var total = bitCompute(content).total;
        var showLen = +(total * percent).toFixed(0) - cfg.placeholder;
        content = bitCompute(content, showLen).content;
        return content + cfg.padding;
    }
    
    function bitCompute(content, maxLen) {
        var total = 0,
            len = arguments[0].length || 0,
            outContent = '';
        for (var i = 0; i < len; i++) {
            if (content[i].charCodeAt() > 255) {
                total += 2;
            } else {
                total += 1;
            }
            if (maxLen && total > maxLen) {
                break;
            }
            outContent += content[i];
        }
        return {
            total: total,
            content: outContent
        }
    }

Copy code
Of course, the amount of text displayed is also related to the font size, so we also need to take the factor of font size into account. Moreover, as a working method, it should not be associated with the elements in the page. Therefore, we should create elements in the method, put in the content, and calculate offsetWidth and scrollWidth

  function cutFactory(opt) {
    var cfg = {
        padding: opt.padding || "...",
        classList: opt.classList || [],
        style: opt.style || {},
        debug: opt.debug
    };
    cfg.placeholder = bitCompute(cfg.padding).total;
    var el = doc.createElement("span");
    el.className = cfg.classList.join(" ");
    var customStyles = [];
    for (var styleKey in cfg.style) {
        if (cfg.style.hasOwnProperty(styleKey)) {
            customStyles.push(styleKey + ":" + cfg.style[styleKey]);
        }
    }
    el.style.cssText = "position:absolute;left:0;top:0;background:transparent;color:transparent;height:100%;white-space:nowrap;overflow:visible;border:0;" + (cfg.debug ? "background:white;color:red;" : "") + customStyles.join(";");
    var div = doc.createElement("div");
    div.appendChild(el);
    div.style.cssText = "width:99%;min-height:50px;line-height:50px;position:absolute;left:3px;top:3px;overflow:hidden;outline:0;background:transparent;" + (cfg.debug ? "outline:1px solid red;background:black;" : "");
    doc.body.appendChild(div);
    var css = win.getComputedStyle(el);
    cfg.fontSize = parseFloat(css.fontSize) || 16;
    
     return function (content) {
        el.innerHTML = content;
        var out = {
            flag: false,
            cut: '',
            all: content,
            last: content
        }
        if (complate().gap > 0) {
            out.flag = true,
            out.last = out.cut = cut(content)
        }
        return out
    }
 }

Copy code
Finally, another method is exposed to facilitate user invocation. For performance reasons, instead of creating too many dom elements, we can cache interception methods with the same font size and container width

function subStringEL(name, fontSize, width) {
    this.subStringELFns || (this.subStringELFns = {});
    var key = 'key_' + fontSize + '_' + width;
    var fn = this.subStringELFns[key];
    if (!fn) {
        fn = this.subStringELFns[key] = cutFactory({
            style: {
                'font-size': fontSize,
                'width': width
            }
        })
    }
    return fn(name);
}

last
If you think this article is a little helpful to you, give it a compliment. Or you can join my development exchange group: 1025263163 learn from each other, and we will have professional technical Q & A to solve doubts

If you think this article is useful to you, please click star: https://gitee.com/ZhongBangKe... esteem it a favor!

PHP learning manual: https://doc.crmeb.com
Technical exchange forum: https://q.crmeb.com

Topics: PHP