vue--计算属性(computed)vs事件(methods)vs监听器(watch)

关于 computed 和 watch 的差异:

    1.computed 是计算一个新的属性 默认初始化会执行一次,并将该属性挂载到 vm(Vue 实例)上,而 watch 是监听已经存在且已挂载到 vm 上的数据 默认需配置才会执行,所以用 watch 同样可以监听 computed 计算属性的变化(其它还有 data、props)
    2.computed 本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,才会计算新的值,computed 第一次加载就监听,而 watch 则是当数据发生变化便会调用执行函数
    3.从使用场景上说,computed 适用一个数据被多个数据影响,而 watch 适用一个数据影响多个数据

一.计算属性(computed)

应用场景:在一个计算属性里可以完成各种复杂的逻辑,包括运算、函数调用等,只要最终返回一个结果就可以。

<template>
    <div class="box">
        <h1>计算属性</h1>
        <hr>
        <!-- 直接渲染得到数据 -->
        <p><input type="text" v-model="message"></p>
        <!-- 对data的数据进行简单的操作
        这样有一个不好的地方就是后期对页面数据的维护不是那么方便 -->
        <p>{{message.toUpperCase()}}</p>
        <!-- 通过计算属性改变mesage进行渲染 -->
        <p>{{computedMessage}}</p>
        <hr>
        <!-- 通过事件来改变属性 -->
        <span>{{message}}</span><button @click="changeMessage()">点击改变</button>
        <hr>
    </div>
</template>
<script>
export default {
    data() {
        return {
            message: 'Hello world!',
            passw2: 'sss',
        }
    },
    // computed属性是data返回值,在使用的时候只使用函数名不是调用函数
    computed:{//计算属性相当于data里的属性
              //什么时候执行:初始化显示/相关的data属性发生变化
        computedMessage(){//计算属性中的get方法,方法的返回值就是属性值
            return this.message.split('')
        },
        // computed属性get和set的使用
        getAndsetMsg: {
            get() {//回调函数 当需要读取当前属性值时执行,根据相关数据依赖计算并返回新的属性值
                return this.message
            },
            set(val) {//计算属性一般是没有set方法, 只读属性.
                      //监视当前属性值的变化,当属性值发生变化时执行,更新相关的属性数据
	              //val就是getAndsetMsg的最新属性值
                this.message = val+ 'muzidigbig'    
            }
        }
    },
    methods:{
        changeMessage(){
            this.message = this.computedMessage+'altman'
        }
    },
}
</script>
 

Setter 函数:可以监听当前值的变化,然后赋值给相应的依赖数据,得到新值

Getter 函数:计算属性本质上是一个函数,但在模板中使用时可以像属性一样访问。

这里需要注意的是computed中的函数名不能和所操作data中的数据一样;computed中的函数名相当于是操作data数据后的新数据,在模块中直接使用这个函数名即可实现对data中数据改变的渲染。

 注意,不应该使用箭头函数来定义 computed (例如 computedMessage: () => { return XXX;})。
 理由:箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,严格模式下this 将是 undefined。

优点:计算属性会进行缓存,如果多次使用使用,计算属性只会调用一次。 

计算属性的原理:

1.计算属性走缓存的机制如何实现:

-首先,计算属性多次被使用时且依赖的data中的属性没发生修改时,计算属性会走缓存机制。

-用脏数据标记(dirty)实现缓存机制。dirty是watcher的属性:dirty为true->读取计算属性时会重新计算;dirty为false->读取计算属性会走缓存。

2.当页面p的计算属性中的c属性依赖data中的a属性时,计算属性的更新步骤:

-因为c依赖于a,所以a可以收集到c的watcher。

-当a发生修改时,把watcher的dirty设置为true。

-a还会收集页面p的watcher,a会通知p进行更新,因为dirty为true,所以页面p会重新计算c。

-c更新完成后,将dirty设置为false。 

二.事件(methods)

应用场景:函数的调用

<template>
  <div class="on">
    <!-- v-on 就是监听事件,可以用v-on指令监听DOM事件来触发一些javascript代码。
