Vue 实例

每个 Vue 应用都是通过创建 Vue 实例开始的。Vue 实例是 Vue 应用的核心,它连接了数据、模板和 DOM。

理解 Vue 实例是掌握 Vue 的基础。实例管理着数据、方法、生命周期钩子,以及与 DOM 的交互。

什么是 Vue 实例

Vue 实例是 Vue 应用的入口点。它是一个对象,包含了应用的所有配置:

const vm = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  },
  methods: {
    greet() {
      alert(this.message)
    }
  }
})

创建实例

基本创建方式

const vm = new Vue({
  el: '#app',
  template: '<div>{{ message }}</div>',
  data: {
    message: 'Hello'
  }
})

使用 $mount

可以不指定 el,稍后手动挂载:

const vm = new Vue({
  template: '<div>{{ message }}</div>',
  data: {
    message: 'Hello'
  }
})

vm.$mount('#app')

或者:

const vm = new Vue({
  data: {
    message: 'Hello'
  }
}).$mount('#app')

创建组件实例

const ComponentClass = Vue.extend({
  template: '<div>{{ message }}</div>',
  data() {
    return {
      message: 'Hello'
    }
  }
})

const instance = new ComponentClass()
instance.$mount('#app')

实例与组件的关系

每个 Vue 组件也是一个 Vue 实例:

Vue.component('my-component', {
  data() {
    return {
      count: 0
    }
  },
  template: '<button @click="count++">{{ count }}</button>'
})

组件实例与根实例的区别:

特性根实例组件实例
data对象函数
el可以有不能有
父实例

实例选项

Vue 实例接受多种选项:

数据选项

new Vue({
  data: {
    message: 'Hello'
  },
  props: {
    title: String
  },
  computed: {
    reversedMessage() {
      return this.message.split('').reverse().join('')
    }
  },
  methods: {
    greet() {
      console.log(this.message)
    }
  },
  watch: {
    message(newVal, oldVal) {
      console.log(`Message changed from ${oldVal} to ${newVal}`)
    }
  }
})

DOM 选项

new Vue({
  el: '#app',
  template: '<div>{{ message }}</div>',
  render(h) {
    return h('div', this.message)
  },
  renderError(h, err) {
    return h('pre', { style: { color: 'red' } }, err.stack)
  }
})

生命周期选项

new Vue({
  beforeCreate() {},
  created() {},
  beforeMount() {},
  mounted() {},
  beforeUpdate() {},
  updated() {},
  beforeDestroy() {},
  destroyed() {},
  activated() {},
  deactivated() {},
  errorCaptured(err, vm, info) {}
})

资源选项

new Vue({
  directives: {
    focus: {
      inserted(el) {
        el.focus()
      }
    }
  },
  filters: {
    uppercase(value) {
      return value.toUpperCase()
    }
  },
  components: {
    'my-component': {
      template: '<div>Component</div>'
    }
  }
})

组合选项

new Vue({
  mixins: [mixin],
  extends: baseComponent,
  provide: {
    theme: 'dark'
  },
  inject: ['userService']
})

实例属性

Vue 实例提供了一些有用的属性:

属性说明
$data数据对象
$propsprops 对象
$elDOM 元素
$options实例选项
$parent父实例
$root根实例
$children子组件实例
$refs引用元素
$attrs非 prop 属性
$listeners事件监听器

使用示例

const vm = new Vue({
  el: '#app',
  data: {
    message: 'Hello'
  },
  mounted() {
    console.log(this.$data)
    console.log(this.$el)
    console.log(this.$options)
  }
})

console.log(vm.$data.message)
console.log(vm.$el.outerHTML)

实例方法

数据方法

vm.$watch('message', (newVal, oldVal) => {
  console.log(`Changed: ${oldVal} -> ${newVal}`)
})

vm.$set(this.obj, 'newProp', 'value')

vm.$delete(this.obj, 'oldProp')

事件方法

vm.$on('event', handler)
vm.$once('event', handler)
vm.$off('event', handler)
vm.$emit('event', payload)

生命周期方法

vm.$mount('#app')
vm.$forceUpdate()
vm.$nextTick(callback)
vm.$destroy()

响应式原理

Vue 实例的 data 是响应式的:

const vm = new Vue({
  data: {
    message: 'Hello'
  }
})

vm.message = 'World'

当 message 改变时,视图会自动更新。

响应式限制

对象:Vue 无法检测属性添加

vm.obj.newProp = 'value'

需要使用 $set:

vm.$set(vm.obj, 'newProp', 'value')

数组:Vue 无法检测某些变更

vm.items[0] = 'new value'
vm.items.length = 0

需要使用变异方法或 $set:

vm.items.splice(0, 1, 'new value')
vm.items.splice(0)

实例代理

Vue 实例代理了 data 和 props 的属性:

const vm = new Vue({
  data: {
    message: 'Hello'
  }
})

console.log(vm.message)
vm.message = 'World'

实际上访问的是 vm.$data.message。

实例与 this

在 Vue 实例的方法中,this 指向实例本身:

new Vue({
  data: {
    message: 'Hello'
  },
  methods: {
    greet() {
      console.log(this.message)
    }
  },
  created() {
    this.greet()
  }
})