1. vue生命周期
1.1 生命周期的顺序
- 创建阶段:响应式数据
- 挂载阶段:渲染模板
- 更新阶段:修改数据,更新视图
- 销毁阶段:销毁实例
1.2 生命周期钩子函数
- 创建阶段:beforeCreate()创建前,created()创建后,可以在此时发起请求
- 挂载阶段:beforeMount()渲染前,mounted()渲染后,在此时可以操作dom
- 更新阶段:beforeUpdate()更新前,updated()更新后
- 销毁阶段:beforeDestroy()销毁前,可以先清除定时器,延时器等,destroy()销毁后
<!-- created应用-发起请求,获取数据进行渲染 -->
<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="./vue.js"></script>
<script src="./axios.js"></script>
<script>
// 接口地址:http://hmajax.itheima.net/api/news
// 请求方式:get
const app = new Vue({
el: '#app',
data: {
list: []
},
async created() {
const res = await axios.get('http://hmajax.itheima.net/api/news')
this.list = res.data.data
}
})
</script>
<!-- mounted应用-输入框自动获取焦点 -->
<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: ''
},
mounted() {
document.querySelector('#inp').focus()
}
})
</script>
小黑记账清单
<div id="app">
<div class="contain">
<!-- 左侧列表 -->
<div class="list-box">
<!-- 添加资产 -->
<form class="my-form">
<input v-model="name" type="text" class="form-control" placeholder="消费名称" />
<input v-model="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="../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: {
list: [],
name: '',
price: ''
},
computed: {
totalPrice () {
return this.list.reduce((sum, item) => sum + item.price, 0)
}
},
created() {
this.getList()
},
mounted() {
//获取容器
this.myecharts = echarts.init(document.querySelector('#main'))
//配置项
this.myecharts.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)'
}
}
}
]
}
)
},
methods: {
async getList() {
const res = await axios.get('https://applet-base-api-t.itheima.net/bill',{
params: {
creator: '小刘'
}
})
this.list = res.data.data
//更新图标
this.myecharts.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>
2. 工程化开发
-
概念:基于构建工具的环境中开发vue
-
快速构建工具vue cli脚手架,集成了webpack配置,无需手动配置
-
组件化开发:将页面拆分成一个又一个组件,从而方便复用以及查找问题根源
- 普通组件的注册-局部注册:创建.vue文件,在使用的组件内进行导入注册。局部注册只能在注册的组件内使用
- 全局注册:在main.js文件中进行导入注册,之后全局组件可以在所有组件中使用
-
组件的三大组成部分:结构template,样式style,逻辑script
- 样式style在组件中默认为全局样式,为了避免组件与组件的样式冲突,可以使用scoped属性将style设置为局部样式,只影响组件内的样式。
- 逻辑script中,data必须是一个函数,从而方便维护数据的独立性,避免相互影响
2.1 组件通信
- 组件关系分为父子关系和非父子关系,通信方式各不相同
2.1.1 父子组件通信
-
父组件向子组件进行数据传递:
- 在子组件标签上添加属性,赋值
- 子组件通过props属性进行获取
- 子组件通过插值表达式进行使用
-
子组件向父组件进行传值
- 在按钮上绑定点击事件,在事件中通过$emit发送消息通知事件
- 父组件通过消息事件绑定处理函数,从而获取数据,处理逻辑
2.1.2 props
- props就是子组件标签上的自定义属性
- props校验
// 1.基础写法(类型校验)
props: {
w: Number,
},
// 2.完整写法(类型、默认值、非空、自定义校验)
props: {
w: {
type: Number,//类型
required: true,//非空
default: 0,//默认值
validator(val) { //自定义校验
if (val >= 100 || val <= 0) {
console.error('传入的范围必须是0-100之间')
return false
} else {
return true
}
},
},
},
- props和data的区别:data是自己的,随便改;props是外部的,不能直接更改,需要通过父子组件通信的方式修改
2.1.3 非父子组件通信
-
事件总线EventBus
- 创建事件总线js文件,新建空vue实例
- 发送方导入vue实例,通过$emit发送消息通知事件
- 接收方导入vue实例,通过$on监听消息通知事件,接受信息,完成通信
-
provide-inject通信
- 祖辈组件通过provide函数提供数据(简单数据类型为非响应式,复杂数据类型为响应式)
- 孙辈组件通过inject属性接受数据,实现通信
2.1.4 子组件与父组件数据的双向绑定
-
通过v-model进行双向绑定
- v-model实际是一种语法糖,在应用到输入框时,原理其实是value属性和input事件的整合,从而实现双向绑定,而在封装表单组件时,则可以利用这一原理
- 表单组件通过props属性接收父组件传值,再通过子传父的方式通知父组件修改数据
- 而当数据的属性名为value,事件名为input时,父组件可以直接通过v-model进行双向绑定,实现子父组件的数据双向绑定
-
通过.sync修饰符实现
- 在父组件传值时,给属性名加上.sync修饰符,从而使得属性名可以自定义,不需要必须为value
- 而子组件要通过给绑定对象对应的事件进行子传父的操作,进行数据传输。如弹框则需绑定update事件
2.1.5 ref和$refs获取dom元素和组件实例
-
获取dom元素(在当前组件进行查找,避免类名重复,导致找不到对应dom元素)
- 在目标标签上添加ref属性
- 通过$refs获取对应目标元素
-
获取组件实例
- 在目标组件上添加ref属性
- 通过$refs获取对应目标组件,获取之后,可以调用目标组件的方法
2.1.6 vue异步更新和$nextTick()
- vue采用的是异步更新dom的方式,即在代码执行完之后才会更新dom元素
- $nextTick(函数体)的作用就是在dom更新完成之后,再进行执行函数的某些操作