实例方法

Vue 实例提供了丰富的方法,用于数据操作、事件处理、生命周期控制等。这些方法都以 $ 开头。

数据方法

$watch

监听数据变化:

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

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

unwatch()

监听对象属性:

vm.$watch('user.name', (newVal, oldVal) => {
  console.log('Name changed:', newVal)
})

深度监听:

vm.$watch('user', {
  handler(newVal, oldVal) {
    console.log('User changed')
  },
  deep: true
})

立即执行:

vm.$watch('userId', {
  handler(newVal) {
    this.fetchUser(newVal)
  },
  immediate: true
})

$set

添加响应式属性:

const vm = new Vue({
  data: {
    user: {
      name: 'John'
    },
    items: ['a', 'b', 'c']
  }
})

vm.$set(vm.user, 'age', 30)
vm.$set(vm.items, 1, 'x')

等价于:

Vue.set(vm.user, 'age', 30)

$delete

删除响应式属性:

const vm = new Vue({
  data: {
    user: {
      name: 'John',
      age: 30
    },
    items: ['a', 'b', 'c']
  }
})

vm.$delete(vm.user, 'age')
vm.$delete(vm.items, 1)

等价于:

Vue.delete(vm.user, 'age')

事件方法

$on

监听事件:

const vm = new Vue()

vm.$on('event', (data) => {
  console.log('Event received:', data)
})

vm.$on('event1', 'event2', (data) => {
  console.log('Multiple events')
})

$once

监听一次事件:

vm.$once('event', (data) => {
  console.log('This will only run once')
})

$off

移除事件监听:

function handler(data) {
  console.log(data)
}

vm.$on('event', handler)
vm.$off('event', handler)

vm.$off('event')

vm.$off()

$emit

触发事件:

vm.$emit('event', { message: 'Hello' })

vm.$emit('update', 1, 2, 3)

事件总线模式

const bus = new Vue()

Vue.component('component-a', {
  created() {
    bus.$on('user-login', this.handleLogin)
  },
  beforeDestroy() {
    bus.$off('user-login', this.handleLogin)
  },
  methods: {
    handleLogin(user) {
      console.log('User logged in:', user)
    }
  }
})

Vue.component('component-b', {
  methods: {
    login() {
      bus.$emit('user-login', { name: 'John' })
    }
  }
})

生命周期方法

$mount

手动挂载实例:

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

vm.$mount('#app')

vm.$mount()
document.body.appendChild(vm.$el)

$forceUpdate

强制重新渲染:

const vm = new Vue({
  data: {
    nonReactive: 'initial'
  }
})

vm.nonReactive = 'changed'
vm.$forceUpdate()

注意:$forceUpdate 只影响实例本身和子组件,不影响父组件。

$nextTick

在下次 DOM 更新后执行回调:

const vm = new Vue({
  data: {
    message: 'Hello'
  },
  methods: {
    update() {
      this.message = 'World'
      
      console.log(this.$el.textContent)
      
      this.$nextTick(() => {
        console.log(this.$el.textContent)
      })
    }
  }
})

$nextTick 返回 Promise:

async update() {
  this.message = 'World'
  await this.$nextTick()
  console.log(this.$el.textContent)
}

$destroy

销毁实例:

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

document.body.appendChild(vm.$el)

vm.$destroy()

document.body.removeChild(vm.$el)

实际案例

表单验证

new Vue({
  data() {
    return {
      form: {
        username: '',
        email: '',
        password: ''
      },
      errors: {}
    }
  },
  created() {
    this.$watch('form.username', (newVal) => {
      if (newVal.length < 3) {
        this.$set(this.errors, 'username', '用户名至少3个字符')
      } else {
        this.$delete(this.errors, 'username')
      }
    })
    
    this.$watch('form.email', (newVal) => {
      if (!newVal.includes('@')) {
        this.$set(this.errors, 'email', '请输入有效邮箱')
      } else {
        this.$delete(this.errors, 'email')
      }
    })
  }
})

动态组件创建

function createComponent(options) {
  const Component = Vue.extend(options)
  const instance = new Component()
  instance.$mount()
  return instance
}

const modal = createComponent({
  template: `
    <div class="modal">
      <div class="modal-content">
        <slot></slot>
      </div>
    </div>
  `,
  methods: {
    show() {
      document.body.appendChild(this.$el)
    },
    hide() {
      document.body.removeChild(this.$el)
    }
  }
})

modal.show()

异步队列处理

new Vue({
  data: {
    items: []
  },
  methods: {
    async addItems(newItems) {
      this.items.push(...newItems)
      
      await this.$nextTick()
      
      this.scrollToBottom()
    },
    scrollToBottom() {
      const container = this.$refs.container
      container.scrollTop = container.scrollHeight
    }
  }
})

全局事件管理

const EventBus = new Vue({
  methods: {
    emit(event, ...args) {
      this.$emit(event, ...args)
    },
    on(event, callback) {
      this.$on(event, callback)
    },
    off(event, callback) {
      this.$off(event, callback)
    },
    once(event, callback) {
      this.$once(event, callback)
    }
  }
})

Vue.prototype.$bus = EventBus

new Vue({
  created() {
    this.$bus.on('notification', this.showNotification)
  },
  beforeDestroy() {
    this.$bus.off('notification', this.showNotification)
  },
  methods: {
    showNotification(message) {
      console.log('Notification:', message)
    }
  }
})

响应式数据恢复

new Vue({
  data() {
    return {
      savedData: null
    }
  },
  created() {
    const saved = localStorage.getItem('app-data')
    if (saved) {
      const data = JSON.parse(saved)
      Object.keys(data).forEach(key => {
        this.$set(this, key, data[key])
      })
    }
  },
  beforeDestroy() {
    const dataToSave = { ...this.$data }
    delete dataToSave.savedData
    localStorage.setItem('app-data', JSON.stringify(dataToSave))
  }
})

方法对比

$watch vs watch 选项

new Vue({
  watch: {
    message(newVal, oldVal) {
      console.log('Changed')
    }
  }
})

new Vue({
  created() {
    this.$watch('message', (newVal, oldVal) => {
      console.log('Changed')
    })
  }
})

$watch 更灵活,可以动态添加/移除监听。

emitvsemit vs dispatch

Vue 2 中 dispatch已移除,使用dispatch 已移除,使用 emit:

this.$emit('event', data)

$set vs 直接赋值

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

this.obj.newProp = 'value'

$set 确保新属性是响应式的。

最佳实践

及时清理监听器

new Vue({
  created() {
    this.unwatch = this.$watch('data', this.handler)
  },
  beforeDestroy() {
    this.unwatch()
  }
})

使用 $nextTick 确保 DOM 更新

this.items.push(newItem)
this.$nextTick(() => {
  this.scrollToNew()
})

避免过度使用 $forceUpdate

this.items = [...this.items]

this.$forceUpdate()

事件命名规范

this.$emit('update:user', user)
this.$emit('change', value)
this.$emit('submit', formData)