Vue中使用MouseMove事件 获取鼠标坐标频率降低或事件卡顿

栏目: JavaScript · 发布时间: 6年前

内容简介:当我们使用Vue进行项目开发时,因为Vue的简介和易用性使我们可能会忽略,Vue的生命周期这件事儿。 尤其是在使用事件时,稍有不意就会造成意外发生!当拖拽一个div元素时,很明显会造成鼠标快速滑动时div跟随卡顿共通代码:

当我们使用Vue进行项目开发时,因为Vue的简介和易用性使我们可能会忽略,Vue的生命周期这件事儿。 尤其是在使用事件时,稍有不意就会造成意外发生!

本文章使用常见的拖拽为案例。

当拖拽一个div元素时,很明显会造成鼠标快速滑动时div跟随卡顿

共通代码:

<script>
    export default {
        data() {
            return {
                // 测试数据
                testData: [
                    {value: '1'},
                    {value: '2'},
                    {value: '3'},
                    {value: '4'},
                    {value: '5'},
                    {value: '6'},
                    {value: '7'},
                    {value: '9'},
                    {value: '10'}
                ],
                /// ...
            };
        },
        methods: {
            testFun(name) {
                console.time(name + '-delay');
                for (let i = 0; i < 10240000; i++) {}
                console.timeEnd(name + '-delay');
            },
            // ...
        }
    }
</script>
<style>
  *::selection {
    background: none;
  }
  .box {
    position: fixed;
    z-index: 100;
    width: 200px;
    height: 80px;
  }
  .dargbtn {
    margin: 15px;
    color: #222222;
    background: #eee;
    cursor: pointer;
  }
  .box1 {
    background: #c0c;
  }
  .box2 {
    background: #0cc;
  }
</style>
复制代码

上述所示,testData是测试的数据(用于数据数据循环),testFun是测试的方法(此方法用于拉长函数执行时长), 以及Style。

Box1代码:

<template>
    <div class="box box1"
         :style="box1Style"
         ref="box1"
    >
      <div class="dargbtn" @mousedown="box1ButtonDown">点此拖拽1</div>
      <div class="delay-box">
        <span
          v-for="(item, index) in testData"
          :key="index"
          :data-testdata="testFun('box1')"
        >{{item.value}}</span>
      </div>
    </div>
</template>
<script>
    export default {
        data() {
            return {
                // 1
                box1X: 0,
                box1Y: 0,
                box1L: 0,
                box1T: 0,
                box1CurrentX: 0,
                box1CurrentY: 0,
            };
        },
        computed: {
          box1Style() {
            return {
              top: this.box1CurrentY + 'px',
              left: this.box1CurrentX + 'px'
            };
          }
        },
        methods: {
          box1Start(e) {
            let dv = this.$refs.box1;
            this.box1X = e.clientX;
            this.box1Y = e.clientY;
    
            this.box1L = dv.offsetLeft;
            this.box1T = dv.offsetTop;
          },
          box1Move(e) {
            console.log('box1 move');
            let nx = e.clientX;
            let ny = e.clientY;
    
            let nl = nx - (this.box1X - this.box1L);
            let nt = ny - (this.box1Y - this.box1T);
    
            // 代码关键处
            this.box1CurrentX = nl;
            this.box1CurrentY = nt;
          },
          box1End(e) {
            window.removeEventListener('mousemove', this.box1Move);
            window.removeEventListener('mouseup', this.box1End);
          },
          box1ButtonDown(e) {
            this.box1Start(e);
            window.addEventListener('mousemove', this.box1Move);
            window.addEventListener('mouseup', this.box1End);
          }
        }
    }
</script>
复制代码

Box2代码:

<template>
    <div class="box box2"
         :style="box2Style"
         ref="box2"
    >
      <div class="dargbtn" @mousedown="box2ButtonDown">点此拖拽2</div>
      <div class="delay-box">
        <span
            v-for="(item, index) in testData2"
            :key="index"
            :data-testdata="testFun('box2')"
        >{{item.value}}</span>
      </div>
    </div>
</template>
<script>
    export default {
        data() {
            return {
                // 2
                box2X: 0,
                box2Y: 0,
                box2L: 0,
                box2T: 0,
                box2CurrentX: 0,
                box2CurrentY: 100
            };
        },
        computed: {
          box2Style() {
            return {
              top: '100px',
              left: '0px'
            };
          }
        },
        methods: {
            box2Start(e) {
                let dv = this.$refs.box2;
                this.box2X = e.clientX;
                this.box2Y = e.clientY;
                
                this.box2L = dv.offsetLeft;
                this.box2T = dv.offsetTop;
            },
            box2Move(e) {
                console.log('box2 move');
                let nx = e.clientX;
                let ny = e.clientY;
                let nl = nx - (this.box2X - this.box2L);
                let nt = ny - (this.box2Y - this.box2T);
                
                // 代码关键处
                this.box2CurrentX = nl;
                this.box2CurrentY = nt;
                let legendBox = this.$refs.box2;
                legendBox.style.left = nl + 'px';
                legendBox.style.top = nt + 'px';
            },
            box2End(e) {
                window.removeEventListener('mousemove', this.box2Move);
                window.removeEventListener('mouseup', this.box2End);
            },
            box2ButtonDown(e) {
                this.box2Start(e);
                window.addEventListener('mousemove', this.box2Move);
                window.addEventListener('mouseup', this.box2End);
            }
        }
    }
</script>
复制代码

运行代码如图所示:

Vue中使用MouseMove事件 获取鼠标坐标频率降低或事件卡顿

代码分析

上诉两段代码中,我们发现唯一的差别只有 box1是通过computed的计算属性对style赋值进行的赋值 box2是通过methos的Move方法对style赋值进行的赋值 但是实际问题不在于此,这也就是该代码的炸弹!

在Vue中数据绑定有两种方式:计算属性和方法

计算属性缓存 vs 方法

<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在组件中
methods: {
  reversedMessage: function () {
    return this.message.split('').reverse().join('')
  }
}
复制代码

我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是 计算属性是基于它们的依赖进行缓存的 。只在相关依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

这也同样意味着下面的计算属性将不再更新,因为 Date.now() 不是响应式依赖:

computed: {
  now: function () {
    return Date.now()
  }
}
复制代码

相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。

我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。

总结:如果能用计算属性满足需求优先使用,如果使用方法需注意方法执行时长

项目源码: github.com/MrDerry/blo…

*版权声明:本文为博主原创文章,未经博主允许不得转载。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C++沉思录

C++沉思录

Andrew Koenig、Barbara Moo / 黄晓春、孟岩(审校) / 人民邮电出版社 / 2002-11-01 / 50.00元

《C++ 沉思录》集中反映了C++的关键思想和编程技术,不仅告诉你如何编程,还告诉你为什么要这样编程。本书曾出现在众多的C++专家推荐书目中。 这将是C++程序员的必读之作。因为: 它包含了丰富的C++思想和技术,从详细的代码实例总结出程序设计的原则和方法。 不仅教你如何遵循规则,还教你如何思考C++编程。 既包括面向对象编程也包括泛型编程。 探究STL这一近年来C++最重要的新成果的内在思想。一起来看看 《C++沉思录》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

MD5 加密
MD5 加密

MD5 加密工具