boxmoe_header_banner_img

Hello! 欢迎来到盒子萌!

加载中

文章导读

03基础选项


avatar
Jack 2023年 1月 3日 140

选项

1. data

  • 类型:Function

  • 详细:

    返回组件对应的各种数据。

    实例创建后,可以通过 vm.$data 访问这些数据,组件实例也代理了 data 对象上所有的 property,因此访问 vm.a 等价于访问 vm.$data.a

    需要注意的是,不允许后续添加初始 data 中没有配置的属性,所以我们需要一开始在就在data中配置好当前组件需要用的所有属性(数据)。

  • 示例:

    Vue.createApp({
      data() {
          return {
              x: 10
          }
      }
    })

2. methods

  • 类型:{ [key: string]: Function }

  • 详细:

    methods 将被混入到组件实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为组件实例。

    注意,不应该使用箭头函数来定义 method 函数 (例如 plus:() => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向组件实例,this.a 将是 undefined。

  • 示例:

    const app = Vue.createApp({
    data() {
      return { a: 1 }
    },
    methods: {
      plus() {
        this.a++
      }
    }
    })
    
    const vm = app.mount('#app')
    
    vm.plus()
    console.log(vm.a) // => 2

3. 计算属性和侦听器

3.1 computed

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如,有一个嵌套数组对象:

Vue.createApp({
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  }
})

我们想根据 author 是否已经有一些书来显示不同的消息

<div id="computed-basics">
  <p>Has published books:</p>
  <span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
</div>

此时,模板不再是简单的和声明性的。你必须先看一下它,然后才能意识到它执行的计算取决于 author.books。如果要在模板中多次包含此计算,则问题会变得更糟。

所以,对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性

<div id="computed-basics">
  <p>Has published books:</p>
  <span>{{ publishedBooksMessage }}</span>
</div>
Vue.createApp({
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  },
  computed: {
    // 计算属性的 getter
    publishedBooksMessage() {
      // `this` 指向 vm 实例
      return this.author.books.length > 0 ? 'Yes' : 'No'
    }
  }
}).mount('#computed-basics')

当数据中 books 数组长度发生变化时,publishedBooksMessage也会自动更变。

3.2 计算属性 vs 方法

你可能已经注意到我们可以通过在表达式中调用方法来达到同样的效果:

<p>{{ calculateBooksMessage() }}</p>
// 在组件中
methods: {
  calculateBooksMessage() {
    return this.author.books.length > 0 ? 'Yes' : 'No'
  }
}

他们的区别在于计算属性是基于它们的反应依赖关系缓存的。计算属性只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 author.books 还没有发生改变,多次访问 publishedBookMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

这也同样意味着下面的计算属性将不再更新,因为 Date.now () 不是响应式依赖:

computed: {
  now() {
    return Date.now()
  }
}

相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。

3.3 计算属性的Setter

计算属性默认只有 getter,不过在需要时你也可以提供一个 setter:

// ...
computed: {
  fullName: {
    // getter
    get() {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set(newValue) {
      const names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
// ...

现在再运行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstNamevm.lastName 也会相应地被更新。

3.4 侦听器

虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

3.5 计算属性 vs 侦听器

Vue 提供了一种更通用的方式来观察和响应当前活动的实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。细想一下这个例子:

<div id="demo">{{ fullName }}</div>
const vm = Vue.createApp({
  data() {
    return {
      firstName: 'Foo',
      lastName: 'Bar',
      fullName: 'Foo Bar'
    }
  },
  watch: {
    firstName(val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName(val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
}).mount('#demo')

上面代码是命令式且重复的。将它与计算属性的版本进行比较:

const vm = Vue.createApp({
  data() {
    return {
      firstName: 'Foo',
      lastName: 'Bar'
    }
  },
  computed: {
    fullName() {
      return this.firstName + ' ' + this.lastName
    }
  }
}).mount('#demo')

好很多了,不是吗?

4. delimiters

用于修改默认的双大括号插值写法,默认值:[', ']。一般用于避免和其他同样使用双大括号的框架出现冲突。

Vue.createApp({
  // 分隔符变成了 ES6 模板字符串风格
  delimiters: ['${', '}']
})

5. 生命周期钩子

img

  • beforeCreate

    在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。

  • created

    在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el property 目前尚不可用。

  • beforeMount

    在挂载开始之前被调用:相关的 render 函数首次被调用。

  • mounted

    实例被挂载后调用,这时 Vue.createApp({}).mount() 被新创建的 vm.$el 替换了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm.$el 也在文档内。

    注意 mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick (opens new window)

    mounted() {
    this.$nextTick(function () {
      // 仅在渲染整个视图之后运行的代码
    })
    }
  • beforeUpdate

    数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。

  • updated

    由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。

  • beforeUnmount

    在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的。

  • unmounted

    卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载。

6. 其他

以下选项和组件密切相关,在学习组件后,我们再来讨论这些选项的作用。

  • props
  • components
  • mixins
  • provide / inject
  • name
  • emits
  • ……
vue


评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码