附录6-4 黑马优购项目-分类和购物车

2024-05-03 12:12

本文主要是介绍附录6-4 黑马优购项目-分类和购物车,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1  分类

1.1  接口

1.2  窗口限制

1.3  选中状态样式判断

1.4  点击左侧时右侧会到顶点

1.5  源码 

2  购物车

2.1  store

2.2  tabBar徽标

2.3  滑动删除

2.4  结算

2.4.1  结算前登录

2.4.2  结算功能

2.5  触发组件事件

2.6  源码


1  分类

分类最上部是搜索区域,与首页的搜索区域相同,这里直接复用

右侧区域的内容 会根据点击不同左侧区域 而变化

左侧区域和右侧区域均可以向下滚动

滚动后切换到别的页面,然后再切换回来,滚动的位置不变(记录位置是scroll-view的默认效果,不用额外进行修改)

1.1  接口

接口中包含三级标题。紫色框子是一级标题,橙色框子是二级标题,绿色框子是三级标题

url是https://api-hmugo-web.itheima.net/api/public/v1/categories 直接发get请求就行了

1.2  窗口限制

分类页面的最外层只有两个部分,一个是搜索框,除了搜索框剩下都属于另外一部分。为了让左侧和右侧都有拖动了效果,所以这里对高度进行了限制

如果取消高度限制,页面中的scroll-view-container就废了,左侧和右侧就会同时进行拖动

限制高度的值根据机型进行调节,wx.getWindowInfo()可以获得当前机型的高度,减50是减去屏幕最下方的tarbar高度。高度在页面初次加载的时候就进行计算

1.3  选中状态样式判断

左侧列表被选中后会有这个红色的部分

每次点击左侧列表会记录left_active_num,讲left_active_num与循环时的index进行比对,如果相同的多给一个active的类名

1.4  点击左侧时右侧会到顶点

每一次点击左侧的时候,右侧的内容是不同的,但实际上元素都是一个。所以点击左侧时,右侧不会默认回到顶点

这里用变量的原因是给0这个常量第二次就懒加载了,只能点击左侧之后每次都赋值一个新的0

1.5  源码 

wxml

<!--pages/category/category.wxml-->
<black_horse_search></black_horse_search>
<view class="scroll-view-container" style="height:{{windowHeight}};">
<!-- <view class="scroll-view-container" style="height:200px;"> --><!-- 左侧滚动区域 --><scroll-view class="left-scroll-view" scroll-y="true"><view  wx:for="{{cateList}}" wx:key="cat_id" class="{{['scroll-view-item',index==left_active_num?'active':'']}}" bindtap="left_scroll_click" data-click_item_index="{{index}}">{{item.cat_name}}</view></scroll-view><!-- 右侧滚动区域 --><!-- 老版本的scroll-top不能给相同的值,也就是你一直给0是不行的 --><scroll-view class="right-scroll-view" scroll-y="true" scroll-top="{{right_scrollTop}}"><view class="cate-lv2" wx:for="{{cateLevel2}}" wx:key="index"><view class="cate-lv2-title">/ {{item.cat_name}} /</view><view class="cate-lv3-list"><view class="cate-lv3-item" wx:for="{{item.children}}" wx:for-index="index3" wx:for-item="item3" wx:key="index3" bindtap="cate_lv3_item_click" data-cat_name="{{item3.cat_name}}" data-cat_id="{{item3.cat_id}}"><image src="{{item3.cat_icon}}" mode="" data-cat_name="{{item3.cat_name}}" data-cat_id="{{item3.cat_id}}"/><text data-cat_name="{{item3.cat_name}}" data-cat_id="{{item3.cat_id}}" >{{item3.cat_name}}</text></view></view></view></scroll-view>
</view>

wxss

/* pages/category/category.wxss */
.scroll-view-container {display: flex;
}.scroll-view-container .left-scroll-view {width: 120px;
}.scroll-view-container .left-scroll-view .scroll-view-item.active {position: relative;background-color: #ffffff;
}.scroll-view-container .left-scroll-view .scroll-view-item.active::before {position:absolute;top:50%;left:0;content:' ';display:block;width: 3px;height:30px;background-color: #C00000;transform: translateY(-50%);
}.scroll-view-container .left-scroll-view .scroll-view-item {background-color: #f7f7f7;line-height: 60px;text-align: center;font-size: 12px;
}.cate-lv2-title {font-size:12px;font-weight:bold;text-align: center;padding: 15px 0;
}.cate-lv3-list {display:flex;flex-wrap:wrap
}.cate-lv3-list .cate-lv3-item {width:33.33%;display:flex;flex-direction:column;justify-content: center;align-items: center;margin-bottom:10px;
}.cate-lv3-list .cate-lv3-item image{width:60px;height:60px;
}.cate-lv3-list .cate-lv3-item text{font-size:12px;
}

