直接上组件代码:
<template>
<div>
<div class="van-picker__columns">
<div class="van-picker-column">
<ul class="van-picker-column__wrapper" ref="sheng" @touchstart="TouchStart"
@touchmove="TouchMove($event, 'sheng', 'shengmove', 'shengY')"
@touchend="TouchEnd('sheng', 'shengmove', 'shengY', 'shenglist')">
<li class="van-picker-column__item van-picker-column__item--selected">
<div class="van-ellipsis">请选择省份</div>
</li>
<li class="van-picker-column__item van-picker-column__item--selected" v-for="item in shenglist"
:key="item">
<div class="van-ellipsis">{{ item }}</div>
</li>
</ul>
</div>
<div class="van-picker-column">
<ul class="van-picker-column__wrapper" ref="shi" @touchstart="TouchStart"
@touchmove="TouchMove($event, 'shi', 'shimove', 'shiY')"
@touchend="TouchEnd('shi', 'shimove', 'shiY', 'shilist')">
<li class="van-picker-column__item van-picker-column__item--selected">
<div class="van-ellipsis">请选择市区</div>
</li>
<li class="van-picker-column__item van-picker-column__item--selected" v-for="item in shilist"
:key="item">
<div class="van-ellipsis">{{ item }}</div>
</li>
</ul>
</div>
<div class="van-picker-column">
<ul class="van-picker-column__wrapper" ref="qu" @touchstart="TouchStart"
@touchmove="TouchMove($event, 'qu', 'qumove', 'quY')"
@touchend="TouchEnd('qu', 'qumove', 'quY', 'qulist')">
<li class="van-picker-column__item van-picker-column__item--selected">
<div class="van-ellipsis">请选择区域</div>
</li>
<li class="van-picker-column__item van-picker-column__item--selected" v-for="item in qulist"
:key="item">
<div class="van-ellipsis">{{ item }}</div>
</li>
</ul>
</div>
<div class="van-picker__mask"></div>
<div class="van-hairline-unset--top-bottom van-picker__frame"></div>
</div>
</div>
</template>
<script>
import axios from "axios"
export default {
data() {
return {
startY: 0,
fuzhi: 110,
shenglist: [],
shilist: [],
qulist: [],
shengY: 0,
shengmove: 0,
shimove: 0,
shiY: 0,
qumove: 0,
quY: 0,
// 每个滚动区域的变量
}
},
methods: {
TouchStart(e) {
// 获取鼠标距离顶部px
this.startY = e.changedTouches[0].pageY;
},
TouchMove(e, params, move, Y) {
// 滑动鼠标 得出距离差 加上 上次滑动的距离 就等于该位移多少
this[move] = this[Y] + e.changedTouches[0].pageY - this.startY
// 位移
this.$refs[params].style = `transform:translate3d(0px, ${this[move] + this.fuzhi}px, 0px)`;
},
TouchEnd(params, move, Y, list) {
// 传入四个参数,parmas是滑动的哪个区域,move是需要保存下来距离顶部的位置,Y是根据距离计算得出的下标,list是区域数组
// 边距判断 判断是不是滑出小于0的下标了,是就让他回去,不是不管
this[Y] = Math.round(this[move] / 44) * 44 >= 0 ? 0 : Math.round(this[move] / 44) * 44
// 判断是不是超出了数组下标,是就回去,不是不管
if (Math.round(this[Y] / 44) * 44 <= -(this[list].length + 2) * 44 + this.fuzhi - 22) {
this[Y] = -(this[list].length + 2) * 44 + this.fuzhi - 22
}
// 根据算出的下标 四舍五入得出距离最近的是哪个下标也就是选的哪个区域, 让他位移加上过度
this.$refs[params].style = `transform:translate3d(0px, ${Math.round(this[Y] / 44) * 44 + this.fuzhi}px, 0px); transition: all 0.3s;`;
// 判断选的哪个区域渲染列表
if (params === 'sheng') {
axios.get('http://hmajax.itheima.net/api/city', {
params: {
pname: this.shenglist[-Math.round(this.shengY / 44) - 1]
}
}).then(res => {
this.shilist = res.data.list
// 掉玩接口让他变成请选则 大于0就不是请选择三个字,
this.shimove = 0
this.shiY = 0
this.$refs.shi.style = `transform:translate3d(0px, 110px, 0px); transition: all 0.3s;`;
this.qumove = 0
this.quY = 0
this.$refs.qu.style = `transform:translate3d(0px, 110px, 0px); transition: all 0.3s;`;
})
}
if (params === 'shi') {
axios.get('http://hmajax.itheima.net/api/area', {
params: {
// 获取数组下标属性
pname: this.shenglist[-Math.round(this.shengY / 44) - 1],
cname: this.shilist[-Math.round(this.shiY / 44) - 1],
}
}).then(res => {
this.qulist = res.data.list;
console.log(this.qulist);
this.qumove = 0
this.quY = 0
this.$refs.qu.style = `transform:translate3d(0px, 110px, 0px); transition: all 0.3s;`;
// 传过去的val值
})
}
this.$emit('val',
[this.shenglist[-Math.round(this.shengY / 44) - 1]
, this.shilist[-Math.round(this.shiY / 44) - 1],
this.qulist[-Math.round(this.quY / 44) - 1]])
},
},
created() {
axios.get('http://hmajax.itheima.net/api/province').then(res => {
this.shenglist = res.data.list
})
},
}
</script>
<style scoped lang="scss">
$r: 37.5;
.van-picker__columns {
height: 264rem/$r;
position: relative;
display: -webkit-box;
display: -webkit-flex;
display: flex;
cursor: grab;
}
.van-picker-column {
-webkit-box-flex: 1;
-webkit-flex: 1;
flex: 1;
overflow: hidden;
font-size: 0.42667rem;
}
.van-picker-column__wrapper {
-webkit-transition-timing-function: cubic-bezier(.23, 1, .68, 1);
transition-timing-function: cubic-bezier(.23, 1, .68, 1);
transform: translateY(110px);
}
ol,
ul {
margin: 0;
padding: 0;
list-style: none;
}
.van-picker-column__item {
height: 44rem/$r;
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 0.10667rem;
color: #000;
}
.van-ellipsis {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.van-picker__mask {
background-size: 100% 110px;
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
background-image: -webkit-linear-gradient(top, hsla(0, 0%, 100%, .9), hsla(0, 0%, 100%, .4)), -webkit-linear-gradient(bottom, hsla(0, 0%, 100%, .9), hsla(0, 0%, 100%, .4));
background-image: linear-gradient(180deg, hsla(0, 0%, 100%, .9), hsla(0, 0%, 100%, .4)), linear-gradient(0deg, hsla(0, 0%, 100%, .9), hsla(0, 0%, 100%, .4));
background-repeat: no-repeat;
background-position: top, bottom;
-webkit-transform: translateZ(0);
transform: translateZ(0);
pointer-events: none;
}
.van-picker__frame {
position: absolute;
top: 50%;
right: 0.42667rem;
left: 0.42667rem;
height: 44rem/$r;
z-index: 2;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
pointer-events: none;
}
[class*=van-hairline]::after {
position: absolute;
box-sizing: border-box;
content: ' ';
pointer-events: none;
top: -50%;
right: -50%;
bottom: -50%;
left: -50%;
border: 0 solid #ebedf0;
-webkit-transform: scale(.5);
transform: scale(.5);
border-width: 0.02667rem 0;
}
</style>
用法如下:
<input type="text" " placeholder="选择省 / 市 / 区" v-model="from.location" @focus="ssx">
定义的参数和js代码
data() {
return {
from: {
location: '',
},
value: '',
}
},
methods:{
ssx() {
this.$refs.uio.style.zIndex = 2000
this.$refs.iop.style.bottom = 0
this.$refs.iop.style.zIndex = 2100
},
lopss(val) {
// 接收
console.log(val);
this.value = val
},
que() {
this.$refs.uio.style.zIndex = -2
this.$refs.iop.style.bottom = -300
this.$refs.iop.style.zIndex = -3
this.from.location = this.value.join('/')
}
}
这边是一个级联选择器的模态框:
<div class="jilian" @touchmove.prevent ref="uio">
<div class="jilian2" ref="iop">
<div class="tous">
<div class="qx">取消</div>
<div class="qd" @click="que">确定</div>
</div>
<jilian @val=lopss></jilian>
</div>
</div>
还有级联选择器的模态框css:
<style scoped lang="scss">
$r: 37.5;
.jilian {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: -1000;
.jilian2 {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 300rem / $r;
background-color: white;
border-radius: 20rem/$r 20rem/$r 0 0;
bottom: -300rem / $r;
transition: all 0.5s;
z-index: -2000;
.tous {
width: 100%;
height: 30rem / $r;
// background-color: red;
margin-top: 10rem/$r;
.qx {
float: left;
font-size: 14rem/$r;
text-indent: 14rem/$r;
// margin-top: 14rem/$r;
line-height: 30rem/$r;
}
.qd {
float: right;
font-size: 14rem/$r;
margin-right: 14rem/$r;
// margin-top: 14rem/$r;
color: #5780C1;
line-height: 30rem/$r;
}
}
}
}
</style>
还有rem文件里面的index像素配置 需要在全局引入一下:
(function flexible(window, document) {
var docEl = document.documentElement
var dpr = window.devicePixelRatio || 1
// adjust body font size
function setBodyFontSize() {
if (document.body) {
document.body.style.fontSize = (12 * dpr) + 'px'
}
else {
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize();
// set 1rem = viewWidth / 10
function setRemUnit() {
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
setRemUnit()
// reset rem unit on page resize
window.addEventListener('resize', setRemUnit)
window.addEventListener('pageshow', function (e) {
if (e.persisted) {
setRemUnit()
}
})
// detect 0.5px supports
if (dpr >= 2) {
var fakeBody = document.createElement('body')
var testElement = document.createElement('div')
testElement.style.border = '.5px solid transparent'
fakeBody.appendChild(testElement)
docEl.appendChild(fakeBody)
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines')
}
docEl.removeChild(fakeBody)
}
}(window, document))