想要做一个基于uni-app的血糖血压刻度滑动控件,hbuilder市场没有好的,参照别人的写了一个。如图:

源码,自己放入components里面。
html
<!-- 刻度滑动选择 -->
<template>
<view>
<view class="slide-title">
<view class="slide-title-left">{{subTitle}}</view>
<view class="slide-title-num">{{selvalue}}</view>
<view class="slide-title-right">{{subUnit}}</view>
</view>
<view class="slide-scroll-border">
<scroll-view scroll-x class="slide-scroll" :enable-flex="true" show-scrollbar="false"
:style="{width: setUnit(screenW)}" @scroll="slideScroll"
:scroll-left="scrollLeft" @touchend="slideMoveEnd" :scroll-with-animation="true">
<view class="slide-scroll slide-border">
<view class="empty-none" :style="{width: screenW /2 + 'px'}"></view>
<view v-for="(s_item, s_index) in list" :key="s_index" class="" :class="{'slide-list':true,'selected': s_index === selInd,'selected1': (s_index === selInd + 1 || s_index === selInd - 1),'selected2': (s_index === selInd + 2 || s_index === selInd - 2),'selected3': (s_index === selInd + 3 || s_index === selInd - 3) }">
<view class="list-num" v-if="s_index%10==0">{{s_item}}</view>
<view class="slide-list-ba"></view>
</view>
<view class="empty-none" :style="{width: screenW / 2 + 'px'}"></view>
</view>
</scroll-view>
</view>
<view class="slide-message" v-if="message">{{message}}</view>
</view>
</template>
<script>
export default {
name:'zlSlider',
data() {
return {
scrollLeft: 0, // 仅用于核准中间位置
d_len:20,
list: [],
selvalue:0,
selInd: 0,
cellWidth:12,// 每小格宽度
screenW:uni.getSystemInfoSync().screenWidth
};
},
props: {
subTitle: { type: String, default: '' },
subUnit: { type: String, default: '' },
message: { type: String, default: '' },
startNum: { type: Number, default: 0 }, // 开始数值
endNum: { type: Number, default: 20 }, // 结束数值
step: { type: Number, default: 1 }, // 结束数值
value: { type: Number, default: 0 }, // 用v-model双向绑定
},
mounted() {
// 获取滑动显示内容的宽度。
uni.createSelectorQuery().in(this).select('.slide-scroll-border').boundingClientRect(data => {
if (data) this.screenW = data.width-60;
}).exec();
this.initSlide();
},
methods: {
setUnit(unit) {
if (typeof unit === 'number') {
return (unit + 'px')
} else {
return unit;
}
},
// 滚动触发
slideScroll(e) {
const { cellWidth} = this;
const scrollL = e.detail.scrollLeft; // 当前滚动距离左边的距离
let ind = parseInt(scrollL / cellWidth); // 当前选中是第几个
if (ind > this.d_len) {
ind = this.d_len;
}
if (ind !== this.selInd) {
this.selInd = ind;
this.selvalue = this.getIntNum(this.selInd*this.step+this.startNum)
}
},
// 触摸结束
slideMoveEnd(e) {
// const end_t = setTimeout(() => {
// const { selInd } = this;
// this.slideTo(selInd);
// this.setEmitFunc();
// clearTimeout(end_t);
// }, 400);
const { selInd } = this;
this.slideTo(selInd);
this.setEmitFunc();
},
// 初始化
initSlide() {
const { startNum, endNum, step } = this;
this.d_len = (endNum - startNum)*(1/step);
// let list = [...Array(this.d_len).keys()].map(index=>this.getIntNum(startNum + index*this.step))
// for (let i = 0; i <= this.d_len; i++) {
// const l_num = this.getIntNum(startNum + i*this.step);
// list.push(l_num);
// }
this.list = [...Array(this.d_len).keys()].map(index=>this.getIntNum(startNum + index*step));
this.getSelInd();
},
// 滚动到正确的刻度
slideTo(ind) {
const { screenW, cellWidth, scrollLeft } = this;
const newLeft = ind * cellWidth + (cellWidth / 2);
this.$nextTick(()=>{
this.scrollLeft = (scrollLeft === newLeft) ? (scrollLeft + 0.001) : newLeft;
})
},
// 四舍五入
getIntNum(n) {
return parseInt(n * 100) / 100
},
// value改变后,计算选中的selInd
getSelInd() {
const { endNum, startNum } = this;
let value = this.value,
isChange = false,
noHave = false;
// 不能超过最小最大值
if (value > endNum) {
value = endNum;
isChange = true;
} else if (value < startNum) {
value = startNum;
isChange = true;
}
let defaultInd = -1;
const itemValue = this.list.map((item,index)=>{
return (item===value)? index :0
}).filter(item=>item>0);
// for (let d = 0; d <= this.d_len; d++) {
// const item = this.getIntNum(startNum + d*this.step);
// if (item === value) {
// defaultInd = d;
// break;
// }
// }
if(itemValue && itemValue.length>0){
defaultInd = itemValue[0]
}else {
defaultInd = 0;
noHave = true;
}
// 没有匹配到的情况 以及 超过了最大最小值 需要通知父组件修改value
(isChange || noHave) && this.setEmitFunc();
if (defaultInd === this.selInd) return;
this.selInd = defaultInd;
this.selvalue = this.getIntNum(this.selInd*this.step+this.startNum)
this.slideTo(defaultInd);
},
// 父组件通知事件
setEmitFunc() {
const { selvalue } = this;
this.$emit('input', selvalue);
this.$listeners.change && this.$emit('change', selvalue);
},
},
watch: {
value: function(newVal, oldVal) {
this.getSelInd();
}
},
}
</script>
<style lang="scss">
.slide-title{
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: center;
margin-top: 10px;
margin-bottom: 5px;
&-left,&-right{
color:$uni-text-color-grey;
font-size: 14px;
}
&-num{
color:$uni-text-color;
text-align: center;
font-size: 30px;
margin: 0 10px;
line-height: 100%;
/* #ifdef H5 */
margin-bottom: 5px !important;
/* #endif */
}
}
.slide-message{
color:$uni-text-color-grey;
font-size: $uni-font-size-sm;
margin: 0 20px;
}
.slide-scroll {
display: flex;
flex-wrap: nowrap;
flex-direction: row;
height: 50px;
::-webkit-scrollbar {width: 0 !important;height: 0 !important;-webkit-appearance: none;background: transparent;color: transparent;}
}
.slide-scroll-border{
padding: 5px 30px;
border: 1px solid #808080;
border-radius: 40px;
overflow: hidden;
}
.slide-list {
flex-shrink: 0;
position: relative;
border-radius: 4px;
transition: background-color .1s;
width:4px;
margin: 0 4px;
height: 50px;
}
.slide-list.selected .slide-list-ba{
background-color: red !important;
height: 27px;
}
.slide-list.selected1 .slide-list-ba{
background-color: red !important;
height: 24px;
}
.slide-list.selected2 .slide-list-ba{
background-color: red !important;
height: 21px;
}
.slide-list.selected3 .slide-list-ba{
background-color: red !important;
height: 18px;
}
.slide-list-ba{
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 15px;
background-color: #D3D3D3;
}
.list-num {
top: 0;
position: absolute;
transform: translateX(-50%);
}
.empty-none {
flex-shrink: 0;
height: 5px;
}
</style>
使用示例
html
<template>
<view>
......
<zl-slider v-model="bloodSugar.value" :step="0.1" :startNum="0" :endNum="50" subTitle="血糖" subUnit="mmol/L" message="范围通常>3.9,空腹<7.0, 饭后两小时内<11.1 mmol/L"></zl-slider>
......
</view>
</template>
<script>
import zlSlider from '@/components/zl-slider/zl-slider.vue';
export default {
components:{zlSlider},
data() {
return {
bloodSugar:{
value:0
}
}
}
}
</script>