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