mina/pages/cart/index.wxml
<!--index.wxml-->
<view class="container"><view class="title-box" wx:if="{{ !list.length }}">购物车空空如也~</view><view class="to-index-btn" bindtap="toIndexPage" wx:if="{{ !list.length }}">去逛逛</view><view class="list-top" wx:if="{{ list.length }}"><view class="label">购物车</view><view class="edit-btn" hidden="{{!saveHidden}}" bindtap="editTap">编辑</view><view class="edit-btn" hidden="{{saveHidden}}" bindtap="saveTap">完成</view></view><view class="goodsList" wx:if="{{ list.length }}"><view class="a-gooods" wx:for="{{ list }}" wx:key="{{index}}" ><view class="a-goods-conts {{item.active? 'active':''}}" bindtap="selectTap" data-index="{{index}}"><view class="goods-info"><view class="img-box"><image src="{{item.pic_url}}" class="img"/></view><view class="text-box"><view class="goods-title">{{item.name}}</view><view class="goods-price">¥ {{item.price}}</view><view class="buy-num"><view class="jian-btn" catchtap="jianBtnTap" data-index="{{index}}">-</view><input type="number" value="{{item.number}}" disabled/><view class="jia-btn" catchtap="jiaBtnTap" data-index="{{index}}">+</view></view></view></view></view></view></view><view class="jiesuan-box" wx:if="{{ list.length }}"><view class="left-price"><view class="all-selected {{allSelect?'active':''}}" bindtap="bindAllSelect">全选</view><view class="total" hidden="{{noSelect}}">合计:¥ {{totalPrice}}</view></view><view class="to-pay-btn {{noSelect?'no-select':''}}" hidden="{{!saveHidden}}" bindtap="toPayOrder">去结算</view><view class="to-pay-btn {{noSelect?'no-select':''}}" hidden="{{saveHidden}}" bindtap="deleteSelected">删除</view></view>
</view>
知识点一:简要代码分析
<view class="to-pay-btn {{noSelect?'no-select':''}}" hidden="{{!saveHidden}}" bindtap="toPayOrder">去结算</view>
根据提供的代码,<view class="to-pay-btn {{noSelect?'no-select':''}}" hidden="{{!saveHidden}}" bindtap="toPayOrder">去结算</view>
是一个视图组件,它有一个类名为to-pay-btn
,并根据noSelect
和saveHidden
的值来动态添加或移除no-select
类。当saveHidden
为false
时,该视图组件会被隐藏。同时,当用户点击该视图组件时,会触发toPayOrder
方法。
web/controllers/api/Cart.py
@route_api.route("/cart/index")
def cartIndex():resp = {'code': 200, 'msg': '添加购物车成功~', 'data': {}}member_info = g.member_infoif not member_info:resp['code'] = -1resp['msg'] = "获取失败,伪登录~~"return jsonify(resp)cart_list = MemberCart.query.filter_by( member_id=member_info.id).all()data_cart_list = []if cart_list:food_ids = selectFilterObj( cart_list,"food_id" )food_map = getDictFilterField( Food,Food.id,"id",food_ids )for item in cart_list:tmp_food_info = food_map[ item.food_id ]tmp_data = {"id":item.id,"number":item.quantity,"food_id": item.food_id,"name":tmp_food_info.name,"price":str( tmp_food_info.price ),"pic_url": UrlManager.buildImageUrl( tmp_food_info.main_image ),"active":True}data_cart_list.append( tmp_data )resp['data']['list'] = data_cart_listreturn jsonify(resp)
common/libs/Helper.py
'''
根据某个字段获取一个dic出来
'''
def getDictFilterField( db_model,select_filed,key_field,id_list ):ret = {}query = db_model.queryif id_list and len( id_list ) > 0:query = query.filter( select_filed.in_( id_list ) )list = query.all()if not list:return retfor item in list:if not hasattr( item,key_field ):breakret[ getattr( item,key_field ) ] = itemreturn retdef selectFilterObj( obj,field ):ret = []for item in obj:if not hasattr(item, field ):breakif getattr( item,field ) in ret:continueret.append( getattr( item,field ) )return ret
food_ids = selectFilterObj( cart_list,"food_id" )
从cart_list里取得food_id
Python getattr() 函数_w3cschool
然后通过下面代码获取mapping的一个信息
food_map = getDictFilterField( Food,Food.id,"id",food_ids )
第一个查 Food对象,
再在Food表里查询id字段等于 “id” 这个值里面的,它的key值 是 ”id“
最终返回的结果集与 fodd_ids 相关
问题1: query = query.filter( select_filed.in_( id_list ) ) 中in_是什么
in_
是SQLAlchemy中的一个操作符,用于在查询中判断某个字段的值是否在给定的列表中。它类似于SQL中的IN
操作符。
下面是一个示例演示如何使用in_
操作符:
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base# 创建数据库连接
engine = create_engine('sqlite:///test.db')
Session = sessionmaker(bind=engine)
session = Session()
# 创建模型类
Base = declarative_base()class User(Base):__tablename__ = 'users'id = Column(Integer, primary_key=True)name = Column(String)# 查询name字段值在给定列表中的记录
id_list = [1, 2, 3]
query = session.query(User).filter(User.name.in_(id_list))
result = query.all()# 输出查询结果
for user in result:print(user.name)
这个示例中,我们创建了一个名为users
的表,其中包含id
和name
两个字段。然后我们使用in_
操作符来查询name
字段值在给定列表id_list
中的记录,并将结果打印出来。
问题2: 为什么此处用filter而不是filter_by?
filter和filter_by都是SQLAlchemy中用于查询的方法,它们的区别如下:
- filter是基于关键字参数的查询方法,可以根据指定的条件进行过滤。例如,可以使用filter方法查询年龄大于18岁的用户:
session.query(User).filter(User.age > 18).all()
- filter_by是基于属性名和属性值的查询方法,可以直接指定属性名和属性值进行过滤。例如,可以使用filter_by方法查询用户名为"John"的用户:
session.query(User).filter_by(username="John").all()
总结来说,filter方法更加灵活,可以使用各种条件进行过滤,而filter_by方法更加简洁,适合于直接根据属性名和属性值进行过滤。
mina/pages/cart/index.js
//index.js
var app = getApp();
Page({data: {},onLoad: function () {this.getCartList();},//每项前面的选中框selectTap: function (e) {var index = e.currentTarget.dataset.index;var list = this.data.list;if (index !== "" && index != null) {list[ parseInt(index) ].active = !list[ parseInt(index) ].active;this.setPageData(this.getSaveHide(), this.totalPrice(), this.allSelect(), this.noSelect(), list);}},//计算是否全选了allSelect: function () {var list = this.data.list;var allSelect = false;for (var i = 0; i < list.length; i++) {var curItem = list[i];if (curItem.active) {allSelect = true;} else {allSelect = false;break;}}return allSelect;},//计算是否都没有选noSelect: function () {var list = this.data.list;var noSelect = 0;for (var i = 0; i < list.length; i++) {var curItem = list[i];if (!curItem.active) {noSelect++;}}if (noSelect == list.length) {return true;} else {return false;}},//全选和全部选按钮bindAllSelect: function () {var currentAllSelect = this.data.allSelect;var list = this.data.list;for (var i = 0; i < list.length; i++) {list[i].active = !currentAllSelect;}this.setPageData(this.getSaveHide(), this.totalPrice(), !currentAllSelect, this.noSelect(), list);},//加数量jiaBtnTap: function (e) {var that = this;var index = e.currentTarget.dataset.index;var list = that.data.list;list[parseInt(index)].number++;that.setPageData(that.getSaveHide(), that.totalPrice(), that.allSelect(), that.noSelect(), list);},//减数量jianBtnTap: function (e) {var index = e.currentTarget.dataset.index;var list = this.data.list;if (list[parseInt(index)].number > 1) {list[parseInt(index)].number--;this.setPageData(this.getSaveHide(), this.totalPrice(), this.allSelect(), this.noSelect(), list);}},//编辑默认全不选editTap: function () {var list = this.data.list;for (var i = 0; i < list.length; i++) {var curItem = list[i];curItem.active = false;}this.setPageData(!this.getSaveHide(), this.totalPrice(), this.allSelect(), this.noSelect(), list);},//选中完成默认全选saveTap: function () {var list = this.data.list;for (var i = 0; i < list.length; i++) {var curItem = list[i];curItem.active = true;}this.setPageData(!this.getSaveHide(), this.totalPrice(), this.allSelect(), this.noSelect(), list);},getSaveHide: function () {return this.data.saveHidden;},totalPrice: function () {var list = this.data.list;var totalPrice = 0.00;for (var i = 0; i < list.length; i++) {if ( !list[i].active) {continue;}totalPrice = totalPrice + parseFloat( list[i].price );}return totalPrice;},setPageData: function (saveHidden, total, allSelect, noSelect, list) {this.setData({list: list,saveHidden: saveHidden,totalPrice: total,allSelect: allSelect,noSelect: noSelect,});},//去结算toPayOrder: function () {wx.navigateTo({url: "/pages/order/index"});},//如果没有显示去光光按钮事件toIndexPage: function () {wx.switchTab({url: "/pages/food/index"});},//选中删除的数据deleteSelected: function () {var list = this.data.list;var cart_ids = [];list = list.filter(function ( item ) {if( !item.active ){cart_ids.append( item.id );}return !item.active;});this.setPageData( this.getSaveHide(), this.totalPrice(), this.allSelect(), this.noSelect(), list);//发送请求到后台删除数据},getCartList: function () {this.setData({list: [{"id": 1080,"food_id":"5","pic_url": "/images/food.jpg","name": "小鸡炖蘑菇-1","price": "85.00","active": true,"number": 1},{"id": 1081,"food_id":"6","pic_url": "/images/food.jpg","name": "小鸡炖蘑菇-2","price": "85.00","active": true,"number": 1}],saveHidden: true,totalPrice: "85.00",allSelect: true,noSelect: false,});this.setPageData( this.getSaveHide(), this.totalPrice(), this.allSelect(), this.noSelect(), this.data.list);}
});
加数量
这段代码是一个小程序中的一个函数,它用于点击加号按钮时执行的操作。具体来说,它会将对应的课程数量加1,并更新页面上的数据。
解释:
jiaBtnTap
是一个函数名,用于点击加号按钮时触发。var that = this;
将当前页面的上下文保存在变量that
中,以便在函数内部使用。- JavaScript 作用域_w3cschool
var index = e.currentTarget.dataset.index;
获取当前点击按钮的索引值。- JavaScript Event 对象_w3cschool
var list = that.data.list;
获取当前页面的数据列表。
list[parseInt(index)].number++;
将对应索引的课程数量加1 。- JavaScript parseInt() 函数_w3cschool
parseInt() 函数可解析一个字符串,并返回一个整数。
当参数 radix 的值为 0,或没有设置该参数时,parseInt() 会根据 string 来判断数字的基数。
当忽略参数 radix , JavaScript 默认数字的基数如下:
- 如果 string 以 "0x" 开头,parseInt() 会把 string 的其余部分解析为十六进制的整数。
- 如果 string 以 0 开头,那么 ECMAScript v3 允许 parseInt() 的一个实现把其后的字符解析为八进制或十六进制的数字。
- 如果 string 以 1 ~ 9 的数字开头,parseInt() 将把它解析为十进制的整数。
-
parseInt(string, radix)
参数 描述 string 必需。要被解析的字符串。 radix 可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。
that.setPageData(that.getSaveHide(), that.totalPrice(), that.allSelect(), that.noSelect(), list);
更新页面上的数据。
示例: 假设当前页面的数据列表为list = [{name: '课程1', number: 2}, {name: '课程2', number: 3}]
,点击第一个课程的加号按钮后,函数执行后的结果为list = [{name: '课程1', number: 3}, {name: '课程2', number: 3}]
。
问题1:为什么在加数量中用that,而在减数量中用this?
这两段代码中使用了不同的变量名来引用当前对象。
第一段代码中,使用了变量名"that"来引用当前对象,
而在第二段代码中,直接使用了关键字"this"来引用当前对象。
使用"that"的目的是为了避免在嵌套函数中出现作用域问题。在JavaScript中,函数内部的this指向的是函数的调用者,而不是定义函数的对象。
因此,在嵌套函数中,如果直接使用this来引用当前对象,可能会导致this指向错误的对象。
为了解决这个问题,可以在外层函数中将this赋值给一个变量that,然后在嵌套函数中使用that来引用当前对象,以确保引用的是正确的对象。
而在第二段代码中,没有出现嵌套函数,所以直接使用this来引用当前对象是没有问题的。
在提供的加减函数代码中,没有明确指出哪个是嵌套函数。嵌套函数是指在一个函数内部定义的函数。根据提供的代码,没有函数在其他函数内部定义,因此没有嵌套函数。