一.生命周期及其四个阶段
Vue生命周期:一个Vue实例从创建到销毁的整个过程
生命周期四个阶段:①创建②挂载③更新④销毁
<body>
<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 响应式数据准备好之前', this.count)
},
created () {
console.log('created 响应式数据准备好之后', this.count)
// this.数据名 = 请求回来的数据
// 可以开始发送初始化渲染的请求了
},
// 2. 挂载阶段(渲染模板)
beforeMount () {
console.log('beforeMount 模板渲染之前', document.querySelector('h3').innerHTML)
},
mounted () {
console.log('mounted 模板渲染之后', document.querySelector('h3').innerHTML)
// 可以开始操作dom了
},
// 3. 更新阶段(修改数据 → 更新视图)
beforeUpdate () {
console.log('beforeUpdate 数据修改了,视图还没更新', document.querySelector('span').innerHTML)
},
updated () {
console.log('updated 数据修改了,视图已经更新', document.querySelector('span').innerHTML)
},
// 4. 卸载阶段
beforeDestroy () {
console.log('beforeDestroy, 卸载前')
console.log('清除掉一些Vue以外的资源占用,定时器,延时器...')
},
destroyed () {
console.log('destroyed,卸载后')
}
})
</script>
</body>
二.created应用
created:响应式数据准备好了,可以开始发送初始化渲染请求
<head>
<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="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>
// 接口地址:http://hmajax.itheima.net/api/news
// 请求方式:get
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>
三.小黑的记账清单
<head>
<!-- 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 + 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.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: [
// { 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>
四.工程化开发和脚手架Vue CLI
开发Vue的两种方式:
1.核心包传统开发模式:基于html / css / js文件,直接引入核心包,开发Vue
2.工程化开发模式:基于构建工具(例如:webpack)的环境中开发Vue
五.项目目录介绍和运行流程
六.组件化开发和根组件
组件化:一个页面可以拆分为一个个组件,每个组件有着自己独立的结构、样式、行为。
好处:便于维护,利于复用 → 提升开发效率
组件分类:普通组件、根组件。
根组件:整个应用最上层的组件,包裹所有普通小组件
APP.vue文件组成
①template:结构(有且只有一个根目录)
②script:js逻辑
③style:样式(可支持less,需要装包)
七.普通组件的注册使用
局部注册:只能在注册的组件内使用
①创建 . vue文件(三个部分组成)
②在使用的组件内导入并注册
<template>
<div class="App">
<!-- 头部组件 -->
<HmHeader></HmHeader>
<!-- 主体组件 -->
<HmMain></HmMain>
<!-- 底部组件 -->
<HmFooter></HmFooter>
<!-- 如果 HmFooter + tab 出不来 → 需要配置 vscode
设置中搜索 trigger on tab → 勾上
-->
</div>
</template>
<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>
<style>
.App {
width: 600px;
height: 700px;
background-color: #87ceeb;
margin: 0 auto;
padding: 20px;
}
</style>
全局注册:所有组件内都能使用
使用:当成html标签使用
注意:组件名规范 → 大驼峰命名法,如HmHeader
①创建 . vue文件(三个部分组成)
②main . js中进行全局注册
<template>
<div class="App">
<!-- 头部组件 -->
<HmHeader></HmHeader>
<!-- 主体组件 -->
<HmMain></HmMain>
<!-- 底部组件 -->
<HmFooter></HmFooter>
<!-- 如果 HmFooter + tab 出不来 → 需要配置 vscode
设置中搜索 trigger on tab → 勾上
-->
</div>
</template>
<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>
<style>
.App {
width: 600px;
height: 700px;
background-color: #87ceeb;
margin: 0 auto;
padding: 20px;
}
</style>
八.小兔鲜首页
<template>
<div class="App">
<!-- 快捷链接 -->
<div class="shortcut">
<div class="wrapper">
<ul>
<li><a href="#" class="login">请先登录</a></li>
<li><a href="#">免费注册</a></li>
<li><a href="#">我的订单</a></li>
<li><a href="#">会员中心</a></li>
<li><a href="#">帮助中心</a></li>
<li><a href="#">在线客服</a></li>
<li>
<a href="#"
><span class="iconfont icon-mobile-phone"></span>手机版</a
>
</li>
</ul>
</div>
</div>
<!-- 头部导航 -->
<div class="header wrapper">
<!-- logo -->
<div class="logo">
<h1>
<a href="#">小兔鲜儿</a>
</h1>
</div>
<!-- 导航 -->
<div class="nav">
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">生鲜</a></li>
<li><a href="#">美食</a></li>
<li><a href="#">餐厨</a></li>
<li><a href="#">电器</a></li>
<li><a href="#">居家</a></li>
<li><a href="#">洗护</a></li>
<li><a href="#">孕婴</a></li>
<li><a href="#">服装</a></li>
</ul>
</div>
<!-- 搜索 -->
<div class="search">
<span class="iconfont icon-search"></span>
<input type="text" placeholder="搜一搜" />
</div>
<!-- 购物车 -->
<div class="cart">
<span class="iconfont icon-cart-full"></span>
<i>2</i>
</div>
</div>
<!-- 轮播区域 -->
<div class="banner">
<div class="wrapper">
<!-- 图 -->
<ul class="pic">
<li>
<a href="#"><img src="@/assets/images/banner1.png" alt="" /></a>
</li>
<li>
<a href="#"><img src="@/assets/images/banner1.png" alt="" /></a>
</li>
</ul>
<!-- 侧导航 -->
<div class="subnav">
<ul>
<li>
<div>
<span><a href="#">生鲜</a></span>
<span><a href="#">水果</a><a href="#">蔬菜</a></span>
</div>
<i class="iconfont icon-arrow-right-bold"></i>
</li>
<li>
<div>
<span><a href="#">美食</a></span>
<span><a href="#">面点</a><a href="#">干果</a></span>
</div>
<i class="iconfont icon-arrow-right-bold"></i>
</li>
<li>
<div>
<span><a href="#">餐厨</a></span>
<span><a href="#">数码产品</a></span>
</div>
<i class="iconfont icon-arrow-right-bold"></i>
</li>
<li>
<div>
<span><a href="#">电器</a></span>
<span
><a href="#">床品</a><a href="#">四件套</a
><a href="#">被枕</a></span
>
</div>
<i class="iconfont icon-arrow-right-bold"></i>
</li>
<li>
<div>
<span><a href="#">居家</a></span>
<span
><a href="#">奶粉</a><a href="#">玩具</a
><a href="#">辅食</a></span
>
</div>
<i class="iconfont icon-arrow-right-bold"></i>
</li>
<li>
<div>
<span><a href="#">洗护</a></span>
<span
><a href="#">洗发</a><a href="#">洗护</a
><a href="#">美妆</a></span
>
</div>
<i class="iconfont icon-arrow-right-bold"></i>
</li>
<li>
<div>
<span><a href="#">孕婴</a></span>
<span><a href="#">奶粉</a><a href="#">玩具</a></span>
</div>
<i class="iconfont icon-arrow-right-bold"></i>
</li>
<li>
<div>
<span><a href="#">服饰</a></span>
<span><a href="#">女装</a><a href="#">男装</a></span>
</div>
<i class="iconfont icon-arrow-right-bold"></i>
</li>
<li>
<div>
<span><a href="#">杂货</a></span>
<span><a href="#">户外</a><a href="#">图书</a></span>
</div>
<i class="iconfont icon-arrow-right-bold"></i>
</li>
<li>
<div>
<span><a href="#">品牌</a></span>
<span><a href="#">品牌制造</a></span>
</div>
<i class="iconfont icon-arrow-right-bold"></i>
</li>
</ul>
</div>
<!-- 指示器 -->
<ol>
<li class="current"><i></i></li>
<li><i></i></li>
<li><i></i></li>
</ol>
</div>
</div>
<!-- 新鲜好物 -->
<div class="goods wrapper">
<div class="title">
<div class="left">
<h3>新鲜好物</h3>
<p>新鲜出炉 品质靠谱</p>
</div>
<div class="right">
<a href="#" class="more"
>查看全部<span class="iconfont icon-arrow-right-bold"></span
></a>
</div>
</div>
<div class="bd">
<ul>
<li>
<a href="#">
<div class="pic"><img src="@/assets/images/goods1.png" alt="" /></div>
<div class="txt">
<h4>KN95级莫兰迪色防护口罩</h4>
<p>¥ <span>79</span></p>
</div>
</a>
</li>
<li>
<a href="#">
<div class="pic"><img src="@/assets/images/goods2.png" alt="" /></div>
<div class="txt">
<h4>KN95级莫兰迪色防护口罩</h4>
<p>¥ <span>566</span></p>
</div>
</a>
</li>
<li>
<a href="#">
<div class="pic"><img src="@/assets/images/goods3.png" alt="" /></div>
<div class="txt">
<h4>法拉蒙高颜值记事本可定制</h4>
<p>¥ <span>58</span></p>
</div>
</a>
</li>
<li>
<a href="#">
<div class="pic"><img src="@/assets/images/goods4.png" alt="" /></div>
<div class="txt">
<h4>科技布布艺沙发</h4>
<p>¥ <span>3759</span></p>
</div>
</a>
</li>
</ul>
</div>
</div>
<!-- 热门品牌 -->
<div class="hot">
<div class="wrapper">
<div class="title">
<div class="left">
<h3>热门品牌</h3>
<p>国际经典 品质认证</p>
</div>
<div class="button">
<a href="#"><i class="iconfont icon-arrow-left-bold"></i></a>
<a href="#"><i class="iconfont icon-arrow-right-bold"></i></a>
</div>
</div>
<div class="bd">
<ul>
<li>
<a href="#">
<img src="@/assets/images/hot1.png" alt="" />
</a>
</li>
<li>
<a href="#">
<img src="@/assets/images/hot2.png" alt="" />
</a>
</li>
<li>
<a href="#">
<img src="@/assets/images/hot3.png" alt="" />
</a>
</li>
<li>
<a href="#">
<img src="@/assets/images/hot4.png" alt="" />
</a>
</li>
<li>
<a href="#">
<img src="@/assets/images/hot5.png" alt="" />
</a>
</li>
</ul>
</div>
</div>
</div>
<!-- 最新专题 -->
<div class="topic wrapper">
<div class="title">
<div class="left">
<h3>最新专题</h3>
</div>
<div class="right">
<a href="#" class="more"
>查看全部<span class="iconfont icon-arrow-right-bold"></span
></a>
</div>
</div>
<div class="topic_bd">
<ul>
<li>
<a href="#">
<div class="pic">
<img src="@/assets/images/topic1.png" alt="" />
<div class="info">
<div class="left">
<h5>吃这些美食才不算辜负自己</h5>
<p>餐厨起居洗护好物</p>
</div>
<div class="right">¥<span>29.9</span>起</div>
</div>
</div>
<div class="txt">
<div class="left">
<p>
<span class="iconfont icon-favorites-fill red"></span>
<i>1200</i>
</p>
<p>
<span class="iconfont icon-browse"></span>
<i>1800</i>
</p>
</div>
<div class="right">
<span class="iconfont icon-comment"></span>
<i>246</i>
</div>
</div>
</a>
</li>
<li>
<a href="#">
<div class="pic">
<img src="@/assets/images/topic2.png" alt="" />
<div class="info">
<div class="left">
<h5>吃这些美食才不算辜负自己</h5>
<p>餐厨起居洗护好物</p>
</div>
<div class="right">¥<span>29.9</span>起</div>
</div>
</div>
<div class="txt">
<div class="left">
<p>
<span class="iconfont icon-fabulous"></span>
<i>1200</i>
</p>
<p>
<span class="iconfont icon-browse"></span>
<i>1800</i>
</p>
</div>
<div class="right">
<span class="iconfont icon-comment"></span>
<i>246</i>
</div>
</div>
</a>
</li>
<li>
<a href="#">
<div class="pic">
<img src="@/assets/images/topic3.png" alt="" />
<div class="info">
<div class="left">
<h5>吃这些美食才不算辜负自己</h5>
<p>餐厨起居洗护好物</p>
</div>
<div class="right">¥<span>29.9</span>起</div>
</div>
</div>
<div class="txt">
<div class="left">
<p>
<span class="iconfont icon-fabulous"></span>
<i>1200</i>
</p>
<p>
<span class="iconfont icon-browse"></span>
<i>1800</i>
</p>
</div>
<div class="right">
<span class="iconfont icon-comment"></span>
<i>246</i>
</div>
</div>
</a>
</li>
</ul>
</div>
</div>
<!-- 版权底部 -->
<div class="footer">
<div class="wrapper">
<div class="service">
<ul>
<li>
<span></span>
<p>价格亲民</p>
</li>
<li>
<span></span>
<p>物流快捷</p>
</li>
<li>
<span></span>
<p>品质新鲜</p>
</li>
<li>
<span></span>
<p>售后无忧</p>
</li>
</ul>
</div>
<div class="help">
<div class="left">
<dl>
<dt>购物指南</dt>
<dd><a href="#">购物流程</a></dd>
<dd><a href="#">支付方式</a></dd>
<dd><a href="#">售后规则</a></dd>
</dl>
<dl>
<dt>配送方式</dt>
<dd><a href="#">配送运费</a></dd>
<dd><a href="#">配送范围</a></dd>
<dd><a href="#">配送时间</a></dd>
</dl>
<dl>
<dt>关于我们</dt>
<dd><a href="#">平台规则</a></dd>
<dd><a href="#">联系我们</a></dd>
<dd><a href="#">问题反馈</a></dd>
</dl>
<dl>
<dt>售后服务</dt>
<dd><a href="#">售后政策</a></dd>
<dd><a href="#">退款说明</a></dd>
<dd><a href="#">取消订单</a></dd>
</dl>
<dl>
<dt>服务热线</dt>
<dd>
<a href="#"
>在线客服<span class="iconfont icon-customer-service"></span
></a>
</dd>
<dd><a href="#">客服电话 400-0000-000</a></dd>
<dd><a href="#">工作时间 周一至周日 8:00-18:00</a></dd>
</dl>
</div>
<div class="right">
<ul>
<li>
<div><img src="@/assets/images/wechat.png" alt="" /></div>
<p>微信公众号</p>
</li>
<li>
<div><img src="@/assets/images/app.png" alt="" /></div>
<p>APP下载二维码</p>
</li>
</ul>
</div>
</div>
<div class="copyright">
<p>
<a href="#">关于我们</a>|<a href="#">帮助中心</a>|<a href="#"
>售后服务</a
>|<a href="#">配送与验收</a>|<a href="#">商务合作</a>|<a href="#"
>搜索推荐</a
>|<a href="#">友情链接</a>
</p>
<p>CopyRight © 小兔鲜</p>
</div>
</div>
</div>
</div>
</template>
<script>
export default {}
</script>
<style></style>