Мы часто выполняем некоторые операции при изменении размера страницы, например повторно отображаем компонент диаграммы, чтобы он адаптировался к текущему размеру страницы, ноwindow.resize
События запускаются очень часто, поэтому мы обычно добавляем debounce для выполнения операции "debounce". Код выглядит следующим образом:
import debounce from 'lodahs/debounce'
export default {
methods: {
resize: debounce(function () {
// do something
}, 100)
},
mounted () {
window.addEventListener('resize', this.resize)
},
beforeDestroy () {
window.removeEventListener('resize', this.resize)
}
}
Однако код выше имеет глубокую яму (долго ползал в яме - .-), давайте поговорим о моем процессе лазания по ямам.
Давайте посмотрим на пример
<template>
<div id="app">
<chart></chart>
<chart></chart>
</div>
</template>
<script>
const Chart = {
template: '<span>chart</span>',
methods: {
resize: _.debounce(function () {
console.log('resize')
}, 1000 /* 时间设长一点,便于后面的观察 */)
},
mounted () {
window.addEventListener('resize', this.resize)
},
beforeDestroy () {
window.removeEventListener('resize', this.resize)
}
}
new Vue({
el: '#app',
components: {
Chart
}
})
</script>
На странице есть два компонента Chart, они будут слушатьwindow.resize
событие, а затем вывести «resize» в консоль.
Теперь я перетаскиваю страницу, меняю ее размер,Через 1 с (задержка, установленная debounce, составляет 1 с), сколько раз консоль будет выводить «resize»?
Это не просто, не правда ли, каждый компонент диаграммы выводит по 1 разу, всего 2 раза?
Вот онлайнdemo, ты можешь пойти и поиграть,На самом деле, каждый раз, когда изменяется размер страницы, консоль выводит «изменить размер» только один раз., не странно?
отmethods
Говоря о
Предположим, мы определяем следующий метод в компоненте Chart:
{
methods: {
resize () {}
}
}
Тогда есть один важный момент, который нужно прояснить в этой статье:Все экземпляры компонента Chart, вызовитеthis.resize()
, в конце концов вызоветthis.$options.methods.resize()
, внутри vue, когда создается экземпляр компонента, он фактически делает следующее:
// 绑定 this
this.resize = this.options.methods.resize.bind(this)
Это соотношение выглядит следующим образом:
Тогда объясним причину странного явления:
Изменение размера в двух экземплярах Chart будет вызывать одну и ту же функцию устранения дребезга, поэтому, когда два компонента одновременно выполняют метод изменения размера, первый устраняется, поэтому мы видим вывод «resize» только один раз.
Отдельный метод изменения размера
из-заmethods
Метод, определенный в , является общим, что приводит к тому, что эффект устранения дребезга влияет друг на друга в компоненте, вызывая ошибки, поэтому, пока избегают совместного использования, каждое изменение размера может быть независимым друг от друга.Улучшенный код выглядит следующим образом:
<template>
<div id="app">
<chart></chart>
<chart></chart>
</div>
</template>
<script>
const Chart = {
template: '<span>chart</span>',
created () {
// 将 resize 的定义从 methods 中拿到这里来
// 这样就能保证 resize 只归某个实例拥有
this.resize = _.debounce(function () {
console.log('resize')
}, 1000 /* 时间设长一点,便于后面的观察 */)
},
mounted () {
window.addEventListener('resize', this.resize)
},
beforeDestroy () {
window.removeEventListener('resize', this.resize)
}
}
new Vue({
el: '#app',
components: {
Chart
}
})
</script>
улучшенdemo
Два последних слова
Внимательные друзья могут обнаружить, что нет, официальный примерv UE JS.org/v2/expensive/m…это поставить debounce вmethods
середина. В официальном примере действительно нет проблем, потому что страница не может иметь два поля ввода одновременно, вызывая в одно и то же времяexpensiveOperation
метод. Однако, если вы установите задержку дребезга немного больше, а затем быстро переключитесь между двумя полями ввода (хотя этот сценарий почти не существует), появится странное явление, о котором я упоминал в начале.