两中事件监听器(无参,有参);事件的行内调用
    v-on 还有一种简单的写法,就是用@代替-->
    <div @click="count++">点击添加1:{{count}}</div>
    <!-- 如果同时传入某个参数,同时需要event时,可以通过$event传入事件 -->
    <!-- 
    .stop - 调用 event.stopPropagation()。
    .prevent - 调用 event.preventDefault()。
    .capture - 添加事件侦听器时使用 capture 模式。
    .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
    .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
    .native - 监听组件根元素的原生事件。
    .once - 只触发一次回调。
    .left - (2.2.0) 只当点击鼠标左键时触发。
    .right - (2.2.0) 只当点击鼠标右键时触发。
    .middle - (2.2.0) 只当点击鼠标中键时触发。
    .passive - (2.3.0) 以 { passive: true } 模式添加侦听器
    -->
    <button type="button" @click.prevent="init(10,$event)">初始值</button>
    <button type="button" @click="add()">+1</button>
    <button type="button" @click="substrack()">-1</button>
    <h2>{{countNum}}</h2>
  </div>
</template>
<script>
export default {
  name: "on",
  data() {
    return {
      count: 0,
      countNum: 0
    };
  },
  methods: {
    /** 
     * 注意,不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.a++)。
     * 理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined。
    */
    init(num, event) {
      this.countNum = num;
      console.log(event);
    },
    add() {
      return this.countNum++;
    },
    // substrack: () => {
    //   return this.countNum--; // undefined
    // }
    substrack() {
      return this.countNum--;
    }
  }
};
</script>

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

三.监听器(watch)

应用场景:数据变化时执行异步或开销较大的操作。

首先确认 watch是一个对象,一定要当成对象来用。
对象就有键,有值。
第一种 键:就是你要监听的那个数据,比如说$route,这个就是要监控路由的变化。或者是data中的某个变量。
值可以是函数:就是当你监控的家伙变化时,需要执行的函数,这个函数有两个形参,第一个是改变后的新值,第二个是改变之前的值。
第二种  值也可以是函数名:不过这个函数名要用单引号来包裹。(不常用)
第三种情况厉害了(监听的那个数据值是一个对象):
值是包括选项的对象:选项包括有三个。

    第一个是handler:其值是一个回调函数。即监听到变化时应该执行的函数。
    第二个是deep:其值是true或false;确认是否深入监听。(监听 对象/数组里面值的变化)。
    第三个是immediate:其值是true或false;确认是否以当前的初始值执行handler的函数。
 

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

用法一:基础用法

<template>
    <div class="box">
        <h1>监听器</h1>
        <label>二次密码:</label>
        <input v-model="watchMsg"  />
    </div>
</template>
<script>
export default {
    data() {
        return {
            message: 'Hello world!',
            watchMsg: '我是监听操作',
        }
    },
    watch:{
        // watch第一次绑定值的时候不会执行监听,修改数据才会触发函数
        watchMsg(newVal,oldVal){
            console.log('newVal:'+newVal,'oldVal:'+oldVal);
        },
    }
}
</script>

用法二:handler方法和immediate属性

<template>
    <div class="box">
        <h1>监听器</h1>
        <label>二次密码:</label>
        <input v-model="watchMsg"  />
    </div>
</template>
<script>
export default {
    data() {
        return {
            message: 'Hello world!',
            watchMsg: '我是监听操作',
        }
    },
    watch:{
        //  如果需要第一次就执行监听 则需要设置:immediate: true
        watchMsg: {
            handler(newVal,oldVal){
                console.log('newVal:'+newVal,'oldVal:'+oldVal);
            },
            immediate:true,
        }
    }
}
</script>

注意到handler了吗,我们给 watchMsg绑定了一个handler方法,之前我们写的 watch 方法其实默认写的就是这个handler,Vue.js会去处理这个逻辑,最终编译出来其实就是这个handler

immediate:true代表如果在 wacth 里声明了watchMsg之后,就会立即先去执行里面的handler方法,如果为 false就跟我们以前的效果一样,不会在绑定的时候就执行。

用法三:

deep属性

watch 里面还有一个属性 deep,默认值是 false,代表是否深度监听,比如我们 data 里有一个obj属性/数组:

<template>
    <div class="box">
        <h1>监听器</h1>
        <label>二次密码:</label>
        <input v-model="obj.watchMsg"  />
    </div>
</template>
<script>
export default {
    data() {
        return {
            message: 'Hello world!',
            obj:{
                watchMsg: '我是监听操作',
            }
        }
    },
    watch:{
        //  注意:属性值发生变化后,handler执行后获取的 newVal 值和 oldVal 值是一样的
        obj: {
            handler(newVal,oldVal){
                console.log('newVal:'+newVal,'oldVal:'+oldVal);
            },
            immediate:true,
            deep:true,
        },
        // 函数执行后,获取的 newVal 值和 oldVal 值不一样
        'obj.watchMsg': {
            handler(newVal,oldVal){
                console.log('newVal:'+newVal,'oldVal:'+oldVal);
            },
            // 立即处理 进入页面就触发
            immediate:true,
        }
    }
}
</script>

2、数组的watch((一维、多维)数组的变化不需要深度监听
<template>
    <div class="box">
        <h1>监听器</h1>
        <p>{{array}}</p>
        <button @click='addArray()'>点击改变数组</button>
    </div>
</template>
<script>
export default {
    data() {
        return {
            message: 'Hello world!',
            array:['mu','zi','dig','big']
        }
    },
    watch:{
        // 需要注意的是这里所监听的对象应该是数组
        array:{
            handler(newVal,oldVal){
                console.log(newVal+'--'+oldVal)
            },
            // deep:true,
            // immediate:true,
        }
    },
    methods:{
        addArray() {
            this.array.push('66')
        }
    }
}
</script>

3、数组对象中对象属性变化监测需要使用deep:true深度监听,多少层内产生变化都可以监测到。
<template>
    <div class="box">
        <h1>监听器</h1>
        <ul>
            <li v-for="(item,index) in arrayObj" :key="item.id">{{index}}--{{item.name}}---<input type="text" v-model="item.age"  @keydown="change(index)"></li>
        </ul>
        <hr>
        <ul>
            <li v-for="(item,index) in arrayObj" :key="item.id">{{index}}--{{item.name}}---{{item.age}}</li>
        </ul>
    </div>
</template>
<script>
export default {
    data() {
        return {
            arrayObj:[
                {name:'张三',age:'23'},
                {name:'李四',age:'22'}
            ],
        }
    },
    watch:{
        // 需要注意的是这里所监听的对象应该是数组
        arrayObj:{
            handler(newVal,oldVal){
                console.log(newVal+'--'+oldVal)
            },
            deep:true,
            immediate:true,
        }
    },
    methods:{
        change(i) {
            // console.log(this.changeValue)
            this.arrayObj[i].age = this.arrayObj[i].age
        }
    }
}
</script>

 4、对象具体属性的watch[活用computed]
<template>
    <div class="box">
        <h1>监听器</h1>
        <p>{{obj.name}}</p>
        <input type="text" v-model="obj.name" name="" id="">
        <p>{{newName}}</p>
    </div>
</template>
<script>
export default {
    data() {
        return {
            obj:{name:'muzi',age:'23'},
        }
    },
    computed:{
        newName(){
            return this.obj.name.toUpperCase();
        }
    },
    watch:{
        newName(newVal,oldVal){
            console.log(newVal+'--'+oldVal)
        },
        // newName:{
        //     handler(newVal,oldVal){
        //         console.log(newVal+'--'+oldVal)
        //     },
        //     deep:true,
        //     immediate:true,
        // }
    },
}
</script>

从效果图上可以看出,计算属性最好使用在更改数据上然后进行渲染;先进行的计算属性再进行的监听。

5.监听路由变化
// 方法一:
watch:{
  $router(to,from){
       console.log(to.path)
  }
}

// 方法二:
watch: {
   $route: {
     handler:  function (val, oldVal){
       console.log(val);
     },
     // 深度观察监听
     deep:  true
   }
},
 

// 方法三:
watch: {
   '$route' : 'getRoutePath'
},
methods: {
   getRoutePath(){
     console.log( this .$route.path);
   }
}

1.1 computed

    1.是计算值
    2.具有缓存性,页面重新渲染值不会变化,计算属性会立即返回之前的计算结果,而不必再次执行函数(只有当依赖数据发生改变才会重新计算)
    3.不支持异步,当computed内有异步操作时无效,无法监听数据的变化
    4.不支持箭头函数
    5.第一次加载就监听,必须 return;默认初始化会执行一次
    6.最典型的栗子:购物车商品结算的时候

        理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,我们这里需要挂载到vm上。

2.2 watch

    1.是观察的动作
    2.无缓存性,页面重新渲染时值不变化也会执行(值改变则直接触发)
    3.支持异步
    4.监听数据必须是 data 中声明过或者父组件传递过来的props中的数据以及挂载到vm上的数据(computed)
    5.不支持箭头函数
    6.无需return;默认无数据改动不会执行,可配置 {immediate:true}来实现初始化执行一次
    7.栗子:搜索数据

        理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,我们这里需要挂载到vm上。

2.3 methods

    1.是函数
    2.无缓存性,页面重新渲染会被重新调用
    3.支持异步
    4.不支持箭头函数
    5.每次调用都会重新执行

        理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,我们这里需要挂载到vm上。

下面还另外总结了几点关于 computed 、watch 和 methods 的差异:

  1. computed 是计算一个新的属性,并将该属性挂载到 vm(Vue 实例)上,而 watch 是监听已经存在且已挂载到 vm 上的数据,所以用 watch 同样可以监听 computed 计算属性的变化(其它还有 dataprops
  2. computed 本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,才会计算新的值,computed 第一次加载就监听,其他直接使用这个计算得到的值,而 watch 则是当数据发生变化便会调用执行函数
  3. 计算属性是有缓存的,只要相关依赖没有改变,多次访问计算属性得到的值是之前缓存的计算结果,不会多次执行
  4. methods则是调用才更新
  5. 从使用场景上说,computed 适用一个数据被多个数据影响,而 watch 适用一个数据影响多个数据


区别:

1.watch和computed都是以Vue的依赖追踪机制为基础的,它们都试图处理这样一件事情:当某一个数据(称它为依赖数据)发生变化的时候,所有依赖这个数据的“相关”数据“自动”发生变化,也就是自动调用相关的函数去实现数据的变动。
2.对methods:methods里面是用来定义函数的,很显然,它需要手动调用才能执行。而不像watch和computed那样,“自动执行”预先定义的函数
【总结】:methods里面定义的函数,是需要主动调用的,而和watch和computed相关的函数,会自动调用,完成我们希望完成的作用

若有不足请多多指教!希望给您带来帮助!

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Vue中的计算属性监听器都是用于响应式数据更新时进行一些操作的。 计算属性是一种基于响应式依赖进行缓存的属性。它的值是根据它的依赖项动态计算而来的。当依赖项发生变化时,计算属性会自动重新计算,并且只有在必要时才会重新求值。计算属性适用于需要进行复杂计算的情况,比如对数据进行筛选、排序等操作。 监听器是一种观察和响应 Vue 实例上数据变动的方法。它可以监听一个或多个数据的变化,并在数据变化时执行相应的回调函数。监听器适用于需要执行一些副作用的情况,比如异步操作、事件触发等。 下面是计算属性监听器的使用示例: ```html <template> <div> <p>计算属性:{{ fullName }}</p> <p>监听器:{{ message }}</p> <input v-model="firstName" placeholder="请输入姓氏"> <input v-model="lastName" placeholder="请输入名字"> <button @click="updateMessage">更新消息</button> </div> </template> <script> export default { data() { return { firstName: '', lastName: '', message: '', }; }, computed: { fullName() { return this.firstName + ' ' + this.lastName; }, }, watch: { message(newValue, oldValue) { console.log(`消息从"${oldValue}"更新为"${newValue}"`); }, }, methods: { updateMessage() { this.message = 'Hello, ' + this.fullName; }, }, }; </script> ``` 在上面的示例中,我们定义了一个计算属性 `fullName` 和一个监听器 `message`。当用户输入姓氏和名字时,`fullName` 会自动更新;当用户点击“更新消息”按钮时,`message` 会更新。在 `message` 更新时,监听器会执行相应的回调函数并输出更新前后的消息。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值