当前位置: 首页 > news >正文

4.6Vue的OptionApi

1.computed计算属性的使用

在模板中可通过插值语法显示 data 中的数据。但有时需对数据转化后显示或结合多个数据显示,如对多个 data 数据运算、用三元运算符决定结果、对数据某种转化后显示。在模板中用表达式可方便实现,其初衷用于简单运算。在模板中放太多逻辑会使其过重且难维护,若多处使用还会有大量重复代码。

接着提出是否有方法将逻辑抽离出去。一种方式是将逻辑抽取到一个 method 中,放到 methods 的 options 中,但弊端是所有 data 使用过程都会变成方法调用;另一种方式是使用计算属性 computed。

官方未给出计算属性直接的概念解释,而是指出对于任何包含响应式数据的复杂逻辑,都应该使用计算属性。计算属性将混入到组件实例中,所有 getter 和 setter 的 this 上下文自动地绑定为组件实例。

计算属性的用法:

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

对计算属性有缓存这一现象的原因进行解释:

  • 计算属性会基于它们的依赖关系进行缓存。
  • 在数据不发生变化时,计算属性不需要重新计算。
  • 但是如果依赖的数据发生变化,在使用时,计算属性依然会重新进行计算。

1.1案例练习来区别

展示三个案例及三种实现思路:
案例一:有 firstName 和 lastName 两个变量,希望拼接后在界面显示。
案例二:有分数 score,score 大于 60 时在界面显示及格,小于 60 时显示不及格。
案例三:有变量 message 记录一段文字如 Hello World,某些情况直接显示,某些情况需对文字反转。
实现思路:
思路一:在模板语法中直接使用表达式。
思路二:使用 method 对逻辑进行抽取。
思路三:使用计算属性 computed。

1.2思路一

介绍思路一(模板语法)的实现及缺点:
缺点一:模板中存在大量复杂逻辑,不便于维护(模板中表达式初衷用于简单计算)。
缺点二:当有大量一样的逻辑时,存在重复代码。
缺点三:多次使用时,很多运算也需要多次执行,没有缓存。

还展示了实现思路一的代码示例:

html

预览

<!-- 1.实现思路一 -->
<template id="my - app"><h2>{{ firstName + lastName }}</h2><h2>{{ score >= 60? "及格" : "不及格" }}</h2><h2>{{ message.split("").reverse().join("") }}</h2>
</template>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><h2>{{message}}</h2><!-- 1.拼接名字 --><h2>{{firstName +"" +lastName}}</h2><!-- 2.显示分数等级 --><h2>{{score>60? "及格" :"不及格"}}</h2><!-- 实现英文字符反转 --><h2>{{message.split("").reverse("").join(" ")}}</h2></div><script src="../lib/Vue.js"></script><script>const app = Vue.createApp({data:function(){return {message:"Hello Vue",firstName:"张三",lastName:"李四",score:70,}},})app.mount('#app')</script>
</body>
</html>   

1.3思路二

内容:介绍思路二(method 实现)及其缺点。
缺点一:实际上先显示的是一个结果,但都变成了一种方法的调用。
缺点二:多次使用方法的时候,没有缓存,也需要多次计算。

代码:

html

预览

<!-- 2.实现思路二 -->
<template id="my - app"><h2>{{ getFullName() }}</h2><h2>{{ getResult() }}</h2><h2>{{ getReverseMessage() }}</h2>
</template>

javascript

运行

methods: {getFullName() {return this.firstName + " " + this.lastName;},getResult() {return this.score >= 60? "及格" : "不及格";},getReverseMessage() {return this.message.split("").reverse().join("");}
}

<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><h2>{{message}}</h2><!-- 1.拼接名字 --><h2>{{method1()}}</h2><!-- 2.显示分数等级 --><h2>{{method2()}}</h2><!-- 实现英文字符反转 --><h2>{{method3()}}</h2></div><script src="../lib/Vue.js"></script><script>const app = Vue.createApp({data:function(){return {message:"Hello Vue",firstName:"张三",lastName:"李四",score:70,}},methods:{method1:function(){return this.firstName +"" +this.lastName},method2:function(){return this.score>60? "及格" :"不及格"},method3:function(){return this.message.split("").reverse("").join(" ")}}})app.mount('#app')</script>
</body>
</html>     

