1.第一个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>01.创建第一个Vue实例</title>
</head>
<body>
<!--创建Vue实例,初始化渲染-->
<!--1.容器(Vue所管理的范围)-->
<!--2.导包(开发版本包/生产版本包) 官网查找-->
<!--(1) 开发环境版本,包含了有帮助的命令行警告 (使用)-->
<!--<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>-->
<!--(2) 生产环境版本,优化了尺寸和速度 -->
<!--<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>-->
<!--3.实例(new对象)-->
<!--4.配置项(el:挂载点,data:数据)-->
<!--5.完成渲染--><!--1.容器-->
<div class="box"></div>
<div class="box2"></div>
<div id="app"><!-- 编写用于渲染的代码逻辑--><h1>{{msg}}</h1>{{count}}
</div>
<!--2.引入开发版本核心包,该包包含完整的注释和警告-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script><!-- 一旦引入VueJS核心包,在全局环境中,就有了Vue构造函数,有了构造函数就可以创建实例-->//基于引入的核心包,创建实例对象,在对象中写入配置项(el,data)const app = new Vue({//通过el配置选择器(指定渲染的容器),只当Vue管理的是哪个盒子el: "#app",//通过data提供数据data: {msg: "hello!!!",count: 666}})
</script>
</body>
</html>
2.插值表达式
<!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>02.插值表达式</title>
</head>
<body>
<!--插值表达式:Vue的一种模板语法
作用:利用表达式,进行插值渲染
语法:{{表达式}}
使用的注意:
(1)不能在标签属性中使用{{}}
(2)使用的数据要存在
(3)支持的式表达式,不是语句 if for
-->
<div id="app"><p>{{nickname}}</p><p>{{nickname.toUpperCase()}}</p><p>{{nickname + ',hello!!!'}}</p><p>{{age>=18?'成年':'未成年'}}</p><p>{{nickname}}的朋友:{{friend.name}}</p><p>{{friend.desc}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>const app = new Vue({el: "#app",data: {nickname: "cc",age:22,friend:{name:"lucy",desc:"热爱学习"}}})
</script>
</body>
</html>
3.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>03.Vue的响应式特性</title>
</head>
<body>
<!--数据的响应式处理--》响应式:数据变化,视图自动更新-->
<!--使用Vue开发--》专注于业务核心逻辑即可-->
<div id="app">{{msg}}{{count}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>const app = new Vue({el: "#app",data: {// 响应式数据msg: "你好,cc",count: 100}})//data中的数据,是会被添加到实例上//1.访问数据 实例.属性名//2.修改数据 实例.属性名=新值
</script>
</body>
</html>
4.Vue指令
4.1 vue-html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>04.Vue指令</title>
</head>
<body>
<!--指令:带有v-前缀的特殊标签属性,不同属性对应不同的功能-->
<!--vue-html:
作用:设置元素的innerHTML,可以解析标签中的数据;
语法:v-html="表达式"-->
<div id="app"><div v-html="msg"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>const app=new Vue({el:"#app",data:{//注:数据值要用''包裹msg:'<a href="https://www.baidu.com/">百度</a>'// msg:'<h3>百度</h3>'}})
</script>
</body>
</html>
4.2 v-show和v-if
<!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>04.vue指令(2)</title>
</head>
<body>
<!--vue指令:v-show和v-if-->
<!--(1)v-show
作用:控制元素显示隐藏
语法:v-show="表达式",表达式值true显示,false隐藏
底层原理:切换css的display:none来控制显示隐藏
适用场景:频繁切换需要隐藏的场景--><!--(2)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:true}
})
</script>
<style>.box{text-align: center;border-radius: 5px;box-shadow: 2px 2px 2px #ccc;}
</style>
</body>
</html>
4.3 v-else 和 v-else-if
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>04.Vue指令(3)</title>
</head>
<body>
<!--vue指令: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>=80">成绩评定B:奖励周末郊游</p><p v-else-if="score>=70">成绩评定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:0,score:80}})
</script>
</body>
</html>
4.4 v-on
<!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>04.Vue指令(4)</title>
</head>
<body>
<!--vue指令:v-on
作用:注册事件,注册事件=添加监听+提供处理逻辑
语法:(1)v-on:事件名=“内联语句(可执行语句)"(2)v-on:事件名=”methods中的函数名“简写: @事件名
-->
<div id="app"><!-- (1)v-on:事件名=”内联语句“--><button v-on:click="count--">-1</button><span>{{count}}</span><button v-on:click="count++">+1</button><button v-on:click="count=count+2">+2</button><!-- v-on简写方式:@事件名(将v-on:替换成@)--><button v-on:click="count=count+2">+2</button><hr><!-- (2)v-on:事件名=”methods中的函数名"--><button @click="fn">切换显示隐藏</button><h1 v-show="isShow">hello</h1><hr><!-- v-on调用传参--><button @click="price(-5)">-5</button><span>{{count}}</span><button @click="price(5)">+5</button><hr><div class="box"><h1>yueyue自动售货机</h1><button @click="yueyue(5)">可乐5元</button><button @click="yueyue(8)">牛奶10元</button><button @click="yueyue(10)">咖啡10元</button></div><p>余额:{{money}}元</p><hr><div class="box2"><button @click="datasum(1,1)">{{param1}}+{{param2}}={{sum}}</button></div></div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>const app = new Vue({el: "#app",//提供数据data: {count: 100,isShow: true,money:100,param1:0,param2:0,sum:0},//提供方法methods: {//让提供的所有methods中的函数,this都指向当前实例fn() {// console.log("执行了fn",app.isShow)console.log(app === this) //trueapp.isShow = !app.isShowthis.isShow = !this.isShow},price(x){this.count+=xconsole.log("count=",this.count)},yueyue(x){this.money-=xif(this.money<0){alert("余额不足,努力挣钱!!!")return}console.log("money=",this.money)},datasum(x,y){this.param1=xthis.param2=ythis.sum=x+yconsole.log(this.param1,"+",this.param2,"=",this.sum(x,y))}}})
</script>
</body>
</html>
4.5 v-bind
<!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>04.Vue指令(5)</title>
</head>
<body>
<!--vue指令:v-bind-->
<!--作用:动态的设置html的标签属性->src url
语法:v-bind:属性名="表达式"
简写: :事件-->
<div id="app"><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: {msg: "波仔",imgUrl: "../images/01.imgs/10-02.png"},})
</script>
</body>
</html>
4.6 v-for
<!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>04.vue指令(6)</title>
</head>
<body>
<!--vue指令:v-for-->
<!--作用:基于数据循环,多次渲染整个元素->数组(常用)、对象、数字
语法:v-for="(item,index) in 数组",item每一项,index下标
注意:v-for中使用的是()
-->
<!--v-for="(item,index) in 数组" :key="item.id"
语法:key属性="唯一标识"
作用:给列表项添加的唯一标识,便于vue进行列表项的正确排序复用
注意点:
(1)key的值只能是字符串或数字类型
(2)key的值必须具有唯一性
(3)推荐使用id作为key(唯一),不推荐使用index作为key(会变化,不对应)-->
<div id="app"><h3>yueyue水果店</h3><ul>
<!-- v-for中的index是可以省略的,且当只有一个参数时,括号()也是可以省略的--><li v-for="item in list">{{item}}</li><hr><li v-for="(item,index) in list ">{{item}}---{{index}}</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: ['西瓜', '苹果', '香蕉']},methods: {}})
</script>
</body>
</html>
4.7 v-model
<!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>04.Vue指令(7)</title>
</head>
<body>
<!--vue指令:v-model-->
<!--作用:给表单元素使用,双向数据绑定->可以快速获取或设置表单元素内容
(1)数据变化->视图自动更新
(2)视图变化->数据自动更新-->
<!--语法:v-model='变量'-->
<div id="app">账户:<input type="text" v-model="username"><br><br>密码:<input type="password" v-model="password"><br><br><button @click="login">登录</button><button @click="reset">重置</button><hr><hr></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(username, password) {this.username = username,this.password = passwordconsole.log(this.username, this.password)},reset() {this.username = '',this.password = ''}}})
</script>
</body>
</html>
4.8 案例
4.8.1 指令案例(yueyue书屋)
<!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>01.yueyue书屋</title>
</head>
<body>
<!--需求:
(1)列表的渲染
(2)删除功能
-->
<div id="app"><h3>yueyue书屋</h3><ul><li v-for="(item,index) in bookList" :key="item.id"><span>{{item.name}}</span><span>{{item.author}}</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: {bookList: [{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.bookList.filter(item => item.id !== id));this.bookList=this.bookList.filter(item => item.id !== id)}}})
</script>
</body>
</html>
4.8.2 指令案例(yueyue记事本)
<!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>02.yueyue记事本</title>
</head>
<body>
<!--需求:
(1)列表渲染
(2)删除功能
(3)添加功能
(4)底部统计和清空
-->
<!--主体区域-->
<section id="app">
<!-- 输入框--><header class="header"><h1>yueyue记事本</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 @click="del(item.id)" class="destroy"></button></div></li></ul></section><!--统计和清空->如果没有任务了,底部隐藏掉(v-show)--><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@2/dist/vue.js"></script>
<script>
//添加功能
//(1)通过v-model绑定输入框-》实时获取表单元素的内容
//(2)点击按钮,进行新增,往数组最前面加(unshift)const app = new Vue({// el: ".main", //删除el: "#app", //添加data: {todoName:"",list: [{id: 1, name: "跑步一公里"},{id: 2, name: "跳绳200次"},{id: 3, name: "游泳100米"}]},methods: {//删除del(id) {console.log(id)// filter():保留所有不等于该id的项this.list = this.list.filter(item => item.id !== id)},//添加add(){if(this.todoName.trim()==''){alert("请输入任务名称")return}this.list.unshift({id: +new Date(),name: this.todoName})this.todoName=''},//清空clear(){this.list=[]}}})
</script>
</body>
</html>
5.指令修改符
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>01.指令修饰符</title>
</head>
<body>
<!--指令修饰符:通过"."指明一些指令后缀,不同后缀封装了不同的操作->简化代码-->
<!--
(1)按键修饰符@keyup.enter:键盘回车监听
(2)v-model修饰符v-model.trim:去除首尾空格v-model.number:转数字
(3)事件修饰符@事件名.stop:阻止冒泡@事件名.prevent:阻止默认行为
--><!--主体区域-->
<section id="app">
<!-- 输入框--><header class="header"><h1>yueyue记事本</h1>
<!-- 使用指令修饰符--><input @keyup.enter="add" v-model="todoName" placeholder="请输入任务" class="text"><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 @click="del(item.id)" class="destroy"></button></div></li></ul></section><!--统计和清空->如果没有任务了,底部隐藏掉(v-show)--><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@2/dist/vue.js"></script>
<script>//添加功能//(1)通过v-model绑定输入框-》实时获取表单元素的内容//(2)点击按钮,进行新增,往数组最前面加(unshift)const app = new Vue({// el: ".main", //删除el: "#app", //添加data: {todoName:"",list: [{id: 1, name: "跑步一公里"},{id: 2, name: "跳绳200次"},{id: 3, name: "游泳100米"}]},methods: {//删除del(id) {console.log(id)// filter():保留所有不等于该id的项this.list = this.list.filter(item => item.id !== id)},//添加add(){if(this.todoName.trim()==''){alert("请输入任务名称")return}this.list.unshift({id: +new Date(),name: this.todoName})this.todoName=''},//清空clear(){this.list=[]}}})
</script>
</body>
</html>
<!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>02.指令修饰符(1)</title>
</head>
<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)}// }}})
</script>
</body>
</html>
<!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>02.指令修饰符(2)</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" type="text"><br>年纪:<input v-model.number="age" type="text"><br><h3>@事件名.stop → 阻止冒泡</h3><div @click="fatherFn" class="father"><div @click.stop="sonFn" class="son">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('father被点击了')},sonFn (e) {// e.stopPropagation()alert('son被点击了')}}})
</script>
</body>
</html>
6.V-bind增强
6.1 v-bind对于样式控制
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>03.v-bind对于样式控制的增强</title><style>.box {width: 200px;height: 200px;border: 3px solid #000;font-size: 30px;margin-top: 10px;}.pink {background-color: pink;}.big {width: 300px;height: 300px;}</style>
</head>
<body>
<!--v-bind对于样式控制的增强-->
<!--为了方便开发者进行样式控制,Vue拓展了v-bind的语法,可以针对class类名和style行内样式进行控制-->
<!--v-bind对于样式控制的增强--操作class -->
<!--语法:class="对象/数组"
(1)对象->键就是类名,值是布尔值,如果值为true,有这个类,否则没有这个类
<div class="box" :class="{类名1:布尔值,类名2:布尔值}"></div>
(2)数组->数组中所有的类,都会添加到盒子上,本质就是一个class列表
<div class="box" :class="[类名1,类名2,类名3]"></div>
--><div id="app"><div class="box" :class="{ pink: true, big: true }">黑马程序员</div><div class="box" :class="['pink', 'big']">黑马程序员</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>
</html>
6.2 v-bind对于样式控制增强
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>03.v-bind对于样式控制的增强-操作style</title><style>.box {width: 200px;height: 200px;background-color: rgb(187, 150, 156);}.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>
<!--语法::style="样式对象"
<div class="box" :style="{CSS属性名1:CSS属性值,CSS属性名2:CSS属性值}"></div>
适用场景:某个具体属性的动态设置
-->
<div id="app2"><div class="box" :style="{ width: '400px', height: '400px', backgroundColor: 'green' }"></div>
</div><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>
</html>
6.3 案例
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>03.案例—京东秒杀tab导航高亮</title><style>* {margin: 0;padding: 0;}ul {display: flex;border-bottom: 2px solid #e01222;padding: 0 10px;}li {width: 100px;height: 50px;line-height: 50px;list-style: none;text-align: center;}li a {display: block;text-decoration: none;font-weight: bold;color: #333333;}li a.active {background-color: #e01222;color: #fff;}</style>
</head>
<body>
<!--核心思路:
(1)基于数据动态渲染tab,->v-for
(2)准备下标高亮的是哪一个tab->activeIndex
(3)基于下标,动态控制class类名 v-bind:class
-->
<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>
</html>
7. v-model应用于其他表单
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>04.v-model应用于其他表单元素</title>
</head>
<body>
<!--常见的表单元素都可以用v-model绑定关联->快速获取或设置表单元素的值
它会根据控件类型自动选取正确的方法来更新元素-->
<div id="app"><h1>yueyue学习网</h1>姓名:<input type="text" v-model="username"><br><br>是否单身:<input type="radio">男<input type="radio">女<br><br><!-- 所在城市:-->所在城市:<select><option>北京</option><option>上海</option><option>河南省</option></select><!--前置理解: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: '',isSingle: false,gender: "2",cityId: '102',desc: ""}})
</script>
</div>
</body>
</html>
8.计算属性
8.1 计算属性的默认用法
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>05.计算属性</title><style>table {border: 1px solid #000;text-align: center;width: 240px;}th,td {border: 1px solid #000;}h3 {position: relative;}</style>
</head>
<body>
<!--计算属性:基于现有的数据,计算出来的新属性,依赖的数据变化,自动重新计算
计算属性->可以将一段求值的代码进行封装-->
<!--语法:
(1)声明再computed配置项中,一个计算属性对应一个函数
(2)使用起来和普通属性一样使用{{计算属性名}}-->
<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>
</html>
8.2.computed和methods
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>06.computed计算属性和methods方法</title><style>table {border: 1px solid #000;text-align: center;width: 300px;}th,td {border: 1px solid #000;}h3 {position: relative;}span {position: absolute;left: 145px;top: -4px;width: 16px;height: 16px;color: white;font-size: 12px;text-align: center;border-radius: 50%;background-color: #e63f32;}</style>
</head>
<body>
<!--
作用方面:
(1)计算属性:封装了一段对于数据的处理,求得一个结果
(2)methods:给实例提供一个方法,调用以处理业务逻辑
语法方面:
(1)计算属性1)写在computed配置项中2)作为属性,直接使用->this.计算属性{{计算属性}}
(2)methods1)写在methods配置项中;2)作为方法,需要调用->this.方法名() {{方法名()}} @事件名=“方法名”使用computed计算属性值的优势:缓存特性(提升性能)
计算属性会对计算出来的结果缓存,再次使用直接读取缓存,依赖项变化了,会自动重新计算->并再次缓存
-->
<div id="app"><h3>小黑的礼物清单🛒<span>{{ totalCountFn() }}</span></h3><h3>小黑的礼物清单🛒<span>{{ totalCountFn() }}</span></h3><h3>小黑的礼物清单🛒<span>{{ totalCountFn() }}</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>礼物总数:{{ totalCountFn() }} 个</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: 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('计算属性执行了')// let total = this.list.reduce((sum, item) => sum + item.num, 0)// return total// }}})
</script>
</body>
</html>
8.3 计算属性的完整写法
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>07.计算属性完整写法</title><style>input {width: 30px;}</style>
</head>
<body>
<!--计算属性完整写法
计算属性默认的简写:只能读取访问,不能“修改”
如果需要“修改”->需要写计算属性的完整写法语法(默认写法):
computed:{计算属性名(){一段代码逻辑(计算逻辑)return 结果}
}语法(完整写法):
computed:{
计算属性名:{get(){一段代码逻辑(计算逻辑)return 结果},set(修改的值){一段代码逻辑(修改逻辑)}}
}
-->
<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>
</html>
9.watch监听器
watch是一种用于监视数据变化并执行相应操作的机制,它通常用于Vue.js框架中,可以监视vue实例中的数据变化,并在数据变化时,执行相应的回调函数或触发其他操作;
在Vue.js中,可以通过在Vue实例的选项中定义一个watch对象来使用watch监视,watch对象的属性是要监视的数据属性,值是一个回调函数,用于在数据变化时执行相应的操作。
9.1 watch监听器(监视器)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>08.watch侦听器(监视器)</title><style>* {margin: 0;padding: 0;box-sizing: border-box;font-size: 18px;}#app {padding: 10px 20px;}.query {margin: 10px 0;}.box {display: flex;}textarea {width: 300px;height: 160px;font-size: 18px;border: 1px solid #dedede;outline: none;resize: none;padding: 10px;}textarea:hover {border: 1px solid #1589f5;}.transbox {width: 300px;height: 160px;background-color: #f0f0f0;padding: 10px;border: none;}.tip-box {width: 300px;height: 25px;line-height: 25px;display: flex;}.tip-box span {flex: 1;text-align: center;}.query span {font-size: 18px;}.input-wrap {position: relative;}.input-wrap span {position: absolute;right: 15px;bottom: 15px;font-size: 12px;}.input-wrap i {font-size: 20px;font-style: normal;}</style>
</head>
<body>
<!--watch侦听器(监视器)
作用:监视数据变化,执行一些业务逻辑或异步操作
语法:
(1)简单写法->简单类型数据,直接监视
data:{word:'苹果',obj:{words:'苹果'}
},
watch:{//该方法会在数据变化时,触发执行数据属性名(newValue,oldValue){一些业务逻辑 或 异步操作},对象.属性名(newValue,oldValue){一些业务逻辑 或 异步操作}
}
(2)完整写法->添加额外配置项--><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数据值的变化,如果变化了就执行console.log(...)方法,注意此处属性名监视属性要使用单引号''包裹,具体是否使用''或反引号``包裹看下面图片内容;'obj.words' (newValue) {console.log('变化了', newValue)}}})
</script>
</body>
</html>
9.2 watch监听器(简写)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>08.watch简写-业务实现</title><style>* {margin: 0;padding: 0;box-sizing: border-box;font-size: 18px;}#app {padding: 10px 20px;}.query {margin: 10px 0;}.box {display: flex;}textarea {width: 300px;height: 160px;font-size: 18px;border: 1px solid #dedede;outline: none;resize: none;padding: 10px;}textarea:hover {border: 1px solid #1589f5;}.transbox {width: 300px;height: 160px;background-color: #f0f0f0;padding: 10px;border: none;}.tip-box {width: 300px;height: 25px;line-height: 25px;display: flex;}.tip-box span {flex: 1;text-align: center;}.query span {font-size: 18px;}.input-wrap {position: relative;}.input-wrap span {position: absolute;right: 15px;bottom: 15px;font-size: 12px;}.input-wrap i {font-size: 20px;font-style: normal;}</style>
</head>
<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">{{ 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: {// 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)}}})
</script>
</body>
</html>
9.3 watch监听器(完整写法)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>08.watch侦听器完整写法</title><style>* {margin: 0;padding: 0;box-sizing: border-box;font-size: 18px;}#app {padding: 10px 20px;}.query {margin: 10px 0;}.box {display: flex;}textarea {width: 300px;height: 160px;font-size: 18px;border: 1px solid #dedede;outline: none;resize: none;padding: 10px;}textarea:hover {border: 1px solid #1589f5;}.transbox {width: 300px;height: 160px;background-color: #f0f0f0;padding: 10px;border: none;}.tip-box {width: 300px;height: 25px;line-height: 25px;display: flex;}.tip-box span {flex: 1;text-align: center;}.query span {font-size: 18px;}.input-wrap {position: relative;}.input-wrap span {position: absolute;right: 15px;bottom: 15px;font-size: 12px;}.input-wrap i {font-size: 20px;font-style: normal;}</style>
</head>
<body>
<!--watch侦听器完整写法->添加额外配置项
(1)deep:true对复杂类型深度监视
(2)immediate:true初始化立刻执行一次handler方法
-->
<!--
data:{obj:{words:'苹果',lang:'italy'},
},
watch:{ //watch完整写法数据属性名:{deep:true,//深度监视handler(newValue){console.log(newValue)}}
}
-->
<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>
</html>
10. Vue的生命周期
10.1 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>01.Vue生命周期(4个阶段)</title>
</head>
<body>
<!--vue生命周期:一个Vue实例从创建到销毁的整个过程;
生命周期的四个阶段:(1)创建;(2)挂载;(3)更新;(4)销毁
(1)创建阶段:new VUe(),初始化操作,将普通数据转化为响应式数据;
(2)挂载阶段:渲染模板,将数据放到标签模板中;
(3)更新阶段:数据修改,更新视图(用户使用);
(4)销毁阶段:浏览器关闭;-->
<!--1)发初始化渲染请求要在创建阶段的最后,响应式数据完成之后才可以;2)操作dom:挂载阶段结束之后,模板数据渲染后;--><!--Vue生命周期函数(钩子函数)-->
<!--Vue生命周期过程中,会自动运行一些函数,被称为【生命周期钩子】,让开发者可以在【特定阶段】运行自己的代码。-->
<!--在生命周期4个阶段中会vue提供8个函数(钩子函数),分别位于每个阶段的前和后,每个钩子函数中可以写自己要执行的逻辑代码,这样可以实现开发者在特定阶段执行想要执行的代码-->
<!--钩子函数:就是承载vue生命周期中每个阶段要执行的代码,例如:在创建阶段后的钩子函数中可以写发送初始化请求的代码、在挂载阶段后可以写操作dom的代码-->
<!--钩子函数(8个):
(1)before Create:
(2)created(常用):发送初始化,渲染请求;
(3)before Mount
(4)mounted(常用):操作dom
(5)before Update
(6)updated
(7)before Destroy:释放Vue以外的资源(清除定时器,延时器...(会配合组件使用))
(8)destroyed:销毁Vue实例
--><div id="app"><h3>{{title}}</h3><div><button @click="count--">-</button><span>{{count}}</span><button @click="count++">+</button></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>const app = new Vue({el: "#app",data: {count: 100,title: '计数器'},// 1.创建阶段(准备阶段)beforeCreate() {console.log("beforeCreate 响应式数据准备好之前")},created() {console.log("created 响应式数据准备好之后",this.count)//this.数据名=请求回来的数据// 可以开始发送初始化渲染的请求},// 2.挂载阶段(渲染阶段)beforeMount() {console.log("beforeMount 模板渲染之前",document.querySelector('h3').innerHTML)},mounted() {console.log("mounted 模板渲染之后",document.querySelector('h3').innerHTML)},// 3.更新阶段beforeUpdate(){console.log("beforeUpdate 更新阶段之前(数据修改了,但视图还没更新)",document.querySelector('h3').innerHTML)},updated(){console.log("updated 更新之后(数据修改了,视图也更新了)",document.querySelector('h3').innerHTML)},// 4.销毁阶段beforeDestory() {console.log("beforeDestory (卸载vue实例)")},destoryed() {console.log("destoryed 销毁之后")}})
</script>
</body>
</html>
10.2 vue的生命周期—created
<!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>02.created应用</title><style>* {margin: 0;padding: 0;list-style: none;}.news {display: flex;height: 120px;width: 600px;margin: 0 auto;padding: 20px 0;cursor: pointer;}.news .left {flex: 1;display: flex;flex-direction: column;justify-content: space-between;padding-right: 10px;}.news .left .title {font-size: 20px;}.news .left .info {color: #999999;}.news .left .info span {margin-right: 20px;}.news .right {width: 160px;height: 120px;}.news .right img {width: 100%;height: 100%;object-fit: cover;}</style><!-- created:响应式数据准备好了,可以开始发送初始化渲染请求-->
</head>
<body>
<div id="app"><ul><li v-for="(item,index) in list" :key="item.id" class="news"><div class="left"><div class="title">{{item.title}}</div><div class="info"><span>{{item.source}}</span><span>{{item.time}}</span></div></div><div class="right"><img src="item.img" alt=""></div></li></ul>
</div>
<script src="./tools/vue.js"></script>
<script src="./tools/axios.js"></script>
<script>// 接口地址:http://hmajax.itheima.net/api/news// 请求方式:getconst app = new Vue({el: '#app',data: {list: []},async created(){//1.发送请求,获取数据const res=await axios.get('http://hmajax.itheima.net/api/news')//2.将数据更新给data中的listthis.list=res.data.data// console.log(res)}})
</script>
</body>
</html>
10.3 vue的生命周期—mounted
<!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>03.mounted应用</title><!-- mounted:模板渲染完成,可以开始操作DOM--><!-- 在mounted完成之后,就代表着dom模板已经渲染完成了,才可以操作dom--><!-- 初始化样式 --><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reset.css@2.0.2/reset.min.css"><!-- 核心样式 --><style>html,body {height: 100%;}.search-container {position: absolute;top: 30%;left: 50%;transform: translate(-50%, -50%);text-align: center;}.search-container .search-box {display: flex;}.search-container img {margin-bottom: 30px;}.search-container .search-box input {width: 512px;height: 16px;padding: 12px 16px;font-size: 16px;margin: 0;vertical-align: top;outline: 0;box-shadow: none;border-radius: 10px 0 0 10px;border: 2px solid #c4c7ce;background: #fff;color: #222;overflow: hidden;box-sizing: content-box;-webkit-tap-highlight-color: transparent;}.search-container .search-box button {cursor: pointer;width: 112px;height: 44px;line-height: 41px;line-height: 42px;background-color: #ad2a27;border-radius: 0 10px 10px 0;font-size: 17px;box-shadow: none;font-weight: 400;border: 0;outline: 0;letter-spacing: normal;color: white;}body {background: no-repeat center /cover;background-color: #edf0f5;}</style>
</head>
<body>
<div class="container" id="app"><div class="search-container"><img src="https://www.itheima.com/images/logo.png" alt=""><div class="search-box"><input type="text" v-model="words" id="inp"><button>搜索一下</button></div></div>
</div><script src="./vue.js"></script>
<script>const app = new Vue({el: '#app',data: {words: ''},// 核心思路:// 1.等输入框渲染出来// 2.让输入框获取焦点mounted() {console.log(document.querySelector('#inp'));document.querySelector('#inp').focus()}})</script>
</body>
</html>
10.4 案例-yueyue记账清单
10.4.1 需求介绍
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>04.yueyue记账清单</title>
<!-- yueyue记账清单功能需求:(1)基本渲染;(2)添加功能;(3)删除功能;(4)饼图渲染;--><!-- CSS only --><linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"/><style>.red {color: red!important;}.search {width: 300px;margin: 20px 0;}.my-form {display: flex;margin: 20px 0;}.my-form input {flex: 1;margin-right: 20px;}.table > :not(:first-child) {border-top: none;}.contain {display: flex;padding: 10px;}.list-box {flex: 1;padding: 0 30px;}.list-box a {text-decoration: none;}.echarts-box {width: 600px;height: 400px;padding: 30px;margin: 0 auto;border: 1px solid #ccc;}tfoot {font-weight: bold;}@media screen and (max-width: 1000px) {.contain {flex-wrap: wrap;}.list-box {width: 100%;}.echarts-box {margin-top: 30px;}}</style>
</head>
<body>
<div id="app"><div class="contain"><!-- 左侧列表 --><div class="list-box"><!-- 添加资产 --><form class="my-form"><input type="text" class="form-control" placeholder="消费名称" /><input type="text" class="form-control" placeholder="消费价格" /><button type="button" class="btn btn-primary">添加账单</button></form><table class="table table-hover"><thead><tr><th>编号</th><th>消费名称</th><th>消费价格</th><th>操作</th></tr></thead><tbody><tr><td>1</td><td>帽子</td><td>99.00</td><td><a href="javascript:;">删除</a></td></tr><tr><td>2</td><td>大衣</td><td class="red">199.00</td><td><a href="javascript:;">删除</a></td></tr></tbody><tfoot><tr><td colspan="4">消费总计: 298.00</td></tr></tfoot></table></div><!-- 右侧图表 --><div class="echarts-box" id="main"></div></div>
</div>
<script src="../echarts.min.js"></script>
<script src="../vue.js"></script>
<script src="../axios.js"></script>
<script>/*** 接口文档地址:* https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058** 功能需求:* 1. 基本渲染* 2. 添加功能* 3. 删除功能* 4. 饼图渲染*/const app = new Vue({el: '#app',data: {},})
</script>
</body>
</html>
10.4.2 删除功能
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>04.yueyue记账清单-删除功能</title><!-- CSS only --><linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"/><style>.red {color: red!important;}.search {width: 300px;margin: 20px 0;}.my-form {display: flex;margin: 20px 0;}.my-form input {flex: 1;margin-right: 20px;}.table > :not(:first-child) {border-top: none;}.contain {display: flex;padding: 10px;}.list-box {flex: 1;padding: 0 30px;}.list-box a {text-decoration: none;}.echarts-box {width: 600px;height: 400px;padding: 30px;margin: 0 auto;border: 1px solid #ccc;}tfoot {font-weight: bold;}@media screen and (max-width: 1000px) {.contain {flex-wrap: wrap;}.list-box {width: 100%;}.echarts-box {margin-top: 30px;}}</style>
</head>
<body>
<div id="app"><div class="contain"><!-- 左侧列表 --><div class="list-box"><!-- 添加资产 --><form class="my-form"><input v-model.trim="name" type="text" class="form-control" placeholder="消费名称" /><input v-model.number="price" type="text" class="form-control" placeholder="消费价格" /><button @click="add" type="button" class="btn btn-primary">添加账单</button></form><table class="table table-hover"><thead><tr><th>编号</th><th>消费名称</th><th>消费价格</th><th>操作</th></tr></thead><tbody><tr v-for="(item, index) in list" :key="item.id"><td>{{ index + 1 }}</td><td>{{ item.name }}</td><td :class="{ red: item.price > 500 }">{{ item.price.toFixed(2) }}</td><td><a @click="del(item.id)" href="javascript:;">删除</a></td></tr></tbody><tfoot><tr><td colspan="4">消费总计: {{ totalPrice.toFixed(2) }}</td></tr></tfoot></table></div><!-- 右侧图表 --><div class="echarts-box" id="main"></div></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
<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://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058** 功能需求:* 1. 基本渲染* (1) 立刻发送请求获取数据 created* (2) 拿到数据,存到data的响应式数据中* (3) 结合数据,进行渲染 v-for* (4) 消费统计 => 计算属性* 2. 添加功能* (1) 收集表单数据 v-model* (2) 给添加按钮注册点击事件,发送添加请求* (3) 需要重新渲染* 3. 删除功能* (1) 注册点击事件,传参传 id* (2) 根据 id 发送删除请求* (3) 需要重新渲染* 4. 饼图渲染*/const app = new Vue({el: '#app',data: {list: [],name: '',price: ''},computed: {totalPrice () {return this.list.reduce((sum, item) => sum + item.price, 0)}},created () {// const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {// params: {// creator: '小黑'// }// })// this.list = res.data.datathis.getList()},methods: {async getList () {const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {params: {creator: '小黑'}})this.list = res.data.data},async add () {if (!this.name) {alert('请输入消费名称')return}if (typeof this.price !== 'number') {alert('请输入正确的消费价格')return}// 发送添加请求const res = await axios.post('https://applet-base-api-t.itheima.net/bill', {creator: '小黑',name: this.name,price: this.price})// 重新渲染一次this.getList()this.name = ''this.price = ''},async del (id) {// 根据 id 发送删除请求const res = await axios.delete(`https://applet-base-api-t.itheima.net/bill/${id}`)// 重新渲染this.getList()}}})
</script>
</body>
</html>
10.4.3 基本渲染
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>yueyue记账清单-基本渲染</title><!-- CSS only --><linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"/><style>.red {color: red!important;}.search {width: 300px;margin: 20px 0;}.my-form {display: flex;margin: 20px 0;}.my-form input {flex: 1;margin-right: 20px;}.table > :not(:first-child) {border-top: none;}.contain {display: flex;padding: 10px;}.list-box {flex: 1;padding: 0 30px;}.list-box a {text-decoration: none;}.echarts-box {width: 600px;height: 400px;padding: 30px;margin: 0 auto;border: 1px solid #ccc;}tfoot {font-weight: bold;}@media screen and (max-width: 1000px) {.contain {flex-wrap: wrap;}.list-box {width: 100%;}.echarts-box {margin-top: 30px;}}</style>
</head>
<body>
<div id="app"><div class="contain"><!-- 左侧列表 --><div class="list-box"><!-- 添加资产 --><form class="my-form"><input type="text" class="form-control" placeholder="消费名称" /><input type="text" class="form-control" placeholder="消费价格" /><button type="button" class="btn btn-primary">添加账单</button></form><table class="table table-hover"><thead><tr><th>编号</th><th>消费名称</th><th>消费价格</th><th>操作</th></tr></thead><tbody><tr v-for="(item, index) in list" :key="item.id"><td>{{ index + 1 }}</td><td>{{ item.name }}</td><td :class="{ red: item.price > 500 }">{{ item.price.toFixed(2) }}</td><td><a href="javascript:;">删除</a></td></tr></tbody><tfoot><tr><td colspan="4">消费总计: {{ totalPrice.toFixed(2) }}</td></tr></tfoot></table></div><!-- 右侧图表 --><div class="echarts-box" id="main"></div></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
<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://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058** 功能需求:* 1. 基本渲染* (1) 立刻发送请求获取数据 created* (2) 拿到数据,存到data的响应式数据中* (3) 结合数据,进行渲染 v-for* (4) 消费统计 => 计算属性* 2. 添加功能* 3. 删除功能* 4. 饼图渲染*/const app = new Vue({el: '#app',data: {list: []},computed: {totalPrice () {return this.list.reduce((sum, item) => sum + item.price, 0)}},async created () {const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {params: {creator: 'yueyue'}})this.list = res.data.data}})
</script>
</body>
</html>
10.4.4 添加功能
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>04.yueyue记账清单-添加功能</title><!-- CSS only --><linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"/><style>.red {color: red!important;}.search {width: 300px;margin: 20px 0;}.my-form {display: flex;margin: 20px 0;}.my-form input {flex: 1;margin-right: 20px;}.table > :not(:first-child) {border-top: none;}.contain {display: flex;padding: 10px;}.list-box {flex: 1;padding: 0 30px;}.list-box a {text-decoration: none;}.echarts-box {width: 600px;height: 400px;padding: 30px;margin: 0 auto;border: 1px solid #ccc;}tfoot {font-weight: bold;}@media screen and (max-width: 1000px) {.contain {flex-wrap: wrap;}.list-box {width: 100%;}.echarts-box {margin-top: 30px;}}</style>
</head>
<body>
<div id="app"><div class="contain"><!-- 左侧列表 --><div class="list-box"><!-- 添加资产 --><form class="my-form"><input v-model.trim="name" type="text" class="form-control" placeholder="消费名称" /><input v-model.number="price" type="text" class="form-control" placeholder="消费价格" /><button @click="add" type="button" class="btn btn-primary">添加账单</button></form><table class="table table-hover"><thead><tr><th>编号</th><th>消费名称</th><th>消费价格</th><th>操作</th></tr></thead><tbody><tr v-for="(item, index) in list" :key="item.id"><td>{{ index + 1 }}</td><td>{{ item.name }}</td><td :class="{ red: item.price > 500 }">{{ item.price.toFixed(2) }}</td><td><a href="javascript:;">删除</a></td></tr></tbody><tfoot><tr><td colspan="4">消费总计: {{ totalPrice.toFixed(2) }}</td></tr></tfoot></table></div><!-- 右侧图表 --><div class="echarts-box" id="main"></div></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
<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://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058** 功能需求:* 1. 基本渲染* (1) 立刻发送请求获取数据 created* (2) 拿到数据,存到data的响应式数据中* (3) 结合数据,进行渲染 v-for* (4) 消费统计 => 计算属性* 2. 添加功能* (1) 收集表单数据 v-model* (2) 给添加按钮注册点击事件,发送添加请求* (3) 需要重新渲染* 3. 删除功能* 4. 饼图渲染*/const app = new Vue({el: '#app',data: {list: [],name: '',price: ''},computed: {totalPrice () {return this.list.reduce((sum, item) => sum + item.price, 0)}},created () {// const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {// params: {// creator: '小黑'// }// })// this.list = res.data.datathis.getList()},methods: {async getList () {const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {params: {creator: '小黑'}})this.list = res.data.data},async add () {if (!this.name) {alert('请输入消费名称')return}if (typeof this.price !== 'number') {alert('请输入正确的消费价格')return}// 发送添加请求const res = await axios.post('https://applet-base-api-t.itheima.net/bill', {creator: 'yueyue',name: this.name,price: this.price})// 重新渲染一次this.getList()this.name = ''this.price = ''}}})
</script>
</body>
</html>
10.4.5 静态结构
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>04.yueyue记账清单-静态结构</title><!-- CSS only --><linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"/><style>.red {color: red!important;}.search {width: 300px;margin: 20px 0;}.my-form {display: flex;margin: 20px 0;}.my-form input {flex: 1;margin-right: 20px;}.table > :not(:first-child) {border-top: none;}.contain {display: flex;padding: 10px;}.list-box {flex: 1;padding: 0 30px;}.list-box a {text-decoration: none;}.echarts-box {width: 600px;height: 400px;padding: 30px;margin: 0 auto;border: 1px solid #ccc;}tfoot {font-weight: bold;}@media screen and (max-width: 1000px) {.contain {flex-wrap: wrap;}.list-box {width: 100%;}.echarts-box {margin-top: 30px;}}</style>
</head>
<body>
<div id="app"><div class="contain"><!-- 左侧列表 --><div class="list-box"><!-- 添加资产 --><form class="my-form"><input type="text" class="form-control" placeholder="消费名称" /><input type="text" class="form-control" placeholder="消费价格" /><button type="button" class="btn btn-primary">添加账单</button></form><table class="table table-hover"><thead><tr><th>编号</th><th>消费名称</th><th>消费价格</th><th>操作</th></tr></thead><tbody><tr><td>1</td><td>帽子</td><td>99.00</td><td><a href="javascript:;">删除</a></td></tr><tr><td>2</td><td>大衣</td><td class="red">199.00</td><td><a href="javascript:;">删除</a></td></tr></tbody><tfoot><tr><td colspan="4">消费总计: 298.00</td></tr></tfoot></table></div><!-- 右侧图表 --><div class="echarts-box" id="main"></div></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
<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://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058** 功能需求:* 1. 基本渲染* 2. 添加功能* 3. 删除功能* 4. 饼图渲染*/const app = new Vue({el: '#app',data: {},})
</script>
</body>
</html>
10.4.6 饼图渲染
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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>04.yueyue记账清单-饼图渲染</title><!-- CSS only --><linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"/><style>.red {color: red!important;}.search {width: 300px;margin: 20px 0;}.my-form {display: flex;margin: 20px 0;}.my-form input {flex: 1;margin-right: 20px;}.table > :not(:first-child) {border-top: none;}.contain {display: flex;padding: 10px;}.list-box {flex: 1;padding: 0 30px;}.list-box a {text-decoration: none;}.echarts-box {width: 600px;height: 400px;padding: 30px;margin: 0 auto;border: 1px solid #ccc;}tfoot {font-weight: bold;}@media screen and (max-width: 1000px) {.contain {flex-wrap: wrap;}.list-box {width: 100%;}.echarts-box {margin-top: 30px;}}</style>
</head>
<body>
<div id="app"><div class="contain"><!-- 左侧列表 --><div class="list-box"><!-- 添加资产 --><form class="my-form"><input v-model.trim="name" type="text" class="form-control" placeholder="消费名称" /><input v-model.number="price" type="text" class="form-control" placeholder="消费价格" /><button @click="add" type="button" class="btn btn-primary">添加账单</button></form><table class="table table-hover"><thead><tr><th>编号</th><th>消费名称</th><th>消费价格</th><th>操作</th></tr></thead><tbody><tr v-for="(item, index) in list" :key="item.id"><td>{{ index + 1 }}</td><td>{{ item.name }}</td><td :class="{ red: item.price > 500 }">{{ item.price.toFixed(2) }}</td><td><a @click="del(item.id)" href="javascript:;">删除</a></td></tr></tbody><tfoot><tr><td colspan="4">消费总计: {{ totalPrice.toFixed(2) }}</td></tr></tfoot></table></div><!-- 右侧图表 --><div class="echarts-box" id="main"></div></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
<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://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058** 功能需求:* 1. 基本渲染* (1) 立刻发送请求获取数据 created* (2) 拿到数据,存到data的响应式数据中* (3) 结合数据,进行渲染 v-for* (4) 消费统计 => 计算属性* 2. 添加功能* (1) 收集表单数据 v-model* (2) 给添加按钮注册点击事件,发送添加请求* (3) 需要重新渲染* 3. 删除功能* (1) 注册点击事件,传参传 id* (2) 根据 id 发送删除请求* (3) 需要重新渲染* 4. 饼图渲染* (1) 初始化一个饼图 echarts.init(dom) mounted钩子实现* (2) 根据数据实时更新饼图 echarts.setOption({ ... })*/const app = new Vue({el: '#app',data: {list: [],name: '',price: ''},computed: {totalPrice () {return this.list.reduce((sum, item) => sum + item.price, 0)}},created () {// const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {// params: {// creator: '小黑'// }// })// this.list = res.data.datathis.getList()},mounted () {this.myChart = echarts.init(document.querySelector('#main'))this.myChart.setOption({// 大标题title: {text: '消费账单列表',left: 'center'},// 提示框tooltip: {trigger: 'item'},// 图例legend: {orient: 'vertical',left: 'left'},// 数据项series: [{name: '消费账单',type: 'pie',radius: '50%', // 饼的半径data: [// { value: 1048, name: '球鞋' },// { value: 735, name: '防晒霜' }],emphasis: {itemStyle: {shadowBlur: 10,shadowOffsetX: 0,shadowColor: 'rgba(0, 0, 0, 0.5)'}}}]})},methods: {async getList () {const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {params: {creator: '小黑'}})this.list = res.data.data// 更新图表this.myChart.setOption({// 数据项series: [{// data: [// { value: 1048, name: '球鞋' },// { value: 735, name: '防晒霜' }// ]data: this.list.map(item => ({ value: item.price, name: item.name}))}]})},async add () {if (!this.name) {alert('请输入消费名称')return}if (typeof this.price !== 'number') {alert('请输入正确的消费价格')return}// 发送添加请求const res = await axios.post('https://applet-base-api-t.itheima.net/bill', {creator: '小黑',name: this.name,price: this.price})// 重新渲染一次this.getList()this.name = ''this.price = ''},async del (id) {// 根据 id 发送删除请求const res = await axios.delete(`https://applet-base-api-t.itheima.net/bill/${id}`)// 重新渲染this.getList()}}})
</script>
</body>
</html>