本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一 效果图
接到这个需求之后,立马在网络上搜索,发现了好几个。但是都与需求有一定的差别。自己从头写,那是不可能的,改造还是可以的。一个是github.com/mehaotian/w… 这个。下载下来运行了,但满足不了需求,而且发现是使用canvas绘制图片实现的,一大堆未使用过的方法。改造起来特别困难。于是放弃了。那只有继续搜索了。找到了这个blog.csdn.net/txtop/artic… 都看得懂,也能够改。但还是想偷懒,于是去群里问了一句。结果还是没有答案。只有硬着头皮弄了。
想到第一个方法是用一个椭圆去覆盖下面,从视觉上看着是弯曲的,但是左右长度就不等了。
代码
wx-scale.js
// components/heightAndWeight/index.js
Component({
/**
* 组件的属性列表
*/
properties: {
min: {
type: Number
},
max: {
type: Number
},
unit: {
type: String
},
currentNumber: {
type: Number
},
multipleItems: {
type: Number,
value: 9
},
offset: {
type: Number,
value: 4
}
},
observers: {
"current": function (current) {
console.log('current-----currentNumber---', current, this.data.currentNumber)
if (current < this.data.offset) {
this.setData({
currentNumber: Math.max(this.data.currentNumber + current - this.data.offset, this.data.minNumber)
})
} else if (current > this.data.offset) {
this.setData({
currentNumber: Math.min(this.data.currentNumber + current - this.data.offset, this.data.maxNumber)
})
}
},
"currentNumber": function (currentNumber) {
console.log('----currentNumber', currentNumber)
let arr = []
for (let l = parseInt(this.data.multipleItems / 2) + this.data.offset; l > 0; l--) {
arr.push(currentNumber - l >= this.data.minNumber ? currentNumber - l : '')
}
arr.push(currentNumber)
for (let l = 1; l <= parseInt(this.data.multipleItems / 2) + this.data.offset; l++) {
arr.push(currentNumber + l <= this.data.maxNumber ? currentNumber + l : '')
}
console.log('-----arr', arr)
this.setData({
arr,
current: this.data.offset
})
}
},
attached() {
this.setData({
minNumber: this.data.min,
maxNumber: this.data.max,
current: 0,
arr: [],
})
},
/**
* 组件的初始数据
*/
data: {
minNumber: null,
maxNumber: null,
current: 0,
arr: []
},
/**
* 组件的方法列表
*/
methods: {
getCurrent(e) {
this.setData({
current: e.detail.current
})
//console.log('eeeeeeeeeeeeee', e.detail.current, this.data.currentNumber)
this.triggerEvent('currentNumber', {
current: this.data.currentNumber
})
}
}
})
wx-scale.wxml 代码
<view class="mydemo">
<view class="myshow">
<text style="color: #4377E9 " ><text class="mytext">{{currentNumber}}</text> {{ unit }}</text>
<text class="line"></text>
</view>
<swiper duration="10" class="swiperss" bindchange="getCurrent" display-multiple-items="{{multipleItems}}" easing-function = "linear" current="{{ current }}">
<swiper-item class="swiperItems" wx:for="{{multipleItems + offset * 2}}" wx:key="index">
<view wx:if="{{arr[item]!=''}}" class="{{arr[item]%5==0?'linestwo':'lines'}}"></view>
<view style="color: #BBBEC3;">{{arr[item]%5==0?arr[item]:''}}</view>
</swiper-item>
</swiper>
<view class="mylineBox circle2">
</view>
</view>
wx-scale.wxss
/* components/heightAndWeight/index.wxss */
.mydemo {
height: 255rpx;
position: relative;
}
.myshow {
left: 0;
right: 0;
top: 5%;
font-size: 24rpx;
position: absolute;
text-align: center;
}
.mytext{
font-size: 44rpx;font-family: DIN-Bold, DIN;font-weight: bold;color: #4377E9 ;line-height: 54rpx;
}
/* components/heightAndWeight/index.wxss */
.swiperss {
height: 100%;
width: 100%;
margin: 0 auto;
overflow: visible;
z-index: 10;
position: absolute;
/* border: 1px solid red; */
}
.mylineBox{
border-bottom: 6rpx solid #EEC40A;
height: 15rpx;
border-radius: 0 0 100% 50%/100%;
position: absolute;
left: 0;
width: 100%;
background: #ffffff;
opacity: 0.3;
/* margin-bottom: -6rpx; */
z-index: 1000;
}
.circle2{
bottom: -7.5rpx;
}
.swiperItems {
font-size: 24rpx;
position: relative;
margin-top: 74rpx;
border-bottom: 1px solid #F5F7F9;
height: 200rpx !important;
width: calc(570rpx / 19) !important;
overflow: visible;
/* border: 1px solid green; */
}
.swiperItems>.lines {
background-color: #EEC40A;
/* background-color: green; */
margin-bottom: 10rpx;
width: 2rpx;
height: 65rpx;
margin-left: 15rpx;
position: absolute;
bottom: 3.5rpx;
}
.linestwo {
margin: 0 auto;
width: 2rpx;
height: 100rpx;
background-color: #EEC40A;
/* background-color: red; */
margin-left: 16rpx;
position: absolute;
bottom: 3.5rpx;
}
.lines+view {
font-size: 24rpx;
font-family: DIN-Regular, DIN;
font-weight: 400;
/* color: #D9D9D9; */
color: red;
line-height: 30rpx;
width: 100%;
text-align: center;
}
.line {
position: absolute;
left: 52.5%;/*关键控制数据*/
top: 64rpx;
/* transform: translateX(-50%); */
width: 4rpx;
height: 120rpx;
background: #43A3FF;
box-shadow: 0px 0px 2rpx 0px #43A3FF;
z-index: 6;
/* margin-right: 100rpx; */
}
第二个方法是在家里想到的,于是今天来公司实践了。功夫不负,实现了。
思路是左右都连续抬高元素位置,实现视觉上弯曲效果,而且左右高度也一致。与需求完全一致。代码如下
是参考 这个blog.csdn.net/txtop/artic… 还是组件化。
二 组件代码
heightAndWeight.js 代码
// components/heightAndWeight/index.js
Component({
/**
* 组件的属性列表
*/
properties: {
min: {
type: Number
},
max: {
type: Number
},
unit: {
type: String
},
currentNumber: {
type: Number
},
multipleItems: {
type: Number,
value: 9
},
offset: {
type: Number,
value: 4
}
},
observers: {
"current": function (current) {
console.log('current-----currentNumber---', current, this.data.currentNumber)
if (current < this.data.offset) {
this.setData({
currentNumber: Math.max(this.data.currentNumber + current - this.data.offset, this.data.minNumber)
})
} else if (current > this.data.offset) {
this.setData({
currentNumber: Math.min(this.data.currentNumber + current - this.data.offset, this.data.maxNumber)
})
}
},
"currentNumber": function (currentNumber) {
console.log('----currentNumber', currentNumber)
let arr = []
for (let l = parseInt(this.data.multipleItems / 2) + this.data.offset; l > 0; l--) {
arr.push(currentNumber - l >= this.data.minNumber ? currentNumber - l : '')
}
arr.push(currentNumber)
for (let l = 1; l <= parseInt(this.data.multipleItems / 2) + this.data.offset; l++) {
arr.push(currentNumber + l <= this.data.maxNumber ? currentNumber + l : '')
}
console.log('-----arr', arr)
this.setData({
arr,
current: this.data.offset
})
}
},
attached() {
this.setData({
minNumber: this.data.min,
maxNumber: this.data.max,
current: 0,
arr: [],
})
},
/**
* 组件的初始数据
*/
data: {
minNumber: null,
maxNumber: null,
current: 0,
arr: []
},
/**
* 组件的方法列表
*/
methods: {
getCurrent(e) {
this.setData({
current: e.detail.current
})
//console.log('eeeeeeeeeeeeee', e.detail.current, this.data.currentNumber)
this.triggerEvent('currentNumber', {
current: this.data.currentNumber
})
}
}
})
heightAndWeight.json 代码
{
"component": true,
"usingComponents": {}
}
heightAndWeight.wxml 代码 很关键,注意看注释说明
<view class="mydemo">
<view class="myshow">
<text style="color: #4377E9 " ><text class="mytext">{{currentNumber}}</text> {{ unit }}</text>
<text class="line"></text>
</view>
<swiper duration="10" class="swiperss" bindchange="getCurrent" display-multiple-items="{{multipleItems}}" easing-function = "linear" current="{{ current }}">
<swiper-item class="swiperItems" wx:for="{{multipleItems + offset * 2}}" wx:key="index">
<!-- <block wx:for="{{(multipleItems + offset * 2+1)/2}}" wx:key="index">
<view wx:if="{{arr[item]!=''}}" class="{{arr[item]%5==0?'linestwo':'lines'}}"></view>
</block> -->
<block wx:if="{{arr[item]!=''}}">
<block wx:if="{{arr[item]%5==0}}">
<block wx:if="{{item<=((multipleItems + offset * 2)+1)/2}}">
<!-- //这里35是(multipleItems + offset * 2)计算得来的,所以更改样式,需要重新调整 -->
<view style='height: 100rpx; width: 2rpx; background-color: #EEC40A;margin-left: 16rpx;position: absolute;bottom: {{45-item}}rpx;'> </view>
<!-- <text style="color: red;"> {{item}}</text> -->
</block>
<block wx:else>
<view style='height: 100rpx; width: 2rpx; background-color: #EEC40A;margin-left: 16rpx;position: absolute;bottom: {{item+5}}rpx;'> </view>
<!-- <text style="color: gold;"> {{item}}</text> -->
</block>
</block>
<block wx:else>
<block wx:if="{{item<=((multipleItems + offset * 2)+1)/2}}">
<view style='background-color: #EEC40A;margin-bottom: 10rpx;width: 2rpx;height: 65rpx;margin-left: 15rpx;position: absolute ;bottom: {{35-item}}rpx;'>
</view>
<!-- {{item}} -->
</block>
<block wx:else>
<view style='background-color: #EEC40A;margin-bottom: 10rpx;width: 2rpx;height: 65rpx;margin-left: 15rpx;position: absolute ;bottom: {{item}}rpx;'> </view>
</block>
</block>
</block>
<!-- <view style='background-color: #D2D6DF;margin-bottom: 10rpx;width: 2rpx;height: 55rpx;margin-left: 15rpx;position: absolute ;bottom: {{35-item}}rpx;'>
</view> -->
<!-- <view wx:if="{{arr[item]!=''}}" class="{{arr[item]%5==0?'linestwo':'lines'}}"></view> -->
<view style="color: #BBBEC3;">{{arr[item]%5==0?arr[item]:''}}</view>
</swiper-item>
</swiper>
<!-- <view class="mylineBox circle2">
</view> -->
</view>
heightAndWeight.wxss 样式代码
/* components/heightAndWeight/index.wxss */
.mydemo {
height: 255rpx;
position: relative;
}
.myshow {
left: 0;
right: 0;
top: 5%;
font-size: 24rpx;
position: absolute;
text-align: center;
}
.mytext{
font-size: 44rpx;font-family: DIN-Bold, DIN;font-weight: bold;color: #4377E9 ;line-height: 54rpx;
}
/* components/heightAndWeight/index.wxss */
.swiperss {
height: 100%;
width: 100%;
margin: 0 auto;
overflow: visible;
z-index: 10;
position: absolute;
/* border: 1px solid red; */
}
.mylineBox{
border: 1rpx solid #F5F7F9;
height: 3rpx;
border-radius: 0 0 100% 50%/100%;
position: absolute;
left: 0;
width: 100%;
background: #F5F7F9;
margin-bottom: -6rpx;
z-index: -1000;
}
.circle2{
bottom: -1.5rpx;
}
.swiperItems {
font-size: 24rpx;
position: relative;
margin-top: 74rpx;
border-bottom: 1px solid #F5F7F9;
height: 200rpx !important;
width: calc(570rpx / 19) !important;
overflow: visible;
/* border: 1px solid green; */
}
.swiperItems>.lines {
background-color: #D2D6DF;
/* background-color: green; */
margin-bottom: 10rpx;
width: 2rpx;
height: 55rpx;
margin-left: 15rpx;
position: absolute;
bottom: 0;
}
.linestwo {
margin: 0 auto;
width: 2rpx;
height: 90rpx;
background-color: #D2D6DF;
/* background-color: red; */
margin-left: 16rpx;
position: absolute;
bottom: 0;
}
.lines+view {
font-size: 24rpx;
font-family: DIN-Regular, DIN;
font-weight: 400;
/* color: #D9D9D9; */
color: red;
line-height: 30rpx;
width: 100%;
text-align: center;
}
.line {
position: absolute;
left: 52.5%;/*关键控制数据*/
top: 64rpx;
/* transform: translateX(-50%); */
width: 6rpx;
height: 170rpx;
background: #43A3FF;
box-shadow: 0px 0px 2rpx 0px #43A3FF;
z-index: 600;
/* margin-right: 100rpx; */
}
三 调用
页面index
index.js 代码
//index.js
//获取应用实例
const app = getApp();
Page({
data: {
ageCurrentNumber:30,
tempData:0
},
onLoad: function (options) {
},
setNum(e){
let that=this
this.setData({
ageCurrentNumber:that.tempData
})
// this.getInputValue(10)
},
getInputValue(e) {
console.log(e,"dss")
this.setData({
ageCurrentNumber: e.detail.value
})
this.tempData=e.detail.value;
},
getCurrentNumberAge(e){ //年龄
console.log('获取当前current值年龄',e,e.detail.current)
let result = e.detail.current;
this.setData({
age:result ,
ageCurrentNumber:result
})
},
})
index.json 代码
{
"navigationStyle":"default",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "刻度尺",
"navigationBarTextStyle": "black",
"disableScroll": true,
"usingComponents": {
"height-weight3": "/components/heightAndWeight",
"scale": "/components/wx-scale"
}
}
调用页面 index.wxml
<view class="mypage-demo">
<!-- <button type="default" plain="true" bindtap="setNum" >按钮</button> -->
<view class="my-input-text">
<view class="my-label">
选择时长
</view>
<view class="my-value">
<input class="demo-value" type="number" maxlength="10" name='price' placeholder="输入时长分钟" bindinput='getInputValue'/> <text class="demo-unit">分</text>
</view>
</view>
<view class="flex" style="flex-wrap:wrap;margin-top: 20rpx">
<!-- 如果调整页面padding 这里offset和multipleItems需要重新调整,否则会出现数值错位 -->
<height-weight3 offset="5" min="0" max="9999" unit="分" multipleItems="25" currentNumber="{{ ageCurrentNumber }}" bind:currentNumber="getCurrentNumberAge"></height-weight3>
</view>
<view class="demo-tips">
有效期半年
</view>
<view class="demo-buy-card">
<view class="buy-left">
<view class="buy-num">合计: <text class="buy-value"> ¥{{ageCurrentNumber}}</text></view>
<view class="buy-time">洗车时长{{ageCurrentNumber}}分钟</view>
</view>
<view class="buy-right">
<view>立即购买</view>
</view>
</view>
<view class="flex" style="flex-wrap:wrap;margin-top: 20rpx">
<scale offset="5" min="0" max="9999" unit="分" multipleItems="25" currentNumber="{{ ageCurrentNumber }}" bind:currentNumber="getCurrentNumberAge"></scale>
</view>
</view>
样式 index.wxss
/*questions.wxss*/
page{
background: #ffffff;
}
.mypage-demo{
margin: 20rpx 0;
padding: 15rpx;
}
.my-input-text{
margin: 50rpx 10rpx;
padding: 40rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.my-label{
width: 150rpx;
}
.my-value{
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
}
.demo-value{
flex: 7;
}
.demo-unit{
flex:3;
color: red;
}
::-webkit-scrollbar {
width: 0;
height: 0;
color: transparent;
display: none;
}
.demo-tips{
margin: 40rpx;
justify-content: center;
align-items: center;
text-align: center;
display: flex;
font-size: 40rpx;
}
.demo-buy-card{
display: flex;
justify-content: space-between;
align-items: center;
margin: 40rpx;
padding: 20rpx;
border: 2rpx solid #ECEDEE;
border-radius: 40rpx;
}
.buy-left{
flex:7;
}
.buy-num{
margin:10rpx 0;
}
.buy-value{
font-size: 36rpx;
font-weight: bold;
}
buy-time-num{
margin:10rpx 0;
}
.buy-right{
flex:3;
}