元件,本質上是解決某個問題封裝的類,在此記錄原生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:
程式碼中的建立節點感覺寫得有點冗餘,如果有剛簡便並且要考慮到效能的好寫法歡迎留言?