创建实例

创建 Vue 实例是每个 Vue 应用的起点。本章详细介绍实例创建的各种方式和注意事项。

基本创建方式

使用 el 选项

最常见的方式是使用 el 选项指定挂载点:

const vm = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})

Vue 会自动查找匹配的 DOM 元素并挂载。

使用 CSS 选择器

el 可以是 CSS 选择器字符串:

new Vue({
  el: '#app',
  data: { message: 'Hello' }
})

new Vue({
  el: '.container',
  data: { message: 'Hello' }
})

使用 DOM 元素

el 也可以是直接的 DOM 元素:

new Vue({
  el: document.getElementById('app'),
  data: { message: 'Hello' }
})

使用 $mount

延迟挂载

可以先创建实例,稍后再挂载:

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

vm.$mount('#app')

不传参数

$mount 不传参数时,实例处于未挂载状态:

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

vm.$mount()

document.getElementById('app').appendChild(vm.$el)

链式调用

可以链式调用:

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

使用 template 选项

内联模板

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

使用模板字符串

new Vue({
  el: '#app',
  template: `
    <div class="container">
      <h1>{{ title }}</h1>
      <p>{{ content }}</p>
    </div>
  `,
  data: {
    title: 'Welcome',
    content: 'Hello Vue!'
  }
})

使用 DOM 模板

如果 el 元素有内容,会作为模板:

<div id="app">
  <h1>{{ title }}</h1>
  <p>{{ content }}</p>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    title: 'Welcome',
    content: 'Hello Vue!'
  }
})
</script>

使用 render 函数

基本用法

new Vue({
  el: '#app',
  data: {
    message: 'Hello'
  },
  render(h) {
    return h('div', this.message)
  }
})

创建复杂结构

new Vue({
  el: '#app',
  data: {
    items: ['Apple', 'Banana', 'Orange']
  },
  render(h) {
    return h('ul', 
      this.items.map(item => 
        h('li', { key: item }, item)
      )
    )
  }
})

使用 JSX

new Vue({
  el: '#app',
  data: {
    message: 'Hello'
  },
  render() {
    return <div>{this.message}</div>
  }
})

使用 Vue.extend

创建组件构造器

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

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

继承扩展

const BaseComponent = Vue.extend({
  methods: {
    greet() {
      console.log('Hello')
    }
  }
})

const ExtendedComponent = BaseComponent.extend({
  methods: {
    greet() {
      console.log('Hello Extended')
    }
  }
})

实例选项详解

data 选项

new Vue({
  data: {
    message: 'Hello',
    count: 0,
    user: {
      name: 'John',
      age: 30
    }
  }
})

methods 选项

new Vue({
  methods: {
    handleClick() {
      console.log('Clicked')
    },
    fetchData() {
      return fetch('/api/data')
    }
  }
})

computed 选项

new Vue({
  data: {
    firstName: 'John',
    lastName: 'Doe'
  },
  computed: {
    fullName() {
      return `${this.firstName} ${this.lastName}`
    }
  }
})

watch 选项

new Vue({
  data: {
    searchQuery: ''
  },
  watch: {
    searchQuery(newVal, oldVal) {
      this.search(newVal)
    }
  },
  methods: {
    search(query) {
      console.log('Searching:', query)
    }
  }
})

完整选项示例

new Vue({
  el: '#app',
  
  data: {
    message: 'Hello Vue!'
  },
  
  props: {
    title: String
  },
  
  computed: {
    reversedMessage() {
      return this.message.split('').reverse().join('')
    }
  },
  
  methods: {
    greet() {
      alert(this.message)
    }
  },
  
  watch: {
    message(newVal, oldVal) {
      console.log(`Changed: ${oldVal} -> ${newVal}`)
    }
  },
  
  beforeCreate() {
    console.log('beforeCreate')
  },
  
  created() {
    console.log('created')
  },
  
  beforeMount() {
    console.log('beforeMount')
  },
  
  mounted() {
    console.log('mounted')
  },
  
  components: {
    'my-component': {
      template: '<div>Component</div>'
    }
  },
  
  directives: {
    focus: {
      inserted(el) {
        el.focus()
      }
    }
  },
  
  filters: {
    uppercase(value) {
      return value.toUpperCase()
    }
  }
})

创建多个实例

一个页面可以有多个 Vue 实例:

const header = new Vue({
  el: '#header',
  data: {
    title: 'My App'
  }
})

const main = new Vue({
  el: '#main',
  data: {
    content: 'Main content'
  }
})

const footer = new Vue({
  el: '#footer',
  data: {
    copyright: '© 2024'
  }
})

实例间通信

通过全局事件总线

const bus = new Vue()

const vm1 = new Vue({
  created() {
    bus.$on('event', (data) => {
      console.log('Received:', data)
    })
  }
})

const vm2 = new Vue({
  methods: {
    send() {
      bus.$emit('event', { message: 'Hello' })
    }
  }
})

通过引用

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

const vm2 = new Vue({
  created() {
    console.log(vm1.message)
  }
})

注意事项

单文件组件

在单文件组件中,实例创建由 Vue 自动处理:

<template>
  <div>{{ message }}</div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello'
    }
  }
}
</script>

生产环境

生产环境建议使用 render 函数,避免模板编译:

new Vue({
  render: h => h(App)
}).$mount('#app')

不要修改 $options

实例创建后,不应修改 $options:

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

vm.$options.data = { message: 'World' }