# Свойства data и методы

Узнайте как работать со свойствами data и методами в бесплатном уроке Vue School

# Свойства data

В компоненте свойство data должно быть функцией. Vue вызывает эту функцию на этапе создания нового экземпляра компонента. Она должна вернуть объект, который затем Vue обернёт в свою систему реактивности и сохранит в экземпляре компонента как $data. Для удобства, все свойства верхнего уровня объекта доступны через экземпляр компонента:

const app = Vue.createApp({
  data() {
    return { count: 4 }
  }
})

const vm = app.mount('#app')

console.log(vm.$data.count) // => 4
console.log(vm.count)       // => 4

// Присвоение значения в vm.count также обновит $data.count
vm.count = 5
console.log(vm.$data.count) // => 5

// ... и наоборот
vm.$data.count = 6
console.log(vm.count) // => 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Эти свойства добавляются только при первом создании экземпляра, поэтому убедитесь, что все они присутствуют в объекте, возвращаемом функцией data. При необходимости используйте null, undefined или какое-либо другое значение по умолчанию для свойств, где нужное значение изначально недоступно.

Конечно есть возможность добавления нового свойства в экземпляр компонента без добавления его в data. Но поскольку этого свойства не было в реактивном объекте $data, то оно не будет автоматически отслеживаться системой реактивности Vue.

Для обозначения встроенного API, предоставляемого через экземпляр компонента Vue использует префикс $. Кроме того для внутренних свойств зарезервирован префикс _. Следует избегать именования свойств data верхнего уровня, которые начинаются с них.

# Методы

Для добавления методов в экземпляр компонента используется опция methods. Значением должен быть объект, который будет содержать все необходимые методы:

const app = Vue.createApp({
  data() {
    return { count: 4 }
  },
  methods: {
    increment() {
      // `this` указывает на экземпляр компонента
      this.count++
    }
  }
})

const vm = app.mount('#app')

console.log(vm.count) // => 4

vm.increment()

console.log(vm.count) // => 5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Vue автоматически привязывает значение this к методам таким образом, чтобы оно указывало на экземпляр компонента. Это гарантирует, что в методе всегда сохраняется правильное значение this, даже при использовании в качестве обработчика события или коллбэка. Следует избегать использования стрелочных функций при определении methods, так как это не позволит Vue привязать корректное значение this.

Как и все остальные свойства экземпляра компонента, methods доступны в шаблоне компонента. Чаще всего они используются в качестве обработчиков событий:

<button @click="increment">Увеличить счётчик</button>
1

В примере выше, метод increment будет вызываться при клике на <button>.

Метод также можно вызвать непосредственно из шаблона. Как скоро увидим, обычно вместо метода лучше подходит вычисляемое свойство. Но использование метода может быть полезно в некоторых случаях, когда вычисляемые свойства не подходят. Вызвать метод можно в любом месте шаблона, где поддерживаются выражения JavaScript:

<span :title="toTitleDate(date)">
  {{ formatDate(date) }}
</span>
1
2
3

Если методы toTitleDate или formatDate обращаются к любым реактивным данным, то они будут отслеживаться как зависимости для отрисовки страницы, как если бы они были непосредственно использованы в шаблоне.

Методы, вызываемые из шаблона, не должны иметь побочных эффектов, таких как изменение данных или запуск асинхронных процессов. Если возникает потребность сделать это, то в этом случае скорее всего лучше подойдёт использование хуков жизненного цикла.

# Реализация debounce и throttle

Vue не предоставляет встроенной поддержки для debounce или throttle, но её легко можно реализовать с помощью сторонних библиотек, например Lodash (opens new window).

Если компонент используется только один раз, можно реализовать debounce в methods:

<script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
<script>
  Vue.createApp({
    methods: {
      // debounce с помощью Lodash
      click: _.debounce(function() {
        // ... обработка клика ...
      }, 500)
    }
  }).mount('#app')
</script>
1
2
3
4
5
6
7
8
9
10
11

Однако, подобный подход имеет потенциальные проблемы для повторно используемых компонентов, поскольку в таком случае все они получат одну и ту же debounce-функцию. Чтобы сохранить изолированность компонентов друг от друга, можно добавить функцию debounce в жизненном хуке created:

app.component('save-button', {
  created() {
    // debounce с помощью Lodash
    this.debouncedClick = _.debounce(this.click, 500)
  },
  unmounted() {
    // Остановка таймера при уничтожении компонента
    this.debouncedClick.cancel()
  },
  methods: {
    click() {
      // ... обработка клика ...
    }
  },
  template: `
    <button @click="debouncedClick">
      Сохранить
    </button>
  `
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20