Vue基础03


小概

本章的学习内容: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
不同的请求头,数据传输处理方式不同。

  1. application/x-form-www-urlencoded
    前端参数拼接: key=value&key=value
    后端切割字符串接收 str.split()
  2. 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生命周期钩子

  1. 钩子:回调函数
  2. 生命周期: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">&#xe931;</span>
          <!---->
          <span v-else-if="item.type.indexOf('晴') != -1 "class="iconfont">&#xe933;</span>
          <!---->
          <span v-else-if="item.type.indexOf('阴') != -1 "class="iconfont">&#xe92d;</span>
          <!---->
          <span v-else-if="item.type.indexOf('雪') != -1 "class="iconfont">&#xeb87;</span>
          <!---->
          <span v-else-if="item.type.indexOf('云') != -1 "class="iconfont">&#xeb79;</span>
          <!---->
          <span v-else-if="item.type.indexOf('雷') != -1 "class="iconfont">&#xeb77;</span>
          <!---->
          <span v-else-if="item.type.indexOf('雹') != -1 "class="iconfont">&#xeb76;</span>
          <!---->
          <span v-else-if="item.type.indexOf('雾') != -1 "class="iconfont">&#xeb75;</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方法中设置。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值