慕尚花坊小程序开发---day3

1.分类页面

1.代码结构

<view>
  <view class="category-container">
    <!-- 左侧的滚动视图区域 -->
    <scroll-view class="category-left-view" scroll-y>
      <!-- 一级分类 -->
      <view class="left-view-item {{ activeIndex === index ? 'active' : '' }}" wx:for="{{categoryList}}" wx:key="id"
       bindtap="updateActive" data-index="{{ index }}">
        {{ item.name}}
      </view>

    </scroll-view>

    <!-- 右侧的滚动视图区域 -->
    <scroll-view class="category-right-view" scroll-y>
      <!-- 二级分类 -->
      <view class="test">
        <view wx:for="{{ categoryList[activeIndex].children }}" wx:key="index" class="right-view-item">
          <navigator class="navigator" url="/pages/goods/list/list?category2Id={{ item.id }}">
            <image class="" src="{{ item.imageUrl}}"></image>
            <text class="goods_item_name">{{ item.name }}</text>
          </navigator>
        </view>
      </view>
    </scroll-view>
  </view>
</view>

2.调用接口获取分类数据

// 导入已经封装好的请求api
import {reqCtegoryData} from '../../api/category'
 
Page({
  data:{
    categoryList:[],
    // 设置被选择的高亮类
    // 默认是第0个
    activeIndex:0
  },

  // 实现一级分类的切换效果
  updateActive(event){
    // console.log(event);
    // 打印点击元素的下标
    // console.log(event.currentTarget.dataset);
    // 将点击元素的下标结构出来
    const {index} = event.currentTarget.dataset;
    console.log(index);

    this.setData ({
      activeIndex:index
    })
  },

  async getCategoryData(){
    // 调用接口获取分类数据
    const res = await reqCtegoryData()
    // 将分类数据打印出来
    console.log(res);

    this.setData({
      categoryList:res.data
    })
  },

  
  // 监听页面加载
  onLoad(){
    this.getCategoryData()
  }
})

3.分类效果图

2.购物车页面

1.代码

js代码
// pages/cart/component/cart.js
Component({
  // 组件的属性列表
  properties: {},

  // 组件的初始数据
  data: {
    cartList: [1],
    emptyDes: '还没有添加商品,快去添加吧~'
  },

  // 组件的方法列表
  methods: {}
})
{
  "component": true,
  "styleIsolation": "shared",
  "usingComponents": {}
}
html代码
<view>
  <!-- 购物车列表结构 -->
  <view
    wx:if="{{ cartList.length }}"
    class="container goods-wrap"
    bindtap="onSwipeCellPageTap"
  >
    <view class="goods-item" wx:for="{{ cartList }}" wx:key="index">
      <van-swipe-cell class="goods-swipe" right-width="{{ 65 }}">
        <van-cell-group border="{{ false }}">
          <view class="goods-info">
            <view class="left">
              <van-checkbox checked-color="#FA4126" value="{{ checked }}"></van-checkbox>
            </view>
            <view class="mid">
              <image class="img" src="/assets/images/floor-img.jpg" />
            </view>
            <view class="right">
              <view class="title">
                腾讯极光盒子4智能网络电视机顶盒6K千兆网络机顶盒4K高分辨率
              </view>
              <view class="buy">
                <view class="price">
                  <view class="symbol">¥</view>
                  <view class="num">99.00</view>
                </view>
                <view class="buy-btn">
                  <van-stepper value="{{ price }}" />
                </view>
              </view>
            </view>
          </view>
        </van-cell-group>
        <view slot="right" class="van-swipe-cell__right">删除</view>
      </van-swipe-cell>
    </view>
  </view>

  <!-- 购物车列表为空展示的结构 -->
  <van-empty wx:else description="{{ emptyDes }}">
    <navigator url="/pages/index/index">
      <van-button round type="danger" class="bottom-button">去购物</van-button>
    </navigator>

    <navigator url="/pages/login/login">
      <van-button round type="danger" class="bottom-button">去登录</van-button>
    </navigator>
  </van-empty>

  <!-- 底部工具栏 -->
  <van-submit-bar
    wx:if="{{ cartList.length }}"
    price="{{ 3050 }}"
    button-text="去结算"
    tip="{{ true }}"
  >
    <van-checkbox value="{{ true }}" checked-color="#FA4126"> 全选 </van-checkbox>
  </van-submit-bar>