1.4思路三

内容:介绍思路三(computed 实现)相关要点。注意计算属性看似是一个函数,但使用时无需加括号,后续讲 setter 和 getter 时会提及;发现无论直观还是效果上计算属性都是更好选择,且计算属性是有缓存的。

代码块:

html

预览

<!-- 3.实现思路三 -->
<template id="my - app"><h2>{{ fullName }}</h2><h2>{{ result }}</h2><h2>{{ reverseMessage }}</h2>
</template>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><h2>{{message}}</h2><!-- 注意使用的时候不需要加上小括号 --><!-- 1.拼接名字 --><h2>{{computed1}}</h2><!-- 2.显示分数等级 --><h2>{{computed2}}</h2><!-- 实现英文字符反转 --><h2>{{computed3}}</h2></div><script src="../lib/Vue.js"></script><script>const app = Vue.createApp({data:function(){return {message:"Hello Vue",firstName:"张三",lastName:"李四",score:70,}},computed:{computed1:function(){return this.firstName +"" +this.lastName},computed2:function(){return this.score>60? "及格" :"不及格"},computed3:function(){return this.message.split("").reverse("").join(" ")}},})app.mount('#app')</script>
</body>
</html>     

2.computed和method区别

3.computed的set和get

内容:计算属性在大多数情况下只需要一个 getter 方法,因此常将计算属性直接写成一个函数。但如果确实想设置计算属性的值,也可以给计算属性设置一个 setter 方法。

代码块:

javascript

运行

