效果图如下:
代码
<template>
<div class="contain" ref="contain" @mousedown.prevent="mousedown">
<ul class="picker-column" :style="`transform: translate3d(0px, ${containY}px, 0px);`">
<li
:class="['picker-column-item',index==selectIndex?'column-item_select':'']"
:key="index"
v-for="(item,index) in list"
:style="`height:${itemHeight}px`"
@click="selectItem(index)"
>{{item}}</li>
</ul>
<div class="picker-mask" style="background-size: 100% 110px;"></div>
</div>
</template>
<script>
export default {
mounted() {
this.$nextTick(() => {
this.init();
});
},
data() {
return {
currentY: 0,
containDom: null,
selectIndex: 0,
itemHeight: 44,
containY: 110,
list: ["杭州", "北京", "苏州", "南京", "上海",'天津']
};
},
watch: {
selectIndex(val){
console.log(val)
}
},
methods: {
//项目初始化
init() {
let dom = this.$refs["contain"];
let cantainHeight = dom.offsetHeight;//整个窗口的高度
this.containDom = dom;//记录一下
//初始top
this.currentY = this.containY =
cantainHeight / 2 -
this.itemHeight / 2 -
this.selectIndex * this.itemHeight;
},
mousedown(e) {
//节流阀
let status = true;
//获取点击元素
const startDom = e.target;
// 刚点击屏幕的坐标
let startPageY = e.clientY;
document.onmousemove = em => {
if (status) {
//移动中的坐标
let movePageY = em.clientY;
// current 拖拽变化
let current = movePageY - startPageY;
// y轴变化最大最小值
let maxY =
this.containDom.offsetHeight / 2 -
this.itemHeight / 2 +
this.itemHeight;
let minY =
this.containDom.offsetHeight / 2 -
this.itemHeight / 2 -
this.list.length * this.itemHeight;
// 滑动距离
let containY = this.currentY + current;
//控制距离
if (containY < minY) {
containY = minY + this.itemHeight;
} else if (containY > maxY) {
containY = maxY - this.itemHeight;
} else {
this.containY = containY;
}
}
};
document.onmouseup = e => {
if(status){
status = false;
let indexObj = this.getIndex(
this.itemHeight,
this.containY - this.currentY
);
if (indexObj.status) {
this.selectIndex =this.selectIndex + indexObj.index;
}else{
this.selectIndex =this.selectIndex - indexObj.index;
}
//索引控制 选中控制
if (this.selectIndex < 0) {
this.selectIndex = 0;
} else if (this.selectIndex > this.list.length) {
this.selectIndex = this.list.length;
}
//弹起记录当前y轴
this.currentY = this.containY =
this.containDom.offsetHeight / 2 -
this.itemHeight / 2 -
this.selectIndex * this.itemHeight;
document.onmousemove = null;
document.onmouseup = null;
}
};
e.stopPropagation();
},
//点击选中
selectItem(index) {
this.selectIndex = index;
this.containY =
this.containDom.offsetHeight / 2 -
this.itemHeight / 2 -
this.selectIndex * this.itemHeight;
},
// 计算索引
getIndex(height, range) {
let num = parseInt(range); //划整数
let status = false; //下划状态
let index = 0;//滑动了多少方位
if (num && num < 0) {
//上划
status = true;
}
if (Math.abs(num) < parseInt(height / 2)||Math.abs(num) ==0) {
//少于一般或者没动
index = 0;
}else {
index = Math.floor(Math.abs(num) / height);
}
return {
status,
index
};
}
}
};
</script>
<style>
.contain {
position: relative;
width: 336px;
height: 264px;
background: #eee;
overflow: hidden;
/* padding-top: 110px; */
box-sizing: border-box;
margin: 20px;
}
.picker-column {
font-size: 16px;
cursor: grab;
transition: all 0.4s;
}
.picker-column-item {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
padding: 0 4px;
color: #000;
}
.picker-mask {
position: absolute;
top: 0;
left: 0;
z-index: 2;
width: 100%;
height: 100%;
background-image: -webkit-linear-gradient(
top,
hsla(0, 0%, 100%, 0.9),
hsla(0, 0%, 100%, 0.4)
),
-webkit-linear-gradient(bottom, hsla(0, 0%, 100%, 0.9), hsla(0, 0%, 100%, 0.4));
background-image: linear-gradient(
180deg,
hsla(0, 0%, 100%, 0.9),
hsla(0, 0%, 100%, 0.4)
),
linear-gradient(0deg, hsla(0, 0%, 100%, 0.9), hsla(0, 0%, 100%, 0.4));
background-repeat: no-repeat;
background-position: top, bottom;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
pointer-events: none;
}
ul,
ol {
margin: 0;
padding: 0;
list-style: none;
}
</style>