• 拖拽(学习)


    拖拽的三大事件:

      onmousedowm / onmousemove / onmouseup

    如果把移动事件放在box上,那么当鼠标移动快的时候,鼠标会脱离盒子,导致盒子不跟着鼠标走。

    解决:把移动事件放在document上,就能解决

    如果把抬起事件放在box上,那么鼠标放到了浏览器的地址栏时,松开鼠标还会导致盒子一直跟着鼠标走。

    解决:把抬起事件放在document上

    当页面中有文字(图片)并且选中的时候,那么会有浏览器的默认行为(使得拖拽元素拖动和抬起有问题)

    解决:在按下的时候阻止默认行为:

      DOM 0:return false

      DOM2 :ev.preventDefault()

    解除事件绑定 :

      普通绑定:

         ele.onmouseup = null

      ES6绑定:

        元素 removeEventListener ( "不带on的事件名",函数名)

        ele.removeEventListener("mousemove",this.m)

    例子1:拖拽盒子ES6的类+DOM2事件绑定练习

    <body>
    <div id="box" style=" 100px;height:100px;background-color: red;position: absolute" ></div>
    <script>
        class Drag{
            constructor(id){
                this.disX = 0;
                this.disY = 0;
                this.box = document.getElementById(id);
                this.m = this.move.bind(this);
                this.u = this.up.bind(this)
            }
            init(){
                this.box.addEventListener("mousedown",this.down.bind(this))
            }
            down(ev){
                this.disX = ev.pageX - this.box.offsetLeft;
                this.disY = ev.pageY - this.box.offsetTop;
                document.addEventListener("mousemove",this.m);
                document.addEventListener("mouseup",this.u)
            }
            move(ev){
                this.box.style.left = ev.pageX - this.disX + "px";
                this.box.style.top = ev.pageY - this.disY + "px"
            }
            up(){
                document.removeEventListener("mousemove",this.m);
                document.removeEventListener("mouseup",this.u);
            }
        }
        let xxx = new Drag("box");
        xxx.init();
    </script>
    </body>

     

    例子2:react 版本 + 加磁吸效果

     

    import React, { Component } from "react";
    import "./BaseMoveBox.css";
    import PropTypes from "prop-types";
    let canRun = true;
    let timer = null;
    let time = null;
    class BaseMoveBox extends Component {
      constructor(props) {
        super(props);
        this.state = {
          boxsInitialTop: null,
          boxsInitialLeft: null
        };
      };
    
      componentWillUnmount() {
        if (timer) {
          clearTimeout(timer)
        }
        if (time) {
          clearTimeout(time)
        }
      }
    
      getPosition = (ev) => {
        const box = document.getElementById(this.props.domId);
        let {boxsInitialTop, boxsInitialLeft} = this.state;
        if(!boxsInitialTop) {  //存下一个初始值,为磁吸做准备。
          boxsInitialTop = box.offsetTop;
          boxsInitialLeft = box.offsetLeft;
          this.setState({
            boxsInitialTop,
            boxsInitialLeft
          })
        }
        const disX = ev.clientX - box.offsetLeft;
        const disY = ev.clientY - box.offsetTop;
        return { disX, disY }  //鼠标点击的位置,到盒子的左边距,和下边距的距离。
      }
    
      onMouseDown = (ev) => {
        if (ev.target.className === "BaseMoveBox_header") { //判断可以拖动的事件源("header"上有其它组件或者按钮,不能触发拖拽)
          ev.target.parentNode.style.zIndex = 20;
          ev.preventDefault(); //阻止默认行为(防止拖拽过程中可能选中文字,"box"错误跟随的尴尬)
          const position = this.getPosition(ev);
          window.onmousemove = this.onMouseMove; //在 window / document 绑定 onmousemove 和 onmouseup
          window.onmouseup = this.onMouseUp;
          this.setState({ disX: position.disX, disY: position.disY });
        }
      }
    
      onMouseMove = (ev) => {
        if (!canRun) return;   //防抖
        canRun = false;
        timer = setTimeout(() => {
          const { disX, disY } = this.state;
          const x = ev.clientX - disX;
          const y = ev.clientY - disY;
          const { clientWidth, clientHeight } = document.documentElement;
          const box = document.getElementById(this.props.domId);
          if (box) {  //控制 left/top 使"box"不要超出合理的范围
            const maxHeight = clientHeight - box.offsetHeight
            const H = document.getElementsByClassName("page_head")[0].offsetHeight; //减去大标题的高度
            const maxWidth = clientWidth - box.offsetWidth;
            let top = y > H ? (y < maxHeight ? y : maxHeight) : H;
            let left = x > 0 ? (x < maxWidth ? x : maxWidth) : 0;
            this.setState({ pageX: left, pageY: top })
          }
          canRun = true;
        }, 17);
      }
    
      onMouseUp = async (ev) => {
        window.onmousemove = null;
        window.onmouseup = null;
        //磁吸效果
        const { boxsInitialTop, boxsInitialLeft } = this.state;
        const T = boxsInitialTop;
        const L = boxsInitialLeft;
        const { pageX, pageY } = this.state;
        const dT = Math.pow(Math.abs(pageY - T), 2) + Math.pow(Math.abs(pageX - L), 2);
        const dZ = Math.sqrt(dT);
        if (dZ < 100) {
          time = setTimeout(() => {
            this.setState({ pageX: L, pageY: T })
            ev.target.parentNode.style.zIndex = 10;
          }, 50)
        }
      }
    
      render() {
        const { title, width, height, domId, renderDom, backgroundColor } = this.props;
        const { pageX, pageY } = this.state;
        // console.log(pageX, pageY)
        return (
          <div className="BaseMoveBox" id={domId} style={{ left: pageX, top: pageY,  width, height: height }}>
            <header className="BaseMoveBox_header" onMouseDown={this.onMouseDown} title={title}>{title}</header>
            <div className="BaseMoveBox_content" style={{backgroundColor: backgroundColor}}>{renderDom}</div>
          </div>
        )
      }
    }
    
    BaseMoveBox.propTypes = {
      T: PropTypes.number,
      L: PropTypes.number,
      domId: PropTypes.string,
      title: PropTypes.string,
       PropTypes.string,
      height: PropTypes.string
    }
    
    BaseMoveBox.defaultProps = {
      domId: `${new Date().getTime() + Math.floor(Math.random() * 1000)}BaseMoveBox`,
      title: "改变标题,传title",
       "27.8rem",
      height: "18.2rem"
    }
    
    export default BaseMoveBox
    
    /*
     * 定位父级很重要 position:"relative"      ,基于Window定位 position:fixed
     *
     */

    // CSS 部分
    .BaseMoveBox{
      height: 100%;
      100%;
      position: fixed;
      border-style: solid;
      border-color: #ccc;
      border- 0.05rem;
      border-radius: 0.2rem;
      /* overflow: hidden; */
      z-index: 10;
      /*background-color: #E1E3EC */
    }
    .BaseMoveBox>.BaseMoveBox_header{
      height: 1.5rem;
      line-height: 1.5rem;
      padding: 0.1rem 0.5rem;
      background-color: #E1E3EC;
      cursor: move;
    }
    .BaseMoveBox>.BaseMoveBox_content{
      height: calc(100% - 1.65rem);
      100%;
    }

     

     

     

     更多好玩的效果,看2018年11月20日的课件

  • 相关阅读:
    剑指Offer-46.孩子们的游戏(圆圈中最后剩下的数)(C++/Java)
    剑指Offer-45.扑克牌顺子(C++/Java)
    剑指Offer-44.翻转单词顺序列(C++/Java)
    剑指Offer-43.左旋转字符串(C++/Java)
    剑指Offer-42.和为S的两个数字(C++/Java)
    剑指Offer-41.和为S的连续正数序列(C++/Java)
    剑指Offer-40.数组中只出现一次的数字(C++/Java)
    剑指Offer-39.把数组排成最小的数(C++/Java)
    Codeforces Round #316 (Div. 2) D Tree Requests
    URAL 1774 Barber of the Army of Mages (最大流)
  • 原文地址:https://www.cnblogs.com/MrZhujl/p/9988165.html
Copyright © 2020-2023  润新知