两小球冲突,仿优信,拖动小球

tsx:

import React, { Component, createRef } from 'react';
import './index.less'
interface Props { }
interface State { }
 
class Ball extends Component<Props, State> {
    // ref获取线div
    line = createRef<HTMLDivElement>()
    // wrap左边到body的left值
    x: number = 0
    // 移动距离
    mx: number = 0
    // 整体最大盒子宽
    px: number = 0
    // 线的当前宽
    wx: number = 0
    // 左球 距离body
    lboll: number = 0
    // 右球 距离body
    rboll: number = 0
 
    constructor(props: Props) {
        super(props)
        this.state = {
        }
    }
    FnStart(e: React.TouchEvent<HTMLDivElement>) {
        // 球到左body的left减wrap到body的left值
        this.x = e.changedTouches[0].pageX - (e.target as HTMLDivElement).offsetLeft
        document.ontouchmove = this.FnMove.bind(this)
        document.ontouchend = this.FnEnd.bind(this)
 
    }
    FnMove(e: TouchEvent) {
        e.stopPropagation()
        // 保证有线盒子,没有返回false
        if (!this.line.current) return false
        // 保证父盒子的div存在
        if (!this.line.current.parentElement) return false
        // 获取包裹盒子的宽
        this.px = this.line.current.parentElement.clientWidth;
        if (!this.wx) {
            this.wx = this.px
        }
        const nowLx = this.lboll
        const nowRx = this.rboll
 
 
        this.lboll = this.line.current.parentElement.children[1].getBoundingClientRect().left
        this.rboll = this.line.current.parentElement.children[2].getBoundingClientRect().left
        // 把目标元素当做div盒子
        const t = (e.target as HTMLDivElement)
        // 移动的距离
        this.mx = e.changedTouches[0].pageX - this.x
        // 如果移动距离超过最大值 移动的值超过(包裹盒子的宽-球体的宽)
        // 线的宽
        if (this.mx > this.px - t.clientWidth) {
            // 把移动距离等于最大值
            this.mx = this.px - t.clientWidth
        }
        // 如果移动距离小于最小值 移动的值小于最开始的值 0 
        if (this.mx < 0) {
            // 把移动的值赋值初始值
            this.mx = 0
        }
        if (t.className === 'l-ball') {
            // 当前线体的宽度
            this.wx = this.rboll - this.lboll
            // 线定位在移动的距离加上目标元素 球 一半宽
            this.line.current.style.left = this.mx + t.clientWidth / 2 + 'px'
            // 设置左球的定位
            t.style.left = this.mx + 'px'
            // 调整线条宽度
            this.line.current.style.width = this.wx + 'px'
            // 如果线条过短,也就是说两球距离太近,并且判断球移动的方向要继续减小线条长度
            if (this.wx < 30 && nowLx <= this.lboll) {
                // 判断球对盒子的left值是否在最大值(父盒子的宽减去一个球的宽度就是最大值)
                if (t.offsetLeft + t.clientWidth < this.px - t.clientWidth) {
                    // 右球定位的left值为左球的left值加上球体宽度
                    (this.line.current.parentElement.children[2] as HTMLDivElement).style.left = t.offsetLeft + t.clientWidth + 'px'
                } else {
                    // 右球最大值为父盒子减去一个球体的宽度
                    (this.line.current.parentElement.children[2] as HTMLDivElement).style.left = this.px - t.clientWidth + 'px'
                }
            }
            // 左球的定位值大于或等于最大盒子的宽去掉左右两球,(触边)
            if (t.offsetLeft >= this.px - t.clientWidth * 2) {
                // 就把左球的定位等于最大值
                t.style.left = this.px - t.clientWidth * 2 + 'px'
                // 线体调整定位在中间
                this.line.current.style.left = this.px - t.clientWidth * 1.5 + 'px'
            }
 
        } else {
            // 操作目标元素的css样式的left 
            t.style.left = this.mx + 'px'
            // 当前线体的宽度
            this.wx = this.rboll - this.lboll
            // 移动时调整线体宽度
            this.line.current.style.width = this.wx + 'px'
            // 如果两球距离过近,并且判断球移动的方向要继续减小线条长度
            if (this.wx < 30 && nowRx > this.rboll) {
                // 左球的定位调整为右球的定位left值减去一个小球的宽度
                (this.line.current.parentElement.children[1] as HTMLDivElement).style.left = t.offsetLeft - t.clientWidth + 'px'
                // 如果右球的定位减去半个球的宽度大于0
                if (t.offsetLeft - t.clientWidth / 2 > 0) {
                    // 线体定位调整为定位宽减去一半球体宽
                    this.line.current.style.left = t.offsetLeft - t.clientWidth / 2 + 'px'
                }
            }
            // 如果右球的定位小于或者等于球体宽度(触边)
            if (t.offsetLeft <= t.clientWidth) {
                // 右球定位值,最小为也要为左球留一个宽度,也就是右球最小宽为一个球体宽
                t.style.left = t.clientWidth + 'px';
                // 左球定位触边
                (this.line.current.parentElement.children[1] as HTMLDivElement).style.left = 0 + 'px'
                // 线体宽度调整为球体宽度
                this.line.current.style.width = t.clientWidth + 'px'
            }
        }
    }
 
    FnEnd(e: TouchEvent) {
        document.ontouchmove = null
    }
    render() {
        return (
            <div className='wrap'>
                <div className='line' ref={this.line}></div>
                <div className='l-ball' onTouchStart={this.FnStart.bind(this)} ></div>
                <div className='r-ball' onTouchStart={this.FnStart.bind(this)}></div>
            </div>
        )
    }
 
}
 
 
 
export default Ball

less:

 .wrap {
     width: 500px;
     height: 40px;
     position: relative;
     background-color: #ddd;

     .line {
         background-color: aqua;
         width: 500px;
         height: 5px;
         position: absolute;
         top: 50%;
         transform: translateY(-50%);
     }

     .l-ball {
         width: 40px;
         height: 40px;
         border-radius: 50%;
         background: rgb(148, 224, 6);
         position: absolute;
         cursor: pointer;
         left: 0;
     }

     .r-ball {
         width: 40px;
         height: 40px;
         cursor: pointer;
         background: rgb(148, 224, 6);
         border-radius: 50%;
         position: absolute;
         left: 500px-40px;
     }
 }

要记住写路由!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值