优购项目

358 阅读2分钟

优购项目准备

image.png

image.png

image.png

首页

配置顶部文字和样式

image.png

封装搜索组件

这不是一个真正可以输入的搜索框, 仅仅是样式而已

<template>
  <view class="searchBox">
    <view class="input">搜索</view>
  </view>
</template><script>
  export default {};
</script><style lang="scss" scoped>
.searchBox {
    height: 100rpx;
    background-color: #eb4450;
    display: flex;
    justify-content: center;
    align-items: center;
    .input {
        width: 700rpx;
        height: 80rpx;
    line-height: 80rpx;
        background-color: #fff;
        border-radius: 5rpx;
        color: #767676;
        font-size: 32rpx;
    text-align: center;
    }
}
</style>

轮播图

image.png

分类导航

image.png

image.png

异步请求封装说明

其实使用的是 uview 组件库为我们封装的函数 $u.get

然后进行全局设定

image.png

分类页

静态左右布局

左右独立滚动

<template>
  <view class="page">
    <!-- 搜索 -->
    <YgSearch />
    <!-- 主要内容 -->
    <view class="catBox">
      <view class="left">
        <view class="leftItem">6666</view>
        <view class="leftItem">6666</view>
        <view class="leftItem">6666</view>
        <view class="leftItem">6666</view>
      </view>
      <view class="right">
        <view class="rightItem">999</view>
        <view class="rightItem">999</view>
        <view class="rightItem">999</view>
        <view class="rightItem">999</view>
        <view class="rightItem">999</view>
        <view class="rightItem">999</view>
        <view class="rightItem">999</view>
        <view class="rightItem">999</view>
      </view>
    </view>
  </view>
</template><script>
  export default {};
</script><style lang="scss" scoped>
  .page {
    display: flex;
    flex-direction: column;
    height: 100vh;
    .catBox {
      width: 100%;
      flex: 1;
      display: flex;
      overflow: hidden;
      .left {
        width: 182rpx;
        overflow: auto;
      }
      .right {
        flex: 1;
        overflow: auto;
      }
    }
  }
</style>

获取数据

image.png

左侧第一层菜单

image.png

右侧二级菜单独立组件

<template>
  <view>
    <view class="mainTitle"> / {{data.cat_name}} / </view>
    <view class="list">
      <!-- 这里再次遍历就是第三层的具体分类了 -->
      <view class="item" v-for="item in data.children" :key="item.cat_id">
        <image
          class="img"
          :src="item.cat_icon"
          mode="scaleToFill"
        />
        <view class="title">
          {{item.cat_name}}
        </view>
      </view>
    </view>
  </view>
</template><script>
export default {
  props: {
    data: {
      type: Object,
      required: true
    }
  }
}
</script><style lang="scss" scoped>
.mainTitle {
  font-size: 26rpx;
  color: #575757;
  text-align: center;
  margin-top: 50rpx;
}
.list {
  display: flex;
  flex-wrap: wrap;
  .item {
    width: 33.33%;
    text-align: center;
    .img {
      width: 120rpx;
      height: 120rpx;
    }
  }
}
</style>

点击切换分类

image.png

切换时没有退回顶部的bug

image.png

image.png

渲染优化

原理

  1. 小程序底层的 setData 应该只包含必要的数据, 不然可能影响渲染性能
  2. uniapp 当中 绑定在 data 当中的数据 其实都出发了 setData
  3. 所以不是非要渲染的内容, 应该尽可能不要放入 data 当中

image.png

商品列表页

创建页面跳转并传参

image.png

image.png

tabs uViewUi 版

image.png

商品列表页

数据获取

以下代码只包含必要部分

export default {
  components: {Tabs},
  data() {
    return {
      prodList: []
    }
  },
  onLoad(options) {
    // 定好发送请求的参数
    this.pageConfig = {
      // 本来应该是跳转时传入id
      // 但是测试的时候由于没有跳转, 可以设定一个默认值
      cid: options.cat_id || 5,
      pagenum: 1,
      pagesize: 10
    }
    // 真正发送请求
    this.loadPage()
  },
  methods: {
    async loadPage() {
      const {message} = await this.$u.get('/goods/search', this.pageConfig)
      this.prodList = message.goods
    }
  }
}

布局渲染

image.png

image.png

滚动到底加载下一页

image.png

image.png

下拉刷新

image.png

商品详情页

创建页面带上id跳转

image.png

获取数据

image.png

显示轮播图

image.png

点击显示轮播图预览

image.png

价格和标题之类的主要信息

image.png

image.png

商品详情

image.png

底部工具条布局

办法一直接参考模板

image.png

办法二手写

image.png

image.png

封装储存购物车数据和添加的功能

image.png

image.png

商品详情底部购物车数量

image.png

数据持久化

js 普通数据赋值, 其实刷新就会重置

数据持久化其实逻辑就是两个

  1. 数据发生变化, 存起来做备份 (存在刷新都不会丢失的本地储存当中)
  2. 每当页面刷新, 优先使用本地数据

image.png

产品选中状态切换

image.png

更改产品数量

image.png

如果数量等于一,再次点击二次询问

image.png

删除商品

image.png

购物车续

底部布局和样式

image.png

.submitBar {
    position: fixed;
    bottom: 0;
    left: 0;
    background-color: #fff;
    border-top: 1rpx solid #ddd;
    width: 100%;
    height: 83rpx;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 23rpx;
    .priceBox {
        flex: 1;
        font-size: 26rpx;
        color: #292929;
        .price {
            color: #eb4450;
            font-size: 28rpx;
            margin-left: 6rpx;
        }
    }
    .btn {
        padding: 0 26rpx;
        line-height: 52rpx;
        background-color: #eb4450;
        color: #fff;
        border-radius: 26rpx;
    }
}

底部数据渲染

image.png

image.png

辅助函数简化

image.png

全选功能

被动显示

image.png

主动变更

image.png

主动变更简化写法

image.png

空状态优化

没有商品时, 全选状态应为 false

默认显示空状态图标

image.png

数据持久化统一封装

image.png

结算页

创建页面配置路由和跳转

image.png

image.png

地址基本布局

image.png

image.png

获取地址信息

image.png

注意有可能包隐私权限错误, 可以通过修改 manifest.json

image.png

产品渲染

image.png

.list {
  background: #fff;
  padding-bottom: 100rpx;
  .mainTitle{
    font-size: 26rpx;
    color: #434343;
    padding: 26rpx;
  }
  .item {
    display: flex;
    .img {
      width: 191rpx;
      height: 191rpx;
    }
    .info {
      flex: 1;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      padding: 16rpx;
      .bottom {
        display: flex;
        justify-content: space-between;
        .price {
          color: #eb4450;
        }
      }
    }
  }
}

底部工具栏

    <view class="submitBar">
      <view class="price">合计 <text class="number">¥{{totalPrice}}</text></view>
      <view class="btn" :class="{disable: !address}">去支付({{totalType}})</view>
    </view>
.submitBar {
  border-top: 1rpx solid #ccc;
  position: fixed;
  background-color: #fff;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 83rpx;
​
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 28rpx;
​
  .price {
    .number {
      color: #eb4450;
      margin-left: 20rpx;
    }
  }
  .btn {
    color: #fff;
    background-color: #eb4450;
    line-height: 52rpx;
    padding: 0 26rpx;
    border-radius: 26rpx;
    font-size: 24rpx;
  }
​
  .disable {
    background-color: #888;
  }
}