computed: {fullName: {get() {return this.firstName + " " + this.lastName;},set(value) {const names = value.split(" ");this.firstName = names[0];this.lastName = names[1];}}
}
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><h2>{{message}}</h2><h2>{{computed1}}</h2></div><script src="../lib/Vue.js"></script><script>const app = Vue.createApp({data:function(){return {message:"Hello Vue",fistName:"zhangsan",lastName:"lisi"}},computed:{// 注意这里的写法computed1:{get(){return this.fistName+" "+this.lastName},//get()获取的值这里会传回来,注意set(value){const names = value.split(" ")this.fistName = names[0]this.lastName = names[1]}}}})app.mount('#app')</script>
</body>
</html>

4.侦听器watch选项的使用

  1. 解释什么是侦听器:开发中在 data 返回的对象中定义数据,该数据通过插值语法等绑定到 template 中,当数据变化时,template 会自动更新显示最新数据。但在某些情况下,希望在代码逻辑中监听某个数据的变化,这时就需要用侦听器 watch 来完成。
  2. 介绍侦听器的用法:
    • 选项:watch
    • 类型:{[key: string]: string | Function | Object | Array }

我们先来看一个例子:

  • 当我们点击按钮的时候会修改 info.name 的值;
  • 这个时候我们使用 watch 来侦听 info,是侦听不到的。这是因为默认情况下,watch 只是在侦听 info 的引用变化,对于内部属性的变化是不会做出响应;
  • 这个时候我们可以使用一个选项 deep 进行更深层的侦听;
  • 注意前面我们说过 watch 里面侦听的属性对应的也可以是一个 Object;
    还有另外一个属性,是希望一开始的就会立即执行一次:
  • 这个时候我们使用 immediate 选项;
  • 这个时候无论后面数据是否有变化,侦听的函数都会有执行一次;
    代码在下一页课件中。
watch: {info: {handler(newValue, oldValue) {console.log(newValue, oldValue);},deep: true,immediate: true},'info.name': function(newValue, oldValue) {console.log(newValue, oldValue);}
}

<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><h2>{{changeMessage()}}</h2><h2>{{changeInfo()}}</h2></div><script src="../lib/Vue.js"></script><script>const app = Vue.createApp({data:function(){return {message:"Hello Vue",info:{name:"张三", age: 18}}},methods:{changeMessage: function(){this.message = "你好啊,界"return this.message},changeInfo: function(){this.info = {name:"Kobe"}return this.info}},watch:{//默认有两个参数:newValue/oldValuemessage: function(newValue,oldValue){console.log("message的数据发生了变化",newValue,oldValue)},info:function(newValue,oldValue){//2.如果是对象类型,那么拿到的是代理对象//console.log("message的数据发生了变化",newValue,oldValue)//3.获取原生对象console.log(Vue.toRaw(newValue))}}})app.mount('#app')</script>
</body>
</html>

Vue的watch侦听选项

<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"><h2>{{changeMessage()}}</h2><h2>{{changeInfo()}}</h2></div><script src="../lib/Vue.js"></script><script>const app = Vue.createApp({data:function(){return {message:"Hello Vue",info:{name:"张三", age: 18}}},methods:{changeMessage: function(){this.message = "你好啊,界"return this.message},changeInfo: function(){this.info = {name:"Kobe"}return this.info}},watch:{//默认有两个参数:newValue/oldValuemessage: function(newValue,oldValue){console.log("message的数据发生了变化",newValue,oldValue)},deep:true,//当点击按钮发生变化的时候,也能够深度的监听到immediate:true,//只是对第一次的监听有效info:function(newValue,oldValue){//2.如果是对象类型,那么拿到的是代理对象//console.log("message的数据发生了变化",newValue,oldValue)//3.获取原生对象console.log(Vue.toRaw(newValue))}}})app.mount('#app')</script>
</body>
</html>

5.侦听器watch其他写法

  1. 提到 Vue3 文档未提及,但 Vue 文档有提到的侦听对象属性的方式:'info.name': function(newValue, oldValue) { console.log(newValue, oldValue); }
  2. 介绍使用$watch API 的方式:在created生命周期中,使用this.$watch来侦听。第一个参数是要侦听的源;第二个参数是侦听的回调函数callback;第三个参数是额外的其他选项,比如deepimmediate

代码块:

javascript

运行

// 侦听对象属性方式
'info.name': function(newValue, oldValue) {console.log(newValue, oldValue);
}
// 使用$watch API方式
created() {this.$watch('message', (newValue, oldValue) => {console.log(newValue, oldValue);}, {deep: true, immediate: true})
}

6.阶段性综合案例练习

<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>table{border-collapse: collapse;text-align: center;}thead{background-color: #f5f5f5;}th,td{border: 1px solid #aaa;padding: 8px 16px;}.active{background-color: pink;}</style>
</head>
<body><div id="app"><template v-if="books.length"><table><thead><tr><th></th><th>书籍名称</th><th>出版日期</th><th>价格</th><th>购买数量</th><th>操作</th></tr></thead><tbody><tr v-for="(item,index) in books" :key="item.id"@click="myclick(index)":class="{active:index===indexClick }"><td>{{index+1}}</td><td>{{item.name}}</td><td>{{item.date}}</td><td>{{fomatPrice(item.price)}}</td><td><!-- 实现禁用功能 --><button :disabled="item.count<=0" @click="decrement(index,item)">-</button>{{item.count}}<button @click="increment(index,item)">+</button></td><td><button @click="myremove(index)">移除</button></td></tr></tbody></table><h1>总价{{fomatPrice(totalPrice)}}</h1></template><template v-else><h1>购物车为空,请添加你喜欢的数据吧</h1></template></div><script src="./data.js"></script><script src="../lib/Vue.js"></script><script>const app = Vue.createApp({data:function(){return {message:"Hello Vue",books:books,indexClick:-1}},computed:{totalPrice(){return this.books.reduce((preValue,item)=>{console.log(preValue,item)return preValue + item.price * item.count},0)}},methods:{fomatPrice:function(value){return "¥"+value},decrement:function(index, item){// item.count++this.books[index].count--},increment: function(index,item){//item.count++this.books[index].count++},myremove:function(index){this.books.splice(index,1)},myclick: function(index){this.indexClick=index}}})app.mount('#app')</script>
</body>
</html>


文章转载自:

http://dGY0uM5h.dkfrd.cn
http://qm9baudk.dkfrd.cn
http://mSqtNSnh.dkfrd.cn
http://TgPGAlmt.dkfrd.cn
http://kSODvuwX.dkfrd.cn
http://eJwB2apB.dkfrd.cn
http://mXb6gp5i.dkfrd.cn
http://bBDNC7pK.dkfrd.cn
http://PzMc9Zfy.dkfrd.cn
http://D48NC8Wo.dkfrd.cn
http://uQShlbMC.dkfrd.cn
http://kfuuY4zR.dkfrd.cn
http://T3PByFPm.dkfrd.cn
http://ZvsvWK8z.dkfrd.cn
http://r4exZ0se.dkfrd.cn
http://krRVevsJ.dkfrd.cn
http://BXFEDKni.dkfrd.cn
http://sIdANjz6.dkfrd.cn
http://Nzb06N1a.dkfrd.cn
http://yMD2s49c.dkfrd.cn
http://ubBSEucf.dkfrd.cn
http://TdJD2kVT.dkfrd.cn
http://aNfxcsTE.dkfrd.cn
http://aKZyfOOK.dkfrd.cn
http://5iECC4Pl.dkfrd.cn
http://wTXJtT3L.dkfrd.cn
http://YctYbK6g.dkfrd.cn
http://WKSJRAZm.dkfrd.cn
http://eO4g671m.dkfrd.cn
http://KRYE5cyY.dkfrd.cn
http://www.dtcms.com/a/377597.html

相关文章:

  • qqq数据结构补充
  • 【Vue2】解决数组监听问题
  • 2025 AI+SEO实战学习资料合集,入门到精通的实操指南
  • AutoTrack-IR-DR200构建栅格地图全解析:为教育领域打造的SLAM学习实践平台
  • mysql分库分表数据量核查问题
  • 深入浅出理解查找算法:从基础到实践
  • 最简单解决GitHub打不开的问题:Fastgithub的使用
  • 2025树莓派5烧录镜像教程
  • Ruoyi-vue-plus-5.x第七篇多租户与权限管理:7.2 租户管理功能
  • 解释器模式(Interpreter Pattern)解析与C++实现
  • 《软件方法》2025版 第2章 业务建模之愿景 Part1(20250908更新)
  • 贪心算法(最优装载问题)
  • JavaWeb04
  • ARM处理器的NEON技术
  • 遥感卫星技术解析:全色、多光谱、高光谱与雷达卫星的底层差异及典型应用案例
  • 吴恩达机器学习笔记(8)—神经网络:反向传播算法(附代码)
  • 仓颉安装文档
  • Product Hunt 每日热榜 | 2025-09-09
  • 大数据毕业设计-大数据-基于大数据的热门游戏推荐与可视化系统(高分计算机毕业设计选题·定制开发·真正大数据)
  • 解读数据仓库知识培训【附全文阅读】
  • LangChain中的Prompt模板如何使用?
  • 防逆流·易安装·高兼容——安科瑞ADL200N-CT/D16-WF阳台光伏电表
  • 性能优化零成本:只加3行代码,FCP从1.8s砍到1.2s
  • 深入 Spring MVC 底层:控制器方法执行流程与参数绑定原理解析
  • UniApp微信小程序-实现蓝牙功能
  • Java集成SmartJavaAI实现旋转框检测、定向边界框目标检测(YOLO-OBB)
  • FreeBSD系统使用freebsd-update命令从14.2升级到14.3
  • 【Java】Hibernate查询性能优化
  • Spring DI/IOC核心原理详解
  • 基于多时间尺度的电动汽车光伏充电站联合分层优化调度(Matlab代码实现)