React列表中实现文案多行收起展开的功能

更新日期: 2020-05-08阅读: 3k标签: 列表

css实现

在我们平时的业务开发中经常会用到文案超出只有收起,点击在展示全部文案;通常的使用时使用css来实现

display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;

效果如下:


使用css实现时只能做多行的省略,也没法根据文字去添加定制化的按钮去实现展开收起的功能,这个只是适合特定要求不是很高的场合下使用。


字符串截取

另一种方法是使用字符串截取的方案

_renderContent = item => {
    const { content, id } = item;
    if (content.length > 69) {
        return (
            <div>
                <div ref={id} className="content">
                    {content.slice(0, 69)}
                </div>
                <div
                    className="content-btn"
                    ref={id + 'btn'}
                    onClick={() => {
                        this.handleContent(item);
                    }}>
                    全文
                </div>
            </div>
        );
    } else {
        return <div className="content">{content}</div>;
    }
};

展示效果:


弊端:数字、中文字符和引文字符的宽度是不一样的,在使用字符串截取是很容易出现如上的偏差,并且每个手机的分辨率不一样,字符渲染的宽度像素也是不同的,这样也会导致误差;所以字符串截取也不是一种很好的方案。


最终实现方案

话不多说直接上代码:content组件

js代码:

import react from 'react';
import cs from 'classnames';

import './style.scss';
export default class TextContainer extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            content: props.content,
            showAll: false,
            btnText: '全文',
            needHidden: false //  文字超出4行 需要隐藏
        };
    }

    /**
     * @description: 处理content文案的点击展开收起
     * @return: null
     */
    handleContent = e => {
        e.stopPropagation();
        let { showAll } = this.state;
        this.setState({
            showAll: !showAll
        });
    };

    // 判断文本超出行数
    isElementCollision = (ele, rowCount = 4, cssStyles, removeChild) => {
        if (!ele) {
            return false;
        }

        const clonedNode = ele.cloneNode(true);
        // 给clone的dom增加样式
        clonedNode.style.overflow = 'visible';
        clonedNode.style.display = 'inline-block';
        clonedNode.style.width = 'auto';
        clonedNode.style.whiteSpace = 'nowrap';
        clonedNode.style.visibility = 'hidden';
        // 将传入的css字体样式赋值
        if (cssStyles) {
            Object.keys(cssStyles).forEach(item => {
                clonedNode.style[item] = cssStyles[item];
            });
        }

        // 给clone的dom增加id属性
        let _time = new Date().getTime();

        const containerID = 'collision_node_id_' + _time;
        clonedNode.setAttribute('id', containerID);

        let tmpNode = document.getElementById(containerID);
        let newNode = clonedNode;
        if (tmpNode) {
            document.body.replaceChild(clonedNode, tmpNode);
        } else {
            newNode = document.body.appendChild(clonedNode);
        }
        // 新增的dom宽度与原dom的宽度*限制行数做对比
        const differ = newNode.offsetWidth - ele.offsetWidth * rowCount + 40;
        // console.log(differ, 'differ');
        if (removeChild) {
            document.body.removeChild(newNode);
        }
        return differ > 0;
    };

    componentDidMount = () => {
        const cssStyles = { fontSize: '0.9375rem', fontWeight: '400', lineHeight: '1.5625rem' };
        // console.log(this.isElementCollision(this.refs['content'], 4, cssStyles, true));
        let needHidden = this.isElementCollision(this.refs['content'], 4, cssStyles, true);
        this.setState({
            needHidden
        });
    };

    render() {
        let { content, needHidden, showAll } = this.state;
        let { headerText } = this.props;
        return (
            <div>
                <div
                    ref={'content'}
                    className={cs('content', { 'hidden-text': !showAll && needHidden })}>
                    {headerText ? headerText() : null}
                    {content}
                </div>
                {needHidden && (
                    <div
                        className="content-btn"
                        onClick={e => {
                            this.handleContent(e);
                        }}>
                        {!showAll ? '全文' : '收起'}
                    </div>
                )}
            </div>
        );
    }
}

css代码:

$baseFontSize:32px !default;

// pixels to rems
@function pxToRem($px) {
    @return $px / $baseFontSize * 1rem;
}

.content {
    font-size: pxToRem(30px);
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: rgba(0, 0, 0, 1);
    line-height: pxToRem(50px);

}

.hidden-text {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    /*! autoprefixer: off */
    -webkit-box-orient: vertical;
    /* autoprefixer: on */
    overflow: hidden;
}

.content-btn {
    font-size: pxToRem(28px);
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 600;
    color: rgba(162, 116, 56, 1);
    line-height: pxToRem(48px);
    margin-top: pxToRem(10px);
}

引用:

import TextContainer from '@/textContainer';
_renderContent = item => {
    const { content, id } = item;
    return <TextContainer content={content} />;
};

效果:


总结

以上是本人在平时开发中使用的方式,希望对大家有所帮助,如果老铁们有更好的方案可留言展示一下。

来自:https://segmentfault.com/a/1190000022834779


链接: https://www.fly63.com/article/detial/9259

CSS实现无外边框列表效果

使用外层容器切割:给每一个 li 设定右边框和下边框线,使用CSS选择器此方法仅适用于每行固定显示两个li的情况,不需要计算宽高,也不需要设置父容器。使用table通过CSS选择器li:nth-last-child(2)和li:last-child隐藏最后两个li的下边框

html列表简单介绍

无序列表使用标签:<ul>,<li>属性:disc,circle,square;有序列表使用标签:<ol>,<li>属性:A,a,I,i,start;嵌套列表使用标签:<ul>,<ol>,<li> ;自定义列表使用标签:<dl>,<dt>,<dd>

css样式li不显示点点什么原因?怎么解决?

实际上用了overflow:hidden 会影响 list-style,即当ul 中的li 的overflow 为hidden的时候, list-style不起作用,不显示前面的点、圈等样式。

Vue.js 多选列表(Multi-Select)组件

多选列表 (Multi-Select) 是一种将所有选项列出,并允许用户利用 Ctrl/Shift 键进行多选的 UI 元素。这是一种常见的设计元素。有时候为了节省空间,我们会将选项折叠于 Combo Box 中

如何让10万条数据的小程序列表如丝般顺滑

某天闲着无聊想练一下手速,去上拉一个小程序项目中一个有1万多条商品数据的列表。在数据加载到1000多条后,是列表居然出现了白屏。看了一下控制台:

了解虚拟列表背后原理,轻松实现虚拟列表

比如 umy-ui (ux-table)虚拟列表table组件, vue-virtual-scroller 以及 react-virtualized 这些优秀的插件快速满足业务需要。为了理解插件背后的原理机制,我们实现一个自己简易版的虚拟列表,希望在实际业务项目中能带来一些思考和帮助。

React 中的列表渲染为什么要加 key

常用写法是用 Arrary.prototype.map 方法,将数组形式的数据映射为 JSX.Element 数组,并嵌入到组件要返回的 JSX.Element 中,如下:

浅说虚拟列表的实现原理

在正文之前,先对虚拟列表做个简单的定义。根据上文,虚拟列表是按需显示思路的一种实现,即虚拟列表是一种根据滚动容器元素的可视区域来渲染长列表数据中某一个部分数据的技术。

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!