Vue
文章目录
- Vue
- 1 什么是Vue
- 2 创建Vue实例
- 2.1 快速创建
- 2.2 插值表达式 {{}}
- 2.3 响应式特性
- 2.3.1 访问与修改
- 3 Vue开发者工具安装
- 4 Vue中的常用指令
- 4.1 内容渲染指令
- 4.2 条件渲染指令
- 4.3 事件绑定指令
- 4.4 属性绑定指令
- 4.5 案例-上下页图片翻页
- 4.6 列表渲染指令
- 4.7 案例-能删除的书架
- 4.8 v-for中的key
- 4.9 双向绑定指令
- 4.10 指令修饰符
- 4.10.1 按键修饰符
- 4.10.2 v-model修饰符
- 4.10.3 事件修饰符
- 4.11 v-bind对样式控制的增强
- 4.11.1 操作class
- 4.11.2 案例-导航栏的切换
- 4.11.3 操作style
- 4.11.4 进度条案例
- 4.12 v-model在其他表单元素的使用
- 4.13 computed计算属性
- 4.13.1 computed计算属性 VS methods方法
- 4.13.2 总结
- 4.13.3 计算属性的完整写法
- 4.14 watch侦听器(监视器)
- 4.14.1 语法
- 4.14.2 简单写法
- 4.14.3 完整写法
1 什么是Vue
Vue (读音 /vjuː/,类似于 view) 是一套 **构建用户界面 **的 渐进式框架
Vue2官网:https://v2.cn.vuejs.org/
什么是构建用户界面?
基于数据渲染出用户可以看到的界面
什么是渐进式?
所谓渐进式就是循序渐进,不一定非得把Vue中的所有API都学完才能开发Vue,可以学一点开发一点
Vue的两种开发方式:
-
Vue核心包开发
场景:局部模块改造
-
Vue核心包&Vue插件&工程化
场景:整站开发
2 创建Vue实例
2.1 快速创建
核心步骤(4步):
- 准备容器
- 引包(官网) — 开发版本/生产版本
- 创建Vue实例 new Vue()
- 指定配置项,渲染数据
- el:指定挂载点
- data提供数据
2.2 插值表达式 {{}}
我们可以用插值表达式渲染出Vue提供的数据
常见错误使用:
1.在插值表达式中使用的数据 必须在data中进行了提供
<p>{{hobby}}</p> //如果在data中不存在 则会报错2.支持的是表达式,而非语句,比如:if for ...
<p>{{if}}</p>3.不能在标签属性中使用 {{ }} 插值 (插值表达式只能标签中间使用)
<p title="{{username}}">我是P标签</p>
2.3 响应式特性
简单理解就是数据变,视图对应变。
2.3.1 访问与修改
data中的数据, 最终会被添加到实例上
① 访问数据: “实例.属性名”
② 修改数据: “实例.属性名”= “值”
3 Vue开发者工具安装
- 通过谷歌应用商店安装(国外网站)
- 极简插件下载(推荐) https://chrome.zzzmh.cn/index
安装失败,采用第一种方法。
两个问题:
-
Vue的图标是灰色的
该页面不是由Vue写的,换一个由Vue写的网页,如bilibili
-
Vue的图标不是灰色的,但显示
Vue.js is detected on this page. Devtools inspection is not available because it's in production mode or explicitly disabled by the author.
按下F12,打开开发者模式,就可以看到Vue的调试面板
4 Vue中的常用指令
概念:指令(Directives)是 Vue 提供的带有 v- 前缀 的 特殊 标签属性。
目的:提高程序员操作 DOM 的效率。
vue 中的指令按照不同的用途可以分为如下 6 大类:
- 内容渲染指令(v-html、v-text)
- 条件渲染指令(v-show、v-if、v-else、v-else-if)
- 事件绑定指令(v-on)
- 属性绑定指令 (v-bind)
- 双向绑定指令(v-model)
- 列表渲染指令(v-for)
指令是 vue 开发中最基础、最常用、最简单的知识点。
4.1 内容渲染指令
内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。常用的内容渲染指令有如下2 个:
-
v-text(类似innerText)
使用语法:
<p v-text="uname">hello</p>
,意思是将 uame 值渲染到 p 标签中类似 innerText,使用该语法,会覆盖 p 标签原有内容
-
v-html(类似 innerHTML)
使用语法:
<p v-html="intro">hello</p>
,意思是将 intro 值渲染到 p 标签中类似 innerHTML,使用该语法,会覆盖 p 标签原有内容
类似 innerHTML,使用该语法,能够将HTML标签的样式呈现出来。
-
示例(语法上能看出两者区别)
<div id="app"> <h2>个人信息</h2> // 既然指令是vue提供的特殊的html属性,所以咱们写的时候就当成属性来用即可 <p v-text="uname">姓名:</p> <p v-html="intro">简介:</p> </div> <script>const app = new Vue({el:'#app',data:{uname:'张三',intro:'<h2>这是一个<strong>非常优秀</strong>的boy<h2>'}}) </script>
4.2 条件渲染指令
条件判断指令,**用来辅助开发者按需控制 DOM 的显示与隐藏。**条件渲染指令有如下两个,分别是:
-
v-show
作用: 控制元素显示隐藏
语法: v-show = “表达式” 表达式值为 true 显示, false 隐藏
原理: 切换 display:none 控制显示隐藏
场景:频繁切换显示隐藏的场景
-
v-if
作用: 控制元素显示隐藏(条件渲染)
语法: v-if= “表达式” 表达式值 true显示, false 隐藏
原理: 基于条件判断,是否创建 或 移除元素节点
场景: 要么显示,要么隐藏,不频繁切换的场景
-
示例:
<div id="app"> <div v-show="flag" class="box">我是v-show控制的盒子</div> <div v-if="flag" class="box">我是v-if控制的盒子</div> </div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> const app = new Vue({el: '#app',data: {flag: false} }) </script>
演示效果:
如果为true:
如果为false
-
v-else 和 v-else-if
作用:辅助v-if进行判断渲染
语法:v-else v-else-if=“表达式”
需要紧接着v-if使用
-
示例:
<div id="app"> <p v-if="gender === 1">性别:♂ 男</p> <p v-else>性别:♀ 女</p> <hr> <p v-if="score >= 90">成绩评定A:奖励电脑一台</p> <p v-else-if="score >= 70">成绩评定B:奖励周末郊游</p> <p v-else-if="score >= 60">成绩评定C:奖励零食礼包</p> <p v-else>成绩评定D:惩罚一周不能玩手机</p> </div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script>const app = new Vue({el: '#app',data: {gender: 2,score: 95} }) </script>
演示效果:
4.3 事件绑定指令
使用Vue时,如需为DOM注册事件,及其的简单,语法如下:
<button v-on:事件名="内联语句">按钮</button>
<button v-on:事件名="处理函数">按钮</button>
<button v-on:事件名="处理函数(实参)">按钮</button>
v-on:
简写为 @
内联语句示例:
<body><div id="app"><button @click="count--">-</button><span>{{ count }}</span><button v-on:click="count++">+</button></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {count: 100}})</script>
</body>
演示效果:
事件处理函数示例:
- 事件处理函数应该写到一个跟data同级的配置项(methods)中(不是method!!!)
- methods中的函数内部的this都指向Vue对象实例
<body><div id="app"><button @click="fn">切换显示隐藏</button><h1 v-show="isShow">Vue的事件处理函数显示与隐藏</h1></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app4 = new Vue({el: '#app',data: {isShow: true},methods: {fn () {// 让提供的所有methods中的函数,this都指向当前实例// console.log('执行了fn', app.isShow)// console.log(app3 === this)this.isShow = !this.isShow}}})</script>
</body>
演示效果:
给事件处理函数传参示例:
- 如果不传递任何参数,则方法无需加小括号,同时methods方法中可以直接使用 e 当做事件对象;
- 如果传递了参数,则实参
$event
表示事件对象,固定用法。
<body><div id="app"><div class="box"><h3>自动售货机</h3><button @click="buy(5)">可乐5元</button><button @click="buy(10)">咖啡10元</button><button @click="buy(8)">牛奶8元</button></div><p>银行卡余额:{{ money }}元</p></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {money: 100},methods: {buy (price) {this.money -= price}}})</script>
</body>
演示效果:
4.4 属性绑定指令
作用:动态设置html的标签属性 比如:src、url、title
语法:**v-bind:**属性名=“表达式”
**v-bind:**可以简写成 :
比如,有一个图片,它的 src
属性值,是一个图片地址。这个地址在数据 data 中存储。
则可以这样设置属性值:
<img v-bind:src="url" />
<img :src="url" />
(v-bind可以省略)
属性绑定指令示例:
<body><div id="app"><!-- v-bind:src => :src --><img v-bind:src="imgUrl" v-bind:title="msg" alt=""><img :src="imgUrl" :title="msg" alt=""></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {imgUrl: './imgs/11-00.gif',msg: 'hello 波仔'}})</script>
</body>
演示结果:
4.5 案例-上下页图片翻页
难点:
- 上一页、下一页按钮的显示和隐藏条件是什么?
- 如何采用数组实现图片的转化?即下标要如何变化?
<body><div id="app"><button v-show="index > 0" @click="index--">上一页</button><div><img :src="list[index]" alt=""></div><button v-show="index < list.length - 1" @click="index++">下一页</button></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {index: 0,list: ['./imgs/11-00.gif','./imgs/11-01.gif','./imgs/11-02.gif','./imgs/11-03.gif','./imgs/11-04.png','./imgs/11-05.png',]}})</script>
</body>
演示效果:
4.6 列表渲染指令
Vue 提供了 v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。
v-for 指令需要使用 (item, index) in arr
形式的特殊语法,其中:
- item 是数组中的每一项
- index 是每一项的索引,不需要可以省略
- arr 是被遍历的数组
此语法也可以遍历**对象和数字**
//遍历对象
<div v-for="(value, key, index) in object">{{value}}</div>
value:对象中的值
key:对象中的键
index:遍历索引从0开始//遍历数字
<p v-for="item in 10">{{item}}</p>
item从1 开始
列表渲染指令示例:
<body><div id="app"><h3>水果店</h3><ul><li v-for="(item, index) in list">{{ item }} - {{ index }}</li></ul><ul><li v-for="item in list">{{ item }}</li></ul></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {list: ['西瓜', '苹果', '鸭梨', '榴莲']}})</script>
</body>
演示效果:
4.7 案例-能删除的书架
难点:
- 运用v-for进行循环显示
- 如何删除(需要用到filter数组的过滤器,得到一个新数组)
filter:根据条件,保留满足条件的对应项,得到一个新数组。
<body><div id="app"><h3>书架</h3><ul><li v-for="(item, index) in booksList" :key="item.id"><span>{{ item.name }}</span><span>{{ item.author }}</span><!-- 注册点击事件 → 通过 id 进行删除数组中的 对应项 --><button @click="del(item.id)">删除</button></li></ul></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {booksList: [{ id: 1, name: '《红楼梦》', author: '曹雪芹' },{ id: 2, name: '《西游记》', author: '吴承恩' },{ id: 3, name: '《水浒传》', author: '施耐庵' },{ id: 4, name: '《三国演义》', author: '罗贯中' }]},methods: {del (id) {// console.log('删除', id)// 通过 id 进行删除数组中的 对应项 → filter(不会改变原数组)// filter: 根据条件,保留满足条件的对应项,得到一个新数组。// console.log(this.booksList.filter(item => item.id !== id))this.booksList = this.booksList.filter(item => item.id != id)}}})</script>
</body>
演示效果:
4.8 v-for中的key
对于用v-for渲染的列表数据来说,数据量可能一般很庞大,而且我们经常还要对这个数据进行一些增删改操作。那么整个列表都要重新进行渲染一遍,那样就会很费事。而key的出现就尽可能的回避这个问题,提高效率。
v-for默认使用就地复用的策略,列表数据修改的时候,**他会根据key值去判断某一个值是否修改,如果修改则重新渲染该项,否则复用之前的元素。**在v-for中我们的key一般为id,也就是唯一的值,但是一般不要使用index作为key。
<body><div id="app"><h3>小黑的书架</h3><ul><li v-for="(item, index) in booksList" :key="item.id"><span>{{ item.name }}</span><span>{{ item.author }}</span><span> key </span><button @click="del(item.id)">删除</button></li></ul></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {booksList: [{ id: 1, name: '《红楼梦》', author: '曹雪芹' },{ id: 2, name: '《西游记》', author: '吴承恩' },{ id: 3, name: '《水浒传》', author: '施耐庵' },{ id: 4, name: '《三国演义》', author: '罗贯中' }]},methods: {del (id) {this.booksList = this.booksList.filter(item => item.id !== id)}}})</script>
</body>
肉眼不能看出区别,但提高了效率
4.9 双向绑定指令
所谓双向绑定就是:
- 数据改变后,呈现的页面结果会更新
- 页面结果更新后,数据也会随之而变
作用: 给表单元素(input、radio、select)使用,双向绑定数据,可以快速 获取 或 设置 表单元素内容
**语法:**v-model=“变量”
双向绑定指令案例:
**需求:**使用双向绑定实现以下需求
- 点击登录按钮获取表单中的内容
- 点击重置按钮清空表单中的内容
<body><div id="app"><!-- v-model 可以让数据和视图,形成双向数据绑定(1) 数据变化,视图自动更新(2) 视图变化,数据自动更新可以快速[获取]或[设置]表单元素的内容-->账户:<input type="text" v-model="username"> <br><br>密码:<input type="password" v-model="password"> <br><br><button @click="login">登录</button><button @click="reset">重置</button></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {username: '',password: ''},methods: {login () {console.log(this.username, this.password)},reset () {this.username = ''this.password = ''}}})</script>
</body>
运行效果:
4.10 指令修饰符
所谓指令修饰符就是通过“.
”指明一些指令后缀 不同的后缀封装了不同的处理操作
目的:简化代码
4.10.1 按键修饰符
@keyup.enter:当点击enter键的时候才触发
按键修饰符示例:
<body><div id="app"><h3>@keyup.enter → 监听键盘回车事件</h3><input @keyup.enter="fn" v-model="username" type="text"></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {username: ''},methods: {fn (e) {// if (e.key === 'Enter') {// console.log('键盘回车的时候触发', this.username)// }console.log('键盘回车的时候触发', this.username)}}})</script>
</body>
运行效果:
4.10.2 v-model修饰符
- v-model.trim:去除首位空格
- v-model.number:转数字
示例:
姓名:<input v-model.trim="username" type="text"><br>
年纪:<input v-model.number="age" type="text"><br>
演示效果:
4.10.3 事件修饰符
-
@事件名.stop : 阻止冒泡
如何理解这里的 “阻止冒泡”
点击子组件,不调用父组件的点击事件
-
@事件名.prevent :阻止默认行为
-
@事件名.stop.prevent :可以连用即阻止事件冒泡也阻止默认行为
示例:
<body><div id="app"><h3>@事件名.stop → 阻止冒泡</h3><div @click="fatherFn" class="father"><div @click.stop="sonFn" class="son">儿子</div></div><h3>@事件名.prevent → 阻止默认行为</h3><a @click.prevent href="http://www.baidu.com">阻止默认行为</a></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {username: '',age: '',},methods: {fatherFn () {alert('父亲被点击了')},sonFn (e) {// e.stopPropagation()alert('儿子被点击了')}}})</script>
</body>
演示效果:
4.11 v-bind对样式控制的增强
4.11.1 操作class
为了方便开发者进行样式控制, Vue 扩展了 v-bind 的语法,可以针对 class 类名 和 style 行内样式 进行控制
语法:
<div> :class = "对象/数组">这是一个div</div>
对象语法:
当class动态绑定的是**对象时,键就是类名,值就是布尔值,如果值是true**,就有这个类,否则没有这个类
<div class="box" :class="{ 类名1: 布尔值, 类名2: 布尔值 }"></div>
适用场景:一个类名,来回切换;
其中的布尔值一般是某个判断式子
数组语法:
当class动态绑定的是**数组**时 → 数组中所有的类,都会添加到盒子上,本质就是一个 class 列表
<div class="box" :class="[ 类名1, 类名2, 类名3 ]"></div>
使用场景:批量添加或删除类
示例:
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.box {width: 100px;height: 100px;border: 3px solid #000;font-size: 20px;margin-top: 10px;}.pink {background-color: pink;}.big {width: 150px;height: 150px;}</style>
</head>
<body><div id="app"><div class="box" :class="{ pink: true, big: true }">Vue前端设计</div><div class="box" :class="{ pink: false, big: false }">Vue前端设计</div><div class="box" :class="['pink', 'big']">Vue前端设计</div></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {}})</script>
</body>
演示效果:
4.11.2 案例-导航栏的切换
难点:
如何让点击的部分激活相关的class产生被选中的效果。
运行效果:
代码:
<body><div id="app"><ul><li v-for="(item, index) in list" :key="item.id" @click="activeIndex = index"><a :class="{ active: index === activeIndex }" href="#">{{ item.name }}</a></li></ul></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {activeIndex: 2, // 记录高亮list: [{ id: 1, name: '京东秒杀' },{ id: 2, name: '每日特价' },{ id: 3, name: '品类秒杀' }]}})</script>
</body>
4.11.3 操作style
语法:
<div class="box" :style="{ CSS属性名1: CSS属性值, CSS属性名2: CSS属性值 }"></div>
示例:
<body><div id="app"><div class="box" :style="{ width: '400px', height: '400px', backgroundColor: 'green' }"></div></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {}})</script>
</body>
效果演示:
4.11.4 进度条案例
关键点:相关的按钮设置style属性为其宽度
代码:
<body><div id="app"><!-- 外层盒子底色 (黑色) --><div class="progress"><!-- 内层盒子 - 进度(蓝色) --><div class="inner" :style="{ width: percent + '%' }"><span>{{ percent }}%</span></div></div><button @click="percent = 25">设置25%</button><button @click="percent = 50">设置50%</button><button @click="percent = 75">设置75%</button><button @click="percent = 100">设置100%</button></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {percent: 30}})</script>
</body>
效果演示:
4.12 v-model在其他表单元素的使用
常见的表单元素都可以用 v-model 绑定关联 → 快速 获取 或 设置 表单元素的值
它会根据 控件类型 自动选取 对应的方法 来更新元素
输入框 input:text ——> value
文本域 textarea ——> value
复选框 input:checkbox ——> checked
单选框 input:radio ——> checked
下拉菜单 select ——> value
...
例如,
如果控件类型是input:text,那么绑定了v-model之后,前后绑定的是其value值
如果控件类型是input:checkbox,那么绑定了v-model之后,前后绑定的是其checked值
代码:
<body><div id="app"><h3>学习注册网</h3>姓名:<input type="text" v-model="username"> <br><br>是否本科及以上学历:<input type="checkbox" v-model="bachelor"> <br><br><!-- 前置理解:1. name: 给单选框加上 name 属性 可以分组 → 同一组互相会互斥2. value: 给单选框加上 value 属性,用于提交给后台的数据结合 Vue 使用 → v-model-->性别: <input v-model="gender" type="radio" name="gender" value="1">男<input v-model="gender" type="radio" name="gender" value="2">女<br><br><!-- 前置理解:1. option 需要设置 value 值,提交给后台2. select 的 value 值,关联了选中的 option 的 value 值结合 Vue 使用 → v-model-->所在城市:<select v-model="cityId"><option value="101">北京</option><option value="102">上海</option><option value="103">成都</option><option value="104">南京</option></select><br><br>自我描述:<textarea v-model="desc"></textarea> <button>立即注册</button></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {username: '',bachelor: false,gender: "2",cityId: '102',desc: ""}})</script>
</body>
演示效果:
4.13 computed计算属性
- 基于现有的数据,计算出来的新属性。
- 如果依赖的数据变化,自动重新计算。
语法:
- 声明在 computed 配置项中,一个计算属性对应一个函数
- 使用起来和普通属性一样使用 {{ 计算属性名}}
注意:
- computed配置项和data配置项是**同级**的
- computed中的计算属性虽然是函数的写法,但他依然是个属性
- computed中的计算属性**不能和data中的属性同名**
- 使用computed中的计算属性和使用data中的属性是一样的用法
- computed中计算属性内部的this依然指向的是Vue实例
示例:计算礼物个数
<body><div id="app"><h3>小黑的礼物清单</h3><table><tr><th>名字</th><th>数量</th></tr><tr v-for="(item, index) in list" :key="item.id"><td>{{ item.name }}</td><td>{{ item.num }}个</td></tr></table><!-- 目标:统计求和,求得礼物总数 --><p>礼物总数:{{ totalCount }} 个</p></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {// 现有的数据list: [{ id: 1, name: '篮球', num: 1 },{ id: 2, name: '玩具', num: 2 },{ id: 3, name: '铅笔', num: 5 },]},computed: {totalCount () {// 基于现有的数据,编写求值逻辑// 计算属性函数内部,可以直接通过 this 访问到 app 实例// console.log(this.list)// 需求:对 this.list 数组里面的 num 进行求和 → reducelet total = this.list.reduce((sum, item) => sum + item.num, 0)return total}}})</script>
</body>
效果展示:
4.13.1 computed计算属性 VS methods方法
-
computed计算属性
作用:封装了一段对于数据的处理,求得一个结果
语法:
- 写在computed配置项中
- 作为属性,直接使用
- js中使用计算属性: this.计算属性
- 模板中使用计算属性:{{计算属性}}
-
methods计算属性
作用:给Vue实例提供一个方法,调用以处理业务逻辑。
语法:
- 写在methods配置项中
- 作为方法调用
- js中调用:this.方法名()
- 模板中调用 {{方法名()}} 或者 @事件名=“方法名”
-
computed计算属性的优势
-
缓存特性(提升性能)
计算属性会对计算出来的结果缓存,再次使用直接读取缓存,
依赖项变化了,会自动重新计算 → 并再次缓存
-
methods没有缓存特性
-
4.13.2 总结
1.computed有缓存特性,methods没有缓存
2.当一个结果依赖其他多个值时,推荐使用计算属性
3.当处理业务逻辑时,推荐使用methods方法,比如事件的处理函数
4.13.3 计算属性的完整写法
既然计算属性也是属性,能访问,应该也能修改了?
- 计算属性默认的简写,只能读取访问,不能 “修改”
- 如果要 “修改” → 需要写计算属性的完整写法
代码示例:
- 当fullName计算属性,被获取求值时,执行get(有缓存,优先读缓存)
- 当fullName计算属性,被修改赋值时,执行set,修改的值,传递给set方法的形参
<body><div id="app">姓:<input type="text" v-model="firstName"> +名:<input type="text" v-model="lastName"> =<span>{{ fullName }}</span><br><br><button @click="changeName">改名卡</button></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {firstName: '刘',lastName: '备',},methods: {changeName () {this.fullName = '黄忠'}},computed: {// 简写 → 获取,没有配置设置的逻辑// fullName () {// return this.firstName + this.lastName// }// 完整写法 → 获取 + 设置fullName: {// (1) 当fullName计算属性,被获取求值时,执行get(有缓存,优先读缓存)// 会将返回值作为,求值的结果get () {return this.firstName + this.lastName},// (2) 当fullName计算属性,被修改赋值时,执行set// 修改的值,传递给set方法的形参set (value) {// console.log(value.slice(0, 1)) // console.log(value.slice(1)) this.firstName = value.slice(0, 1)this.lastName = value.slice(1)}}}})</script>
</body>
运行效果:
4.14 watch侦听器(监视器)
监视数据变化,执行一些业务逻辑或异步操作
4.14.1 语法
-
watch同样声明在跟data同级的配置项中
-
简单写法: 简单类型数据直接监视
data: { words: '苹果',obj: {words: '苹果'} },watch: {// 该方法会在数据变化时,触发执行数据属性名 (newValue, oldValue) { //ewValue新值, oldValue老值(一般不用)一些业务逻辑 或 异步操作。 },'对象.属性名' (newValue, oldValue) {一些业务逻辑 或 异步操作。 } }
-
完整写法:添加额外配置项
watch: {// watch 完整写法数据属性名: {deep: true, // 深度监视(针对复杂类型)immediate: true, // 是否立刻执行一次handlerhandler (newValue) {console.log(newValue)}} }
4.14.2 简单写法
<body>
<div id="app"><!-- 条件选择框 --><div class="query"><span>翻译成的语言:</span><select><option value="italy">意大利</option><option value="english">英语</option><option value="german">德语</option></select></div><!-- 翻译框 --><div class="box"><div class="input-wrap"><textarea v-model="obj.words"></textarea><span><i>⌨️</i>文档翻译</span></div><div class="output-wrap"><div class="transbox">mela</div></div></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>// 接口地址:https://applet-base-api-t.itheima.net/api/translate// 请求方式:get// 请求参数:// (1)words:需要被翻译的文本(必传)// (2)lang: 需要被翻译成的语言(可选)默认值-意大利// -----------------------------------------------const app = new Vue({el: '#app',data: {// words: ''obj: {words: ''}},// 具体讲解:(1) watch语法 (2) 具体业务实现watch: {// 该方法会在数据变化时调用执行// newValue新值, oldValue老值(一般不用)// words (newValue) {// console.log('变化了', newValue)// }'obj.words' (newValue) {console.log('变化了', newValue)}}})
</script>
</body>
演示效果:
防抖:
防抖: 延迟执行 → 干啥事先等一等,延迟一会,一段时间内没有再次触发,才执行
const app = new Vue({el: '#app',data: {// words: ''obj: {words: ''},result: '', // 翻译结果// timer: null // 延时器id},// 具体讲解:(1) watch语法 (2) 具体业务实现watch: {// 该方法会在数据变化时调用执行// newValue新值, oldValue老值(一般不用)// words (newValue) {// console.log('变化了', newValue)// }'obj.words' (newValue) {// console.log('变化了', newValue)// 防抖: 延迟执行 → 干啥事先等一等,延迟一会,一段时间内没有再次触发,才执行clearTimeout(this.timer)this.timer = setTimeout(async () => {const res = await axios({url: 'https://applet-base-api-t.itheima.net/api/translate',params: {words: newValue}})this.result = res.data.dataconsole.log(res.data.data)}, 300)}}})
4.14.3 完整写法
完整写法:添加额外的配置项
-
deep:true 对复杂类型进行深度监听
递归地监听对象内部属性的变化。当你需要监视嵌套对象或数组内部属性的变化时,可以使用深度监视。
考虑一个场景,我们有一个用户对象,其中包含名称(name)和详细信息(details)。详细信息又包含年龄(age)和城市(city)。我们希望监视用户对象的变化,特别是用户详细信息内部属性的变化。
如果不使用深度监听,我们只监听
user
对象本身的变化。如果我们直接修改user.details.age
,watch
将不会触发如果使用深度监听,无论是直接修改
user
的引用还是修改其内部的details
属性,handler
函数都会被触发。 -
immdiate:true 初始化 立刻执行一次handler函数,而不需要等待数据变化。
代码示例:
<body>
<div id="app"><!-- 条件选择框 --><div class="query"><span>翻译成的语言:</span><select v-model="obj.lang"><option value="italy">意大利</option><option value="english">英语</option><option value="german">德语</option></select></div><!-- 翻译框 --><div class="box"><div class="input-wrap"><textarea v-model="obj.words"></textarea><span><i>⌨️</i>文档翻译</span></div><div class="output-wrap"><div class="transbox">{{ result }}</div></div></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>// 需求:输入内容,修改语言,都实时翻译// 接口地址:https://applet-base-api-t.itheima.net/api/translate// 请求方式:get// 请求参数:// (1)words:需要被翻译的文本(必传)// (2)lang: 需要被翻译成的语言(可选)默认值-意大利// -----------------------------------------------const app = new Vue({el: '#app',data: {obj: {words: '你好',lang: 'italy'},result: '', // 翻译结果},watch: {obj: {deep: true, // 深度监视immediate: true, // 立刻执行,一进入页面handler就立刻执行一次handler (newValue) {clearTimeout(this.timer)this.timer = setTimeout(async () => {const res = await axios({url: 'https://applet-base-api-t.itheima.net/api/translate',params: newValue})this.result = res.data.dataconsole.log(res.data.data)}, 300)}}// 'obj.words' (newValue) {// clearTimeout(this.timer)// this.timer = setTimeout(async () => {// const res = await axios({// url: 'https://applet-base-api-t.itheima.net/api/translate',// params: {// words: newValue// }// })// this.result = res.data.data// console.log(res.data.data)// }, 300)// }}})
</script>
</body>
演示效果:(obj中任意一个发生变化,控制台都会有所响应)
一个Vue的常用模板:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><style></style>
</head><body><div id="app"></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>const app = new Vue({el: '#app',data: {},mounted() {},methods: {test() {var _this = this;axios({method: "get",url: "#",}).then(function (resp) {_this.$message({message: "添加成功。",type: 'success'});})setTimeout(function () {window.location.reload();}, 1500);}},computed: {totalCount() {let total = "res";return total}},watch: {obj: {deep: true, // 深度监视immediate: true, // 立刻执行,一进入页面handler就立刻执行一次handler(newValue) {clearTimeout(this.timer)this.timer = setTimeout(async () => {}, 300)}}}})</script>
</body>
</html>