效果
ruler.gif
import React, { useState, useEffect } from "react"
import { View } from "@tarojs/components"
import Ruler from "./Ruler"
const back = "https://cdn.lucahealthcare.cn/common/images/sugar/bg_weight.png"
export default function WeightInfo() {
const handleChange = (v) => {
console.log(v)
}
const rulerProps = { step:10,defaultValue: 60, min: 30, max: 150, unit: "kg", type: "weight", onChange: onChange }
return (
<View
style={{
background: `#FFFFFF url(${back}) top left no-repeat`,
backgroundSize: "100% auto",
width:750,
height:'100vh'
}}
>
<Ruler {...rulerProps} />
</View>
)
}
Ruler.jsx
// 尺子滑动选择组件
import React, { useState, useEffect, useRef } from "react"
import Taro, { Component } from "@tarojs/taro"
import { View, Image, ScrollView } from "@tarojs/components"
import "./css/ruler.scss"
import ic_rule_triangle from "../../../assets/images/ic_rule_triangle.png"
export default function Ruler(props) {
const { step ,min, max, unit, defaultValue, onChange } = props
const [marks, setMarks] = useState([])
const [rulerLength, setRulerLength] = useState(0)
const [num, setNum] = useState(0)
const [scrollLeft, setScrollLeft] = useState(0)
const setMarkers = () => {
let arr = []
for (let i = 0; i < Math.ceil((max - min) / step); i++) {
arr.push(i * step + min)
}
// console.log(arr)
setMarks(arr)
}
useEffect(() => {
setTimeout(() => {
const dom = Taro.createSelectorQuery()
dom
.select(".ruler-content .ruler-ul")
.boundingClientRect(rect => {
if (rect[0] ) {
setRulerLength(rect[0] .width)
setScrollLeft((((defaultValue - min) * rect[0] .width) / (max - min)).toFixed(0))
}
})
.exec()
}, 50)
setMarkers()
}, [props])
const onScrollToUpper = () => {
setNum(min)
}
const onScrollToLower = () => {
setNum(max)
}
const onScroll = e => {
let movePercent = (e.detail.scrollLeft / rulerLength).toFixed(6)
let moveNum = Math.round((max - min) * movePercent) + min
let NUM = moveNum > max ? max : moveNum < min ? min : moveNum
setNum(NUM)
onChange(NUM)
}
return (
<View className="compo-ruler" >
<View className="num">
<View class="num_text">
{num}
<View class="unit_text">{unit}</View>
</View>
</View>
<View className="num_pointer_wrap">
<Image class="num_pointer" src={ic_rule_triangle} />
</View>
<View className="ruler" data-offset="0">
<ScrollView
className="ruler-content"
scrollX
onScrollToLower={onScrollToLower}
onScrollToUpper={onScrollToUpper}
onScroll={onScroll}
scrollLeft={scrollLeft}
>
<View className="leftBlank"></View>
<View className="ruler-ul">
{marks.map((item, index) => (
<View className="marker" key={index}>
<View className="markerScale">
{Array.from({ length: 11 }).map((a, i) => {
return (
<View
key={i}
className="scaleItem"
id={`scaleItem_${index * 11 + i}`}
style={{
height: i === 5 ? 15 : 9,
background: i === 0 || i == 10 ? "transparent" : "#555555",
}}
/>
)
})}
</View>
<View className="markerNum"> {item}</View>
</View>
))}
</View>
<View className="rightBlank">
<View className="rightBlankMax">{max}</View>
</View>
</ScrollView>
<View className="pointer"></View>
</View>
</View>
)
}
ruler.scss
.compo-ruler {
width: 100%;
height: 500rpx;
position: relative;
margin: 0 auto;
margin-top: 60rpx;
overflow: hidden;
.num {
display: inline-block;
text-align: center;
font-size: 80rpx;
font-family: PingFang SC-Medium, PingFang SC;
font-weight: 500;
color: #181818;
position: relative;
left: 50%;
transform: translateX(-50%);
.num_text {
position: relative;
.unit_text {
font-size: 28rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #555555;
position: absolute;
top: 50rpx;
right: -40rpx;
}
}
}
.num_pointer_wrap{
width:100%;
margin-top: -16rpx;
text-align: center;
.num_pointer {
width: 22rpx;
height: 16rpx;
}
}
.ruler {
width: 100%;
position: relative;
.pointer {
position: absolute;
left: 50%;
top: 40rpx;
width: 10rpx;
height: 68rpx;
background: #ff941a;
opacity: 1;
border-radius: 5rpx;
transform: translateX(-50%);
}
}
.ruler-content {
width: 100%;
height: 220rpx;
position: relative;
white-space: nowrap;
background: #f6f6f6;
}
.ruler-ul {
height: 180rpx;
margin-top: 40rpx;
display: inline-flex;
flex-shrink: 0;
white-space: nowrap;
pointer-events: auto;
.marker:first-of-type {
border-left: 2rpx solid #555555;
}
}
.leftBlank {
width: 50%;
height: 1rpx;
flex-shrink: 0;
display: inline-block;
}
.rightBlank {
width: 50%;
height: 1rpx;
flex-shrink: 0;
display: inline-block;
.rightBlankMax {
position: relative;
top: 50rpx;
left: -32rpx;
text-align: left;
font-size: 36rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #555555;
}
}
.ruler-ul .marker {
flex-shrink: 0;
width: 260rpx;
height: 66rpx;
border-right: 2rpx solid #555555;
position: relative;
box-sizing: border-box;
display: inline-block;
position: relative;
}
.ruler-ul .marker .markerNum {
width: 64rpx;
text-align: center;
position: absolute;
top: 80rpx;
left: -32rpx;
font-size: 36rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #555555;
}
.markerScale {
position: absolute;
width: 100%;
height: 16rpx;
display: flex;
justify-content: space-between;
left: 0;
}
.markerScale .scaleItem {
background: #555555;
width: 1rpx;
}
// .ruler-ul .marker::before{
// content: '';
// position: absolute;
// left: 50%;
// width: 2px;
// height: 8px;
// background: #555555;
// }
}