Vue.js应用实例

每个Vue应用都是通过创建一个新的Vue实例开始的。Vue实例是Vue.js的核心,它连接了数据模型和DOM,实现了响应式数据绑定。本章将深入讲解Vue实例的创建、配置和使用方法。

创建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实例的行为。以下是常用的选项:

el
类型: String | Element Vue 2必需

指定Vue实例要管理的DOM元素。可以是CSS选择器字符串或实际的DOM元素。


// 使用选择器
el: '#app'

// 使用DOM元素
el: document.getElementById('app')
                                    
data
类型: Object | Function Vue 3必需

Vue实例的数据对象。在Vue 2中可以是对象,在Vue 3中必须是返回对象的函数。


// Vue 2
data: {
  message: 'Hello',
  count: 0
}

// Vue 3
data() {
  return {
    message: 'Hello',
    count: 0
  }
}
                                    
methods
类型: Object

定义Vue实例的方法。这些方法可以在模板中调用,也可以在实例内部调用。


methods: {
  greet: function() {
    alert('Hello!');
  },
  increment() {
    this.count++;
  }
}
                                    
computed
类型: Object

计算属性,基于依赖的响应式数据缓存计算结果,只有依赖变化时才重新计算。


computed: {
  reversedMessage: function() {
    return this.message.split('').reverse().join('');
  }
}
                                    
watch
类型: Object

侦听器,用于观察和响应Vue实例上的数据变化。


watch: {
  message: function(newVal, oldVal) {
    console.log('消息变化:', oldVal, '→', newVal);
  }
}
                                    
components
类型: Object

注册在当前实例中可用的组件。


components: {
  'my-component': {
    template: '<div>自定义组件</div>'
  }
}
                                    

完整的Vue实例示例

下面是一个完整的Vue实例示例,展示了各种选项的用法:

HTML模板


<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>
                            

JavaScript代码


// 创建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();
  }
});
                            
提示:使用this访问实例属性和方法

在Vue实例的选项(如methods、computed、watch等)中,可以通过this访问实例的属性和方法。例如:this.message访问data中的message,this.increment()调用methods中的increment方法。

生命周期钩子

Vue实例从创建到销毁会经历一系列初始化过程,这个过程就是Vue实例的生命周期。在每个阶段,Vue都提供了相应的生命周期钩子,允许我们在特定阶段执行自定义代码。

Vue生命周期图示

Vue实例生命周期图示

创建阶段
beforeCreate created

实例初始化,数据观测(data observer)和事件/侦听器配置。


beforeCreate() {
  // 实例初始化之后,数据观测之前调用
  console.log('beforeCreate: 实例刚创建');
},
created() {
  // 实例创建完成,数据观测已完成
  console.log('created: 实例已创建');
  // 可以访问数据,但DOM还未挂载
  console.log('message:', this.message);
}
                                    
挂载阶段
beforeMount mounted

实例挂载到DOM,模板编译/挂载。


beforeMount() {
  // 挂载开始之前调用,相关render函数首次被调用
  console.log('beforeMount: 挂载前');
},
mounted() {
  // 实例被挂载后调用,DOM已生成
  console.log('mounted: 挂载完成');
  // 可以访问DOM元素
  console.log('DOM元素:', this.$el);
}
                                    
更新阶段
beforeUpdate updated

数据变化时,虚拟DOM重新渲染和打补丁。


beforeUpdate() {
  // 数据更新时,虚拟DOM重新渲染之前
  console.log('beforeUpdate: 更新前');
},
updated() {
  // 数据更改导致虚拟DOM重新渲染后
  console.log('updated: 更新完成');
  // DOM已更新,可执行依赖DOM的操作
}
                                    
销毁阶段
beforeDestroy destroyed

实例销毁,清理工作,解绑事件和移除观察者。


beforeDestroy() {
  // 实例销毁之前调用,实例仍然完全可用
  console.log('beforeDestroy: 销毁前');
  // 清理定时器、取消订阅等
  clearInterval(this.timer);
},
destroyed() {
  // 实例销毁后调用,所有指令解绑,事件监听器移除
  console.log('destroyed: 已销毁');
}
                                    
注意:避免在生命周期钩子中使用箭头函数

在Vue实例选项中,不要使用箭头函数来定义生命周期钩子,因为箭头函数绑定了父级作用域的上下文,所以this不会指向Vue实例。例如:created: () => console.log(this.message)会导致thisundefined

实例属性和方法

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实例的实际应用。尝试修改输入框内容或点击按钮,观察数据的变化。

{{ title }}

消息: {{ 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 与 Vue 3 实例创建对比

Vue 2 实例创建


// 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 实例创建


// 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');
                                    
主要区别
  • 全局API: Vue 3使用createApp()工厂函数,避免了Vue 2中全局配置污染的问题
  • data选项: Vue 3中data必须是函数,Vue 2中可以是对象(在根实例中)
  • 多个应用: Vue 3可以创建多个独立的应用实例,互不影响
  • Tree-shaking: Vue 3的API设计支持更好的Tree-shaking,减小打包体积

最佳实践与注意事项

应该做的
  • 为Vue实例变量使用vm前缀(ViewModel的缩写)
  • data中声明所有需要响应式的数据
  • 使用计算属性缓存复杂计算的结果
  • mounted钩子中访问DOM元素
  • 使用$nextTick在DOM更新后执行操作
  • 在组件销毁前清理定时器和事件监听器
避免做的
  • 避免直接修改$data对象,使用实例属性访问
  • 不要在选项中使用箭头函数,会改变this指向
  • 避免在data中使用以$_开头的属性名
  • 不要过度使用$forceUpdate(),让Vue自动管理更新
  • 避免在createdbeforeMount中访问DOM
  • 不要忘记在beforeDestroy中清理资源

本章总结

  • Vue实例是Vue应用的基础,通过new Vue()(Vue 2)或Vue.createApp()(Vue 3)创建
  • 选项对象用于配置Vue实例,包括eldatamethodscomputedwatch
  • 生命周期钩子允许在实例创建、挂载、更新、销毁的不同阶段执行代码
  • 实例属性和方法通过$前缀访问,如$data$el$watch()$nextTick()
  • 理解Vue实例是掌握Vue.js框架的关键,后续的组件、指令等都是建立在实例基础上的

下一步:模板语法与数据绑定

现在你已经了解了如何创建和配置Vue实例,接下来我们将学习Vue的模板语法,包括插值、指令和数据绑定,这是Vue实现声明式渲染的核心。