</view>
css代码
// 商品列表样式
.goods-wrap {
  padding: 16rpx 16rpx 100rpx 16rpx;

  .goods-item {
    .goods-swipe {
      width: 100%;

      .goods-info {
        display: flex;
        align-items: center;
        padding: 24rpx 16rpx;
        border-radius: 16rpx;
        margin-bottom: 16rpx;
        background-color: white;
        box-sizing: border-box;
        transition: transform 1s cubic-bezier(0.18, 0.89, 0.32, 1) !important;

        .left {
          /* width: 56px; */
          display: flex;
          align-items: center;
          justify-content: center;
        }

        .mid {
          width: 114px;
          height: 125px;

          .img {
            height: 100%;
          }
        }

        .right {
          height: 125px;
          flex: 1;
          display: flex;
          flex-direction: column;
          justify-content: space-between;
          margin-left: 10px;

          .title {
            flex: 1;
            flex-shrink: 0;
            font-size: 26rpx;
            color: #333;
            line-height: 44rpx;
            font-weight: 400;
            overflow: hidden;
            word-break: break-word;
          }

          .buy {
            display: flex;
            justify-content: space-between;

            .price {
              display: flex;
              color: #fa4126;
              font-size: 36rpx;

              .symbol {
                font-size: 10px;
                margin-right: 2px;
                margin-top: 8px;
              }
            }
          }
        }
      }

      .van-swipe-cell__right {
        background-color: #fa4126;
        text-align: center;
        display: flex;
        align-items: center;
        justify-content: center;
        width: 130rpx;
        color: #fff;
        font-size: 24rpx;
		height: 100%;
      }
    }
  }
}

// 提交订单栏样式
.submit-footer {
  display: flex;
  position: fixed;
  left: 0;
  bottom: 0;
  width: 100%;
  background-color: white;
  padding: 12px 8px;
  align-items: center;
  justify-content: space-between;
  z-index: 10;

  .right {
    display: flex;
    margin-right: 16px;
    align-items: center;
    justify-content: center;
  }
}
购物车页面总体分析

整体结构上页面主体使用了<view>标签包裹,其中包含了购物车列表的展示逻辑及底部工具栏。

利用了条件渲染wx:if="{{ cartList.length }}"来判断购物车列表是否为空,据此展示不同的内容。

在购物车页面的完成上,我结合了数据绑定、条件渲染、列表循环和第三方UI库组件,实现了商品展示、选择、数量调整及结算功能。

2.效果图

3.商品细节页面

1.代码

js代码
// pages/goods/detail/index.js
Page({
  // 页面的初始数据
  data: {
	goodsInfo: {}, // 商品详情
    show: false, // 控制加入购物车和立即购买弹框的显示
    count: 1, // 商品购买数量,默认是 1
    blessing: '' // 祝福语
  },

  // 加入购物车
  handleAddcart() {
    this.setData({
      show: true
    })
  },

  // 立即购买
  handeGotoBuy() {
    this.setData({
      show: true
    })
  },

  // 点击关闭弹框时触发的回调
  onClose() {
    this.setData({ show: false })
  },

  // 监听是否更改了购买数量
  onChangeGoodsCount(event) {
    console.log(event.detail)
  }
})
html代码
<view class="container goods-detail">
  <!-- 商品大图 -->
  <view class="banner-img">
    <image class="img" src="/assets/images/floor-img.jpg" />
  </view>

  <!-- 商品的基本信息 -->
  <view class="content">
    <view class="price">
      <view class="price-num">¥299</view>
      <view class="price-origin-num">¥399</view>
    </view>
    <view class="title">亲爱的/情人节网红款/19枝亲爱的/情人节网红款</view>
    <view class="desc">用最温暖的最有情的心意,用最温暖的最有情的心意</view>
  </view>

  <!-- 商品的详细信息 -->
  <view class="detail">
    <image class="img" mode="widthFix" src="/assets/images/floor-img.jpg" />
    <image class="img" mode="widthFix" src="/assets/images/floor-img.jpg" />
    <image class="img" mode="widthFix" src="/assets/images/floor-img.jpg" />
  </view>

  <!-- 商品的底部商品导航 -->
  <van-goods-action>
    <navigator url="/pages/index/index" open-type="switchTab">
      <van-goods-action-icon icon="wap-home-o" text="首页" />
    </navigator>
    <navigator url="/pages/cart/cart" open-type="switchTab">
      <van-goods-action-icon icon="cart-o" text="购物车" info="{{ allCount }}" />
    </navigator>
    <van-goods-action-icon
      open-type="contact"
      icon="chat-o"
      text="客服"
      bind:click="onClickIcon"
    />
    <van-goods-action-button text="加入购物车" type="warning" bindtap="handleAddcart" />
    <van-goods-action-button text="立即购买" bindtap="handeGotoBuy" />
  </van-goods-action>

  <!-- 加入购物车、立即购买弹框 -->
  <!-- show 控制弹框的隐藏和展示 -->
  <!-- bind:close 点击关闭弹框时触发的回调 -->
  <van-action-sheet show="{{ show }}" sh>
    <view class="sheet-wrapper">
      <view class="goods-item">
        <!-- 需要购买的商品图片 -->
        <view class="mid">
          <image class="img" src="/assets/images/floor-img.jpg" />
        </view>

        <!-- 商品基本信息 -->
        <view class="right">
          <!-- 商品名字 -->
          <view class="title"> 亲爱的/情人节网红款/19枝 </view>
          <!-- 商品价格 -->
          <view class="buy">
            <view class="price">
              <view class="symbol">¥</view>
              <view class="num">100</view>
            </view>

            <!-- 步进器组件控制购买数量 -->
            <view class="buy-btn">
              <!-- Stepper 步进器,由增加按钮、减少按钮和输入框组成,控制购买数量 -->
              <van-stepper value="{{ count }}" bind:change="onChangeGoodsCount" />
            </view>
          </view>
        </view>
      </view>

      <!-- 祝福语输入框 -->
      <view class="time-wraper">
        <view class="title">祝福语</view>
        <textarea
          model:value="{{ blessing }}"
          bindinput="onTextAreaChange"
          class="form-textarea"
          placeholder="必填,写上您的祝福语,给心爱的他(她)送上你的祝福(请勿填写特殊符号或表情符号)"
          name="textarea"
        />
      </view>

      <!-- 确定按钮 -->
      <view class="sheet-footer-btn">
        <van-button block type="primary" round> 确定 </van-button>
      </view>
    </view>
  </van-action-sheet>
