复杂data的处理方式

我们在模板中可以直接通过插值语法显示一些data中的数据。
但是在某些情况下,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示

  • 比如我们需要对多个data数据进行运算、三元运算符来决定结果、数据进行某种转化后显示
  • 在模板中使用表达式,可以非常方便的实现,但是设计它们的初衷是用于简单的运算
  • 在模板中放入太多的逻辑会让模板过重和难以维护
  • 并且如果多个地方都使用到,那么会有大量重复的代码

我们怎么把逻辑抽离出去呢?

  • 使用methods,把逻辑抽取到methods的方法中
  • 但是这有一个直观的弊端,就是所有data使用过程都变成了一个方法的调用
  • 还可以使用计算数学computed

    认识计算属性computed

    什么是计算属性?

  • 官方并没有给出直接的解释

  • 而是说:对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性
  • 计算属性将被混入到组件实例中。所有getter和setter的this上下文自动地绑定为组件实例

计算属性的用法:

  • 选项:computed
  • 类型:{ [key: string]: Function | {get: Function,set: Function} }

    案例:

    案例一:我们有两个变量,firstName和lastName,希望它们拼接之后在界面上显示
    案例二:我们有一个分数:score

  • 当score大于60的时候,在界面上显示及格

  • 当score小于60的时候,在界面上显示不及格

案例三:我们有一个变量message,记录一段文字:Hello World

  • 某些情况下我们直接显示这段文字
  • 某些情况下我们对这段文字进行反转

    1. <template>
    2. <h2>{{fullName}}</h2>
    3. <h2>{{result}}</h2>
    4. <h2>{{reverseMessage}}</h2>
    5. </template>
    6. <script>
    7. data() {
    8. return {
    9. firstName: 'Kobe',
    10. lastName: 'Bryant',
    11. score: 80,
    12. message: 'Hello World'
    13. }
    14. },
    15. computed: {
    16. fullName() {
    17. return this.firstName + this.lastName
    18. },
    19. result() {
    20. return this.score >= 60 ? "及格" : "不及格"
    21. },
    22. reverseMessage() {
    23. return this.message.split(" ").reverse()
    24. }
    25. }
    26. </script>

    计算属性 vs methods

    计算属性和methods的实现看起来差别不大,但是计算属性是有缓存的
    接下来我们看一下同一个计算多次使用,计算属性和methods的差异:
    image.png
    image.png
    计算属性是有缓存的,当我们多次使用计算属性时,计算属性中的运算只会执行一次
    计算属性会随着依赖数据的改变,而进行重新计算

    计算属性的缓存

    为什么计算属性只做了一次打印呢?

  • 这是因为计算属性会基于它们的依赖关系进行缓存

  • 在数据不发生变化时,计算属性是不需要重新计算的
  • 但是如果依赖的数据发生变化,在使用时,计算属性依然会重新进行计算

image.png

计算属性的setter和getter

计算属性在大多数情况下,只需要一个getter方法即可,所以我们会将计算属性直接写成一个函数

计算属性的完整写法:

  1. computed: {
  2. // fullName的getter写法
  3. fullName: function(){
  4. return this.firstName + this.lastName
  5. }
  6. // fullName的setter和getter写法
  7. fullName: {
  8. get: function() {
  9. return this.firstName + this.lastName
  10. },
  11. set: function(newValue) {
  12. console.log(newValue)
  13. }
  14. }
  15. },
  16. methods:{
  17. changeFullName() {
  18. this.fullName = "kobe"
  19. }
  20. }

这样写,当我们执行changeFullName方法,内部的this.fullName = “Kobe”就会将Kobe传给fullName的set方法,Kobe就是newValue,最终会打印“kobe”,我们实际业务中如果需要对计算属性做修改,那么在set函数中定义如何修改即可。

vue中computed源码阅读

vue中,通过解构语法获取整个实例的options,computed也在其中,并且vue给computed赋了一个别名computedOptions。
第一步:遍历computedOptions,遍历时会拿到computed中的key,再通过computedOptions[key]的方式获取值,这个值既可能是一个函数,也可能是一个对象,所以做了一个是否为函数的判断,如果是函数那么就给这个函数绑定publicThis(一个vue定义的对象,包含一些vue内部实现的功能以及当前实例的上下文等),再用一个常量get接收函数执行后的返回值;如果不是函数,那它就是一个对象,vue就获取这个对象的get值,把前面绑定publicThis的步骤在获取到的这个get上做一遍;如果都没有,就返回一个空函数,说明没有get。并且如果获取到了get,那么就说明它有set,将set也做一遍前面的是否为函数的判断,如果是函数也绑定publicThis,不是的话返回空函数。
第二步:第一步的目的就是获取get以及set并且给他们绑定上下文,然后通过vue内部实现的computed函数给get和set添加上响应式的效果(具体效果等学习到响应式再具体学习),最终实现computed的功能。

认识侦听器watch

什么是侦听器?

  • 开发中我们在data返回的对象中定义了数据,这个数据通过插值语法等方式绑定到template中
  • 当数据变化时,template会自动进行更新来显示最新的数据
  • 但是在某些情况下,我们希望在代码逻辑中监听某个数据的变化,这个时候就需要用侦听器watch来完成了

侦听器的用法如下:

  • 选项:watch
  • 类型:{ [key: string]: string | Function | Object | Array }

    侦听器的配置选项

    深度侦听

    deep

    立即执行

    immdiate

    侦听器的其他用法

    以字符串的形式使用方法

    1. data() {
    2. return {
    3. b: 'b'
    4. }
    5. },
    6. watch: {
    7. b: 'someMethod'
    8. },
    9. methods: {
    10. someMethod(newVal,oldVal){
    11. }
    12. }

    回调数组

    1. f: [
    2. "handle1":,
    3. funcion handle2(newVal, oldVal) {
    4. console.log("handle2 triggered")
    5. },
    6. {
    7. handler: function handle3(newVal, oldVal) {
    8. console.log("handle3 triggered")
    9. }
    10. }
    11. ]

    侦听对象的某个属性

    1. "info.name": function(newVal, oldVal) {
    2. console.log(newVal, oldVal)
    3. }

    $watchAPI

    我们可以在vue的生命周期函数中使用this.$watchs来侦听:

  • 第一个参数是要真听的源数据

  • 第二个参数是侦听的回调函数callback
  • 第三个参数是额外的其他选项,比如deep、immediate
    1. created() {
    2. this.$watch('info', (newVal, oldVal) => {
    3. console.log(newVal)
    4. },{ deep: true, immediate: true })
    5. },