|
<!-- |
|
* @Description: banner |
|
* @Author: ekibun |
|
* @Date: 2019-09-17 14:47:44 |
|
* @LastEditors: ekibun |
|
* @LastEditTime: 2019-09-18 16:27:24 |
|
--> |
|
<!DOCTYPE html> |
|
<html> |
|
|
|
<head> |
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;" name="viewport" /> |
|
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> |
|
<style> |
|
body, |
|
#pager { |
|
width: 100%; |
|
height: 100%; |
|
position: absolute; |
|
top: 0px; |
|
bottom: 0px; |
|
padding: 0px; |
|
margin: 0px; |
|
background-color: antiquewhite; |
|
overflow: hidden; |
|
user-select: none; |
|
touch-action: none; |
|
} |
|
|
|
#pager * { |
|
position: absolute; |
|
width: 80%; |
|
top: 10%; |
|
left: 50%; |
|
margin-left: -40%; |
|
height: 80%; |
|
} |
|
</style> |
|
</head> |
|
|
|
<body> |
|
|
|
<div id="app"> |
|
<div id="pager" @pointermove="onPointerMove" @pointerup="onPointerUp"> |
|
<div v-for="(item, index) in items" :style="itemStyles(item, index)"></div> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
let DISTANCE = 100; |
|
new Vue({ |
|
el: '#app', |
|
data: () => ({ |
|
offset: 0, |
|
curIndex: 1, |
|
dragging: false, |
|
items: [ |
|
{ |
|
color: "red" |
|
}, |
|
{ |
|
color: "green" |
|
}, |
|
{ |
|
color: "blue" |
|
}, |
|
{ |
|
color: "yellow" |
|
}] |
|
}), |
|
computed: { |
|
newIndex() { |
|
return this.offset < -DISTANCE ? (this.curIndex + 1) % this.items.length : |
|
this.offset > DISTANCE ? (this.curIndex - 1 + this.items.length) % this.items.length : this.curIndex |
|
} |
|
}, |
|
methods: { |
|
onPointerMove(e) { |
|
if (e.buttons != 1) return; |
|
this.dragging = true; |
|
this.offset += e.movementX; |
|
this.offset = Math.min(2 * DISTANCE, Math.max(-2 * DISTANCE, this.offset)); |
|
}, |
|
onPointerUp(e) { |
|
this.dragging = false; |
|
this.curIndex = this.newIndex; |
|
this.offset = 0; |
|
}, |
|
indexDistance(a, b) { |
|
return (a - b + this.items.length * 3 / 2) % this.items.length - this.items.length / 2; |
|
}, |
|
itemStyles(item, index) { |
|
let distance = this.indexDistance(index, this.curIndex); |
|
if (this.offset < 0 && -2 * distance >= this.items.length) distance = -distance; |
|
let indexOffset = this.offset + 2 * distance * DISTANCE; |
|
distance = this.indexDistance(index, this.newIndex); |
|
return { |
|
transition: this.dragging ? undefined : 'transform .2s ease-out', |
|
'background-color': item.color, |
|
'z-index': 2 - Math.abs(distance), |
|
'visibility': Math.abs(distance) > 1 ? "hidden" : "visible", |
|
transform: `scale(${ |
|
1 - Math.min(2 * DISTANCE, Math.abs(indexOffset)) / (10 * DISTANCE) |
|
}) translateX(${ |
|
Math.max(-2 * DISTANCE, Math.min(2 * DISTANCE, indexOffset)) / 5 |
|
}%)` |
|
} |
|
} |
|
} |
|
}) |
|
</script> |
|
</body> |
|
|
|
</html> |