| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- <template>
- <view class="lView" ref="lViewRef">
- <view class="angleNumber" :style="angleNumStyle">
- <text class="angleTxt">{{angleNumber}}°</text>
- </view>
- <view class="outbox">
- <view class="plusicon" @click="clickSub">
- <text class="plusTxt">-</text>
- </view>
- <view class="container" ref="containerRef" @touchstart="onTouchStart" @touchmove="onTouchMove"
- @touchend="onTouchEnd">
- <view class="trackBg"></view>
- <view class="block" :style="blockStyle" @touchstart.stop="onBlockTouchStart"
- @touchmove.stop="onBlockTouchMove" @touchend.stop="onTouchEnd">
- <image class="barimg" src="/static/device/barimg.png" mode="aspectFill"></image>
- </view>
- </view>
- <view class="plusicon" @click="clickPlus">
- <text class="plusTxt">+</text>
- </view>
- </view>
- </view>
- </template>
- <script>
- const dom = weex.requireModule('dom')
- export default {
- props: {
- // 当前角度值
- anglenum: {
- type: Number,
- default: 90
- },
- // 最小值
- min: {
- type: Number,
- default: 90
- },
- // 最大值
- max: {
- type: Number,
- default: 150
- },
- // 步长
- step: {
- type: Number,
- default: 15
- }
- },
- data() {
- return {
- angleNumber: 90,
- containerWidth: 0,
- containerLeft: 0,
- lViewLeft: 0, // lView左侧偏移
- containerOffsetX: 0, // container相对于lView的左侧偏移
- blockWidth: 62, // 滑块宽度 px (约124rpx)
- currentX: 0, // 当前滑块left值
- isDragging: false
- }
- },
- computed: {
- blockStyle() {
- return 'left:' + this.currentX + 'px;'
- },
- angleNumStyle() {
- // 数字容器与滑块同宽,加上 container 相对 lView 的偏移量
- const left = this.currentX + this.containerOffsetX
- return 'left:' + left + 'px;width:' + this.blockWidth + 'px;'
- }
- },
- watch: {
- anglenum: {
- immediate: true,
- handler(newVal) {
- this.angleNumber = newVal
- this.$nextTick(() => {
- this.updatePositionFromValue(newVal)
- })
- }
- }
- },
- mounted() {
- setTimeout(() => {
- this.getContainerRect()
- }, 300)
- },
- methods: {
- getContainerRect() {
- // 先获取 lView 的位置
- dom.getComponentRect(this.$refs.lViewRef, (lRes) => {
- if (lRes && lRes.result) {
- this.lViewLeft = lRes.size.left
- }
- // 再获取 container 的位置
- dom.getComponentRect(this.$refs.containerRef, (res) => {
- if (res && res.result) {
- const rect = res.size
- this.containerWidth = rect.width
- this.containerLeft = rect.left
- // container 相对于 lView 的偏移
- this.containerOffsetX = rect.left - this.lViewLeft
- // 初始化位置
- this.updatePositionFromValue(this.angleNumber)
- }
- })
- })
- },
- // 根据值计算位置
- updatePositionFromValue(val) {
- if (this.containerWidth <= 0) return
- const trackWidth = this.containerWidth - this.blockWidth
- const ratio = (val - this.min) / (this.max - this.min)
- this.currentX = ratio * trackWidth
- },
- // 根据位置计算值(不吸附,实时显示)
- getRawValueFromPosition(x) {
- const trackWidth = this.containerWidth - this.blockWidth
- if (trackWidth <= 0) return this.min
- let ratio = x / trackWidth
- ratio = Math.max(0, Math.min(1, ratio))
- const rawValue = this.min + ratio * (this.max - this.min)
- // 四舍五入到步长
- const steps = Math.round((rawValue - this.min) / this.step)
- return Math.min(this.max, Math.max(this.min, this.min + steps * this.step))
- },
- // 容器触摸开始(点击轨道跳转)
- onTouchStart(e) {
- this.isDragging = true
- const touch = e.touches[0]
- const x = touch.screenX - this.containerLeft - this.blockWidth / 2
- this.smoothMove(x)
- },
- onTouchMove(e) {
- const touch = e.touches[0]
- const x = touch.screenX - this.containerLeft - this.blockWidth / 2
- this.smoothMove(x)
- },
- // 滑块触摸
- onBlockTouchStart(e) {
- this.isDragging = true
- },
- onBlockTouchMove(e) {
- if (!this.isDragging) return
- const touch = e.touches[0]
- const x = touch.screenX - this.containerLeft - this.blockWidth / 2
- this.smoothMove(x)
- },
- onTouchEnd(e) {
- this.isDragging = false
- // 松手时吸附到步进位置
- const val = this.getRawValueFromPosition(this.currentX)
- this.angleNumber = val
- this.updatePositionFromValue(val)
- this.$emit('change', this.angleNumber)
- },
- // 拖拽时丝滑跟手,不吸附
- smoothMove(x) {
- const trackWidth = this.containerWidth - this.blockWidth
- x = Math.max(0, Math.min(trackWidth, x))
- this.currentX = x
- // 实时计算角度显示(吸附到最近步进值)
- this.angleNumber = this.getRawValueFromPosition(x)
- },
- clickSub() {
- if (this.angleNumber > this.min) {
- this.angleNumber -= this.step
- this.updatePositionFromValue(this.angleNumber)
- this.$emit('change', this.angleNumber)
- }
- },
- clickPlus() {
- if (this.angleNumber < this.max) {
- this.angleNumber += this.step
- this.updatePositionFromValue(this.angleNumber)
- this.$emit('change', this.angleNumber)
- }
- }
- }
- }
- </script>
- <style scoped>
- .lView {
- height: 96rpx;
- position: relative;
- padding-top: 40rpx;
- }
- .angleNumber {
- position: absolute;
- top: 0;
- align-items: center;
- justify-content: center;
- }
- .angleTxt {
- font-size: 36rpx;
- color: #FFFFFF;
- font-weight: bold;
- text-align: center;
- }
- .outbox {
- height: 56rpx;
- background-color: rgba(255, 255, 255, 0.7);
- border-radius: 40rpx;
- flex-direction: row;
- justify-content: space-between;
- align-items: center;
- padding-left: 10rpx;
- padding-right: 10rpx;
- }
- .plusicon {
- width: 50rpx;
- height: 50rpx;
- justify-content: center;
- align-items: center;
- }
- .plusTxt {
- font-size: 44rpx;
- color: #389588;
- font-weight: bold;
- }
- .container {
- flex: 1;
- height: 56rpx;
- position: relative;
- justify-content: center;
- }
- .trackBg {
- height: 6rpx;
- background-color: rgba(56, 149, 136, 0.3);
- border-radius: 3rpx;
- }
- .block {
- position: absolute;
- width: 124rpx;
- height: 44rpx;
- background-color: #389588;
- border-radius: 40rpx;
- justify-content: center;
- align-items: center;
- }
- .barimg {
- width: 30rpx;
- height: 36rpx;
- }
- </style>
|