Vue Instance
Tạo instance
var vm = new Vue({
// options object
})
Quy ước đặt tên vm = ViewModel. Mọi component cũng là một Vue instance nên nhận cùng options object, trừ các option chỉ dành cho root instance như el.
Cây component
Root Instance (new Vue)
└─ TodoList
├─ TodoItem
│ ├─ TodoButtonDelete
│ └─ TodoButtonEdit
└─ TodoListFooter
├─ TodosButtonClear
└─ TodoListStatistics
Data & Reactivity
Mọi property trong data được đưa vào reactivity system lúc instance khởi tạo. Thay đổi giá trị thì view tự re-render.
var data = { a: 1 }
var vm = new Vue({ data: data })
vm.a === data.a // true — instance proxy tới data gốc
vm.a = 2
data.a // 2
data.a = 3
vm.a // 3
Chỉ reactive nếu khai báo từ đầu
Property chỉ reactive nếu đã tồn tại lúc tạo instance. Thêm property sau đó sẽ không được track:
var vm = new Vue({ data: { a: 1 } })
vm.b = 'hi' // KHÔNG reactive
Luôn khai báo trước mọi property với giá trị khởi tạo (kể cả rỗng):
data: {
newTodoText: '',
visitCount: 0,
hideCompletedTodos: false,
todos: [],
error: null
}
Cần thêm reactive property sau khi tạo thì dùng vm.$set(obj, key, value).
Object.freeze()
Object.freeze() chặn Vue setup getter/setter, làm object không reactive:
var obj = { foo: 'bar' }
Object.freeze(obj)
new Vue({ el: '#app', data: obj })
<div id="app">
<p>{{ foo }}</p>
<!-- foo không update vì obj đã bị freeze -->
<button v-on:click="foo = 'baz'">Thay đổi</button>
</div>
Dùng cho data read-only lớn (lookup table, config tĩnh) để bỏ overhead reactivity và tiết kiệm bộ nhớ.
Instance Properties & Methods
Tất cả được prefix $ để tách khỏi property do user định nghĩa.
var data = { a: 1 }
var vm = new Vue({ el: '#example', data: data })
vm.$data === data // true
vm.$el === document.getElementById('example') // true
vm.$watch('a', function (newVal, oldVal) {
console.log(`a: ${oldVal} -> ${newVal}`)
})
Các instance properties quan trọng
Các instance methods quan trọng
Lifecycle Hooks
Mỗi instance đi qua các bước: setup data observation, compile template, mount vào DOM, update DOM khi data thay đổi, teardown khi destroy. Hooks cho phép chèn code tại từng thời điểm.
Toàn bộ lifecycle hooks
new Vue({
// --- Khởi tạo ---
beforeCreate() {
// Instance vừa tạo, data/events chưa setup; this.$data chưa có
},
created() {
// Data, computed, watch, methods đã sẵn sàng; DOM chưa mount ($el chưa có)
// Dùng cho: gọi API, khởi tạo state
console.log('created - a is:', this.a)
},
// --- Mount vào DOM ---
beforeMount() {
// Template đã compile, sắp mount; hầu như không dùng
},
mounted() {
// Instance đã mount ($el tồn tại)
// Dùng cho: thao tác DOM, init thư viện third-party
console.log('mounted - el:', this.$el)
},
// --- Cập nhật ---
beforeUpdate() {
// Data đã đổi, DOM sắp re-render; có thể đọc DOM cũ trước khi patch
},
updated() {
// DOM đã re-render; tránh thay đổi data ở đây để khỏi loop vô hạn
},
// --- Destroy ---
beforeDestroy() {
// Instance sắp destroy; dùng cho: cleanup listeners, timers, subscriptions
},
destroyed() {
// Instance đã destroy; mọi directive và event listener đã unbind
}
})
Sơ đồ Lifecycle
Hook nào dùng cho việc gì?
Không dùng Arrow Function trong Hooks
// SAI — arrow function không có `this` riêng
new Vue({
created: () => {
console.log(this.a) // this = undefined hoặc window
}
})
// SAI trong $watch
vm.$watch('a', newValue => this.myMethod())
// ĐÚNG — dùng regular function
new Vue({
created() {
console.log(this.a) // this = Vue instance
}
})
// ĐÚNG trong $watch
vm.$watch('a', function (newValue, oldValue) {
this.myMethod() // this = Vue instance
})
Lý do: arrow function không có this riêng nên this bind vào scope cha (window hoặc undefined ở strict mode), gây lỗi Cannot read property of undefined.
Vue Instance trong AEM
Mount Vue vào element HTL render ra
HTL render server-side trước nên Vue instance chỉ cần mount vào DOM đã có:
<!-- HTL component: myComponent.html -->
<div data-sly-use.model="com.example.MyModel"
id="my-app"
data-items="${model.itemsJson}">
</div>
// clientlib/js/myComponent.js
(function() {
var el = document.getElementById('my-app')
if (!el) return // guard: element không tồn tại
var vm = new Vue({
el: el,
data: function() {
return {
// Parse JSON data từ HTL thông qua data attribute
items: JSON.parse(el.dataset.items || '[]'),
loading: false
}
},
created: function() {
console.log('[MyApp] Vue instance created, items:', this.items.length)
},
mounted: function() {
console.log('[MyApp] Mounted to DOM element:', this.$el.id)
}
})
})()
Dùng $nextTick sau khi cập nhật data
var vm = new Vue({
el: '#app',
data: { items: [] },
methods: {
loadItems: function() {
this.items = fetchItems() // data thay đổi
// DOM chưa cập nhật tại đây, query có thể sai
console.log(this.$el.querySelectorAll('.item').length)
// Đợi DOM update xong
this.$nextTick(function() {
console.log(this.$el.querySelectorAll('.item').length) // chính xác
})
}
}
})
Expose Vue instance ra window để debug
// Chỉ dùng trong development!
var vm = new Vue({ /* ... */ })
if (process.env.NODE_ENV !== 'production') {
window.__vm = vm
}
Cleanup đúng cách khi AEM SPA navigate
Trong AEM SPA hoặc khi component bị remove khỏi DOM, luôn destroy Vue instance:
var vm = new Vue({ el: '#app' /* ... */ })
// Khi component bị unmount/remove
function cleanup() {
if (vm) {
vm.$destroy()
vm = null
}
}
Tham khảo API