在React16中向长字符串的中间添加省略号

时间:2018-02-09 09:28:19

标签: javascript string render react-16

我正在尝试在字符串的中点添加省略号,但有以下复杂情况:

  • 我不知道字符串将会持续多长时间
  • 我只知道父元素的最大宽度和最小宽度
  • 该字符串可能适合也可能不适合它的父级而不需要省略号

我有一个plunk here来说明它。该脚本只假设一个实例,但您应该明白这一点:

(function(){
    // variables
    var parent = document.querySelectorAll(".wrapper")[0],
    parentWidth = parent.clientWidth,x = 0, elem, hellip
    txtStr = document.querySelector("#shorten"),
    strWidth = txtStr.clientWidth,
    strTxt = txtStr.innerText,
    ending = document.createElement("span"),
    endTxt = strTxt.slice(Math.max(strTxt.length - (strTxt.length / 4))) || endTxt;
    txtStr.style.overflow = "hidden"
    txtStr.style.textOverflow = "ellipsis"
    ending.appendChild(document.createTextNode(endTxt))
    ending.classList.add("ellipsis")
    document.querySelectorAll(".wrapper")[0].appendChild(ending)
    var ell = function(a, b){
        if (a <= b){
            ending.classList.add("visible")
        }
        else {
            ending.classList.remove("visible")
        }
    }
    ell(parentWidth, strWidth) // We need to display any changes immediately
    window.onresize = function(){ // if the window is resized, we also need to display changes
        hellip = document.querySelectorAll(".ellipsis")[0].clientWidth
        parentWidth = parent.clientWidth
        // the use of 'calc()' is because the length of string in px is never known
        txtStr.style.width = "calc(100% - " + hellip + "px"
        ell(parentWidth, strWidth)
    }
})();

它有点笨拙,但表明了这个想法。

我在React 16中遇到的问题是,字符串不是在我需要测量它以在结尾处创建文本位时呈现的。因此,在创建新节点时,它没有维度,无法测量,因为它不存在于DOM中。

功能有效 - 可以在屏幕调整大小时使用,但除了这一点之外。我需要让它在渲染时完成。

实际应用是专有的,我不能在此论坛中分享我的任何代码。

编辑:要记住的另一件事(在这里教鸡蛋)是在示例中,脚本仅在呈现DOM之后加载,因此所需的所有信息都是已经存在且可以衡量。

1 个答案:

答案 0 :(得分:2)

感谢所有关注此事的人,但我设法找出问题所在。

一旦我完成了生命周期的精细化,它实际上仍然非常棘手。问题在于测量原始文本字符串。现在回想起来,这看起来微不足道。

基本上,我将一些元素作为props传递给组件:id,任何必需的填充,上下文所需的结束文本的长度以及文本(子项)。

一旦它们进入,我需要等到它被装载,直到我可以做任何事情,因为它取决于在被测量任何东西之前渲染的DOM。因此,componentDidMount()和componentDidUpdate()是我感兴趣的阶段.componentWillUnmount()用于删除关联的事件侦听器,在此实例中是一个resize事件。

安装完成后,我可以获得测量所需的位:元素,重要的是它的父元素。

getElements(){
  return {
    parent: this.ellipsis.offsetParent,
    string: this.props.children
  }
}

然后,我需要确保我可以实际测量元素,以便实现一些内联样式以允许:

prepareParentForMeasure(){
  if(this.getElements().parent != null){
    this.getElements().parent.style.opacity = 0.001
    this.getElements().parent.style.overflow = 'visible'
    this.getElements().parent.style.width = 'auto'
  }
}

一旦我进行了这些测量,我就删除了样式。

此时,如果我沿着相同的路径继续,脚本将部分工作。但是,添加一个额外的元素作为指导是踢球者。

返回的元素被拆分为三个元素(span标记),每个元素都有不同的用途。如果您愿意,可以使用主要的文本或this.props.children。这始终可用,永远不会改变。接下来是文本的尾部,字符串末尾的'n'个字符用于在上下文中显示字符串的结尾 - 这是一个'省略号'的类,尽管实际上添加了省略号原始和第一个元素。第三个与第一个完全相同,但隐藏且不可交互,尽管它确实有尺寸。这是因为前两个 - 在渲染时 - 具有不同的宽度而不能依赖,因为两者都有助于元素的宽度,而第三个则没有。

<Fragment>
  <span className='text'>{this.props.children}</span>
  <span className='ellipsis'>{this.tail()}</span>
  <span className='text guide' ref={node => this.ellipsis = node}>
    {this.props.children}</span>
</Fragment>

这些是片段,以便不需要周围的元素。

所以,我有周围父级的宽度,我有文本元素的宽度(在第三个范围内)。这意味着如果我发现文本字符串比周围的包装器宽,我将一个类添加到'visible'的省略号范围,并将一个类添加到'trimmed'的'text'元素,我在中间得到一个省略号字符串和我使用resize事件确保如果有人这样做,所有测量都会重新完成,并重新计算和重新计算内容。