原生js实现一个侧滑删除取消组件(item slide)

组件,本质上是解决某个问题封装的类,在此记录原生js实现侧滑删除

 

先上效果图

 

 

实现思路

1. 确定渲染的数据结构

2. 思考划分布局,总的有两个主要的模块:内容区域和按钮区域

  2.1 内容区域保持宽度永远占满设备的宽度

  2.2 内容区域和按钮区域之和的宽度等于每一行item的总宽度

3. 每行超出的item的部分设置overflow: hidden; 通过touch相关的API事件监听手势是左滑还是右滑

4. 左滑的时候通过改变元素的一个特定属性来表明左滑,右滑同理

5. 通过css3 slector提前写好左滑情况和右滑情况下的样式,这里的样式主要是改变item的左右偏移

6. 创建元素的时候做的一些性能优化,尽量减少reflow,reflow的来源是由于dom的改变引起的,所以可以思考先将所有元素都写好后一次性插入,减少dom的变化,减少reflow

7. 左滑和右滑的样式的动画优化,让滑动更自然,这里使用了过度效果

 

整体代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximun-scale=1.0, user-scalable=0">
    <title>item slide</title>
    <style type="text/css">
        body,p {
            margin: 0;
        }
        .list-container {
            padding: 0;
            overflow: hidden;
            margin: 0;
        }
        .item-container {
            list-style: none;
            border-bottom: 0.5px solid #9e9e9e73;
            width: calc(100% + 10em);
            display: flex;
            align-items: stretch;
            transition: all ease-in-out 0.2s;
        }
        .left-contianer {
            padding: 10px 10px;
            flex: 100%;
        }
        .delete-container,
        .cancle-container {
            width: 5em;
            background: #f44336;
            position: relative;
        }

        .delete-Content,
        .cancle-Content {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: white;
        }

        .delete-container{
            border-right: 0.5px solid #ffffff80;
        }
        
        .item-container[data-type = "1"]{
            transform: translate3d(-10em, 0, 0);
        }

        .item-container[data-type = "0"]{
            transform: translate3d(0, 0, 0);
        }
    </style>
</head>
<body>
    <ul class="list-container"></ul>

    <script type="text/javascript">

        let list = [
            {
                remark:'1111111',
                value: '1111111dsdsdsdsdadsd'
            },
            {
                remark: '2222222',
                value: '2222222ssdsdadsdsadsa'
            },
            {
                remark: '3333333',
                value: '3333333sfsdsddsdsd'
            }
        ];

        class ItemSlide {
            constructor(obj){
                this.data = obj['data'] ? obj['data'] : [];
                this.name = obj['name'] ? obj['name'] : 'name';
                this.value = obj['value'] ? obj['value'] : 'value';
                this.startX = 0;
                this.endX = 0;
            }

            init(){
                this.listContainer = document.querySelector('.list-container');
                this.fragment = document.createDocumentFragment();
                this.render();
            }

            render(){
                this.data.map((v, i) => {
                    let item = document.createElement('li');
                    item.classList.add('item-container');
                    item.setAttribute('resource-id', i);
                    item.addEventListener('touchstart', this.touchStart.bind(this));
                    item.addEventListener('touchend', this.touchEnd.bind(this))

                    let leftContianer = document.createElement('div');
                    leftContianer.classList.add('left-contianer');

                    let name = document.createElement('p');
                    name.textContent = v[this.name];

                    let address = document.createElement('p');
                    address.textContent = v[this.value];

                    leftContianer.appendChild(name);
                    leftContianer.appendChild(address);
                    
                    let deleteBtn = document.createElement('div');
                    deleteBtn.classList.add('delete-container');
                    deleteBtn.addEventListener('click', this.delItem.bind(this), true);
                    

                    let deleteContent = document.createElement('span');
                    deleteContent.textContent = 'delete';
                    deleteContent.classList.add('delete-Content');
                    deleteBtn.appendChild(deleteContent);

                    let cancleBtn = document.createElement('div');
                    cancleBtn.classList.add('cancle-container');

                    let cancleContent = document.createElement('span');
                    cancleContent.textContent = 'cancle';
                    cancleContent.classList.add('cancle-Content');
                    cancleBtn.appendChild(cancleContent);

                    item.appendChild(leftContianer);
                    item.appendChild(deleteBtn);
                    item.appendChild(cancleBtn);

                    this.fragment.appendChild(item);
                });
                this.listContainer.appendChild(this.fragment);
            }

            touchStart(e) {
                this.startX = e.touches[0].clientX;
            }

            touchEnd(e) {
                const liEl = e.target.parentElement.parentElement;

                this.endX = e.changedTouches[0].clientX;
                let distance = this.startX - this.endX;

                // 左滑
                if(distance > 0) {
                    this.setSlide(liEl);
                // 右滑
                }else if(distance < 0) {
                    this.resetSlide(liEl);
                }
            }

            setSlide(el){
                el.setAttribute('data-type', "1");
            }

            resetSlide(el) {
                el.setAttribute('data-type', "0");
            }

            delItem(e){
                const parentEl = this.findParent(e, 'resource-id');
                this.listContainer.removeChild(parentEl);
            }

            findParent(childEl, attr){
                const parentEl = childEl.target ?
                     childEl.target.parentElement : 
                     childEl.parentElement;
                const id = parentEl.getAttribute(attr);
                if(id) {
                    return parentEl;
                }
                 return this.findParent(parentEl, attr);
            }

        }

        new ItemSlide({
            data: list,
            name: 'remark'
        }).init();
    </script>
</body>
</html>

 

 PS: 

代码中的创建节点感觉写得有点冗余,如果有刚简便并且要考虑到性能的好写法欢迎留言👍

posted @ 2019-06-10 17:02  承蒙时光  阅读(862)  评论(1编辑  收藏  举报