VUE学习笔记(黑马2023版 第一天~第三天)
VUE学习笔记(黑马2023版)第一天1.Vue是什么?2.创建一个Vue实例2.1.准备容器(Vue所管理的范围)2.2.引包(开发版本包/生产版本包)2.3.创建实例2.4.指定配置项 el data3.插值表达式3.1.作用:3.2.语法:3.3.注意点3.4.实践案例4.Vue响应式特性4.1.什么是响应式?4.2.访问和修改数据5.Vue开发者工具安装:装插件调试Vue应用5.1浏览器为
VUE学习笔记(黑马2023版)
第一天
第一天准备文件:
链接:https://pan.baidu.com/s/14Cd_aMQMsgMTZi72AefZ1g?pwd=6666
提取码:6666
1.Vue是什么?
Vue是一个用于构建用户界面的渐进式框架
1.构建用户界面:基于数据动态渲染页面
2.渐进式:循序渐进的学习
3.框架:一套完整的项目解决方案,提升开发效率
2.创建一个Vue实例
创建Vue实例,初始化渲染
2.1.准备容器(Vue所管理的范围)
比如:
<div id="app">
<!-- 这里将会编写一些用于渲染的代码逻辑 -->
<div>
2.2.引包(开发版本包/生产版本包)
前往官网下载包
进入官网后依次点击起步
点击安装
在安装时选择开发版本,因为开发版本包含完整的警告和调试模式
如果不想安装,可以用用一下语句直接导入
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
2.3.创建实例
<script>
//一旦引入VueJS核心包,在全局环境,就有了Vue构造函数
const app = new Vue()
</script>
2.4.指定配置项 el data
el指定挂载点,选择器指定控制的是哪个盒子
data提供数据
比如在第三步的基础上:
<script>
const app = new Vue({
el:'#app',
data:{
msg:'Hello 黑马'
}
})
</script>
上述代码指控制id为app的盒子,数据为‘Hello 黑马’
再将第一步的div盒子更改为:
<div id="app">
{{msg}}
</div>
最后在网页中运行的效果为:
完整代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
{{msg}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
msg:'Hello 黑马'
}
})
</script>
</body>
</html>
3.插值表达式
插值表达式{{ }}
插值表达式是一种Vue的模板语法
3.1.作用:
利用表达式进行插值,渲染到页面中
表达式:是可以被求值的代码,JS引擎会将其计算出一个结果
3.2.语法:
{{ 表达式 }}
比如:
<div id="app">
{{msg}}
</div>
3.3.注意点
(1)使用的数据必须存在,要事先声明
(2)支持的是表达式,而不是语句,比如:if for…
例如以下是错误的:
<p>
{{ if }}
</p>
(3)不能再标签属性中使用{{ }}插值
例如以下是错误的:
<p title="{{ username }}">
</p>
3.4.实践案例
实践案例如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<p>{{ nickname }}</p>
<p>{{ nickname.toUpperCase() }}</p>
<p>{{ nickname + '你好' }}</p>
<p>{{ age>=18 ? '成年' : '未成年' }}</p>
<p>{{ friend.name }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
nickname: 'tony',
age: 18,
friend: {
name: 'jepson',
desc: '热爱学习'
}
}
})
</script>
</body>
</html>
效果图如下:
4.Vue响应式特性
4.1.什么是响应式?
数据改变,视图自动更新
4.2.访问和修改数据
访问数据:“实例.属性名”
例如:在上一个案例实践的网页中,按f12进入控制台输入一下代码,成功访问数据
修改数据:“实例.属性名”=“值”
例如:在上一个案例实践的网页中,按f12进入控制台输入一下代码,成功修改数据
5.Vue开发者工具安装:装插件调试Vue应用
5.1浏览器为谷歌的安装方法
通过极简插件安装
1.点击链接打开极简网址
2.搜索Vue
3.安装Vue Devtools
4.点击推荐下载
5.下载完成后解压
6.打开管理扩展程序
7.将刚下载解压好的后缀为.crx的程序拖拽到下图所示页面的空白部分中
8.弹出提示框,点击添加扩展程序
9.安装完成后点击插件详情
10.将允许访问文件网址打开
11.重启浏览器(一定要重启,不是刷新),插件生效
5.2浏览器为Edge的安装方法
1.如图点击扩展
2.在弹出的窗口中选择“打开Microsoft Edge加载项”
3.在新窗口中搜索vue
4.安装Vue.js devtools
5.安装完成后,点击管理扩展
6.点击Vue.js devtools的“详细信息”,将“允许访问文件URL”打上勾
7.重启浏览器(一定要重启,不是刷新),插件生效
6.Vue指令
Vue会根据不同的指令,针对标签实现不同的功能
指令:带有v-前缀的特殊标签属性
6.1 v-html
- 作用:设置元素的innerHTML
- 语法:v-html=“表达式”
<div v-html="表达式"></div>
- 案例实践:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<div v-html="msg"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
msg:`<a href="http://www.itheima.com">
黑马程序员
</a>`//注意``是模版字符串,不要省略
}
})
</script>
</body>
</html>
效果展示:
6.2 v-show 和 v-if
6.2.1 v-show
- 作用:控制元素显示隐藏
- 语法:v-show=“表达式” 表达式值true显示,false隐藏
- 原理:切换display:none控制显示隐藏
- 适用场景:频繁切换显示隐藏的场景
6.2.2v-if
- 作用:控制元素显示隐藏(条件渲染)
- 语法:v-if=“表达式” 表达式值true显示,false隐藏
- 原理:基于条件判断,是否创建或移除元素节点
- 使用场景:要么显示,要么隐藏,不频繁切换的场景
6.2.3案例实践
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box{
height: 50px;
width: 100px;
border-radius: 5px;
text-align: center;
border: solid 3px;
padding: 10px;
margin: 10px;
}
</style>
</head>
<body>
<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.7.14/dist/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
flag:true
}
})
</script>
</body>
</html>
flag:true//当flag元素为true时,id为app的控件显示
效果如图:
flag:false//当flag元素为false时,id为app的控件不显示
效果如图:
6.3 v-else和v-else-if
- 作用:辅助v-if进行判断渲染
- 语法:
v-else
v-else-if=“表达式”
<p v-if="表达式">我是一个p标签</p>
<p v-else-if="表达式">我是一个p标签</p>
<p v-else>我是一个p标签</p>
- 注意:需要紧挨v-if使用
- 案例实践
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<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.7.14/dist/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
gender: 2,
score: 80
}
})
</script>
</body>
</html>
案例结果如下:
6.4v-on
- 作用:注册事件=添加监听+提供处理逻辑
- 语法:
①v-on:事件名=“内联语句”
例如:
<button v-on:click="count--">我是一个按钮</button>
②v-on:事件名=“methods中的函数名”
例如:
<button v-on:click="fn">我是一个按钮</button>
- 简写:@事件名
<!--这种方法更为常用-->
<button @click="fn">我是一个按钮</button>
- 案例实践
①v-on:事件名="内联语句"的案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 点击移除实现count减一 -->
<button v-on:click="count--">-</button>
<span>{{ count }}</span>
<!-- 点击一次实现count加1,此处'@'为v-on的简写方式,平常生活中更为常用 -->
<button @click="count++">+</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
count: 100
}
})
</script>
</body>
</html>
案例结果如下:
②v-on:事件名="methods中的函数名"的案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 此处的@click=""内部的值要与methods中的方法名一致 -->
<button @click="fn">切换显示隐藏</button>
<h1 v-show="isshow">黑马程序员</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
const app2 = new Vue({
el:'#app',
data:{
isshow: true
},
methods:{
fn(){
//此处的语句可以替换为app2.isshow = !app2.isshow,但鼓励下面的做法,更利于代码的维护
this.isshow = !this.isshow
}
}
})
</script>
</body>
</html>
案例结果如下:
- v-on参数传递
- 语句
<button @click="fn(参数一,参数二)">
按钮
</button>
const app= new Vue({
el:#app,
methods:{
fn (a, b) {
console.log('这是一个fn函数')
}
}
})
- 参数传递案例实践
案例说明:通过点击对应的饮品,实现银行卡余额减少对应价钱
代码如下:
<!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>
.box {
border: 3px solid #000000;
border-radius: 10px;
padding: 20px;
margin: 20px;
width: 200px;
}
h3 {
margin: 10px 0 20px 0;
}
p {
margin: 20px;
}
</style>
</head>
<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>
</html>
部分案例效果图如下:
6.5v-bind
- 作用:动态的设置html的标签属性(src url title…)
- 语法:v-bind:属性名=“表达式”
<img v-bind:属性名="表达式">
- 简写::属性名=“表达式”
<img :属性名="表达式">
- 案例实践
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<img v-bind:src="imgUrl" v-bind:title="msg" alt="">
<!-- 此处:src和:title均为上面v-bind的简写 -->
<img :src="imgUrl" :title="msg" alt="">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
imgUrl:'./imgs/10-01.png',
msg:'hello 波仔'
}
})
</script>
</body>
</html>
案例结果如下:
图片切换案例-波仔学习之旅
- 核心思路分析:
1.数组存储图片路径
2.准备下标index,数组[下标] - 案例代码如下:
<!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>
</head>
<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>
</html>
案例部分效果如下:
6.6v-for
- 作用:基于数据循环,多次渲染整个元素
- 遍历数组语法:
v-for=“(item,index) in 数组”
item:每一项
index:下标
<li v-for="(item,index) in list">我是一个li标签</li>
- 省略index
v-for = “item in 数组”
<li v-for="item in list">我是一个li标签</li>
- 案例实践
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<h3>小黑水果店</h3>
<ul>
<li v-for="(item,index) in list">{{ item }} - {{ index }}</li>
</ul>
<ul>
<!-- 省略index形式 -->
<li v-for="item in list">{{ item }}</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
list:['西瓜','苹果','鸭梨']
}
})
</script>
</body>
</html>
案例结果如下:
图书管理案例-小黑的书架
- 案例说明:
实现下图页面,并按删除按钮后,实现对应项的删除
- 核心思路分析:
①通过v-for遍历数组
②给删除按钮绑上@click,实现点击后删除的功能 - 实现代码
<!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>
</head>
<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.7.14/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 ) {
//通过id进行删除数组中的对应项
//filter(不会改变原数组):根据条件,保留满足条件的对应项,得到一个新数组
this.booksList=this.booksList.filter(item => item.id != id)
}
}
})
</script>
</body>
</html>
6.7 v-for中的key
- 作用:给列表项添加的唯一标识。便于Vue进行列表项的正确排序复用
- 语法:
key属性=“唯一标识”
<li v-for="(item,index) in 数组" :key="唯一值">
- 注意点:
①key的值只能是字符串或数字类型
②key的值必须具有唯一性
③推荐使用id作为key(唯一),不推荐使用index作为key(会变化,不对应)
6.8 v-model
- 作用:
给表单元素使用,双向数据绑定 -> 可以快速获取或设置表单元素内容
①数据变化 -> 视图自动更新
②视图变化 -> 数据自动更新 - 语法:v-model=‘变量’
<input type="text" 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>Document</title>
</head>
<body>
<div id="app">
<!-- v-model让数据和视图,形成双向数据绑定 -->
账户:<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.7.14/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>
</html>
综合案例-小黑记事本
功能需求:
1.列表渲染
v-for key的设置,{{}}插值表达式
2.删除功能
①v-on调用传参
②filter过滤,覆盖原数组
3.添加功能
①通过v-model绑定输入框 -> 实时获取表单元素的内容
②点击按钮,进行新增,往数组最前面加unshift
4.底部统计和清空
①数组.length累计长度
②覆盖数组清空列表
③v-show控制隐藏
代码实现:
<!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" />
<link rel="stylesheet" href="./css/index.css" />
<title>记事本</title>
</head>
<body>
<!-- 主体区域 -->
<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 @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/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
todoName:'',
list:[
{id: 1, name: '跑步一公里'},
{id: 2, name: '跳绳200次'},
{id: 3, name: '游泳100米'}
]
},
methods:{
del(id){
this.list = this.list.filter( item =>item.id !== id)
},
add(){
//trim()去除空格
if(this.todoName.trim() === ''){
alert('请输入任务名称')
return
}
//unshift()增加到数组的最前面
this.list.unshift({
id: +new Date(),//用时间戳临时作为id
name:this.todoName,
})
this.todoName=''
},
clear(){
this.list=[]
}
}
})
</script>
</body>
</html>
第二天
第二天准备文件:
链接:https://pan.baidu.com/s/1_3NUO6dKECpi7OmV5VMSzg?pwd=6666
提取码:6666
7.指令修饰符
通过"."指明一些指令后缀,不同后缀封装了不同的处理操作
7.1按键修饰符
@keyup.enter 用于键盘回车监听(较为常用)
例如:
<!-- 回车后执行add操作 -->
<input @keyup.enter="add" v-model="todoName"/>
7.2 v-model修饰符
- v-model.trim去除首尾空格(较为常用)
例如:
<input v-model.trim="username" type="text"><br>
- v-model.number转数字(较为常用)
例如:
<input v-model.number="age" type="text"><br>
7.3 事件修饰符
- @事件名.stop阻止冒泡
<!-- 当点击son div时,父级元素father div的@click不会被执行 -->
<div @click="alert('老父亲被点击了')" class="father">
<div @click.stop="alert('儿子被点击了')" class="son">儿子</div>
</div>
- @事件名.prevent阻止默认行为
<a @click.prevent="notLink" href="http://www.baidu.com">阻止默认行为</a>
8. v-bind对于样式控制的增强 - 操作class
语法:
:class=“对象/数组”
①对象->键就是类名,值是布尔值。如果值为true,有这个类,否则没有这个类
适用场景:一个类名,来回切换
<div class="box" :class="{ 类名1: 布尔值, 类名2: 布尔值 }"></div>
②数组->数组中所有的类,都会添加到盒子上,本质就是一个class列表
适用场景:批量添加或删除类
<div class="box" :class="[类名1, 类名2 ,类名3 ]"></div>
案例:京东秒杀tab导航高亮
- 案例说明:点击不同的链接,实现点击的链接高亮功能
- 核心思路:
1.基于数据动态渲染tab(v-for实现)
2.准备下标记录高亮的是哪一个tab
3.基于下标,动态控制class类名(v-bind:class) - 案例实现:
<!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>
* {
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>
<div id="app">
<ul>
<!-- 用v-for遍历数组,将选中的index传给activeIndex -->
<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/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
activeIndex: 0, //存储选中的下标
list: [
{ id: 1, name: '京东秒杀' },
{ id: 2, name: '每日特价' },
{ id: 3, name: '品类秒杀' }
]
}
})
</script>
</body>
</html>
9.v-bind对于样式控制的增强 - 操作style
- 语法:
:style=“样式对象”
<div class="box" :style="{ CSS属性名1: CSS属性, CSS属性名2: CSS属性}"></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=75">设置75%</button>
<button @click="percent=100">设置100%</button>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
percent: 30
}
})
</script>
</body>
</html>
10.v-model应用于其他表单元素
常见的表单元素都可以用v-model绑定关联 -> 快速获取或设置表单元素的值
他会根据控件类型自动选取正确的方法来更新元素
- 输入框 input:text -> value
- 文本域 textarea -> value
- 复选框 input:checkbox -> checked
- 单选框 input:radio -> checked
- 下拉菜单 select -> value
案例实践如下:
<!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>
textarea {
display: block;
width: 240px;
height: 100px;
margin: 10px 0;
}
</style>
</head>
<body>
<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="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="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username:'',
isSingle:false,
gender:"",
cityId:'101',
desc:""
}
})
</script>
</body>
</html>
11.计算属性
- 概念:基于现有的数据,计算出来的新属性。因爱的数据变化,自动计算
- 语法:
- ①声明在computed配置项中,一个计算属性对应一个函数
- ②使用起来和普通属性一样使用{{ 计算属性名 }}
computed: {
计算属性名(){
基于现有数据,编写求值逻辑
return 结果
}
}
案例实践
<!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>
table {
border: 1px solid #000;
text-align: center;
width: 240px;
}
th,td {
border: 1px solid #000;
}
h3 {
position: relative;
}
</style>
</head>
<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/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(){
//0表示求和起始值,reduce遍历list,将每个item的值加上后返回给sum
let total= this.list.reduce((sum, item) => sum + item.num, 0)
return total
}
}
})
</script>
</body>
</html>
案例效果展示:
11.1computed计算属性 vs methods方法
- computed计算属性
作用:封装了一段对于数据的处理,求得一个结果
缓存特性:计算属性会对计算出来的结果缓存,再次使用直接读取缓存,依赖项变化了,会自动重新计算 -> 并再次缓存 - methods方法:
作用:给实例提供一个方法,调用以处理业务逻辑
11.2 计算属性完整写法
计算属性默认的简写,只能读取访问,不能“修改”
如果要**“修改”,需要写计算属性的完整写法**
简写:
computed: {
计算属性名(){
一段代码逻辑(计算逻辑)
return 结果
}
}
完整写法:
computed: {
计算属性名(){
get(){
一段代码逻辑(计算逻辑)
return 结果
},
set(修改的值){
一段代码逻辑(修改逻辑)
}
}
}
综合案例 - 成绩案例
- 案例说明:
制作一个成绩表,有编号,科目,成绩属性,并且有删除,添加,和求总分,平均分的功能
- 需求说明
- 渲染功能
v-if v-else:用来判断呈现表格的形式
v-for:遍历数组
v-bind:设置不及格的高亮 - 删除功能
点击传参,filter过滤覆盖原数组
.prevent阻止默认行为 - 添加功能
v-model(.trim ,number)绑定数据
unshift修改数组更新视图 - 统计总分,求平均分
- 代码实现:
<!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" />
<link rel="stylesheet" href="./styles/index.css" />
<title>Document</title>
</head>
<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="www.baidu.com">删除</a></td>
</tr>
</tbody>
<tbody v-else>
<tr>
<td colspan="5">
<span class="none">暂无数据</span>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5">
<span>总分:{{ totalScore }}</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="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: ''
},
methods: {
del(id){
//filter():筛选,根据id判断筛选内容是否符合条件,若不等则返回给list
this.list = this.list.filter(item => item.id !== id)
},
add(){
if(!this.subject){
alert("请输入科目")
return
}
if(typeof this.score !== 'number'){
alert("请输出正确的成绩")
return
}
//往前面加unshift,往后面加push
this.list.unshift({
id: +new Date(),
subject: this.subject,
score: this.score
})
this.subject=''
this.score=''
}
},
computed:{
totalScore(){
return this.list.reduce((sum, item) => sum+item.score , 0)
},
averageScore(){
if(this.list.length === 0){
return 0
}
//计算属性可以直接使用,toFixed(2)保留两位小数
return (this.totalScore / this.list.length).toFixed(2)
}
}
})
</script>
</body>
</html>
12.watch侦听器(监视器)
- 作用:监听数据变化,执行一些业务逻辑或异步操作
- 语法:
- 简单写法:
简单类型数据,直接监视
data:{
words:'苹果',
obj:{
words:'苹果'
}
},
watch: {
数据属性名(newValue, oldValue) {
一些业务逻辑 或 异步操作
},
'对象.属性名'(newValue, oldValue) {
一些业务逻辑 或 异步操作
}
}
案例:
需求:输入内容,实时翻译
代码实现:
<!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>
* {
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
},
// 具体讲解:(1) watch语法 (2) 具体业务实现
watch: {
// 该方法会在数据变化时调用执行
// newValue新值, oldValue老值(一般不用)
// words (newValue) {
// console.log('变化了', newValue)
// }
'obj.words' (newValue) {
//console.log('变化了', newValue)
//防抖:延迟执行 -> 干啥事先等一等,延迟一会,一段时间内没有再次触发,才执行
clearTimeout(this.timer)
this.timer = setTimeout(async () => {
//这里是ajax的内容
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>
- 完整写法
添加额外配置项
(1)deep:true 对复杂类型深度监视
(2)immediate:true 初始化立刻执行一次handler方法
data:{
obj:{
words:'苹果',
lang:'italy'
}
},
watch: {
数据属性名(newValue, oldValue) {
deep: true,//深度监视
handler(newValue){
console.log(newValue)
}
}
}
案例演示:
需求:在上个案例的基础上,输入内容,修改语言,实时翻译
代码:
<!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>
* {
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 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: {
// words: ''
obj: {
words: '',
lang:'italy'
},
result:'',//翻译结果
timer: null
},
// 具体讲解:(1) watch语法 (2) 具体业务实现
watch: {
obj: {
deep: true, //深度监视
immediate: true, //立刻执行,一进入页面handler立刻执行
handler( newValue ){
// //防抖:延迟执行 -> 干啥事先等一等,延迟一会,一段时间内没有再次触发,才执行
clearTimeout(this.timer)
this.timer = setTimeout(async () => {
//这里是ajax的内容
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)
}
}
}
})
</script>
</body>
</html>
综合案例 - 水果购物车
-
案例说明:
完成一个水果购物车网页,如图所示
-
需求说明:
- 渲染功能
v-if v-else:渲染body
v-for:遍历水果数组
:class:设置选中的css效果 - 删除功能
点击传参@click,filter过滤覆盖原数组 - 修改个数
点击传参@click,find找对象 - 全选反选
计算属性computed(完整写法) - 统计选中的总价和总数量
计算属性computed,reduce条件求和 - 持久化到本地
watch监视,localStorage,JSON.stringify,JSON.parse
- 完整代码:
<!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" />
<link rel="stylesheet" href="./css/inputnumber.css" />
<link rel="stylesheet" href="./css/index.css" />
<title>购物车</title>
</head>
<body>
<div class="app-container" id="app">
<!-- 顶部banner -->
<div class="banner-box"><img src="./img/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 v-for="(item, index) in fruitList" :key="item.id" class="tr" :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 :disabled="item.num <= 1" class="decrease" @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.num * item.price }}</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: './img/火龙果.png',
isChecked: true,
num: 2,
price: 6,
},
{
id: 2,
icon: './img/荔枝.png',
isChecked: false,
num: 7,
price: 20,
},
{
id: 3,
icon: './img/榴莲.png',
isChecked: false,
num: 3,
price: 40,
},
{
id: 4,
icon: './img/鸭梨.png',
isChecked: true,
num: 10,
price: 3,
},
{
id: 5,
icon: './img/樱桃.png',
isChecked: false,
num: 20,
price: 34,
}
]
const app = new Vue({
el: '#app',
data: {
// 水果列表
fruitList: JSON.parse(localStorage.getItem('list')) || defaultArr,
},
methods:{
del(id){
this.fruitList = this.fruitList.filter(item => item.id !== id)
},
add (id) {
const fruit = this.fruitList.find(item => item.id === id)
fruit.num++;
},
sub (id) {
const fruit = this.fruitList.find(item => item.id === id)
fruit.num--;
}
},
computed:{
isAll:{
get () {
return this.fruitList.every(item => item.isChecked)
},
set (value) {
//基于拿到的布尔值,要让所有的小选框同步状态
this.fruitList.forEach(item => {
item.isChecked = value
});
}
},
//统计选中的总数
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)
}
},
watch: {
fruitList: {
deep:true,
handler(newValue){
//将变化后的newValue存入本地(转JSON)
localStorage.setItem('list',JSON.stringify(newValue))
}
}
}
})
</script>
</body>
</html>
第三天
13.Vue生命周期和生命周期的四个阶段
- Vue生命周期:一个Vue实例从创建到校徽的整个过程
- 生命周期四个阶段
- 创建阶段:创建响应式数据
发送初始化渲染请求 - 挂载阶段:渲染模版
操作dom - 更新阶段:修改数据、更新视图
- 销毁阶段:销毁实例
- 钩子函数
Vue生命周期过程中,会自动运行一些函数,被称为生命周期钩子,让开发者可以在特定阶段运行自己的代码
综合案例-小黑记账清单
- 案例说明:完成下图页面,实现增删,消费总计,与饼图渲染功能
- 核心思路分析:
- 基本渲染
(1)发送请求,获取数据,封装起来,再在created中调用
(2)将获取到的数据存到data中
(3)结合数据,v-for进行渲染
(4)用计算属性完成消费统计功能 - 添加功能
(1)收集表单数据,用v-model进行关联
(2)给添加按钮注册点击事件,发送添加请求
(3)重新渲染 - 删除功能
(1)给’删除’注册点击事件,传参数id
(2)根据id发送删除请求
(3)重新渲染 - 饼图渲染
(1)在mounted中初始化echarts实例
(2)渲染函数中setOption,动态更新饼图
- 代码实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<!-- CSS only -->
<link rel="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 }}</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}}</td>
</tr>
</tfoot>
</table>
</div>
<!-- 右侧图表 -->
<div class="echarts-box" id="main"></div>
</div>
</div>
<script src="https://cdn.bootcss.com/echarts/3.7.1/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.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: ''
},
created() {
// 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: '消费账单列表',
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)'
}
}
}
]
})
},
computed: {
totalPrice() {
return this.list.reduce((sum, item) => sum + item.price, 0)
}
},
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() {
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) {
const res = await axios.delete(`https://applet-base-api-t.itheima.net/bill/${id}`)
this.getlist()
}
}
})
</script>
</body>
</html>
14. 工程化开发和脚手架Vue CLI
开发Vue的两种方式:
- 核心包传统开发模式:基于 html / css / js 文件,直接引入核心包,开发Vue
- 工程化开发模式:基于构建工具(例如: webpack)的环境中开发Vue
脚手架的基本介绍
Vue CLI 是 Vue 官方提供的一个全局命令工具
可以帮助我们快速创建一个开发Vue项目的标准化基础架子【集成 webpack 配置】
安装教程:(前置条件需要node环境)
- 右键单击win开始菜单
在弹出的窗口中,选择Windows PowerShell(管理员) - 在窗口中输入
npm i @vue/cli -g
(用yarn一直没装上,在这里选了npm)
- 安装完成后,用以下命令检验安装
vue --verison
出现以下信息,表示安装成功
创建项目和启动项目
1.打开vscode,在你想要创建项目的位置打开中断,并输入以下命令
vue create 你的项目名称
- 出现以下信息,选择第二个vue 2项目
出现以下信息,表示创建成功
- 按照控制台的提示信息启动项目
分别输入以下命令
cd 你的项目名称
npm run serve
- 进入控制台提示信息中的两个网址
出现以下画面表示运行成功
15.组件化开发和根组件
- 组件化:一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为
好处:便于维护,利于复用,有利于提升开发效率
组件分类:普通组件、根组件 - 根组件:整个应用最上层的组件,包括所有普通小组件
App.vue文件(单文件组成的三个组成部分)
- 语法高亮插件:Vetur
- 三部分组成
- template:结构(Vue2中有且只能一个元素)
- script:js逻辑
- style:样式(可支持less,需要装包)
具体结构如以下代码所示
<template>
<!-- Vue2中只能有一个根元素 -->
<div class="app" @click="fn()">
我是结构
</div>
</template>
<script>
export default{
methods:{
fn(){
alert("hello")
}
}
}
</script>
<style lang="less">
.app {
width: 400px;
height: 400px;
background-color: pink;
}
</style>
- 安装less的方法:
在控制台输入以下命令,即可安装成功(此处为用npm安装的方式)
npm install less-loader less --save-dev
16.普通组件的注册使用
组件注册的两种方式:
- 局部注册
- 创建.vue文件(三个组成部分:Header,Mian,Footer)
- 在使用的组件内导入并注册
- 全局注册
- 创建.vue文件(三个组成部分)
- main.js中进行全局注册
eg.
//导入需要全局注册的组件
import HmButton from './components/HmButton'
//调用Vue.component进行全局注册
//Vue.component('组件名',组件对象)
Vue.component('HmButton', HmButton)
使用:
- 当成html标签使用
<组件名></组件名>
- 组件名规范:驼峰命名法
eg:HmHeader
局部注册使用范例:
<!-- App.vue文件 -->
<script>
import HmHeader from './components/HmHeader.vue'
import HmMain from './components/HmMain.vue'
import HmFooter from './components/HmFooter.vue'
export default {
components:{
HmHeader:HmHeader,
HmMain,
HmFooter
}
}
</script>
更多推荐
所有评论(0)