Vue 计算属性和监听属性

2024-03-19 324 0

1. 计算属性computed

1)为什么要使用计算属性?

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

<div id='root'>
    <span> {{ message.split('').reverse().join('') }} </span>

</div>

上面代码,模板不再是简单的声明式逻辑,当模板中的逻辑较为复杂时,就会难以处理。

2)计算属性的使用

姓名示例:实现输入姓和名,计算全名的效果:

<div id='root'>
    姓:<input type="text" v-model="firstName" /><br><br>
    名:<input type="text" v-model="lastName" /><br><br>
    全名:<span>{{ fullName }}</span>
</div>
<script>
    const vm = new Vue({
        el: '#root',
        data: {
            firstName: '张',
            lastName: '三'
        },
        computed: {
            fullName: {
                get() {
                    console.log('get被调用了')
                    //此处this是vm
                    return this.firstName +'-'+ this.lastName;
                },
                set(value) {
                    console.log('set被调用了', value)
                    const arr = value.split('-');
                    this.firstName = arr[0];
                    this.lastName = arr[1];
                }
            }
        }
    });
</script>

结果:

原理:底层借助了Object.defineProperty()方法提供的getter和setter。计算属性默认只有 getter,不过在需要时你也可以提供一个 setter。

备注:

  • 计算属性最终会出现在vm上,直接读取使用即可
  • 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引用计算时依赖的数据发生改变
  • 计算属性中的get和set不能使用箭头函数

3)计算属性简写

绝大多数情况下,我们只会用默认的getter 方法来读取一个计算属性,在业务中很少用到setter,所以在声明一个计算属性时,可以直接使用默认的写法,不必将getter 和setter 都声明。

<div id='root'>
    姓:<input type="text" v-model="firstName" /><br><br>
    名:<input type="text" v-model="lastName" /><br><br>
    全名:<span>{{ fullName }}</span>
</div>
<script>
    const vm = new Vue({
        el: '#root',
        data: {
            firstName: '张',
            lastName: '三'
        },
        computed: {
            fullName() {
                console.log('get被调用了')
                //此处this是vm
                return this.firstName +'-'+ this.lastName;
            }
        }
    });
</script>

4)计算属性缓存 和methods方法

我们可以通过在表达式中调用方法来达到同样的效果。

<div id='root'>
    姓:<input type="text" v-model="firstName" /><br><br>
    名:<input type="text" v-model="lastName" /><br><br>
    全名:<span>{{ fullName }}</span><br><br>
    <!-- 全名:<span>{{ fullName() }}</span> -->
</div>
<script>
    const vm = new Vue({
        el: '#root',
        data: {
            firstName: '张',
            lastName: '三'
        },
        methods: {
            // fullName() {
            //     return this.firstName +'-'+ this.lastName;
            // }
        },
        computed: {
            fullName() {
                console.log('get被调用了')
                //此处this是vm
                return this.firstName +'-'+ this.lastName;
            }
        }
    });
</script>

我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。

然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 firstName和lastName还没有发生改变,多次访问 fullName, 计算属性会立即返回之前的计算结果,而不必再次执行函数。

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

2. 监听属性 watch

Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性watch 可以监听数据的变化,并在数据变化时执行所指定的回调函数。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

1)简单变量的监听

天气示例:点击按钮切换天气状态效果:

<div id='root'>
    <h2>今天天气很{{ info }}</h2>
    <button @click="changeWeather">点击切换天气</button>
</div>
<script>
    const vm = new Vue({
        el: '#root',
        data: {
            isHot: true
        },
        computed: {
            info() {
                return this.isHot ? '炎热' : '凉爽'
            }
        },
        methods: {
            changeWeather() {
                this.isHot = !this.isHot;
            }
        },
        // 监听属性
        watch: {
            //监听的属性名
            isHot: {
                //初始化时是否立即调用handler,默认false
                immediate: true,
                //handler什么时候调用?isHot发生改变时
                handler(newValue, oldValue) {
                    console.log('isHot被修改了',newValue, oldValue);
                }
            }
        }
    });
</script>

其中,handler是监听属性对应的回调函数,第一个参数是监听属性的新值,第二个参数是属性的旧值。immediate控制是否立即执行handler回调函数。

watch可以监听Vue实例上的任何数据的变化,包括简单数据类型,对象,数组和计算属性等。

除了watch选项外,还可以使用命令式的vm.$watch API监听:

//另一种写法
vm.$watch('isHot', {
    //初始化时是否立即调用handler,默认false
    immediate: true,
    //handler什么时候调用?isHot发生改变时
    handler(newValue, oldValue) {
        console.log('isHot被修改了',newValue, oldValue);
    }
});

2)深度监听

A. 监听对象的某个属性。比如监听numbers中a属性的变化:

<div id='root'>
    <h3>a的值是:{{ numbers.a }}</h3>
    <button @click="numbers.a++">点我+1</button>
</div>
<script>
    const vm = new Vue({
        el: '#root',
        data: {
             numbers: {
                a: 1,
                b: 2
            }
        },
        // 监听属性
        watch: {
            //监听对象属性
            'numbers.a': {
                handler() {
                    console.log('a变了')
                }
            }
        }
    });
</script>

B. 监听某个对象中所有属性的变化

<div id='root'>
    <h3>a的值是:{{ numbers.a }}</h3>
    <button @click="numbers.a++">点我+1</button>
    <h3>b的值是:{{ numbers.b }}</h3>
    <button @click="numbers.b++">点我+1</button>
</div>
<script>
    const vm = new Vue({
        el: '#root',
        data: {
             numbers: {
                a: 1,
                b: 2
            }
        },
        // 监听属性
        watch: {
            //监听对象中所有属性的变化
            numbers: {
                //深度监听
                deep: true, //开启深度监视
                handler() {
                    console.log('numbers变化了')
                }
            }
        }
    });
</script>

深度监视:

  • vue中的watch默认不监测对象内部值的改变
  • 配置 deep:true 可以监听对象内部值的改变(多层)

3)监听属性简写形式

<div id='root'>
    <h2>今天天气很{{ info }}</h2>
    <button @click="changeWeather">点击切换天气</button>
</div>
<script>
    const vm = new Vue({
        el: '#root',
        data: {
            isHot: true
        },
        computed: {
            info() {
                return this.isHot ? '炎热' : '凉爽'
            }
        },
        methods: {
            changeWeather() {
                this.isHot = !this.isHot;
            }
        },
        // 监听属性
        watch: {
            // 简写 - 监听值为处理函数
            isHot(newValue, oldValue) {
                console.log('isHot被修改了',newValue, oldValue);
            }
       }
    });
</script>

也可用另一种写法:

// 或
vm.$watch('isHot', function(newValue, oldValue) {
    console.log('isHot被修改了',newValue, oldValue);
});

相关文章

Vue 过滤器
Vue 自定义指令
Vue key的作用与原理
Vue MVVM与数据代理
Vue el与data的两种写法
vue-codemirror编辑器使用(vue3)

发布评论