vue简单实现picker效果
实现基础 Picker 组件
使用 Vue 的 v-model 和事件绑定实现基础选择器。以下是一个基于原生下拉菜单的简单实现:
<template>
<select v-model="selectedValue" @change="handleChange">
<option v-for="item in options" :key="item.value" :value="item.value">
{{ item.label }}
</option>
</select>
</template>
<script>
export default {
props: {
options: {
type: Array,
default: () => []
}
},
data() {
return {
selectedValue: ''
}
},
methods: {
handleChange() {
this.$emit('change', this.selectedValue)
}
}
}
</script>
自定义样式 Picker
通过 CSS 隐藏原生 <select> 元素,用 <div> 模拟选择器效果:
<template>
<div class="custom-picker" @click="togglePicker">
<div class="selected-item">{{ displayValue }}</div>
<div class="picker-options" v-show="isOpen">
<div
v-for="item in options"
:key="item.value"
@click="selectItem(item)"
>
{{ item.label }}
</div>
</div>
</div>
</template>
<script>
export default {
props: {
options: Array,
value: [String, Number]
},
data() {
return {
isOpen: false,
selectedValue: this.value
}
},
computed: {
displayValue() {
const selected = this.options.find(item => item.value === this.selectedValue)
return selected ? selected.label : '请选择'
}
},
methods: {
togglePicker() {
this.isOpen = !this.isOpen
},
selectItem(item) {
this.selectedValue = item.value
this.$emit('input', item.value)
this.isOpen = false
}
}
}
</script>
<style>
.custom-picker {
position: relative;
border: 1px solid #ccc;
padding: 8px;
cursor: pointer;
}
.picker-options {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: white;
border: 1px solid #eee;
z-index: 10;
}
.picker-options div {
padding: 8px;
}
.picker-options div:hover {
background: #f5f5f5;
}
</style>
使用第三方库实现
对于更复杂的需求,可以使用现成的 Vue Picker 组件库:

-
安装
vant库:npm install vant -
使用 Picker 组件:

<template> <van-picker v-model="currentValue" :columns="columns" @change="onChange" /> </template>
export default { components: {
},
data() {
return {
currentValue: '',
columns: ['杭州', '宁波', '温州', '嘉兴', '湖州']
}
},
methods: {
onChange(picker, value, index) {
console.log(当前值:${value}, 当前索引:${index})
}
}
}
移动端优化实现
针对移动端添加触摸事件和动画效果:
<template>
<div class="mobile-picker">
<div class="picker-mask" v-show="visible" @click="hide"></div>
<transition name="picker-slide">
<div class="picker-panel" v-show="visible">
<div class="picker-header">
<button @click="hide">取消</button>
<button @click="confirm">确定</button>
</div>
<div class="picker-content">
<div class="picker-wheel" ref="wheel">
<div v-for="(item, index) in data" :key="index">
{{ item }}
</div>
</div>
</div>
</div>
</transition>
</div>
</template>
<script>
import Hammer from 'hammerjs'
export default {
props: {
data: Array,
value: [String, Number],
visible: Boolean
},
mounted() {
this.initTouchEvents()
},
methods: {
initTouchEvents() {
const hammer = new Hammer(this.$refs.wheel)
hammer.get('pan').set({ direction: Hammer.DIRECTION_VERTICAL })
hammer.on('panstart panmove panend', (ev) => {
// 处理触摸滚动逻辑
})
},
hide() {
this.$emit('update:visible', false)
},
confirm() {
this.$emit('input', this.selectedValue)
this.hide()
}
}
}
</script>
<style>
.picker-slide-enter-active, .picker-slide-leave-active {
transition: transform 0.3s;
}
.picker-slide-enter, .picker-slide-leave-to {
transform: translateY(100%);
}
.picker-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
}
.picker-panel {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #fff;
}
.picker-header {
display: flex;
justify-content: space-between;
padding: 10px;
border-bottom: 1px solid #eee;
}
.picker-content {
height: 200px;
overflow: hidden;
position: relative;
}
.picker-wheel {
transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
}
</style>
这些实现方式覆盖了从基础到高级的 Picker 组件需求,可以根据项目具体需求选择合适的方案。






