笔记内容:学习编写能够让模板产生响应式变化的数据。
目录:
众所周知,Vue是一个响应式的前端组件框架。响应式即是当业务逻辑中的数据发生改变的时候视图中的内容也会跟着改变。
计算属性和侦听器
例子
假设班上有许一、许二、许三三位同学,在页面中,名字名字前面是序号,名字后面是获得小红花的数字。
<template> <div class="hello"> <div v-for="(p, index) in classmates" :key="p.id"> {{ `${index}.${p.name}` }} : {{ p.count }} <button @click="add(index)">+</button> <button @click="del(index)">-</button> </div> </div> </template> <script> export default { data(){ return{ classmates: [ {id: 1, name: "许一", count: 0}, {id: 2, name: "许二", count: 0}, {id: 3, name: "许三", count: 0}, ] }; }, methods: { add(i){ this.classmates[i].count += 1; }, del(i){ this.classmates[i].count -= 1; } } } </script>
第13-21行:定义数据结构,通过函数 data 返回数组 classmates。
第3-7行:通过 v-for 生成一个模板,classmates 是数组,p 是当
前的值,index 是当前索引。设置“+”“-”按钮,点击“+”按钮调用
add 方法(第23-25行),add 的参数 index 是当前索引,对应数
组 classmate 中元素在数组中的索引。点击“-”按钮调用 del 方法(第26-28行)
下面实现:计算班级同学获得的小红花的总数 count, 在页面上显示出来。
有几种实现方案。
方案 1 :通过计算属性实现
<template> <div class="hello"> <div v-for="(p, index) in classmates" :key="p.id"> {{ `${index}.${p.name}` }} : {{ p.count }} <button @click="add(index)">+</button> <button @click="del(index)">-</button> </div> <div> count: {{count}} </div> </div> </template> <script> export default { data(){ return{ classmates: [ {id: 1, name: "许一", count: 0}, {id: 2, name: "许二", count: 0}, {id: 3, name: "许三", count: 0}, ] }; }, computed: { count(){ return this.classmates.reduce((p, c) => { p = p + c.count; return p; }, 0) } }, methods: { add(i){ this.classmates[i].count += 1; }, del(i){ this.classmates[i].count -= 1; } } } </script>
第21-31行:
reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
p 是初始值,计算后的返回值
c 是当前元素
0 是传递给函数的初始值
可以参考:
https://www.runoob.com/jsref/jsref-reduce.html
相关笔记:
https://www.cnblogs.com/xiaoxuStudy/p/12604515.html#map
页面表现:
点击按钮分别给许一、许二、许三添加小红花,count 处输出小红花总数。
方案 2 :通过方法实现
<template> <div class="hello"> <div v-for="(p, index) in classmates" :key="p.id"> {{ `${index}.${p.name}` }} : {{ p.count }} <button @click="add(index)">+</button> <button @click="del(index)">-</button> </div> <div> count: {{count()}} </div> </div> </template> <script> export default { data(){ return{ classmates: [ {id: 1, name: "许一", count: 0}, {id: 2, name: "许二", count: 0}, {id: 3, name: "许三", count: 0}, ] }; }, methods: { count(){ return this.classmates.reduce((p, c) => { p = p + c.count; return p; }, 0) }, add(i){ this.classmates[i].count += 1; }, del(i){ this.classmates[i].count -= 1; } } } </script>
页面表现同上。
方案 1 跟方案 2 的区别
通过计算属性实现比通过方法实现性能好。
通过计算属性实现
计算属性是基于其内部的响应式依赖进行缓存的,只有相关响应式依赖发生改变时它们才会重新求值。
上面方案 1 例子中 computed 依赖的是 this.classmates,只有 this.classmates 发生改变的时候 count 函数才会进行一次计算,计算以后模板就会进行更新重新渲染。
通过方法实现
方法是无缓存的,每当触发重新渲染时,调用方法总会再次执行函数。
计算属性是基于其内部的响应式依赖进行缓存的
在实际的组件使用的过程中,如果希望在模板中去使用常量内容又不希望将常量内容放在 data 里去做响应式依赖收集,可以利用 computed 的缓存特性,将模板中使用的常量内容放到计算属性中。
侦听器就是一个 watch 函数,watch能够侦听数据实例上的变化。
用途:在数据变化后执行异步操作或者开销较大的操作
watch 函数跟 computed 函数都能侦听数据上的变化,但是,computed 是依赖数据的变化然后进行计算的,如果这个计算比较消耗时间、消耗数据量比较大或者消耗内存是会阻塞渲染的,所以,在这种情况下就不建议放到 computed 里去做。如果,在数据变化后需要执行异步操作或者开销比较大的操作,建议放到 watch 函数里面去做。
例子
<template> <div> {{ count }} <button @click="count = count + 1">add</button> </div> </template> <script> const log = index => index; export default { data(){ return{ count: 0 }; }, watch: { count(){ log(this.count); } } } </script>
页面表现:
点击按钮,按钮前面的数字跟着变化,比如,点击 3 次按钮之后,页面表现:
Prop&Data的笔记: https://www.cnblogs.com/xiaoxuStudy/p/12880361.html
数组操作的笔记:https://www.cnblogs.com/xiaoxuStudy/p/13230631.html