当咱们使用Vue进行项目开发时,由于Vue的简介和易用性使咱们可能会忽略,Vue的生命周期这件事儿。 尤为是在使用事件时,稍有不意就会形成意外发生!vue
当拖拽一个div元素时,很明显会形成鼠标快速滑动时div跟随卡顿git
共通代码:github
<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代码:bash
<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>
复制代码
运行代码如图所示:函数
上诉两段代码中,咱们发现惟一的差异只有 box1是经过computed的计算属性对style赋值进行的赋值 box2是经过methos的Move方法对style赋值进行的赋值 可是实际问题不在于此,这也就是该代码的炸弹!性能
在Vue中数据绑定有两种方式:计算属性和方法测试
<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在组件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
复制代码
咱们能够将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是彻底相同的。然而,不一样的是计算属性是基于它们的依赖进行缓存的。只在相关依赖发生改变时它们才会从新求值。这就意味着只要 message 尚未发生改变,屡次访问 reversedMessage 计算属性会当即返回以前的计算结果,而没必要再次执行函数。ui
这也一样意味着下面的计算属性将再也不更新,由于 Date.now() 不是响应式依赖:
computed: {
now: function () {
return Date.now()
}
}
复制代码
相比之下,每当触发从新渲染时,调用方法将总会再次执行函数。
咱们为何须要缓存?假设咱们有一个性能开销比较大的计算属性 A,它须要遍历一个巨大的数组并作大量的计算。而后咱们可能有其余的计算属性依赖于 A 。若是没有缓存,咱们将不可避免的屡次执行 A 的 getter!若是你不但愿有缓存,请用方法来替代。
若是能用计算属性知足需求优先使用,若是使用方法需注意方法执行时长
本文提供demo见:GitHub
*