Vue2(一):创建实例、插值表达式、Vue响应式特性、Vue指令、指令修饰符、计算属性
Vue:一个构建用户界面的渐进式框架
1、创建Vue实例
核心步骤:
准备容器、引包(官网)-开发版本/生产版本、创建Vue实例 new Vue()、指定配置项(在创建的实例里面)->渲染数据 - 1.el指定挂载点 2.data提供数据
<body><div class="box"><h3>{{msg}}</h3><a href="#">{{cnt}}</a></div><p>--------------------------------------------------</p><div id="app"><h3>{{msg}}</h3><a href="#">{{cnt}}</a></div><script src="vue.js"></script><script>// 一旦引入VueJS核心包,在全局环境,就有了Vue构造函数const app = new Vue({// 通过el配置选择器,指定Vue管理的是哪一个盒子el: '#app',// 通过data提供数据data: {msg: 456,cnt: '张三'}})</script>
</body>
2、插值表达式
是Vue的模板语法
作用:利用表达式进行插值,渲染到页面中。 表达式:是可以被求值的代码
语法:{{ 表达式 }}
注意点:
3、Vue响应式特性
响应式:数据改变,视图自动更新
<div id="app"><!-- 插值表达式 -->{{msg}}{{cnt}}</div><script src="vue.js"></script><script>const app = new Vue({// 通过el配置选择器,指定视图容器el: '#app',// 通过data提供数据data: {// 响应式数据:数据变化了,视图自动更新msg: 'abc',cnt: 123,}})// data中的数据,是会被添加到实例上// 访问数据 实例.属性名// 修改数据 实例.属性名 = 新值// 在控制台</script>
4、Vue指令
文档:Vue指令
Vue会根据不同的指令,针对标签实现不同的功能,解决不同业务场景需求。
指令:带有v-前缀的特殊标签属性
1)v-html
作用:设置元素的innerHTML,能够动态解析标签
语法:v-html = "表达式"
<div id="app"><!-- 插值表达式 不能解析标签--><!-- {{msg}} --><div v-html="msg"></div></div><script src="vue.js"></script><script>const app = new Vue({// 通过el配置选择器,指定视图容器el: '#app',// 通过data提供数据data: {// 响应式数据:数据变化了,视图自动更新msg: `<a href="https://www.baidu.com/">百度</a>`}})</script>
2)v-show和v-if
(1)v-show
作用:控制元素显示隐藏
语法:v-show = "表达式" 表达式值 true显示,false隐藏
原理:切换 display: none 控制显示隐藏
使用场景:适用于频繁切换显示隐藏的场景
(2)v-if
作用:控制元素显示隐藏(条件渲染)
语法:v-if= "表达式" 表达式值 true显示,false隐藏
原理:基于条件判断,是否创建或移除元素节点
使用场景:要么显示,要么隐藏,不频繁切换的场景
(3)代码演示
v-show底层原理:切换 css 的 display: none 来控制显示隐藏(简单的显示隐藏)
v-if 底层原理:根据判断条件控制元素的创建和移除(条件渲染)
<div id="app"><div v-show="flag" class="box">v-show</div><div v-if="flag" class="box">v-if</div></div><script src="vue.js"></script><script>const app = new Vue({el: '#app',data: {flag: true}})</script>
<div id="app"><div v-show="flag" class="box">v-show</div><div v-if="flag" class="box">v-if</div></div><script src="vue.js"></script><script>const app = new Vue({el: '#app',data: {flag: false}})</script>
3)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="./vue.js"></script><script>const app = new Vue({el: '#app',data: {gender: 2,score: 80}})</script>
4)v-on
作用:注册事件 = 添加监听 + 提供处理逻辑
语法:1. v-on:事件名 = "内联语句" (只适用于逻辑简单的情况)
2. v-on: 事件名 = "methods中的函数名"
v-on:事件名可以用@事件名代替
第一种:
<div id="app"><!-- v-on: 可以替换为@ --><!-- <button v-on:click="cnt--">-</button> --><button @click="cnt--">-</button><span>{{cnt}}</span><!-- <button v-on:click="cnt++">+</button> --><button @click="cnt++">+</button></div><script src="./vue.js"></script><script>const app = new Vue({el: '#app',data: {cnt: 10}})</script>
第二种:
<div id="app"><!-- <button @click="isShow = !isShow">切换显示隐藏</button> --><button @click="fn">切换显示隐藏</button><h1 v-show="isShow">Hello World!</h1></div><script src="./vue.js"></script><script>const app = new Vue({el: '#app',// data 用来提供数据data: {isShow: true},// methods 用来提供方法methods: {fn() {// app.isShow = !app.isShow// 让提供的所有methods中的函数,this都指向当前的Vue实例// console.log(this)this.isShow = !this.isShow}}})</script>
v-on调用传参:
<div id="app"><div class="box"><h3>小黑自动售货机</h3><button @click="buy(5)">可乐5元</button><button @click="buy(10)">咖啡10元</button></div><p>银行卡余额:{{resMoney}}元</p></div><script src="./vue.js"></script><script>const app = new Vue({el: '#app',data: {resMoney: 1000},methods: {buy(price) {this.resMoney -= price}}})</script>
5)v-bind
作用:动态的设置 html 的标签属性 src、url、title......
语法:v-bind:属性名="表达式" v-bind:src 简写为 :src
<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="./vue.js"></script><script>const app = new Vue({el: '#app',data: {imgUrl: './images/10-01.png',msg: 123}})</script>
图片切换案例:
<div id="app"><button v-show="index > 0" @click="index--">上一页</button><div><!-- 通过 :src="list[index]" 动态设置图片的url --><img :src="list[index]" alt=""></div><button v-show="index<list.length-1" @click="index++">下一页</button></div><script src="./vue.js"></script><script>const app = new Vue({el: '#app',// 用数组存放需要切换的图片data: {index: 0,list: ['./images/11-00.gif','./images/11-01.gif','./images/11-02.gif','./images/11-03.gif','./images/11-04.png','./images/11-05.png',]}})</script>
6)v-for
作用:基于数据循环,多次渲染整个元素
遍历数组语法:v-for = "(item,index) in 数组名" 省略index:v-for = "item in 数组"
<div id="app"><h3>小黑水果店</h3><ul><!-- 数组有几项就有循环几次 --><li v-for="(item) in list">{{item}}</li></ul></div><script src="./vue.js"></script><script>const app = new Vue({el: '#app',data: {list: ['西瓜', '苹果', '鸭梨']}})</script>
图书管理案例-小黑的书架
<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="./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) {// filter:根据条件,保留满足条件的对应项,得到一个新数组(不会改变原数组)// 因此要把filter得到的数组赋值回原数组this.booksList = this.booksList.filter(item => item.id != id)}}})</script>
v-for中的key
语法:key属性="唯一标识"
作用:给列表项添加的唯一标识。便于Vue进行列表项的正确排序服用
注意点:key的值只能是字符串或数字类型、key的值必须具有唯一性、推荐使用 id 作为key(唯一),不推荐使用index作为key(会变化,不能唯一标识)
<li v-for="(item,index) in xxx" :key="唯一值">
v-for的默认行为会尝试原地修改元素(就地复用)
不加key的情况,删除第一个 li 实际是把后面三个移上去,然后把最后一个li删掉,如下所示:
7)v-model
作用:给表单元素使用,双向数据绑定 -> 可以快速获取或设置表单元素内容
1. 数据变化 -> 视图自动更新
2. 视图变化 -> 数据自动更新
语法:v-moder='变量'
<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="./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>
5、综合案例 - 小黑记事本
<!-- 主体区域 --><section id="app"><!-- 输入框 --><header class="header"><h1>小黑记事本</h1><input v-model="todoName" placeholder="请输入任务" class="new-todo" /><button @click="add()" class="add">添加任务</button></header><!-- 列表区域 --><section class="main"><ul class="todo-list"><li class="todo" v-for="(item,index) in list" :key="item.id"><div class="view"><span class="index">{{index+1}}.</span> <label>{{item.name}}</label><button class="destroy" @click="del(item.id)"></button></div></li></ul></section><!-- 统计和清空 --><footer class="footer" v-show="list.length>0"><!-- 统计 --><span class="todo-count">合 计:<strong> {{list.length}} </strong></span><!-- 清空 --><button @click="clear()" class="clear-completed">清空任务</button></footer></section><!-- 底部 --><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><script>// 添加功能// 通过 v-model 绑定输入框// 点击按钮 ,新增,往数组最前面加,unshiftconst app = new Vue({el: '#app',data: {todoName: '',list: [{ id: 1, name: '敲代码' },{ id: 2, name: '听音乐' },{ id: 3, name: 'Timi' }]},methods: {del(id) {this.list = this.list.filter(item => item.id != id)},add() {if (this.todoName) {this.list.unshift({id: +new Date,name: this.todoName})} else {alert('请输入任务名称')}this.todoName = ''},clear() {this.list = []}}})</script>
6、指令修饰符
通过"."指明一些指令后缀,不同后缀封装了不同的处理操作 -> 简化代码
修饰符
按键修饰符 eg:小黑记事本案例,输入回车就可以添加
<!-- 输入框 --><header class="header"><h1>小黑记事本</h1><input @keyup.enter="add" v-model="todoName" placeholder="请输入任务" class="new-todo" /><button @click="add()" class="add">添加任务</button></header>
底层实现原理:
<div id="app"><h3>@keyup.enter → 监听键盘回车事件</h3><input @keyup.enter="fn" v-model="username" type="text"></div><script src="./vue.js"></script><script>const app = new Vue({el: '#app',data: {username: ''},methods: {fn(e) {// @key.后面加enter相当于下面的判断// if (e.key === 'Enter') {// console.log('回车触发', this.username)// }console.log('回车触发', this.username)}}})</script>
<!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>.father {width: 200px;height: 200px;background-color: pink;margin-top: 20px;}.son {width: 100px;height: 100px;background-color: skyblue;}</style>
</head><body><div id="app"><h3>v-model修饰符 .trim .number</h3>姓名:<input v-model.trim="username" v-model="username" type="text"><br><!-- v-model-number 尝试为我们转数字;abc就转不了 -->年纪:<input v-model-number="age" v-model="age" type="text"><br><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="./vue.js"></script><script>const app = new Vue({el: '#app',data: {username: '',age: '',},methods: {fatherFn() {alert('老父亲被点击了')},sonFn() {// e.stopPropagation()alert('儿子被点击了')}}})</script>
</body></html>
7、v-bind操作class和style
1)操作class
语法::class="对象/数组"
案例:tab导航高亮
<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="./vue.js"></script><script>const app = new Vue({el: '#app',data: {activeIndex: 0, //记录哪个 li 高亮list: [{ id: 1, name: '京东秒杀' },{ id: 2, name: '每日特价' },{ id: 3, name: '品类秒杀' }]}})</script>
2)操作style
语法::style="样式对象"
<div id="app"><!-- <div class="box" :style="{width:'400px',height:'400px','background-color':'pink'}"></div> --><div class="box" :style="{width:'400px',height:'400px',backgroundColor:'pink'}"></div></div>
案例:进度条
<!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>.progress {height: 25px;width: 400px;border-radius: 15px;background-color: #272425;border: 3px solid #272425;box-sizing: border-box;margin-bottom: 30px;}.inner {width: 50%;height: 20px;border-radius: 10px;text-align: right;position: relative;background-color: #409eff;background-size: 20px 20px;box-sizing: border-box;transition: all 1s;}.inner span {position: absolute;right: -20px;bottom: -25px;}</style>
</head><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 = 70">设置75%</button><button @click="percent = 100">设置100%</button></div><script src="./vue.js"></script><script>const app = new Vue({el: '#app',data: {percent: 0}})</script>
</body></html>
8、v-model应用于其他表单元素
<div id="app"><h3>小黑学习网</h3>姓名:<input type="text" v-model="username"><br><br>是否单身:<input type="checkbox" v-model="isSingle"><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="10">北京</option><option value="11">上海</option><option value="12">成都</option><option value="13">南京</option></select><br><br>自我描述:<textarea v-model="desc"></textarea><button>立即注册</button></div><script src="./vue.js"></script><script>const app = new Vue({el: '#app',data: {username: '',isSingle: true,gender: 1,cityId: '10',desc: ''}})</script>
9、计算属性
<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="./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 ,不加括号,因为 computed 是(计算)属性totalCount() {// 计算属性函数内部,可以直接通过 this 访问到 app 实例console.log(this.list)let cnt = this.list.reduce((sum, item) => sum + item.num, 0)return cnt}}})</script>
与methods的区别
<div id="app"><h3>小黑的礼物清单🛒<span>{{totalCount}}</span></h3><h3>小黑的礼物清单🛒<span>{{totalCountFn()}}</span></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="./vue.js"></script><script>const app = new Vue({el: '#app',data: {// 现有的数据list: [{ id: 1, name: '篮球', num: 3 },{ id: 2, name: '玩具', num: 2 },{ id: 3, name: '铅笔', num: 5 },]},methods: {totalCountFn() {console.log(methods) // 执行一次,打印一次let total = this.list.reduce((sum, item) => sum + item.num, 0)return total}},computed: {// 计算属性:有缓存的,一旦计算出结果,就会立刻缓存// 下一次读取 -> 直接读缓存就行totalCount() {console.log(computed) //不修改数据,只打印一次let total = this.list.reduce((sum, item) => sum + item.num, 0)return total}}})</script>
计算属性的完整写法
计算属性默认的简写,只能读取访问,不能“修改”,如果要“修改”,需要写计算属性的完整写法
<div id="app">姓:<input type="text" v-model="firstName"><br>名:<input type="text" v-model="lastName"><br><p>姓名:<span>{{ fullName }}</span></p><button @click="changeName">修改姓名</button></div><script src="./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: {// 当fullName计算属性,被获取求值时,执行get(有缓存,先执行缓存)// 会将返回值作为求值的结果get() {return this.firstName + this.lastName},// 当fullName计算属性被修改赋值时,执行set// 修改的值,传递给set方法的形参set(value) {console.log(value)this.firstName = value.slice(0, 1)this.lastName = value.slice(1)}}}})</script>
10、综合案例:成绩案例
<div id="app" class="score-case"><div class="table"><table><thead><tr><th>编号</th><th>科目</th><th>成绩</th><th>操作</th></tr></thead><tbody v-if="list.length > 0"><tr v-for="(item,index) in list" :key="item.id"><td>{{index+1}}</td><td>{{item.subject}}</td><td :class="{ red:item.score < 60 }">{{item.score}}</td><td><a @click.prevent="del(item.id)" href="#">删除</a></td></tr></tr></tbody><tbody v-else><tr><td colspan="5"><span class="none">暂无数据</span></td></tr></tbody><tfoot><tr><td colspan="5"><span>总分:{{tetalScore}}</span><span style="margin-left: 50px">平均分:{{averageScore}}</span></td></tr></tfoot></table></div><div class="form"><div class="form-item"><div class="label">科目:</div><div class="input"><input type="text" placeholder="请输入科目" v-model.trim="subject" /></div></div><div class="form-item"><div class="label">分数:</div><div class="input"><input type="text" placeholder="请输入分数" v-model.number="score" /></div></div><div class="form-item"><div class="label"></div><div class="input"><button @click="add()" class="submit">添加</button></div></div></div></div><script src="./vue.js"></script><script>const app = new Vue({el: '#app',data: {list: [{ id: 1, subject: '语文', score: 20 },{ id: 7, subject: '数学', score: 99 },{ id: 12, subject: '英语', score: 70 },],subject: '',score: ''},methods: {del(id) {this.list = this.list.filter(item => item.id != id)},add() {if (!this.subject) {alert('请输入科目')return}if (typeof this.score !== 'number') {alert('请输入正确的分数')return}this.list.unshift({id: +new Date(),subject: this.subject,score: this.score})this.subject = ''this.score = ''}},computed: {tetalScore() {return this.list.reduce((sum, item) => sum + item.score, 0)},averageScore() {if (this.list.length === 0) return 0return (this.tetalScore / this.list.length).toFixed(2)}}})</script>
11、watch侦听器(监视器)
作用:监视数据变化,执行一些业务逻辑或异步操作