js

// pages/category/category.js
import {createStoreBindings} from 'mobx-miniprogram-bindings'
import {store} from '../../store/store.js'const App = getApp()Page({cate_lv3_item_click(e) {wx.navigateTo({url:'/subpackage_goods_list/goods_list?cid=' + e.target.dataset.cat_id + '&&query=' + e.target.dataset.cat_name})},left_scroll_click(e) {const click_item_index = e.target.dataset.click_item_indexthis.setData({left_active_num:click_item_index})this.setData({cateLevel2:this.data.cateList[Number(click_item_index)].children})this.setData({right_scrollTop:0})},get_cateList() {wx.request({url:App.base_url + '/api/public/v1/categories',method:'GET',success:(val) => {// 获取所有分类this.setData({cateList:val.data.message})// 获取二级分类,二级分类的内容在一级分类中有,我们在这里弄好处理,这里给一个初始值,后面在左侧点击事件中还会再改this.setData({cateLevel2:val.data.message[0].children})},fail:() => {console.log('获取左侧失败')wx.showToast({title:'获取左侧失败',icon:'error',duration:2000})}})},/*** 页面的初始数据*/data: {windowHeight:0 + 'px',cateList:[],cateLevel2:[],left_active_num:0,right_scrollTop:0},/*** 生命周期函数--监听页面加载*/onLoad(options) {this.storeBindings = createStoreBindings(this,{store,actions:['set_cart_tabBar_badge']})this.setData({windowHeight:(wx.getWindowInfo().windowHeight-50) + 'px'})},/*** 生命周期函数--监听页面初次渲染完成*/onReady() {// 获取分类列表this.get_cateList()// 设置购物车tabBar的徽标this.set_cart_tabBar_badge()},/*** 生命周期函数--监听页面显示*/onShow() {},/*** 生命周期函数--监听页面隐藏*/onHide() {},/*** 生命周期函数--监听页面卸载*/onUnload() {},/*** 页面相关事件处理函数--监听用户下拉动作*/onPullDownRefresh() {},/*** 页面上拉触底事件的处理函数*/onReachBottom() {},/*** 用户点击右上角分享*/onShareAppMessage() {}
})

2  购物车

购物车中的内容在这个项目中都是放在本地的,在实际开发中一般是放在云端

购物车为空时会显示这个页面

2.1  store

store.js是放全局变量的js文件,创建方法可以参考 18.全局数据共享 mobx-miniprogram与mobx-miniprogram-bindings-CSDN博客

源码

import {action,observable
} from 'mobx-miniprogram'export const store = observable({// 购物车总数的计算属性// 计算购物车一共多少件get cart_shop_total() {let total = 0this.cart_list.forEach(goods => total += goods.goods_count)return total},// 计算购物车选中的一共多少钱get cart_shop_choosed_total_price() {let total_price = 0this.cart_list.forEach(goods => {if (goods.goods_state == true) {total_price = total_price + goods.goods_count * goods.goods_price}})return total_price.toFixed(2)},// 计算购物车选中的一共多少件get cart_shop_choosed_total_num() {let total_num = 0this.cart_list.forEach(goods => {if (goods.goods_state == true) {total_num = total_num + goods.goods_count}})return total_num},// 计算是否全选get is_all_checked() {let all_checked = truethis.cart_list.forEach(goods => {if (goods.goods_state == false) {all_checked = false}})return all_checked},// 从本地存储中获取购物车商品信息cart_list: wx.getStorageSync('cart_list') || [],// 添加购物车方法add_cart_obj: action(function (goods_obj) {let findResult = this.cart_list.find((x) => x.goods_id === goods_obj.goods_id)if (!findResult) {this.cart_list = [...this.cart_list, goods_obj]} else {findResult.goods_count++}wx.setStorageSync('cart_list', this.cart_list)}),// 设置购物车tabBar的徽标set_cart_tabBar_badge:action(function() {wx.setTabBarBadge({index: 2,text: String(this.cart_shop_total),})}),// 改变购物车商品所有选中状态updateAllGoodsState:action(function(all_checked_now_state) {this.cart_list.forEach(goods => {goods.goods_state = !all_checked_now_state})let new_cart_list = JSON.stringify(this.cart_list)this.cart_list = JSON.parse(new_cart_list)wx.setStorageSync('cart_list', this.cart_list)}),// 改变购物车商品选中状态updateGoodsState:action(function(goods) {let findResult = this.cart_list.find(x=>x.goods_id === goods.goods_id)if (findResult) {findResult.goods_state = !goods.goods_statuslet new_cart_list = JSON.stringify(this.cart_list)this.cart_list = JSON.parse(new_cart_list)}wx.setStorageSync('cart_list', this.cart_list)}),// 购物车商品数量 + 1add_one_GoodsNum:action(function(goods) {let findResult = this.cart_list.find(x=>x.goods_id === goods.goods_id)if (findResult) {findResult.goods_count = findResult.goods_count + 1let new_cart_list = JSON.stringify(this.cart_list)this.cart_list = JSON.parse(new_cart_list)}wx.setStorageSync('cart_list', this.cart_list)}),// 购物车商品数量 - 1sub_one_GoodsNum:action(function(goods) {let findResult = this.cart_list.find(x=>x.goods_id === goods.goods_id)if (findResult) {if (findResult.goods_count > 1) {findResult.goods_count = findResult.goods_count - 1let new_cart_list = JSON.stringify(this.cart_list)this.cart_list = JSON.parse(new_cart_list)}}wx.setStorageSync('cart_list', this.cart_list)}),// 删除购物车商品delete_store_goods:action(function(goods) {this.cart_list = this.cart_list.filter(x=>x.goods_id != goods.goods_id)wx.setStorageSync('cart_list', this.cart_list)}),// 是否是从“购物车”跳转到“我的”界面且需要跳转回“购物车”页面need_navigate_back:false,yes_need_navigate_back:action(function() {this.need_navigate_back = true}),cancel_need_navigate_back:action(function() {this.need_navigate_back = false})
})

2.2  tabBar徽标

tarBar上的徽标是购物车中商品的数量

用到的是wx.setTabBarBadge()这个api

index是第几个tarbar,按0、1、2这么排,购物车是第二个

text是要写什么东西,类型为字符串,也就是说可以写其他的文字上去

当切换到任意tarbar的时候会更新徽标,在加入购物车的时候会更新徽标,在改变商品数量的时候会更新徽标

使用方法时引入store然后用this调用就行了

2.3  滑动删除

用的是movable-area与movable-view

movable-view必须放在movable-area中,其余就没什么好讲的了,有例子照抄就行了

2.4  结算

2.4.1  结算前登录

这个功能需要“购物车”和“我的”这两个tarbar共同完成,所以需要用到全局数据

这个变量是给"我的"中的一键登录按钮用的,直接点一键登录按钮就不需要跳转,从购物车界面过来再点一键登录按钮就需要跳转

2.4.2  结算功能

目前小程序结算功能是不开放给个人开发者的,如果要开通的话只有一个公司的营业执照也是不行的,需要有实际的开发需求才能用微信支付的接口

2.5  触发组件事件

这些是触发组件的事件,感兴趣可以看一下这个 15-5.自定义组件的通信-CSDN博客

2.6  源码

wxml

<!--pages/cart/cart.wxml--><!-- 收货地址区域 -->
<view class="cart-container" wx:if="{{cart_list.length != 0}}"><view><!-- 选择收货地址的盒子 --><view class="address-choose-box" wx:if="{{!choosed_address.username}}"><button type="primary" size="mini" class="btnChooseAddress" bind:tap="go_to_choose_address">请选择收货地址+</button></view><!-- 渲染收货信息的盒子 --><view class="address-info-box" wx:else bind:tap="go_to_choose_address"><view class="row1"><view class="row1-left"><view class="username">收货人:<text>{{choosed_address.username}}</text></view></view><view class="row1-right"><view class="phone">电话:<text>{{choosed_address.phone}}</text></view><image src="/src/arrowright.png" mode="" style="width:16px;height:16px" /></view></view><view class="row2"><view class="row2-left">收货地址:</view><view class="row2-right">{{choosed_address.address_detail}}</view></view></view><!-- 底部的边框线 --><image src="/src/cart_border@2x.png" class="address-border"></image></view><!-- 购物车标题 --><view class="cart-title"><image src="../../src/shop.png" mode="" style="width:18px;height:18px;"/><text class="cart-title-text">购物车</text></view><!-- 购物车内容 --><view class="cart_content_view"><block wx:for="{{cart_list}}" wx:key="index" ><movable-area data-goods_id="{{item.goods_id}}"><movable-view direction="horizontal" data-goods_id="{{item.goods_id}}"><goods_list_item goods_small_logo="{{item.goods_small_logo}}" goods_id="{{item.goods_id}}" goods_price="{{item.goods_price}}" goods_name="{{item.goods_name}}" goods_count="{{item.goods_count}}" showRadio="true" showNumberBox="true" goods_checked="{{item.goods_state}}" bind:radio_change="change_radio_state" bind:add_one="add_one" bind:sub_one="sub_one"></goods_list_item><view class="itemDelet" bindtap="delete_goods" data-goods_id="{{item.goods_id}}">删除</view></movable-view></movable-area></block></view><!-- 底部结算区域 --><view class="my-settle-container"><label class="radio"><checkbox color="#C00000" checked="{{is_all_checked}}" bind:tap="click_all_checked_button"/><text>全选</text></label><view class="amount-box">合计:<text class="amount">¥{{cart_shop_choosed_total_price}}</text></view><view class="btn-settle" bind:tap="buy_cart">结算({{cart_shop_choosed_total_num}})</view></view>
</view>
<!-- 当购物车里什么都没有时出现的东西 -->
<view class="empty-cart" wx:else><image src="/src/empty_cart.png" class="empty-img"></image><text class="tip-text">空空如也~</text></view>

wxss

/* pages/cart/cart.wxss *//* 购物车标题 */
.cart-title {height:40px;display:flex;align-items:center;font-size:14px;padding-left:5px;border-bottom:1px solid #efefef;white-space: wrap;
}.cart-title .cart-title-text {margin-left:10px;white-space: wrap;
}/* 购物车内容的滑动效果 */
movable-area {display: flex;flex-direction: row;width: calc(100% + 120rpx);justify-content: center;left: -120rpx;height: 130px;z-index:0;
}movable-view {display: flex;flex-direction: row;width: calc(100% - 120rpx);z-index: 1001;left: 120rpx;
}.itemDelet {position: absolute;text-align: center;right: -125rpx;line-height: 130px;height:130px;background-color: rgb(194,0,2);margin-top: 0rpx;margin-right: 6rpx;width: 100rpx;text-align: right;padding-right: 20rpx;color: #fff;
}/* 收货地址 */
.address-border {display: block;width: 100%;height: 5px;
}.address-choose-box {height: 90px;display: flex;align-items: center;justify-content: center;
}.address-info-box {font-size:12px;height:90px;display:flex;flex-direction:column;justify-content:center;padding:0 5px;
}.address-info-box .row1 {display: flex;justify-content: space-between;
}.address-info-box .row1 .row1-right {display: flex;align-items: center;
}.phone {margin-right: 5px;
}.address-info-box .row2 {display: flex;align-items: center;margin-top: 10px;
}.address-info-box .row2 .row2-left {white-space: nowrap;
}/* 底部结算区域 */
.my-settle-container {position: fixed;bottom: 0;left: 0;width: 100%;height: 50px;background-color: white;display: flex;justify-content: space-between;align-items: center;padding-left: 5px;font-size: 14px;z-index:999;
}.my-settle-container .radio {display:flex;align-items:center;
}.my-settle-container .amount {color:#c00000
}.my-settle-container .btn-settle {height: 50px;min-width: 100px;background-color: #c00000;color: white;line-height: 50px;text-align: center;padding: 0 10px;
}.cart_content_view {padding-bottom:50px;
}/* 当购物车什么都没有的时候的区域 */
.empty-cart {display: flex;flex-direction: column;align-items: center;padding-top: 150px;
}.empty-cart .empty-img {width:90px;height:90px;
}.empty-cart .tip-text {font-size:12px;color:gray;margin-top:15px;
}

js

// pages/cart/cart.js
import {createStoreBindings} from 'mobx-miniprogram-bindings'
import {store} from '../../store/store.js'const App = getApp()Page({buy_cart() {if (this.data.cart_shop_choosed_total_num == 0) {wx.showToast({title: '请选择要结算的商品',mask:true,icon:'none'})setTimeout(function() {wx.hideToast()},800)return}if (!this.data.choosed_address.username) {wx.showToast({title: '请选择收货地址',mask:true,icon:'none'})setTimeout(function() {wx.hideToast()},800)return}if (this.data.userinfo == '') {wx.showToast({title: '请先登录',mask:true,icon:'none'})setTimeout(()=>{wx.hideToast()wx.switchTab({url: '/pages/my/my',success:()=>{this.yes_need_navigate_back()}})},800)return }},click_all_checked_button() {this.updateAllGoodsState(this.data.is_all_checked)},go_to_choose_address() {wx.navigateTo({url:'/subpackage_choose_address/choose_address'})},change_radio_state(e) {this.updateGoodsState(e.detail)},add_one(e) {this.add_one_GoodsNum(e.detail)this.set_cart_tabBar_badge()},sub_one(e) {this.sub_one_GoodsNum(e.detail)this.set_cart_tabBar_badge()},delete_goods(e) {this.delete_store_goods(e.target.dataset)this.set_cart_tabBar_badge()},/*** 页面的初始数据*/data: {// address:{'name':'suyu'}choosed_address:{},userinfo:'',from:''},/*** 生命周期函数--监听页面加载*/onLoad(options) {this.storeBindings = createStoreBindings(this,{store,fields:['cart_list','cart_shop_choosed_total_price','cart_shop_choosed_total_num','is_all_checked'],actions:['set_cart_tabBar_badge','updateGoodsState','add_one_GoodsNum','sub_one_GoodsNum','delete_store_goods','updateAllGoodsState','yes_need_navigate_back']})},/*** 生命周期函数--监听页面初次渲染完成*/onReady() {// 设置购物车tabBar的徽标this.set_cart_tabBar_badge()this.setData({choosed_address:wx.getStorageSync('choosed_address') || {}})},/*** 生命周期函数--监听页面显示*/onShow() {this.setData({choosed_address:wx.getStorageSync('choosed_address') || {}})this.setData({userinfo:wx.getStorageSync('userinfo') || ''})},/*** 生命周期函数--监听页面隐藏*/onHide() {},/*** 生命周期函数--监听页面卸载*/onUnload() {},/*** 页面相关事件处理函数--监听用户下拉动作*/onPullDownRefresh() {},/*** 页面上拉触底事件的处理函数*/onReachBottom() {},/*** 用户点击右上角分享*/onShareAppMessage() {}
})

这篇关于附录6-4 黑马优购项目-分类和购物车的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/956722

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

SpringBoot项目是如何启动

启动步骤 概念 运行main方法,初始化SpringApplication 从spring.factories读取listener ApplicationContentInitializer运行run方法读取环境变量,配置信息创建SpringApplication上下文预初始化上下文,将启动类作为配置类进行读取调用 refresh 加载 IOC容器,加载所有的自动配置类,创建容器在这个过程

Maven创建项目中的groupId, artifactId, 和 version的意思

文章目录 groupIdartifactIdversionname groupId 定义:groupId 是 Maven 项目坐标的第一个部分,它通常表示项目的组织或公司的域名反转写法。例如,如果你为公司 example.com 开发软件,groupId 可能是 com.example。作用:groupId 被用来组织和分组相关的 Maven artifacts,这样可以避免

2. 下载rknn-toolkit2项目

官网链接: https://github.com/airockchip/rknn-toolkit2 安装好git:[[1. Git的安装]] 下载项目: git clone https://github.com/airockchip/rknn-toolkit2.git 或者直接去github下载压缩文件,解压即可。

9.8javaweb项目总结

1.主界面用户信息显示 登录成功后,将用户信息存储在记录在 localStorage中,然后进入界面之前通过js来渲染主界面 存储用户信息 将用户信息渲染在主界面上,并且头像设置跳转,到个人资料界面 这里数据库中还没有设置相关信息 2.模糊查找 检测输入框是否有变更,有的话调用方法,进行查找 发送检测请求,然后接收的时候设置最多显示四个类似的搜索结果