</view>
css代码
/* pages/goods/detail/index.wxss */

.container {
  padding: 0rpx !important;
}

.goods-detail {
  margin-bottom: 100px;
}

// 商品大图
.banner-img {
  height: 800rpx;

  image {
    height: 100%;
  }
}

// 商品的基本信息
.content {
  margin: 0 16rpx;
  background: white;
  padding: 40rpx;
  position: relative;
  border-radius: 18rpx;
  top: -80px;
  height: 170rpx;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  overflow: hidden;

  .price {
    display: flex;

    .price-num {
      font-size: 18px;
      color: #fa4126;
      font-weight: bold;
    }

    .price-origin-num {
      font-size: 12px;
      color: #b4babf;
      margin-left: 4px;
      text-decoration: line-through;
      margin-top: 6px;
    }
  }

  .title {
    font-size: 16px;
    font-weight: bold;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .desc {
    font-size: 12px;
    color: #999999;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

// 详细图片
.detail {
  margin: -130rpx 16rpx 100rpx;
  background: white;
  padding: 20rpx 16rpx;
  border-radius: 16rpx;
}

// 加入购物车、立即购买弹框
.sheet-wrapper {
  padding: 16px;

  .sheet-footer-btn {
    padding: 16px;
  }
}

// 商品详情
.goods-item {
  display: flex;
  align-items: center;
  padding: 0 32rpx 40rpx 0;

  .left {
    width: 56px;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .mid {
    width: 114px;
    height: 125px;

    image {
      height: 100%;
    }
  }

  .right {
    height: 125px;
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    margin-left: 10px;

    .title {
      flex: 1;
      flex-shrink: 0;
      font-size: 28rpx;
      color: #333;
      line-height: 40rpx;
      font-weight: 400;
      display: -webkit-box;
      -webkit-box-orient: vertical;
      overflow: hidden;
      word-break: break-word;
    }

    .buy {
      display: flex;
      justify-content: space-between;

      .price {
        display: flex;
        /* align-items: flex-end; */
        color: #fa4126;
        font-size: 36rpx;

        .symbol {
          font-size: 10px;
          margin-right: 2px;
          margin-top: 8px;
        }
      }
    }
  }
}

// 祝福语
.time-wraper {
  margin-bottom: 12px;

  .title,
  .time {
    justify-content: space-between;
    font-size: 14px;
    color: #333333;
  }

  .form-textarea {
    border-radius: 12px;
    background-color: #f7f8fa;
    padding: 16px 12px;
    font-size: 13px;
    margin-top: 12px;
    width: 94%;
    height: 84px;
  }
}
页面总体分析

在代码片段中我结合微信小程序的原生能力与Vant Weapp UI库组件,构建一个包含商品展示、操作导航、数量选择、个性化留言等多功能的商品详情页面,实现了良好的用户体验和高效的开发流程。

2.效果图

4.订单页面

1.代码

js代码
// pages/order/list/index.js
Page({
  // 页面的初始数据
  data: {
    orderList: [1, 2, 3]
  }
})
html代码
<!--pages/order/list/index.wxml-->
<view class="order-container container">
  <view class="order-list" wx:if="{{ orderList.length > 0 }}">
    <view class="order-item" wx:for="{{ orderList }}" wx:key="index">
      <view class="order-item-header list-flex">
        <view class="orderno">订单号<text class="no">1679246470200</text></view>
        <view class="order-status">已支付</view>
      </view>
      <view class="goods-item list-flex">
        <view class="left">
          <image src="/assets/images/floor-img.jpg" mode="widthFix" class="img" />
        </view>
        <view class="mid">
          <view class="goods-name">不变的承诺</view>
          <view class="goods-blessing">不变的承诺</view>
        </view>
        <view class="right">
          <view class="goods-price">¥100</view>
          <view class="goods-count">x1</view>
        </view>
      </view>
      <view class="order-item-footer">
        <view class="total-amount list-flex">
          <text class="text">实付</text>
          <text class="price"><text>¥</text> 666</text>
        </view>
      </view>
    </view>
  </view>
  <van-empty wx:else description="还没有购买商品,快去购买吧~" />
</view>
css代码
/* pages/order/list/index.wxss */

.list-flex {
  display: flex;
}

.order-item {
  margin-top: 16rpx;
  padding: 24rpx 32rpx 24rpx;
  background-color: white;
  border-radius: 14rpx;

  &:first-child {
    margin: 0rpx;
  }

  .order-item-header {
    align-items: center;
    justify-content: space-between;
    margin-bottom: 24rpx;
  }
}

.orderno {
  font-size: 28rpx;
  font-weight: normal;
  color: #333333;
  display: flex;
  align-items: center;
  line-height: 40rpx;

  .no {
    margin-left: 6px;
  }
}

.order-status {
  font-size: 26rpx;
  line-height: 40rpx;
}

.order-active {
  color: #fa4126;
}

.goods-item {
  padding: 16rpx 0;

  .left {
    width: 176rpx;
    height: 176rpx;
    background: #333333;
  }

  .mid {
    flex: 1;
    margin: 0 12px;

    .goods-name {
      font-size: 28rpx;
      color: #333;
      line-height: 40rpx;
      font-weight: 400;
    }

    .goods-blessing {
      font-size: 24rpx;
      height: 32rpx;
      line-height: 32rpx;
      color: #999999;
      margin: 8rpx 0;
    }
  }

  .right {
    .goods-price {
      white-space: nowrap;
      color: #fa4126;
      font-size: 24rpx;
      line-height: 48rpx;
    }

    .goods-count {
      white-space: nowrap;
      order: 4;
      text-align: right;
      font-size: 24rpx;
      color: #999;
      margin: 20rpx 0 0 auto;
    }
  }
}

.order-item-footer {
  .total-amount {
    justify-content: flex-end;
    align-items: center;
  }

  .text {
    font-size: 28rpx;
    line-height: 40rpx;
    color: #333333;
    margin-right: 4px;
  }

  .price {
    font-size: 32rpx;
    color: #fa4126;
    font-weight: bold;

    text {
      font-weight: normal;
    }
  }
}
页面总体分析

这段代码是一个典型的订单列表展示页面,我利用条件渲染和列表循环展示了订单信息,同时通过Vant Weapp的组件增强了页面的实用性和美观度。页面设计考虑到了用户体验,既展现了必要的订单信息,也提供了友好的空状态提示,引导用户进行下一步操作。

2.效果图

5.通用模块的封装

1.1消息模块的封装

1.消息弹出框
App({
 
//页面显示生命周期函数,每打开页面就会调用一次
  onShow(){
    wx.showToast({
      title: '消息提示框',
      // 提示图标:默认成功(一个对勾)
      // error:(失败) loading(加载)  none(不显示图标)
      icon:'success',
      duration:2000,
      // 是否显示透明蒙层
      mask:true
 
 }
    })
        })
2.封装模块

1.在utils文件夹中新建一个extendApI.js文件,

2.创建⼀个 toast ⽅法对 wx.showToast() ⽅法进⾏封装,

3.使用箭头函数

// 普通函数
// function name(params){}
 
// 箭头函数
// name => (参数) {函数体}
 
// toast = ( { 默认参数 } = {实际参数}) => {函数体}
 
// ()里为参数
// ()等号左边为函数toast默认的参数
// ()等号右边为调用函数toast传入的参数
const toast = ({title="消息提示框",icon='success',duration=2000,mask=true} = {}) => {
  wx.showToast({
    title,
    icon,
    duration,
    mask
  })
}
// 局部暴露toast方法
export{ toast }
 
// 全局挂载方法
wx.toast = toast

第一步在appj上创建一个 toast 方法对 wx·&hgwTa&&.()方法进行封装对象中包含 title、icon、dur ation、mask 参数,并给参数设置默认值。

    // wx:showToast({
    //   title: "消息提示框",
    //   // success(成功)、error(失败)、loading(加载)、none(不显示图标)
    //   icon:'success',
    //   duration:2000,
    //   // 是否显示透明蒙层
    //   mask:true
    // })

duration:是否显出透明蒙层

局部导入又分为不传入参数导入和传入参数导入

不传入参数导入

   // 不计入参数的局部导入
    // toast()

不传入参数就会一直成功,不传递参数,使用默认参值。

传入参数导入

传入参数的局部导入
    // toast({title:'数据加载完毕'})

传入部分参数,覆盖默认的参数

不传入参数的全局挂载方法wx. toast()

 传入全局参数的挂载方法

    // wx.toast({icon:'none'})

3.在app.js中调用
import { modal } from '/utils/extendApi'

1.2 模块对话框封装

1 // exendApi.js
2  
3 // function toast () {}
4  
5 // 在调⽤modal⽅法时,可以传递参数,也可以不传递参数。
6 // 如果不传递参数,默认值就是空对象。
7 // 如果传递参数,参数需要时⼀个对象,对象中的属性需要和wx.showModal参数保持⼀致。
8 const modal = (options = {}) => {
9 // 在⽅法内部需要通过Promise返回⽤户的操作
10 // 如果⽤户点击了确认,需要通过resolve返回true
11 // 如果⽤户点击了取消,需要通过resolve返回false
12  
13 return new Promise((resolve) => {
14 // 默认的参数
15 const defaultOpt = {
16 title: '提示', // 提示的标题
17 content: '您确定执⾏该操作吗?', // 提示的内容
18 confirmColor: '#f3514f',
19 // 接⼝调⽤结束的回调函数(调⽤成功、失败都会执⾏)
20 complete({ confirm, cancel }) {
21 confirm && console.log('点击了确定')
22 cancel && console.log('点击了取消')
23 }
24 }
25  
26 // 通过object.assgin⽅法将参数进⾏合并
27 // 需要使⽤传⼊的参数覆盖默认的参数
28 // 为了不影响默认的参数,需要将合并以后的参数赋值给⼀个空对象
29 const opts = Object.assign({}, defaultOpt, options)
30  
31 wx.showModal({32 // 将合并以后的参数通过展开运算符赋值给wx.showModal对象
33 ...opts,
34 complete({ confirm, cancel }) {
35 // 如果⽤户点击了确定,通过 resolve 抛出 true
36 // 如果⽤户点击了取消,通过 resolve 抛出 false
37 confirm && resolve(true)
38 cancel && resolve(false)
39 }
40 })
41 })
42 }
43  
44 export { modal }
45  
46 wx.modal = modal
47  
1 // app.js
2  
3 // app.js
4 // import { toast } from './utils/extendApi'
5 import './utils/extendApi'
6  
7 App({
8 // ⻚⾯显示⽣命周期函数
9 async onShow() {
10  
11 // wx.showModal({
12 // title: '提示', // 提示的标题
13 // content: '您确定执⾏该操作吗?', // 提示的内容
14 // confirmColor: '#f3514f',
15 // // 接⼝调⽤结束的回调函数(调⽤成功、失败都会执⾏)
16 // complete({ confirm, cancel }) {
17 // confirm && console.log('点击了确定')
18 // cancel && console.log('点击了取消')
19 // }
20 // })在⼩程序中,经常需要将⼀些数据存储到本地,⽅便多个⻚⾯的读取使⽤,例如:将⽤户的登录状
态、⽤户的个⼈信息存储到本地。
⼩程序提供了同步、异步两类 API 来实现本地存储操作。例如: wx.setStorageSync 、 wx.setStorage
等⽅法。
21  
22 // 不传⼊参数
23 // const res = await wx.modal()
24  
25 // 传⼊参数
26 const res = await wx.modal({
27 title:'新的提示',
28 showCancel:false
29 })
30  
31 console.log(res);
32 
33 }
34  
35 })
// 再调用modal方法是,可以传递参数,也可以不传递参数
// 如果不传递参数,默认值就是空对象
// 如果传递参数,参数需要是一个对象,对象中的属性需要和wxwx.showModal参数保持一致
const modal = (options = {}) => {
  // 通过new关键字构建一个promise对象
  // 在方法内部通过promise返回用户的操作
  // resolve为用户点击确认框的结果
  return new Promise((resolve) => {
    // 用户使用model函数时,使用showModal的默认参数
    const defaultOpt = {
      title:'提示',
      content:'你确定要执行该操作吗',
      confirmColor:'#f2514f',
      // 接口调用结束后的回调函数
      complete({confirm,cancel}){
        confirm && console.log('点击了确定');
        cancel && console.log('点击了取消');
      }
    }
    // Object.assign()方法用于将对象复制到目标对象
    // 通过Object.assign()方法将参数合并
    // 如果用户传递进来了options,就会覆盖默认参数
    // 第一个空对象参数会被赋值合并后的参数
    const opts = Object.assign({},defaultOpt,options)
 
    wx.showModal({
      // ...扩展运算符
      // 将合并后的参数通过展开运算符赋值给wx.showModal对象。
      ...opts,
      complete({confirm,cancel}){
        // 如果用户点击了确认,通过resolve抛出true
        confirm && console.log('点击了确定');
        // 如果用户点击了取消,通过resolve抛出false
        cancel && console.log("点击了取消");
      }
    })
  })
}
// 局部暴露modal方法
export{ modal }

当我们在调用modal方法时,可以传递参数,也可以不传递参数
如果不传递参数,默认值就是空对象如果传递参数,参数需要是一个对象,对象中的属性需要和wx,showModal参数保持一致通过new关键字构建-个promise对象在方法内部通关promise返回用户的操作
resolve为用户点击确认框的结果
日户使用modal函数时,使用showModal的默认参数
Dbiect.assiqn0方法用于将对象复制到目标对象。
通过Obiect.assiqn0方法将参数合并
如果用户传递进来了options,就会覆盖默认参数
局部暴露:先在extendApi.js中暴露modal,然后在appjs中使用import引入modal,最后在onShow()中写入modal0)完成局部暴露

全局暴露:先在extendApijs中完成全局挂载,然后在app,js中的onShow0)中写入wx.modal0)完成全局暴露
 

1.3封装本地存储 API

我们在 utils ⽬录下新建 storage.js ⽂件 在该⽂件中,封装对本地数据进⾏ 存储、获取、删除、清除的⽅法

// wx.setStorage(option)是微信小程序存储数据的api
// setStorage()是自定义函数
 
// key 本地存储中的变量名
// value 变量名对应的变量值
 
// 以同步方法存储数据
export const setStorage = (key,value) => {
  try {
    wx.setStorageSync(key,value)
  }catch (error){
    console.log("存储失败");
  }
}
// 以同步方法获取数据
export const getStorage = (key) => {
  try{
    const value = wx.getStorageSync(key)
    if(value){
      return value
    }
  }catch (error){
    console.log("存储失败");
  }
}
// 删除数据
export const removeStorage = (key) => {
  try {
    wx.removeStorageSync(key)
  }catch(e){
    console.log("删除失败");
  }
}
// 删除全部数据
export const clearStorage = () => {
  try{
    wx.clearStorageSync()
  }catch(e){
    console.log("清除失败");
  }
}

6.网络请求封装

1.1请求封装-request⽅法

1.request⽅法封装
// 1.使用了微信自带的请求api wx.request
// 2.将wx.request封装到了一个名为request的函数中
// 3.将函数封装到了一个名为wxRequest的类中
 
// 创建一个WxRequest类
// 通过类的方式进行封装,会让代码更具有复用性
// 也可以方便添加新的属性和方法
 
class WxRequest{
// 用于创建和初始化类的属性和方法
constructor(){}
// request实例方法接受一个对象类型的参数
request(options){
return new Promise((resolve,reject) => {
wx.request({
        // 使用拓展运算符将request函数传来的对象参数展开
        ...options,
        // 当接口调用成功就会触发success回调函数
        success:(res) => {
resolve(res)
},
//当接口调用失败时会触发fail回调函数
fail:(err)=>{
reject(err)
}
})
})
}
}
//对wxRequest进行实例化
const instance = new WxRequest()
//将WxRequest实例暴露出去,方便在其他文件中进行使用
export default instance





// 导入在request页面中封装并暴露的instance实例
import instance from '../../utils/http'
// pages/test/test.js
Page({
// 具体阐述按钮点击事件要做什么事情
async handler(){
  //  第一种调用方法:通过.then和.catch接受返回的值
//    instance
//    .request({
//     //  请求地址
//     url:'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
//     // 请求方式
//     method:"GET"
//    })
//    .then((res) => {
//      console.log(res);
//    })
//    .catch((err) => {
//      console.log(err);
//    })
 
// 第二种调用方法:通过await和async接受返回的值
  // const res = await instance.request({
  //   url:'/index/findBanner',
  //   method:"GET"
  // })
 
  // 第三种调用方式:通过调用快捷方式接受返回的值
  // const res = await instance.get('/index/findBanner')
 
  // 调用并传参
  // const res = await instance.get('/index/findBanner',{test:111},
  // {timeout:20000})
 
  //当前请求地址是获取购物车数据,需要token才行
  const res = await instance.get('/cart/getCartList')
 
  console.log(res);
 },
})





/* pages/test/test.wxss */
.box{
  display: flex;
  // 主轴方向上居中
  justify-content: center;
  //  副轴方向上居中
  align-items: center;
  // 将盒子高度设置为页面高度
  height: 100vh;
}





<!--pages/test/test.wxml-->
<!-- <text>pages/test/test.wxml</text> -->
<view class="box">
<!-- 设置一个按钮 并给按钮设置一个名为handler的点击事件 点击按钮则会发送请求 -->
  <button type="warn" size="mini" plain bindtap="handler">测试发送请求</button>
</view>

 1.2请求封装-设置请求参数

1.创建一个WxRequest类,通过类的方式进行封装 会让代码更具有复用性,也可以方便添加新的属性和方法。
2.通过WxRequest来设定默认参数对象,请求基地址,服务器接口地址,请求方式、参数和请求头,设置数据的交互格式并且设置默认超时时间。
3.定义拦截对象包括请求拦截和响应拦截方法,方便在请求或响应之前进行处理。请求拦截器:request,响应拦截器:response
4.创建params为用户传入的请求配置项,使用Object.assign方法合并默认参数以及传递的请求参数,需要传入的参数,会覆盖默认的参数,因此传入的参数放在最后。
5.request需要接受一个对象类型的参数, 拼接完整的请求路径options.url,合并请求参数options  ={...this.defaults,...options},在发送请求之前调用请求拦截器options = this.interceptors.request(options)
6.   使用拓展运算符将request函数传来的对象参数展开 ...options, 当接口调用成功就会触发success回调函数。
不管接口成功还是失败,都需要调用响应拦截器;响应拦截器需要接受服务器响应的数据,然后对数据进行逻辑处理,处理好后进行返回;在给响应拦截器传递参数时 需要将请求参数也一起上传;方便进行代码的调式或者其他逻辑处理,所以需要合并数据;然后将合并的参数给响应拦截器。
当接口调用失败时会触发fail回调函数
7.第一个参数:需要合并的目标对象;第二个参数:服务器响应的数据;第三个参数:请求配置以及自定义属性
8.GET POST PUT DELETE四个封装方法
9.对WxRequest进行实例化
10.配置请求拦截器并且发送请求;响应拦截器了解发送前需要做什么
11.将WxRequest实例暴露出去 方便在其他文件中进行使用 export default instance

 1.3封装请求快捷⽅法

⽬前已经完成了 request() 请求⽅法的封装,同时处理了请求参数。 每次发送请求时都使⽤ request() ⽅法即可,但是项⽬中的接⼝地址有很多,不是很简洁。所以我们在 request() 基础上封装⼀些快捷⽅法,简化 request() 的调⽤。

 // 封装GET方法
  get(url,data={},config={}){
    return this.request(Object.assign({url,data,method:'GET',config}))
  }
  // 封装POST实例方法
  post(url,data={},config={}){
    return this.request(Object.assign({url,data,method:'POST',config}))
  }
  // 封装PUT方法
  put(url,data={},config={}){
    return this.request(Object.assign({url,data,method:'PUT',config}))
  }
  // 封装DELETE方法
  delete(url,data={},config={}){
    return this.request(Object.assign({url,data,method:'DELETE',config}))
  }
// 对类进行实例化
const instance = new WxRequest({
  baseURL: 'https://gmall-prod.atguigu.cn/mall-api',
  timeout: 15000
})
// 将 WxRequest 实例进⾏暴露出去,⽅便在其他⽂件中进⾏使⽤
export default instance






// 导入在request页面中封装并暴露的instance实例
import instance from '../../utils/http'
// pages/test/test.js
Page({
// 具体阐述按钮点击事件要做什么事情
async handler(){
  //  第一种调用方法:通过.then和.catch接受返回的值
//    instance
//    .request({
//     //  请求地址
//     url:'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
//     // 请求方式
//     method:"GET"
//    })
//    .then((res) => {
//      console.log(res);
//    })
//    .catch((err) => {
//      console.log(err);
//    })
 
// 第二种调用方法:通过await和async接受返回的值
  // const res = await instance.request({
  //   url:'/index/findBanner',
  //   method:"GET"
  // })
 
  // 第三种调用方式:通过调用快捷方式接受返回的值
  // const res = await instance.get('/index/findBanner')
 
  // 调用并传参
  // const res = await instance.get('/index/findBanner',{test:111},
  // {timeout:20000})
 
  //当前请求地址是获取购物车数据,需要token才行
  const res = await instance.get('/cart/getCartList')
 
  console.log(res);
 },
}

1.4 定义请求/响应拦截器

为了⽅便统⼀处理请求参数以及服务器响应结果,为 WxRequest 添加拦截器功能,拦截器包括 请求 拦截器 和 响应拦截器

请求拦截器本质上是在请求之前调⽤的函数,⽤来对请求参数进⾏新增和修改

响应拦截器本质上是在响应之后调⽤的函数,⽤来对响应数据做点什么

// 1.使用了微信自带的请求api wx.request
// 2.将wx.request封装到了一个名为request的函数中
// 3.将函数封装到了一个名为wxRequest的类中
 
// 创建一个WxRequest类
// 通过类的方式进行封装,会让代码更具有复用性
// 也可以方便添加新的属性和方法
 
class WxRequest{
  // 默认参数对象
  defaults = {
    // 请求基地址
    baseURL:'',
    // 服务器接口地址
    url:'',
    // 请求方式
    method:'GET',
    // 请求参数
    data:null,
    // 请求头
    header: {
    'Content-type': 'application/json' // 设置数据的交互格式
    },
    // 默认超时时间为一分钟
    timeout:100
  }
 
  // 定义拦截对象,包括请求拦截和响应拦截,方便在请求或响应之前进行处理
  interceptors = {
    // 请求拦截
    request:(config) => config,
    // 响应拦截
    response:(response) => response
  }
 
  // 用于创建和初始化类的属性和方法
  // params为用户传入的请求配置项
  constructor(params = {}){
    // 使用Object.assign方法合并默认参数以及传递的请求参数
    // 需要传入的参数,会覆盖默认的参数,因此传入的参数放在最后
    this.defaults = Object.assign({},this.defaults,params)
  }
  // request实例方法接受一个对象类型方法
  request(options){
    // 拼接完整的请求路径
    options.url = this.defaults.baseURL + options.url
    // 合并请求参数
    options = {...this.defaults,...options}
    // 发送请求之前添加loading
    wx.showLoading({})
    // 在发送请求之前调用请求拦截器
    options = this.interceptors.request(options)
 
    console.log(options);
    return new Promise((resolve,reject) => {
      wx.request({
        // 使用拓展运算符将request函数传来的对象参数展开
        ...options,
        // 当接口调用成功就会触发success回调函数
        success:(res) => {
 
          // 不管接口成功还是失败,都需要调用响应拦截器
          // 响应拦截器需要接受服务器响应的数据,然后对数据进行逻辑处理,处理好后进行返回
          //  在响应拦截器传递参数时,需要将请求参数也一起上传
          // 方便进行代码的调试或者其他逻辑处理,所以需要合并参数
          // 然后将合并的参数给响应拦截器
          // 第一个参数:需要合并的目标对象
          // 第二个参数:服务器响应的数据
          // 第三个参数:请求配置以及自定义属性
          // 不管是请求失败还是请求成功,都会将响应的数据传递给响应拦截器
          // 这个时候合并参数时,就需要追加一个属性:isSuccess
          // 如果属性值为true说明执行了success回调函数
          const mergetRes = Object.assign({},res,{config:options,isSuccess:true})
          // resolve(res)
          resolve(this.interceptors.response(mergetRes))
        },
        // 当接口调用失败就会触发fail回调函数
        fail:(err) => {
          // 如果属性值为false,说明执行了fail回调函数
          const mergetErr = Object.assign({},err,{config:options,isSuccess:false})
          // reject(err)
          reject(this.interceptors.response(mergetErr))
        },
        // 不管promisse请求是否成功
        // 都会执行complete里面的内容
        complete:()=>{
          // 接口调用完成后隐藏loading
          wx.hideLoading()
        }
      })
    })
  }
  // 封装GET方法
  get(url,data={},config={}){
    return this.request(Object.assign({url,data,method:'GET',config}))
  }
  // 封装POST实例方法
  post(url,data={},config={}){
    return this.request(Object.assign({url,data,method:'POST',config}))
  }
  // 封装PUT方法
  put(url,data={},config={}){
    return this.request(Object.assign({url,data,method:'PUT',config}))
  }
  // 封装DELETE方法
  delete(url,data={},config={}){
    return this.request(Object.assign({url,data,method:'DELETE',config}))
  }
 
}
export default WxRequest

1.5完善请求/响应拦截器

在响应拦截器,我们需要判断是请求成功,还是请求失败,然后进⾏不同的业务逻辑处理。 例如:请求成功以后将数据简化返回,⽹络出现异常则给⽤户进⾏⽹络异常提示。 ⽬前不管请求成功 (success),还是请求失败(fail),都会执⾏响应拦截器 那么怎么判断是请求成功,还是请求失败呢 ?

 1.6使⽤请求/响应拦截器

使⽤响应拦截器: 在使⽤ wx.request 发送⽹络请求时。只要成功接收到服务器返回,⽆论 statusCode 是多少,都会进 ⼊ success 回调。 因此开发者根据业务逻辑对返回值进⾏判断。

11 // 响应拦截器
12 instance.interceptors.response = async (response) => {
13  
14 console.log(response);
15  
16 // 从response中结构isSuccess
17 // const { isSuccess } = response
18 const { isSuccess, data } = response
1.
2.
3.19  
20 // 如果isSuccess为false,说明执⾏了fail回调函数
21 // 这时候说明⽹络异常,需要给⽤户提示⽹络异常
22 if (!isSuccess) {
23 wx.showToast({
24 title: '⽹络异常请重试',
25 icon: 'error'
26 })
27  
28 return response
29 }
30  
31 // 判断服务器响应的业务状态码
32 switch(data.code){
33  
34 // 如果后端返回的业务状态码等于200,说明请求成功,服务器成功响应了数据
35 case 200:
36 // 对服务器响应数据做点什么
37 return data
38  
39 // 如果返回的业务状态码等于208,说明没有token,或者token失效
40 // 就需要让⽤户登录或者重新登录
41 case 208:
42 const res = await modal({
43 content:'鉴权失败,请重新登录',
44 showCancel:false // 不显示取消按钮
45 })
46 if(res){
47 // 清除之前失效的token,同时要清除本地存储的全部信息
48 clearStorage()
49 wx.navigateTo({
50 url: '/pages/login/login',
51 })
52 }
53 return Promise.reject(response)
54 
55 default:
56 toast({
57 title:'程序出现异常,请联系客服或稍后重试'
58 })
59 return Promise.reject(response)
60 }
61  
62 // 对响应数据做点什么
63 // return response
64 // return data
65 }
66  
67 // 将 WxRequest 的实例通过模块化的⽅式暴露出去
68 export default instance

  • 20
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快习中学乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值