vue复习1~45
1.关于vue
要理解记忆规则,可以到官网上去找
vue的两种使用方式
- vue核心包开发
场景:局部模块改造 - vue核心包 & vue插件 工程化开发
场景:整站开发
2.创建vue实例
构建用户页面->创建vue实例初始化渲染
学习阶段用开发版本
3.插值表达式
- 使用的数据必须存在(data)
- 里面不能写语句
- 不能在 标签属性 里面使用{{ }}插值
4.vue响应式
数据变化,视图自动更新
data中的数据,是会被添加到实例上
- 访问数据 实例.属性名
- 修改数据 实例.属性名 = 新值
修改数据-> vue监听到数据修改-> 自动更新视图DOM操作
5.vue指令v–html
动态的设置innerhtml
动态的解析标签
代码:
<body>
<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: `
<h3>学前端~来黑马!</h3>
`
}
})
</script>
</body>
6.v-show和v-if
均控制元素显示隐藏
区别:
v-show底层原理:切换 css 的 display: none 来控制显示隐藏
v-show=“false”
场景:频繁切换显示隐藏的场景v-if 底层原理:根据 判断条件 控制元素的 创建 和 移除(条件渲染)
v-if=“false”
场景:不频繁切换显示隐藏的场景,eg:登录
7.v-else和v-else-if
两者均辅助v-if进行判断渲染,紧挨着v-if使用
v-else,特别的,不能单独使用
使用情况
- v-else,只有两种,eg:性别
- v-else-if,两个以上,eg:等级
<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>
8.v-on
注册事件=添加监听+提供处理逻辑
语法1:
简写
<button @click="count--">-</button>
详写
<button v-on:click="count++">+</button>
语法2:
v-on:事件名=”methods中的函数名“
必须先加this指向vue实例(app)才能拿到data里面的数据
<body>
<div id="app">
<button @click="fn">切换显示隐藏</button>
<h1 v-show="isShow">黑马程序员</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都指向当前实例
this.isShow = !this.isShow
}
}
})
</script>
</body>
9.v-on调用传参
要用this
传两个,三个参数也是可以的
<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>
10.v-bind
动态的设置html的标签属性
<img v-bind:src="imgUrl" v-bind:title="msg" alt="">
简化版
<img :src="imgUrl" :title="msg" alt="">
11.波仔的学习之旅
代码:
<body>
<div id="app">
<button v-show="index > 0" @click="index--">上一页</button>
<img :src="list[index]" alt="">
<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>
12.v-for
基于数据循环,多次渲染整个元素,有对象,数组,数字
item是遍历时的每一项
index是数组的下标
v-for="(item, index) in list"
例:
<li v-for="(item, index) in list">
{{ item }} - {{ index }}
</li>
不用index时
<li v-for="item in list">
{{ item }}
</li>
v-for 里面的key
给列表添加唯一的标识,便于vue进行列表项的正确排序复用
注意:
- key的值只能是字符串或者是数字类型
- key的值必须唯一
- 推荐使用id作为key,不推荐使用index(会变化,不对应)
13.小黑的书架
** filter: 根据条件,保留满足条件的对应项,得到一个新数组。**
this.bookList = this.bookList.filter(item => item.id !=id)
<body>
<div id="app">
<h3>小黑的书架</h3>
<ul>
<li v-for="(item,index) in booksList">
<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: {
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>
14.v-model
给表单元素使用
v-model 可以让数据和视图,形成双向数据绑定
(1) 数据变化,视图自动更新
(2) 视图变化,数据自动更新
可以快速[获取]或[设置]表单元素的内容
v-model的绑定内容写在data里面
<body>
<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>
</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>
15.小黑记事本
<body>
<!-- 主体区域 -->
<section id="app">
<!-- 输入框 -->
<header class="header">
<h1>小黑记事本</h1>
<input v-model="todoName" placeholder="请输入任务" class="new-todo" />
<button class="add" @click="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>
<!-- 统计和清空 -> 如果没有任务底部需清空-->
<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
//点击按钮,进行新增,往数组最前面加 unshift
const app = new Vue({
el: '#app',
data: {
todoName: '',
list: [
{ id: 1, name: '跑步一公里' },
{ 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>
16.指令修饰符
通过"."指明一些指令 后缀,不同后缀封装不同的处理操作 -> 简化代码
- 按键修饰符
@keyup.enter="fn" 键盘回车监听
- v-model修饰符
v-model.trim="username" 去除首尾空格
v-model.number="age" 转数字
- 事件修饰符
@click.stop="sonFn" 阻止冒泡
@click.prevent 阻止默认行为
17.v-bind对于样式控制的增强
语法:
:class=“对象/数组”
- 对象:键就是类名,值是布尔值,true则有类,反之
<div class="box" :class="{ pink: true, big: true }">黑马程序员</div>
使用场景:一个类名,来回切换
2. 数组:数组中所有的类,都会添加到盒子上,本质就是class列表
<div class="box" :class="['pink', 'big']">黑马程序员</div>
使用场景:批量添加或删除类
操作style
语法:
值必须用引号引起来!
行内样式强大的是对单个属性的控制
<div class="box" :style="{ width: '400px', height: '400px', backgroundColor: 'green' }"></div>
案例:
<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>
18.京东秒杀tab导航高亮
<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>
19.v-model应用于其他表单元素
常见的表单元素
- 输入框 input:text ->value
- 文本域textarea ->value
- 复选框 input:checkbox ->checked
- 单选框 input:radio ->checked
- 下拉菜单 select ->value
name: 给单选框加上 name 属性 可以分组 → 同一组互相会互斥
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>
option 需要设置 value 值,提交给后台
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>
20.计算属性
放在与data并列的computed里
基于现有的数据,编写求值逻辑
在computed配置项里,一个计算属性对应一个函数
使用:{{ 计算属性名 }}
一定要return
computed: {
//计算属性名 () {
// 基于现有的数据,编写求值逻辑
return 结果
}
求和用reduce
需求:
对 this.list 数组里面的 num 进行求和 → reduce
//0 是求和的起始值
let total = this.list.reduce((sum, item) => sum + item.num,0)
return total
21.computed计算属性 VS methods 方法
computed计算属性
封装数据处理,求结果
特别的:有缓存的,一旦计算出来结果,就会立刻缓存,下一次读取 → 直接读缓存就行 → 性能特别高
作为属性直接使用,this.计算属性{{ 计算属性 }}methods 方法
给实例提供方法,调用以处理业务逻辑
作为方法,需要调用,this.方法名() {{ 方法名() }} @事件名=“方法名”
22.计算属性完整写法
computed: {
// 完整写法 → 获取 + 设置
fullName: {
get () {
一段代码逻辑(计算逻辑)
return 结果
},
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>
23.成绩案例
<body>
<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>
</tbody>
<tbody v-else>
<tr>
<td colspan="5">
<span class="none">暂无数据</span>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5">
<span>总分:{{ totalCount }}</span>
<span style="margin-left: 50px">平均分:{{ averageCount }}</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="https://cdn.jsdelivr.net/npm/vue@2/dist/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: ''
},
computed:{
totalCount() {
return this.list.reduce((sum,item) => sum + item.score,0)
},
averageCount () {
if (this.list.length === 0) {
return 0
}
//toFixed(2)保留两位小数
return (this.totalCount / this.list.length).toFixed(2)
}
},
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
}
//在开头插入元素 unshift
this.list.unshift({
id: +new Date(),
subject: this.subject,
score: this.score
})
this.subject = ''
this.score = ''
}
}
})
</script>
</body>
24.watch侦听器(监视器)
可持久化到本地
监视数据变化,执行业务逻辑或异步操作
- 简单写法:简单类型数据,直接监视
- 完整写法:添加额外配置项
简单写法
** ‘obj.words’ ,对象里面的子属性,方法名一定要加引号**
若是直接属性名,则不用加引号
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)
}
}
})
加上防抖效果,防止多次触发
'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.data
console.log(res.data.data)
}, 300)
}
完整写法
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.data
console.log(res.data.data)
}, 300)
}
25.水果购物车
!!!!!!!!!!!!!!!!!!!!!!!!!!
计算属性的完整写法 isAll: { get() {}, set() {} } 全名用冒号
watch监听器 里的监听的对象要用冒号 watch : { list: {} }
computed计算属性 、methods 方法、watch监听一律用冒号
<body>
<div class="app-container" id="app">
<!-- 顶部banner -->
<div class="banner-box"><img src="http://autumnfish.cn/static/fruit.jpg" alt="" /></div>
<!-- 面包屑 -->
<div class="breadcrumb">
<span>🏠</span>
/
<span>购物车</span>
</div>
<!-- 购物车主体 -->
<div class="main" v-if="fruitList.length > 0">
<div class="table">
<!-- 头部 -->
<div class="thead">
<div class="tr">
<div class="th">选中</div>
<div class="th th-pic">图片</div>
<div class="th">单价</div>
<div class="th num-th">个数</div>
<div class="th">小计</div>
<div class="th">操作</div>
</div>
</div>
<!-- 身体 -->
<div class="tbody">
<div class="tr" v-for="(item,index) in fruitList" :key="item.id" :class="{active: item.isChecked}">
<div class="td"><input type="checkbox" v-model="item.isChecked" /></div>
<div class="td"><img :src="item.icon" alt="" /></div>
<div class="td">{{ item.price }}</div>
<div class="td">
<div class="my-input-number">
<button class="decrease" :disabled="item.num <= 1" @click="sub(item.id)"> - </button>
<span class="my-input__inner">{{ item.num }}</span>
<button class="increase" @click="add(item.id)"> + </button>
</div>
</div>
<div class="td">{{ item.price*item.num }}</div>
<div class="td"><button @click="del(item.id)">删除</button></div>
</div>
</div>
</div>
<!-- 底部 -->
<div class="bottom">
<!-- 全选 -->
<label class="check-all">
<input type="checkbox" v-model="isAll"/>
全选
</label>
<div class="right-box">
<!-- 所有商品总价 -->
<span class="price-box">总价 : ¥ <span class="price">{{ totalPrice }}</span></span>
<!-- 结算按钮 -->
<button class="pay">结算( {{ totalCount }} )</button>
</div>
</div>
</div>
<!-- 空车 -->
<div class="empty" v-else>🛒空空如也</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const defaultArr = [
{
id: 1,
icon: 'http://autumnfish.cn/static/火龙果.png',
isChecked: true,
num: 2,
price: 6,
},
{
id: 2,
icon: 'http://autumnfish.cn/static/荔枝.png',
isChecked: false,
num: 7,
price: 20,
},
{
id: 3,
icon: 'http://autumnfish.cn/static/榴莲.png',
isChecked: false,
num: 3,
price: 40,
},
{
id: 4,
icon: 'http://autumnfish.cn/static/鸭梨.png',
isChecked: true,
num: 10,
price: 3,
},
{
id: 5,
icon: 'http://autumnfish.cn/static/樱桃.png',
isChecked: false,
num: 20,
price: 34,
},
]
const app = new Vue({
el: '#app',
data: {
// 水果列表
fruitList: JSON.parse(localStorage.setItem('list') || defaultArr),
},
computed: {
//完整写法= get + set
isAll : {
get() {
//必须所有的小选框都选中,全选按钮才选中 => every
return this.fruitList.every(item => item.isChecked)
},
set(value) {
//拿到的value值是true或false
//同步状态是赋值,=
this.fruitList.forEach(item => item.isChecked = true)
}
},
//统计选中的总数 reduce
totalCount(){
return this.fruitList.reduce((sum,item) => {
if(item.isChecked){
return sum + item.num
}else{
return sum
}
} ,0)
},
//统计选中的总价
totalPrice() {
return this.fruitList.reduce((sum,item) => {
if(item.isChecked){
return (sum + item.num) * item.price
}else{
return sum
}
} ,0)
}
},
methods: {
del(id) {
this.fruitList = this.fruitList.filter(item => item.id !==id)
},
add(id) {
//find
const fruit = this.fruitList.find(item => item.id === id)
fruit.num++
},
sub(id) {
const fruit = this.fruitList.find(item => item.id === id)
fruit.num--
}
},
//持久化到本地就是要用到监听
watch : {
fruitList: {
deep: true,
handler(newValue) {
//将变化的newValue存入本地(转JSON)
localStorage.setItem('list',JSON.stringify(newValue))
}
}
}
})
</script>
</body>
26.vue生命周期和生命周期的四个钩子
vue生命周期 :一个vue实例从创建到销毁的整个过程
创建 响应式数据
挂载 渲染模板
更新 数据修改,更新视图
销毁 销毁实例
before Create
created 发送初始化渲染请求 常用
before Mount
mounted 操作DOM 常用
before Update
updated
before Destroy 释放vue以外的资源(清楚定时器,延时器…)常用
destroyed
27.created应用,mounted应用
created钩子与data并列
created:响应式数据准备好了,可以发送初始化渲染请求
- created应用
async created () {
// 1. 发送请求获取数据
const res = await axios.get('http://hmajax.itheima.net/api/news')
// 2. 更新到 list 中,用于页面渲染 v-for
this.list = res.data.data
}
- mounted应用
// 核心思路:
// 1. 等input框渲染出来 mounted 钩子
// 2. 让input框获取焦点 inp.focus()
mounted () {
document.querySelector('#inp').focus()
}
})
28.小黑记账清单
功能需求:
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({ … })
<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. 基本渲染
* 2. 添加功能
* 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 () {
//只有get和delate时,要用params
//重新渲染,多次使用,得封装
// const res = await axios.get('https://applet-base-api-t.itheima.net/bill',{
// params: {
// creator: '小智'
// }
// })
// this.list = res.data.data
this.getList()
},
mounted () {
this.myChart = echarts.init(document.querySelector('#main'))
this.myChart.setOption
({
title: {
text: '消费账单列表',
subtext: 'Fake Data',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
//数据项
series: [
{
name: '消费账单',
type: 'pie',
radius: '50%',
data: [
],
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: this.list.map(item => ({value: item.price, name: item.name}))
}
]
})
},
async add() {
//如果name不存在
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) {
// this.list = this.list.filter(item => item.id !== id)
//根据id发送删除请求
const res = await axios.delete(`https://applet-base-api-t.itheima.net/bill${id}`)
this.getList()
}
}
})
</script>
</body>
29.组件化开发&根组件
我们把app.vue叫做根组件
**组件化:**一个页面拆分成一个个组件,每个组件有自己独立的结构,样式,行为
好处:便于维护,利于复用,提升开发效率
组件分类:普通组件,根组件
根组件:整个应用最上层的组件,包裹所有普通小组件
app.vue的三个组成部分:结构,样式,行为(template,script,style)
export default {
//里面可以提供data(特殊),methods,computed,watch,生命周期钩子
}
30.普通组件的注册使用-局部注册
局部注册:只能在注册的组件内使用
全局注册:在所有组件都能使用
使用:当成html标签使用,大驼峰命名法
`<组件名></组件名>`
在app.vue里面进行
导入,import
注册: components:{
//同名可省略
‘组件名’:组件对象
}
使用: 在template里<组件名></组件名>
export default {
components:{
'组件名':组件对象
}
}
31.普通组件的注册使用-全局注册
全局注册:在所有组件都能使用
在main.js 中进行全局注册
- 导入:在上面导入需要的组件 import
- 全局注册:Vue.component(‘HmButton(组件名)’,HmButton(组件对象)),这样在component里面的任何组件中都可以使用