1.布尔值为false和true的条件
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" />
<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">
<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">
<!-- active: index%2:当 index%2 为真(即索引为奇数时),加上 active 这个类名;为假(索引为偶数时),不加 active。 -->
<div :class="{tr:true, active: item.isChecked}" v-for="(item,index) in fruitList" :key="item.id">
<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">
<!-- disabled:禁用属性 (当item.num<=1)时,按钮禁用-->
<button class="decrease" @click="reduce(index)" :disabled="item.num<=1"> - </button>
<span class="my-input__inner">{{item.num}}</span>
<button class="increase" @click="add(index)"> + </button>
</div>
</div>
<div class="td">{{item.price*item.num}}</div>
<div class="td"><button @click="del(item.id)">删除</button></div>
</div>
<!-- <div class="tr">
<div class="td"><input type="checkbox" /></div>
<div class="td"><img src="./img/荔枝.png" alt="" /></div>
<div class="td">7</div>
<div class="td">
<div class="my-input-number">
<button disabled class="decrease"> - </button>
<span class="my-input__inner">1</span>
<button class="increase"> + </button>
</div>
</div>
<div class="td">14</div>
<div class="td"><button>删除</button></div>
</div> -->
</div>
</div>
<!-- 底部 -->
<div class="bottom">
<!-- 全选 -->
<label class="check-all">
<input type="checkbox" v-model="checkedAll" />
全选
</label>
<div class="right-box">
<!-- 所有商品总价 -->
<span class="price-box">总价 : ¥ <span class="price">{{amount}}</span></span>
<!-- 结算按钮 -->
<button class="pay">结算</button>
</div>
</div>
</div>
<!-- 空车 -->
<div class="empty">🛒空空如也</div>
</div>
<script src="./js/vue-2.7.14.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
// 水果列表
// 优先使用本地存储,如果没有本地存储的话,就默认使用默认数据
fruitList: JSON.parse(localStorage.getItem('fruitList')) || [
{
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,
},
],
},
// 侦听器存储
// deep: true:深度侦听。因为 fruitList 是一个对象(数组),里面的每个元素也是对象。只有加上 deep: true,才能侦听到 fruitList 内部对象属性的变化(比如数量、选中状态等)。
// handler(value):当 fruitList 发生变化时会自动执行的函数。value 就是变化后的 fruitList。
watch: {
fruitList: {
deep: true, //侦听对象属性的变化,必须加上
handler(value) {
localStorage.setItem('fruitList', JSON.stringify(value))
}
}
},
methods: {
del(id) {
// filter 是 JavaScript 数组的一个内置方法,它的主要作用是:
// 根据指定条件,从原数组中筛选出符合条件的元素,生成一个新数组。
// 例如,id 传入 3,那么所有 id 为 3 的水果会被移除,其他的都保留
this.fruitList = this.fruitList.filter(item => item.id !== id)
},
reduce(index) {
this.fruitList[index].num--
},
add(index) {
this.fruitList[index].num++
},
},
computed: {
//总价格
amount() {
// 先筛选出勾选的商品(isChecked为true)的商品
let result = this.fruitList.filter(item => item.isChecked)
return result.reduce((preValue, item) => {
return preValue + item.num * item.price
}, 0)
},
//总数
total() {
let result = this.fruitList.filter(item => item.isChecked)
return result.reduce((preValue, item) => {
return preValue + item.num
}, 0)
},
// 全选
checkedAll: {
get() {
return this.fruitList.every(item => item.isChecked === true)
},
set(value) {
this.fruitList.forEach(item => item.isChecked = value)
}
}
}
})
</script>
</body>
</html>
3.Vue生命周期和生命周期的四个阶段
3.1 生命周期
3.2 钩子函数
3.2.1 钩子函数使用
<!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">
<h2>{{ title }}</h2>
<div>
<button @click="count--">-</button>
<span>{{ count }}</span>
<button @click="count++">+</button>
</div>
</div>
<script src="./js/vue-2.7.14.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
title: '生命周期钩子函数演示',
count: 100
},
// 创建阶段
beforeCreate() {// 此时还不能调用data数据,也不能调用methods方法
console.log('beforeCreate',
this.title,
this.count
)
},
created() {// 此时可以调用data数据,调用methods方法
console.log('created',
this.title,
this.count
)
},
// 挂载阶段
beforeMount() {// 此时不能调用DOM元素
console.log('beforeMount',
this.title,
this.count
)
},
mounted() {// 此时可以调用DOM元素
console.log('mounted',
this.title,
this.count
)
},
// 挂载阶段(渲染页面)
beforeUpdate() {// 此时不能调用DOM元素
console.log('beforeUpdate',
document.querySelector('h2'),
)
},
mounted() {// 此时可以调用DOM元素
console.log('mounted',
document.querySelector('h2'),
)
},
//更新阶段
//数据更新了,页面还没有更新
beforeUpdate() {
console.log('beforeUpdate', this.count, document.querySelector('span').innerHTML)
},
updated() {
// 数据和页面都更新了
console.log('updated', this.count, document.querySelector('span').innerHTML)
},
// 销毁阶段
beforeDestroy() {
console.log('beforeDestroy', this.count)
},
destroyed() {
console.log('destroyed')
}
})
</script>
</body>
结果:
3.2.2 created和mounted的使用例子
3.2.2.1 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>Document</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>
</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="./js/vue-2.7.14.js"></script>
<script src="./js/axios.js"></script>
<script>
// 接口地址:http://hmajax.itheima.net/api/news
// 请求方式:get
// async 用于声明异步函数,配合 await 让异步操作更简单直观。
// 在 Vue 的生命周期钩子(如 created)中加 async,可以直接用 await 等待数据请求完成后再赋值,页面渲染更自然。
const app = new Vue({
el: '#app',
data: {
list: []
},
async created() {
// 1. 发送请求获取数据
const res = await axios.get('http://hmajax.itheima.net/api/news')
// 2. 更新到 list 中,用于页面渲染 v-for
this.list = res.data.data
}
})
</script>
</body>
</html>
3.2.2.2 mounted-输入框获取焦点
<!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 class="container" id="app">
<div class="search-container">
<img src="" alt="">
<div class="search-box" id="inp">
<input type="text" ref="searchInput" placeholder="请输入要搜索的内容">
<button>搜索一下</button>
</div>
</div>
</div>
<script src="./js/vue-2.7.14.js"></script>
<script>
const app = new Vue({
el: '#app',
mounted() {
this.$refs.searchInput.focus()
}
})
</script>
</body>
</html>
结果:
4. 案例-小黑记账清单
4.1 使用axios渲染页面,同时实现当价格超过500时,自动标红
<!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 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>
<!-- 如果价格大于500,则显示红色 -->
<td :class="{red: item.price>500}">{{item.price}}</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: {
list: [], //准备存储接口返回的数据
},
async created() {
// 把axios获取到的数据的data属性赋值给res
const { data: res } = await axios({
url: "https://applet-base-api-t.itheima.net/bill",
params: {
creator: 'jayjay'
}
})
// console.log(res);
this.list = res.data
}
})
</script>
</body>
</html>
结果:
4.1 添加功能
5.工程化开发&&脚手架Vue CLI
5.1 安装步骤
1.命令行输入
npm config get prefix
2.检查该目录下是否有 vue.cmd或者vue文件
3.将npm全局路径(如:C:\Users\用户\AppData\Roaming\npm)粘贴进环境的用户变量
4.检查版本号
vue --version
5.执行创建
vue create vue-demo -m npm
6.运行
npm run serve
使用浏览器打开终端出现的8080端口
打开文件夹
5.2 Vue插件
[提示](Vue VSCode Snippets - Visual Studio Marketplace)
[高亮](Vue (Official) - Visual Studio Marketplace)
5.3 启动项目
目录详情解释
5.4 注意事项
5.4.1 组件命名和三个组成部分
小驼峰大驼峰命名法多词格式
1.小驼峰写法:abcDef.vue
2.大驼峰写法:AbcDef.vue
3.中横线写法:abc-def.vue
4.如果文件名不符合规定,补救方法:
5.4.2 template标签中只能有一个根元素
5.4.3 data要写成函数
5.4.4 less使用
5.4.4.1 lang=“less”
5.4.4.2 安装包
npm i less less-loader -D