笔记目录
小概
本章的学习内容:axios的使用,vue生命周期钩子函数,两个小案例
1. axios
1.1 了解axios
axios的作用:发送ajax请求
为什么不使用jq中的ajax呢?jQuery体积大,有一堆的DOM操作方法在vue中用不上,如果单纯去使用ajax而引入jq的话,没必要。
axios的优点:体积小,只有发送ajax功能;技术先进,基于Promise技术封装ajax(解决请求回调地域)
axios缺点:浏览器兼容性(下面会讲解决方法)
1.2 axios基本使用
axios使用流程
axios.get(‘url’)
.then(res=>{ //成功回调 res.data })
.catch(err=>{ //失败回调 })
.then(()=>{ //请求完成,不管成功失败只要请求完成的 })
/* 创建vue实例 */
var app = new Vue({
//el:挂载点
el: '#app',
//data: 要渲染的数据
data: {
msg: 'hello vue.js!'
},
methods: {
getClick () {
axios
.get('https://autumnfish.cn/api/jok')
.then(res => {
console.log(res) //响应对象 : axios配置、响应数据、请求头
console.log(res.data) //响应数据,等价于之前的backData
})
.catch(err => {
console.log(err)
})
.then(() => {
console.log('请求完成,无论成功失败,只要ajax完成就会执行')
})
},
postClick () {
axios
.post('http://toutiao-app.itheima.net/v1_0/authorizations', {
mobile: '13912345678',
code: '246810'
})
.then(res=>{
console.log(res);
})
}
}
})
</script>
1.3 axios推荐方式
axios常用方法
axios({
method:‘请求方法’,
url:‘请求路径’,
params:{ get参数 }
,
data:{ post参数 }
})
.then(res=>{})
.catch(err=>{})
/* 创建vue实例 */
var app = new Vue({
//el:挂载点
el: '#app',
//data: 要渲染的数据
data: {
msg: ' '
},
methods: {
getClick () {
//如果get请求参数较少,也可以直接在url后面拼接
axios({
url: 'https://autumnfish.cn/api/joke/list',
method: 'get',
params: { num: 10 }
}).then(res => {
console.log(res)
console.log(res.data)
});
},
postClick () {
axios({
url: 'http://toutiao-app.itheima.net/v1_0/authorizations',
method: 'post',
data: { mobile: '13912345678', code: '246810' }
})
.then(res => {
console.log(res)
console.log(res.data)
});
}
}
})
1.4 axios设置请求头兼容问题
背景:很久很久以前,ajax技术还没有发明以前。 网络请求都是通过form表单发送的,form表单默认的请求头是
application/x-form-www-urlencoded
随着互联网的发展,ajax技术的普及,对应的json格式也在不断的普及。后来的服务器发送请求主要以json格式来发送。 json格式的请求头是:application/json;charset=UTF-8
不同的请求头,数据传输处理方式不同。
- application/x-form-www-urlencoded
前端参数拼接:key=value&key=value
后端切割字符串接收 str.split()- application/json;charset=UTF-8
前端json格式:{key:value,key1:value1}
后端解析json : JSON.parse(str)导致axios兼容性的根本就在于,axios使用的是新的数据传输处理方式(application/json;charset=UTF-8),老后端接口还是针对key=value&key=value这种数据进行处理,就会报错 参数错误 …
/* 创建vue实例 */
var app = new Vue({
//el:挂载点
el: '#app',
//data: 要渲染的数据
data: {
msg: 'kunkunnb!'
},
methods: {
//老版本post
getClick () {
//js原生的将参数拼接的方式 'key=value&key=value'
let sp = new URLSearchParams();
sp.append('username','admin');
axios({
url:'https://autumnfish.cn/api/user/check',
method:'post',
data: sp,
headers:{ 'Content-type':'application/x-www-form-urlencoded'}
}).then(res=>{
//成功回调
console.log(res)
});
},
//新版本post
postClick () {
axios({
url: 'http://toutiao-app.itheima.net/v1_0/authorizations',
method: 'post',
data: { mobile: '13912345678', code: '246810' }
}).then(res => {
console.log(res)
console.log(res.data)
})
}
}
})
</script>
如果是旧接口post方式,用axios的话,解决方法:
1.请求头设置数据传输处理方式为 headers:{ ‘Content-type’:‘application/x-www-form-urlencoded’},
2.传输参数变成key=value&key=value 类型
let sp = new URLSearchParams();
sp.append(‘username’,‘admin’);
1.5 axios上传文件
axios文件上传没有兼容性
使用fromdata获取带文件的表单数据
<form action="">
<input type="text" placeholder="请输入英雄名字" name="heroName" />
<input type="text" placeholder="请输入技能名字" name="heroSkill" />
<input type="file" name="heroIcon" />
</form>
<button id="btn">提交</button>
<script>
document.querySelector('#btn').onclick = function () {
/* axios文件上传没有兼容性 */
//1.使用fromdata获取带文件的表单数据
let fd = new FormData( document.querySelector('form') );
//2.使用fd作为参数,formdata会自动帮你处理文件请求头
axios({
url:'https://autumnfish.cn/api/cq/add',
method:'post',
data: fd,
}).then(res=>{
//成功回调
console.log(res)
});
}
</script>
2. vue生命周期钩子函数
vue生命周期钩子
- 钩子:回调函数
- 生命周期:vue从创建到销毁的过程
vue生命周期由8个钩子组成
- 生命周期钩子不能使用箭头函数,要用function函数
/* 创建vue实例 */
var app = new Vue({
//el:挂载点
el: '#app',
//data: 要渲染的数据
data: {
msg: '我是坤坤!',
},
/* vue生命周期钩子 */
//1.beforeCreate():创建vue实例
beforeCreate() {
//这个钩子只是创建vue实例本身,还没有创建el和data
console.log( this.el );
console.log( this.data );
},
//2.created() : 创建了data (常用:这个钩子可以加载ajax)
created() {
//这个钩子只是创建data(平铺到vue实例),还没有创建el
console.log( this.el );
console.log( this.msg );
},
//3.beforeMount() : 创建el
beforeMount() {
//这个钩子创建了el,但是没有渲染数据(准备渲染)
console.log( this.$el );
console.log( this.msg );
},
//4.mounted() : 完成初始渲染(常用,这个钩子可以获取dom元素 $refs )
mounted() {
//这个钩子中完成了将data中的数据渲染到el挂载点
console.log( this.$el );
console.log( this.$refs );//$refs也是在这个钩子中完成存储
console.log( this.msg );
},
//5.beforeUpdate() : 多次执行,检测data数据变化 (data中任何数据变化都会触发)
beforeUpdate() {
//数据驱动:检测data中数据是否有变化 (准备重新渲染,没有渲染)
console.log('data中数据变化了');
},
//6.updated() : 多次执行,完成数据更新渲染
updated() {
//完成数据重新渲染
console.log('数据重新渲染完毕');
},
//7.beforeDestroy() : 准备销毁vue实例(解除data与el的绑定)
beforeDestroy() {
//准备销毁 app.$destroy()
/*
vue销毁: 不是销毁vue实例,也不是移除dom。 而是解除vue中数据与挂载点的绑定。
说人话: 修改data,页面不会变化。
*/
console.log('vue准备销毁');
},
//8.destroyed() : 销毁完成
destroyed() {
//完成销毁
console.log('vue销毁完成');
},
})
console.log( app.$refs );
</script>
vue生命周期钩子函数:
1.beforeCreate()
创建vue实例 这个钩子只是创建vue实例本身,还没有创建el和data
2.created()
创建了data(平铺到vue实例)还没创建el,常用这个钩子加载ajax请求
3.beforeMount()
这个钩子创建了el,但是没有渲染数据(准备渲染)
4.mounted()
完成初始渲染,将data中的数据渲染到el挂载点 这个钩子可以获取dom元素 $refs
5.beforeUpdate()
多次执行,检测data数据变化 (data中任何数据变化都会触发)准备重新渲染,没有渲染.
6.updated()
多次执行,完成数据更新渲染
7.beforeDestroy()
准备销毁vue实例(解除data与el的绑定) vue销毁: 不是销毁vue实例,也不是移除dom。 而是解除vue中数据与挂载点的绑定。之后是修改date页面没有变化
8.destroyed()
销毁完成
3. 案例
天气查询页面
<div class="wrap" id="app">
<div class="search_form">
<div class="logo"><img src="img/logo.png" alt="logo" /></div>
<div class="form_group">
<input
type="text"
class="input_txt"
placeholder="请输入查询的天气"
@keyup.enter="searchCity"
v-model.lazy="city"
/>
<button class="input_sub" @click="searchCity" :class="{loading:isLoading}">搜 索</button>
</div>
<div class="hotkey">
<a ref="firstCity" @click="hotClick('北京')" href="javascript:;" >北京</a>
<a @click="hotClick('上海')" href="javascript:;" >上海</a>
<a @click="hotClick('广州')" href="javascript:;" >广州</a>
<a @click="hotClick('深圳')" href="javascript:;" >深圳</a>
</div>
</div>
<ul class="weather_list">
<li class="weather" v-for="item in list">
<div class="info_type">
<!-- 雨 -->
<span v-if="item.type.indexOf('雨') != -1 "class="iconfont"></span>
<!-- 晴 -->
<span v-else-if="item.type.indexOf('晴') != -1 "class="iconfont"></span>
<!-- 阴 -->
<span v-else-if="item.type.indexOf('阴') != -1 "class="iconfont"></span>
<!-- 雪 -->
<span v-else-if="item.type.indexOf('雪') != -1 "class="iconfont"></span>
<!-- 云 -->
<span v-else-if="item.type.indexOf('云') != -1 "class="iconfont"></span>
<!-- 雷 -->
<span v-else-if="item.type.indexOf('雷') != -1 "class="iconfont"></span>
<!-- 雹 -->
<span v-else-if="item.type.indexOf('雹') != -1 "class="iconfont"></span>
<!-- 雾 -->
<span v-else-if="item.type.indexOf('雾') != -1 "class="iconfont"></span>
</div>
<div class="info_temp"><b>{{ item.high }}</b><br />{{ item.low }}</div>
<div class="info_date"><b>{{ city }}</b><span>{{ item.date }}</span></div>
</li>
</ul>
</div>
<!-- 导包 -->
<script src="./js/vue.js"></script>
<script src="./js/axios.js"></script>
<script>
/* 需求分析
1.搜索框点击 + 输入框enter : @click
1.1 获取用户输入的城市 : v-model双向绑定
1.2 ajax请求 http://wthrcdn.etouch.cn/weather_mini?city=深圳
1.3 服务器响应之后,渲染数据。 v-for="item in list"
2.热门城市列表点击
2.1 修改输入框文本为当前点击的文本 : v-model双向绑定
2.2 ajax请求城市并且渲染 : 主动触发事件
3.搜索按钮loading加载效果 : v-bind:class="{}"
4.页面一加载,默认请求第一个热门城市列表 : vue生命周期钩子
*/
let app = new Vue({
el:'#app',
data:{
city:'',
isLoading:false,
list:[]//天气列表
},
methods: {
//1.搜索城市
searchCity(){
//1.1获取用户输入的城市
console.log( this.city );
this.isLoading = true;//加载动画
//1.2 axios发送请求
axios({
url:`http://wthrcdn.etouch.cn/weather_mini?city=${this.city}`,
method:'get',
}).then(res=>{
//成功回调
console.log(res)
/* 如果网速太快,用户可能看不到loading动画。可以使用定时器,让用户多看一会儿酷炫的动画效果
注意点:这里定时器不能使用function,否则this会变成window.
使用箭头函数,this还是上级作用域this->vue实例
*/
setTimeout(()=>{
//绑定数据
this.list = res.data.data.forecast
//取消loading
this.isLoading = false
},1000)
});
},
//2.热门城市
hotClick(city){
//2.1 修改输入框文本
this.city = city;
//2.2 主动触发事件 : vue主动触发事件不需要通过DOM,直接调用methods中方法即可
this.searchCity();
}
},
//生命周期钩子
mounted() {
//这个钩子完成初始渲染,才可以操作dom
console.log( this.$refs.firstCity );
this.hotClick( this.$refs.firstCity.innerText );
},
});
</script>
</body>
案例知识点:vue虽然不提倡直接操作dom元素,但是也会有需要操作的时候,vue中操作dom元素 1.在dom标签中加一个ref=“自定义名称”,2.就可以通过$refs.自定义名称来操作该dom元素;
vue钩子函数中操作dom时机是mounted()这个钩子已经完成了dom挂载el。(注意钩子函数与el,methods同级)
4. 案例
购物车案例
<body>
<div class="shopping-car-container" id="app">
<div class="car-headers-menu">
<div class="row">
<div class="col-md-1 car-menu">
<label><span id="checkAll">全选</span></label>
</div>
<div class="col-md-3 car-menu">商品信息</div>
<div class="col-md-3 car-menu">商品参数</div>
<div class="col-md-1 car-menu">单价</div>
<div class="col-md-1 car-menu">数量</div>
<div class="col-md-1 car-menu">金额</div>
<div class="col-md-2 car-menu">操作</div>
</div>
</div>
<div class="goods-content">
<!--goods display-->
<div class="goods-item" v-for="(item,index) in list" :key="item.id">
<div class="panel panel-default">
<div class="panel-body">
<div class="col-md-1 car-goods-info">
<label
><input
v-model="item.goods_state"
type="checkbox"
class="goods-list-item"
/></label>
</div>
<div class="col-md-3 car-goods-info goods-image-column">
<img
class="goods-image"
:src="item.goods_img"
style="width: 100px; height: 100px;"
/><span id="goods-info">{{ item.goods_name }}</span>
</div>
<div class="col-md-3 car-goods-info goods-params">货到付款</div>
<div class="col-md-1 car-goods-info goods-price">
<span>¥</span
><span class="single-price">{{ item.goods_price }}</span>
</div>
<div class="col-md-1 car-goods-info goods-counts">
<div class="input-group">
<div class="input-group-btn">
<button
type="button"
class="btn btn-default car-decrease"
@click="item.goods_count==0?item.goods_count=0:item.goods_count--">
-
</button>
</div>
<input
type="text"
class="form-control goods-count"
v-model="item.goods_count"
/>
<div class="input-group-btn">
<button type="button" class="btn btn-default car-add" @click="item.goods_count++">
+
</button>
</div>
</div>
</div>
<div class="col-md-1 car-goods-info goods-money-count">
<span>¥</span
><span class="single-total"
>{{ item.goods_count*item.goods_price }}</span
>
</div>
<div class="col-md-2 car-goods-info goods-operate">
<button type="button" class="btn btn-danger item-delete" @click="list.splice(index,1)">
删除
</button>
</div>
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-body bottom-menu-include">
<div class="col-md-1 check-all-bottom bottom-menu">
<label>
<input
type="checkbox"
id="checked-all-bottom"
:checked="allChecked"
@click="allChecked = !allChecked"
/>
<span id="checkAllBottom">全选</span>
</label>
</div>
<div class="col-md-1 bottom-menu">
<span id="deleteMulty" @click="list=[]">
删除
</span>
</div>
<div class="col-md-6 bottom-menu"></div>
<div class="col-md-2 bottom-menu">
<span>已选商品 <span id="selectGoodsCount">{{ totalCount }}</span> 件</span>
</div>
<div class="col-md-1 bottom-menu">
<span>合计:<span id="selectGoodsMoney">{{ totalPrice }}</span></span>
</div>
<div class="col-md-1 bottom-menu submitData submitDis">
结算
</div>
</div>
</div>
</div>
<script>
/* 需求分析
1.页面一加载,ajax请求购物车数据。 created钩子
2.渲染数据 : data中创建list数组,使用v-for
3.全选与选择框
4.商品加/减
5.删除
6.求和 : 计算属性
*/
let app = new Vue({
el: '#app',
data: {
list: [] //购物车列表
},
//生命周期钩子
created () {
//ajax发送请求
axios({
url: 'https://www.escook.cn/api/cart',
method: 'get'
}).then(res => {
//成功回调
console.log(res)
//渲染数据
this.list = res.data.list
})
},
//计算属性
computed: {
allChecked: {
get () {
//every:判断数组中是不是所有元素都满足条件
return this.list.every(value => value.goods_state)
},
set (val) {
//遍历数组修改每一个元素的goods_state
this.list.forEach(value => (value.goods_state = val))
}
},
totalCount(){
return this.list.reduce((sum,value)=>{
if( value.goods_state ){
return sum + +value.goods_count
}else{
return sum
}
},0);
},
totalPrice(){
return this.list.reduce((sum,value)=>{
if( value.goods_state ){
return sum + value.goods_price*value.goods_count
}else{
return sum
}
},0);
}
}
})
</script>
</body>
ervery()方法不会对数组遍历,但是如果数组是空的时候,every()会返回turn,some()则是返回false,当购物车为空的时候,全选checkbox的checked=ture,如果不想让购物车为空的时候全选按钮选中的话,allChecked计算属性的get方法先if (this.list.length == 0) return false。
总结
计算属性是一个computed中的函数,函数return值就是计算结果,如果想设置计算属性就像案例二中把全选的计算属性allChecked的状态设置给每一个商品,就需要在allChecked属性中的set方法中设置。