计算属性

@Computed Properties
数据绑定时,可以使用简单的表达式实现数据的2次处理;如根据 num 判断奇偶、根据折扣计算最终价格
<div>{{ num }} is {{ num % 2 ? 'odd' : 'even' }}</div>
<div>{{ price * (1 - discount) }}</div>
逻辑复杂时,应该使用计算属性实现
Feature
需要引入 computed 包
import { computed } from 'vue';
计算属性是一个属性,不是方法,使用时不需要()
计算属性是响应式数据,会触发页面更新
计算属性返回的值是只读的,且永远不应该被更改 - 应该更新它所依赖的源状态以触发新的计算
计算属性返回的值是派生状态,可以把它看作是一个“临时快照” - deriving values from your reactive state;每当源状态发生变化时,就会创建一个新的快照
除了数据计算外,不应该有其它操作,如数据请求,DOM修改等副作用,即:只做一件事情
如果还需要执行其它操作,可以使用 侦听函数 - watch
更多信息,请访问 计算属性 - Computed Properties
[] 判断奇偶
<div>{{ num }} is {{ res }}</div>
import { ref, computed } from 'vue';
const num = ref(0);
const res = computed(() => num.value % 2 === 0 ? 'even' : 'odd')
[] 判断性别
[] 参照B站规则处理关注、粉丝、点赞和播放数量
Computed Caching vs. Methods
方法可以没有返回,且每次执行方法都会导致页面渲染
[] 执行2次方法 inc 和执行2次计算属性 dec
创建方法 inc 和计算属性 dec
import { computed } from 'vue';
const inc = () => {
  console.log('do function inc');
}
const dec = computed(() => {
  console.log('do computed dec');
})
使用2次方法;2次计算属性
<div>第1次 inc - {{ inc() }}</div>
<div>第2次 inc - {{ inc() }}</div>
<div>第1次 dec - {{ dec }}</div>
<div>第2次 dec - {{ dec }}</div>
分析
数据变化时,2次方法都会执行
数据变化时,计算属性仅第1次执行;第2次没有检测到数据变化,就不会执行
do function inc
do function inc
do function dec
使用 value 指定属性值
import { ref, computed } from 'vue';
let age = ref(18)
const res = computed(() => {
    return age.value >= 18 ? 'adault' : 'teenage'
})
<div> {{ res }} </div>
Advance
计算属性是一个属性,不是方法,所以不能直接传递参数
通过 闭包 - closure 的形式间接传递参数
[] 将资源服务器地址和图片路径拼接为一个完整的在线地址
const getUrl = computed(() => {
    return (url) => {
        return 'http://127.0.0.1:3000' + url
    }
})
[] 根据成绩求绩点
let score = ref(80)
const grade = computed(() => {
  return (score) => {
    switch (Math.floor(score / 10)) {
      case 6:
        return 'D'
      case 7:
        return 'C'
      case 8:
        return 'B'
      case 9:
        return 'A'
      default:
        return 'E'
    }
  }
})
以上逻辑有什么需要改进的地方
<div>grade {{ score }} - {{ grade(score) }}</div>
使用静态数据
<div>grade 55 - {{ grade(55) }}</div>
<div>grade 60 - {{ grade(60) }}</div>
<div>grade 71 - {{ grade(71) }}</div>
<div>grade 80 - {{ grade(80) }}</div>
<div>grade 90 - {{ grade(90) }}</div>
<div>grade 100 - {{ grade(100) }}</div>
Summary & Homework
Summary
计算属性的引入和使用
无参计算属性
带参计算属性
Homework
[] 商品列表页 Goods.vue → goodsItem.vue 折扣处理
单个数据 - 直接处理
<div>{{ priceWithDis }}</div>
const priceWithDis = computed(() => price.value * (1 - discount.value))
多个数据 - 使用参数;toFixed() 是系统数据处理函数,可以指定保留小数点位数
const getDiscount = computed(() => {
  return item => {
    return (item.price * (1 - item.discount)).toFixed(2)
  }
})
[] 分别使用普通方法和计算属性处理数据

处理前

处理后

[] 使用计算属性处理图片数组,得到图片的url
import { ref, computed } from 'vue';
const imgs = ref(['coffee0.jpg', 'coffee1.jpg', 'coffee2.jpg', 'coffee3.jpg', 'coffee4.jpg'])
const imgsUrl = computed(() => {
  return imgs.value.map(img => new URL(`/src/assets/imgs/${img}`, import.meta.url).href)
})
[] 标签页内联样式 - 根据当前导航项动态移动指示器;ind 是导航项的索引
结构中直接使用数据;逻辑应该加带使用.value
方案1:传统方案 - 直接拼接样式
<div class="line" :style="{ transform: `translateX(${ind * 100}px)` }"></div>
方案2:使用对象和计算属性 - 部分
<div class="line" :style="`transform: translateX(${dis}px)`"></div>
const dis = computed(() => ind.value * 100)
方案33:使用对象和计算属性 - 全部
<div class="line" :style="{ transform: trans }"></div>
const dis = computed(() => `translateX(${ind.value * 100}px)`)
方案4:使用 CSS 内联变量,可以直接在样式中应用 - 推荐