每个Vue应用都是通过创建一个新的Vue实例开始的。Vue实例是Vue.js的核心,它连接了数据模型和DOM,实现了响应式数据绑定。本章将深入讲解Vue实例的创建、配置和使用方法。
创建Vue实例非常简单,只需要调用Vue构造函数,并传入一个选项对象:
// Vue 2 语法
var vm = new Vue({
// 选项对象
el: '#app',
data: {
message: 'Hello Vue!'
}
});
// Vue 3 语法
const app = Vue.createApp({
data() {
return {
message: 'Hello Vue 3!'
}
}
});
const vm = app.mount('#app');
这里的vm(ViewModel的缩写)是Vue实例的常用变量名。虽然不强制要求,但遵循这个约定有助于理解Vue的设计思想。
创建Vue实例时传入的选项对象可以包含多种属性,用于配置Vue实例的行为。以下是常用的选项:
指定Vue实例要管理的DOM元素。可以是CSS选择器字符串或实际的DOM元素。
// 使用选择器
el: '#app'
// 使用DOM元素
el: document.getElementById('app')
Vue实例的数据对象。在Vue 2中可以是对象,在Vue 3中必须是返回对象的函数。
// Vue 2
data: {
message: 'Hello',
count: 0
}
// Vue 3
data() {
return {
message: 'Hello',
count: 0
}
}
定义Vue实例的方法。这些方法可以在模板中调用,也可以在实例内部调用。
methods: {
greet: function() {
alert('Hello!');
},
increment() {
this.count++;
}
}
计算属性,基于依赖的响应式数据缓存计算结果,只有依赖变化时才重新计算。
computed: {
reversedMessage: function() {
return this.message.split('').reverse().join('');
}
}
侦听器,用于观察和响应Vue实例上的数据变化。
watch: {
message: function(newVal, oldVal) {
console.log('消息变化:', oldVal, '→', newVal);
}
}
注册在当前实例中可用的组件。
components: {
'my-component': {
template: '<div>自定义组件</div>'
}
}
下面是一个完整的Vue实例示例,展示了各种选项的用法:
<div id="app">
<h1>{{ title }}</h1>
<p>{{ message }}</p>
<p>反转消息: {{ reversedMessage }}</p>
<p>计数器: {{ count }}</p>
<button @click="increment">增加</button>
<button @click="reset">重置</button>
<input v-model="message" placeholder="编辑消息">
</div>
// 创建Vue实例
var app = new Vue({
// 挂载元素
el: '#app',
// 数据
data: {
title: 'Vue实例示例',
message: '欢迎学习Vue.js!',
count: 0
},
// 计算属性
computed: {
reversedMessage: function() {
return this.message.split('').reverse().join('');
}
},
// 方法
methods: {
increment: function() {
this.count++;
},
reset: function() {
this.count = 0;
},
greet: function() {
alert('Hello Vue!');
}
},
// 侦听器
watch: {
count: function(newVal, oldVal) {
console.log('计数器从 ' + oldVal + ' 变为 ' + newVal);
},
message: function(newVal) {
console.log('消息已更新: ' + newVal);
}
},
// 生命周期钩子
created: function() {
console.log('Vue实例已创建');
},
mounted: function() {
console.log('Vue实例已挂载到DOM');
this.greet();
}
});
在Vue实例的选项(如methods、computed、watch等)中,可以通过this访问实例的属性和方法。例如:this.message访问data中的message,this.increment()调用methods中的increment方法。
Vue实例从创建到销毁会经历一系列初始化过程,这个过程就是Vue实例的生命周期。在每个阶段,Vue都提供了相应的生命周期钩子,允许我们在特定阶段执行自定义代码。
Vue实例生命周期图示
实例初始化,数据观测(data observer)和事件/侦听器配置。
beforeCreate() {
// 实例初始化之后,数据观测之前调用
console.log('beforeCreate: 实例刚创建');
},
created() {
// 实例创建完成,数据观测已完成
console.log('created: 实例已创建');
// 可以访问数据,但DOM还未挂载
console.log('message:', this.message);
}
实例挂载到DOM,模板编译/挂载。
beforeMount() {
// 挂载开始之前调用,相关render函数首次被调用
console.log('beforeMount: 挂载前');
},
mounted() {
// 实例被挂载后调用,DOM已生成
console.log('mounted: 挂载完成');
// 可以访问DOM元素
console.log('DOM元素:', this.$el);
}
数据变化时,虚拟DOM重新渲染和打补丁。
beforeUpdate() {
// 数据更新时,虚拟DOM重新渲染之前
console.log('beforeUpdate: 更新前');
},
updated() {
// 数据更改导致虚拟DOM重新渲染后
console.log('updated: 更新完成');
// DOM已更新,可执行依赖DOM的操作
}
实例销毁,清理工作,解绑事件和移除观察者。
beforeDestroy() {
// 实例销毁之前调用,实例仍然完全可用
console.log('beforeDestroy: 销毁前');
// 清理定时器、取消订阅等
clearInterval(this.timer);
},
destroyed() {
// 实例销毁后调用,所有指令解绑,事件监听器移除
console.log('destroyed: 已销毁');
}
在Vue实例选项中,不要使用箭头函数来定义生命周期钩子,因为箭头函数绑定了父级作用域的上下文,所以this不会指向Vue实例。例如:created: () => console.log(this.message)会导致this为undefined。
Vue实例提供了一些有用的属性和方法,可以通过$前缀访问。这些属性和方法在处理特定任务时非常有用。
| 属性/方法 | 描述 | 示例 |
|---|---|---|
$data |
Vue实例观察的数据对象(即data选项返回的对象) | vm.$data.message |
$props |
当前组件接收到的props对象 | vm.$props.userId |
$el |
Vue实例使用的根DOM元素(只在mounted之后可用) | vm.$el.innerHTML |
$options |
用于当前Vue实例的初始化选项 | vm.$options.name |
$parent |
父级Vue实例(如果当前实例有父级) | vm.$parent |
$root |
当前组件树的根Vue实例 | vm.$root |
$children |
当前实例的直接子组件数组 | vm.$children[0] |
$refs |
持有注册过ref特性的所有DOM元素和组件实例 | vm.$refs.myInput |
$slots |
访问被插槽分发的内容 | vm.$slots.default |
$attrs |
包含了父作用域中不作为prop被识别的特性绑定 | vm.$attrs |
| 实例方法 | 描述 | 示例 |
|---|---|---|
$watch() |
观察Vue实例上的一个表达式或函数计算结果的变化 | vm.$watch('count', callback) |
$set() |
向响应式对象中添加一个属性,并确保新属性也是响应式的 | vm.$set(obj, 'newProp', value) |
$delete() |
删除对象的属性,确保触发视图更新 | vm.$delete(obj, 'prop') |
$on() |
监听当前实例上的自定义事件 | vm.$on('event', callback) |
$emit() |
触发当前实例上的事件 | vm.$emit('event', data) |
$off() |
移除自定义事件监听器 | vm.$off('event', callback) |
$once() |
监听一个自定义事件,但只触发一次 | vm.$once('event', callback) |
$nextTick() |
将回调延迟到下次DOM更新循环之后执行 | vm.$nextTick(() => {}) |
$forceUpdate() |
迫使Vue实例重新渲染 | vm.$forceUpdate() |
$destroy() |
完全销毁一个Vue实例 | vm.$destroy() |
// 创建Vue实例
var vm = new Vue({
el: '#app',
data: {
count: 0
},
mounted() {
// 访问实例属性
console.log('根DOM元素:', this.$el);
console.log('数据对象:', this.$data);
// 使用$watch方法监听数据变化
this.$watch('count', function(newVal, oldVal) {
console.log(`count从${oldVal}变为${newVal}`);
});
// 使用$nextTick在DOM更新后执行代码
this.count = 5;
this.$nextTick(function() {
console.log('DOM已更新,当前count:', this.count);
});
}
});
下面的演示展示了Vue实例的实际应用。尝试修改输入框内容或点击按钮,观察数据的变化。
消息: {{ message }}
反转后的消息: {{ reversedMessage }}
计数器: {{ count }}
点击次数: {{ clickCount }}
new Vue({
el: '#vue-demo',
data: {
title: 'Vue实例演示',
message: '尝试编辑我!',
count: 0,
clickCount: 0
},
computed: {
reversedMessage() {
return this.message.split('').reverse().join('');
}
},
methods: {
increment() {
this.count++;
this.clickCount++;
},
decrement() {
if (this.count > 0) {
this.count--;
this.clickCount++;
}
},
reset() {
this.count = 0;
this.message = '尝试编辑我!';
this.clickCount = 0;
}
},
mounted() {
console.log('演示Vue实例已挂载');
}
});
// Vue 2 - 使用构造函数
var vm = new Vue({
el: '#app',
data: {
message: 'Hello Vue 2!'
},
methods: {
greet() {
alert(this.message);
}
}
});
// 或者先创建实例,后挂载
var vm2 = new Vue({
data: {
message: 'Hello Vue 2!'
}
});
// 手动挂载
vm2.$mount('#app2');
// Vue 3 - 使用createApp工厂函数
const app = Vue.createApp({
data() {
return {
message: 'Hello Vue 3!'
}
},
methods: {
greet() {
alert(this.message);
}
}
});
// 创建根实例
const vm = app.mount('#app');
// 可以创建多个应用实例
const app2 = Vue.createApp({ /* 配置 */ });
const vm2 = app2.mount('#app2');
createApp()工厂函数,避免了Vue 2中全局配置污染的问题vm前缀(ViewModel的缩写)data中声明所有需要响应式的数据mounted钩子中访问DOM元素$nextTick在DOM更新后执行操作$data对象,使用实例属性访问this指向data中使用以$或_开头的属性名$forceUpdate(),让Vue自动管理更新created或beforeMount中访问DOMbeforeDestroy中清理资源new Vue()(Vue 2)或Vue.createApp()(Vue 3)创建el、data、methods、computed、watch等$前缀访问,如$data、$el、$watch()、$nextTick()等现在你已经了解了如何创建和配置Vue实例,接下来我们将学习Vue的模板语法,包括插值、指令和数据绑定,这是Vue实现声明式渲染的核心。