原生js實現一個側滑刪除取消元件(item slide)

承蒙時光發表於2019-06-10

元件,本質上是解決某個問題封裝的類,在此記錄原生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 = [
            {
                name:'1111111',
                address: '1111111dsdsdsdsdadsd'
            },
            {
                name: '2222222',
                address: '2222222ssdsdadsdsadsa'
            },
            {
                name: '3333333',
                address: '3333333sfsdsddsdsd'
            }
        ];

        class ItemSlide {
            constructor(obj){
                this.data = obj['data'] ? obj['data'] : [];
                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 + 1);
                    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.name;

                    let address = document.createElement('p');
                    address.textContent = v.address;

                    leftContianer.appendChild(name);
                    leftContianer.appendChild(address);
                    
                    let deleteBtn = document.createElement('div');
                    deleteBtn.classList.add('delete-container');
                    

                    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");
            }

        }

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

 PS: 

程式碼中的建立節點感覺寫得有點冗餘,如果有剛簡便並且要考慮到效能的好寫法歡迎留言?

相關文章