mina/pages/food/index.wxml
<!--index.wxml-->
<!--1px = 750/320 = 2.34rpx;-->
<view class="container">
<!--轮播图-->
<view class="swiper-container">
<swiper class="swiper_box" autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}" bindchange="swiperchange">
<block wx:for="{{banners}}" wx:key="id">
<swiper-item>
<image bindtap="tapBanner" data-id="{{item.id}}" src="{{item.pic_url}}" class="slide-image" width="750rpx" height="562.5rpx" />
</swiper-item>
</block>
</swiper>
<view class="dots">
<block wx:for="{{banners}}" wx:key="unique">
<view class="dot{{index == swiperCurrent ? ' active' : ''}}"></view>
</block>
</view>
</view>
<!--分类展示-->
<view class="type-container">
<scroll-view class="type-navbar" scroll-x="true">
<view class="type-box" wx:for-items="{{categories}}" wx:key="id">
<view id="{{item.id}}" class="type-navbar-item {{activeCategoryId == item.id ? 'type-item-on' : ''}}" bindtap="catClick">
{{item.name}}
</view>
</view>
</scroll-view>
</view>
<!--搜索框-->
<view class="search-view" style="background:{{ scrollTop === 0 ?'-webkit-linear-gradient(top, rgba(105,195,170, 1), rgba(105,195,170, 0.3))' :( scrollTop<200 ? 'rgba(105,195,170,'+(scrollTop/400+0.3) +')' : 'rgba(105,195,170,1)') }} ">
<view class="search-content">
<image src="/images/search-pic.png" class="search-icon" />
<input placeholder="请输入搜索内容" class="search-input" maxlength="30" confirm-type="搜索" bindinput='listenerSearchInput'>
</input>
<button class='search-btn' bindtap="toSearch">搜索</button>
</view>
</view>
<view class="goods-container">
<view class="goods-box" wx:for-items="{{goods}}" bindtap="toDetailsTap" data-id="{{item.id}}">
<view class="img-box">
<image src="{{item.pic_url}}" class="image" mode="aspectFill" lazy-load="true" />
</view>
<view class="goods-title">{{item.name}}</view>
<view style='display:flex;'>
<view class="goods-price">¥ {{item.min_price}}</view>
<view wx:if="{{item.price && item.price > 0 && item.min_price != item.price}}" class="goods-price" style='color:#aaa;text-decoration:line-through'>¥ {{item.price}}</view>
</view>
</view>
</view>
<view hidden="{{loadingMoreHidden ? true : false}}" class="no-more-goods">哥也是有底线的</view>
</view>
轮播图
问题1: <swiper> </swiper>是什么?
swiper 英 /ˈswaɪpə n. 猛击者;偷窃者
滑块视图容器。其中只可放置swiper-item组件,否则会导致未定义的行为。
使用 worklet
函数需要开启开发者工具 “将 JS 编译成 ES5” 或 “编译 worklet 函数” 选项
interval | number | 5000 | 否 | 自动切换时间间隔 |
duration | number | 500 | 否 | 滑动动画时长 |
bindchange | eventhandle | 否 | current 改变时会触发 change 事件,event.detail = {current, source} |
问题2: swiper 内为什么用block?
在WXML页面中,使用<block>
标签可以用来循环渲染一组元素。在你提供的代码中,<block>
标签被用来循环渲染<swiper-item>
元素。这是因为在WXML中,如果我们想要循环渲染一组元素,我们需要使用<block>
标签来包裹这组元素,并使用wx:for
属性来指定要循环的数据源。
在你的代码中,wx:for="{{banners}}"
指定了要循环渲染的数据源为banners
,而wx:key="id"
指定了每个循环项的唯一标识符为id
。然后,<swiper-item>
元素会根据banners
中的每个元素进行循环渲染,生成对应的轮播项。
使用<block>
标签可以让我们在WXML中更方便地循环渲染一组元素,提高代码的可读性和维护性
因为 wx:if
是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 <block/>
标签将多个组件包装起来,并在上边使用 wx:if
控制属性。
<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
注意: <block/>
并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
banner 美 /ˈbænər/ n. 横幅标语;(网页上的)横幅广告;信仰,准则;旗帜
wx:if
vs hidden
因为 wx:if
之中的模板也可能包含数据绑定,所以当 wx:if
的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。
同时 wx:if
也是惰性的,如果在初始渲染条件为 false
,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。
相比之下,hidden
就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。
一般来说,wx:if
有更高的切换消耗而 hidden
有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden
更好,如果在运行时条件不大可能改变则 wx:if
较好。
分类展示
用于展示一个包含滚动视图和下拉菜单的页面
该段代码是一个简单的小程序页面,包含了一个横向滚动的导航栏和对应的内容展示区域。下面是各部分功能的简单赘述:
-
<view class="type-container">
:定义一个视图容器,用于包裹整个页面的内容。 -
<scroll-view class="type-navbar" scroll-x="true">
:定义一个横向滚动的视图容器,用于展示导航栏。 -
<view class="type-box" wx:for-items="{{categories}}" wx:key="id">
:定义一个视图容器,用于包裹导航栏的每个选项。 -
<view id="{{item.id}}" class="type-navbar-item {{activeCategoryId == item.id ? 'type-item-on' : ''}}" >
:定义一个视图容器,表示导航栏的每个选项。根据activeCategoryId
的值来判断当前选项是否被选中,如果选中则添加type-item-on
样式。bindtap属性绑定了一个点击事件。 -
{{item.name}}
:展示导航栏选项的名称,使用双花括号{{}}
来插入动态数据,在导航栏选项中显示当前元素的名称。
总体来说,该段代码实现了一个横向滚动的导航栏,点击不同的选项可以切换对应的内容展示区域。
事件 | 微信开放文档 如bindtap
,当用户点击该组件的时候会在该页面对应的Page中找到相应的事件处理函数。
问题1:wx:for-items是什么作用?为什么不是wx:for-item? 其中wx:key的作用是什么?
wx:for-items是一个用于循环渲染列表的属性,它接受一个数组作为参数,然后将数组中的每个元素渲染为对应的组件。在给定的例子中,wx:for-items=”{{categories}}”将会遍历categories数组,并将数组中的每个元素渲染为一个view组件。
wx:for-item是wx:for的一个子属性,用于指定在循环过程中每个元素的别名。在给定的例子中,没有使用wx:for-item属性,因为在循环过程中并不需要引用每个元素的别名。
wx:key是一个用于标识列表中每个元素的唯一性的属性。它的作用是为了提高列表渲染的性能。在给定的例子中,wx:key=”id”将会使用每个元素的id属性作为唯一标识,以便在列表发生变化时能够准确地找到需要更新的元素。
问题2: ?的作用是什么?
代码中?的作用是用于动态绑定数据。在这段代码中,?用于绑定categories数组中的每个元素的name属性,将其显示在视图中。通过这种方式,可以根据categories数组的内容动态生成视图,并且在用户点击时可以触发相应的事件。
问题3:’type-item-on’ : ”的作用是什么?
代码中’type-item-on’ : ”的作用是根据条件判断是否给元素添加一个类名,用于控制元素的样式。当条件为真时,即activeCategoryId等于item.id时,给元素添加类名”type-item-on”,从而改变元素的样式。当条件为假时,即activeCategoryId不等于item.id时,不给元素添加任何类名,保持元素原有的样式。
问题3:categories值从何来,是什么?
在food.js的getBannerAndCat函数下的success:fuction{}li有个setData{categories: resp.data.cat_list}
在服务器端的Food.py的@route_api.route(“/food/index” )中是FoodCate模型的query值
搜索框
知识点一:
<view class="search-view" style="background:{{ scrollTop === 0 ?'-webkit-linear-gradient(top, rgba(105,195,170, 1), rgba(105,195,170, 0.3))' :( scrollTop<200 ? 'rgba(105,195,170,'+(scrollTop/400+0.3) +')' : 'rgba(105,195,170,1)') }} ">
这段代码是一个视图元素的类名为”search-view”的样式设置。其中使用了三元表达式来动态设置背景颜色。让我来解释一下具体的代码含义:
-
scrollTop === 0 ? '-webkit-linear-gradient(top, rgba(105,195,170, 1), rgba(105,195,170, 0.3))'
:当滚动条的scrollTop值等于0时,背景颜色设置为从上到下的渐变色,起始颜色为rgba(105,195,170, 1),结束颜色为rgba(105,195,170, 0.3)。 -
scrollTop < 200 ? 'rgba(105,195,170,'+(scrollTop/400+0.3) +')'
:当滚动条的scrollTop值小于200时,背景颜色设置为固定的颜色,颜色的透明度根据scrollTop值的变化而变化,透明度的计算公式为scrollTop/400+0.3。 -
: 'rgba(105,195,170,1)'
:当滚动条的scrollTop值大于等于200时,背景颜色设置为固定的颜色,不再根据scrollTop值的变化而变化。
这段代码的作用是根据滚动条的scrollTop值来动态改变视图元素的背景颜色,实现了一个渐变色效果。
===
是JavaScript中的严格相等运算符,用于比较两个值是否相等且类型相同。如果两个值相等且类型相同,则返回true
,否则返回false
。
?
和:
是JavaScript中的条件(三元)运算符。它是一种简洁的写法,用于根据条件的真假来选择不同的值或执行不同的操作。它的语法是条件 ? 表达式1 : 表达式2
,如果条件为真,则返回表达式1的值,否则返回表达式2的值。
在给定的代码中,===
用于比较scrollTop
的值是否等于0。如果等于0,则返回'-webkit-linear-gradient(top, rgba(105,195,170, 1), rgba(105,195,170, 0.3))'
作为background
样式的值。否则,使用条件运算符?
和:
来判断scrollTop
的值,并根据不同的值返回不同的background
样式的值。
三元表达式是JavaScript语言的一部分,但也被其他编程语言如Python、C++等所支持。
? : 条件运算符 即 简洁的if else
== 比较两个运算数的返回值是否相等
=== 比较两个运算数的 返回值 及 数据类型 是 否 相等 且 相同
问题1: &&的作用是什么?
&&是逻辑与运算符,用于判断多个条件是否同时成立。
在给定的代码中,&&用于判断三个条件是否同时满足,只有当这三个条件都为真时,才会执行其中的代码。
具体来说,只有当item.price存在且大于0且item.min_price不等于item.price时,才会将item.price的值显示在视图中,并且添加了删除线样式。
需要注意的是,&&是wx小程序上的使用方法,而不是Python语言中的运算符。
问题2: ? 在 代码中的作用
<view hidden="{{loadingMoreHidden ? true : false}}" class="no-more-goods">哥也是有底线的</view>
在给定的代码中,<view hidden="{{loadingMoreHidden ? true : false}}" class="no-more-goods">哥也是有底线的</view>
是一个小程序(微信小程序)的视图层代码。它使用了小程序的模板语法和组件标签。
hidden="{{loadingMoreHidden ? true : false}}"
是一个属性绑定,它根据变量 loadingMoreHidden
的值来决定是否隐藏该视图元素。如果 loadingMoreHidden
的值为真,则该视图元素会被隐藏;如果 loadingMoreHidden
的值为假,则该视图元素会显示出来。
class="no-more-goods"
是为该视图元素添加了一个 CSS 类名,可以用来对该元素进行样式设置或者选择器选择
mina/pages/food/food.js
实现网络相关请求的加载
//index.js
//获取应用实例
var app = getApp();
Page({
data: {
indicatorDots: true,
autoplay: true,
interval: 3000,
duration: 1000,
loadingHidden: false, // loading
swiperCurrent: 0,
categories: [],
activeCategoryId: 0,
goods: [],
scrollTop: "0",
loadingMoreHidden: true,
searchInput: '',
p:1,
processing:false
},
onLoad: function () {
var that = this;
wx.setNavigationBarTitle({
title: app.globalData.shopName
});
},
//解决切换不刷新维内托,每次展示都会调用这个方法
onShow:function(){
this.getBannerAndCat();
},
scroll: function (e) {
var that = this, scrollTop = that.data.scrollTop;
that.setData({
scrollTop: e.detail.scrollTop
});
},
//事件处理函数
swiperchange: function (e) {
this.setData({
swiperCurrent: e.detail.current
})
},
listenerSearchInput:function( e ){
this.setData({
searchInput: e.detail.value
});
},
toSearch:function( e ){
this.setData({
p:1,
goods:[],
loadingMoreHidden:true
});
this.getFoodList();
},
tapBanner: function (e) {
if (e.currentTarget.dataset.id != 0) {
wx.navigateTo({
url: "/pages/food/info?id=" + e.currentTarget.dataset.id
});
}
},
toDetailsTap: function (e) {
wx.navigateTo({
url: "/pages/food/info?id=" + e.currentTarget.dataset.id
});
},
getBannerAndCat: function () {
var that = this;
wx.request({
url: app.buildUrl("/food/index"),
header: app.getRequestHeader(),
success: function (res) {
var resp = res.data;
if (resp.code != 200) {
app.alert({"content": resp.msg});
return;
}
that.setData({
banners: resp.data.banner_list,
categories: resp.data.cat_list
});
that.getFoodList();
}
});
},
catClick: function (e) {
this.setData({
activeCategoryId: e.currentTarget.id
});
this.setData({
loadingMoreHidden: true,
p:1,
goods:[]
});
this.getFoodList();
},
onReachBottom: function () {
var that = this;
setTimeout(function () {
that.getFoodList();
}, 500);
},
getFoodList: function () {
var that = this;
if( that.data.processing ){
return;
}
if( !that.data.loadingMoreHidden ){
return;
}
that.setData({
processing:true
});
wx.request({
url: app.buildUrl("/food/search"),
header: app.getRequestHeader(),
data: {
cat_id: that.data.activeCategoryId,
mix_kw: that.data.searchInput,
p: that.data.p,
},
success: function (res) {
var resp = res.data;
if (resp.code != 200) {
app.alert({"content": resp.msg});
return;
}
var goods = resp.data.list;
that.setData({
goods: that.data.goods.concat( goods ),
p: that.data.p + 1,
processing:false
});
if( resp.data.has_more == 0 ){
that.setData({
loadingMoreHidden: false
});
}
}
});
}
});
toDetailstop:function(){}
wx.navigateTo(Object object) | 微信开放文档
保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。
getBannerAndCat:function(){ }
banner 美/ˈbænər/ adj.极好的,出色的
RequestTask | 微信开放文档 发起 HTTPS 网络请求。
wx.request是微信小程序中用于发起网络请求的API。它可以向服务器发送HTTP请求,并在请求成功或失败时执行相应的回调函数。
以下是一个使用wx.request发起GET请求的示例:
wx.request({
url: 'https://api.example.com/data',
method: 'GET',
success: function(res) {
console.log(res.data); // 请求成功时的处理逻辑
},
fail: function(err) {
console.error(err); // 请求失败时的处理逻辑
},
complete: function() {
console.log('请求完成'); // 无论请求成功或失败都会执行的回调函数
}
});
在上述示例中,我们通过传入一个对象作为参数来调用wx.request函数。该对象包含了请求的URL、请求方法、成功、失败和完成时的回调函数。
成功时的回调函数会接收一个参数res,其中包含了py服务器返回的数据。我们可以通过res.data来获取返回的数据。
失败时的回调函数会接收一个参数err,其中包含了请求失败的错误信息。
完成时的回调函数不论请求成功或失败都会执行。
需要注意的是,wx.request只能在小程序的前端代码中使用,不能在小程序的云函数中使用。
知识点1:setData({})
setData是小程序中用于更新页面数据的方法。它可以修改this.data中的数据,并将修改后的数据同步到页面上,从而实现页面的更新。
以下是使用setData方法的示例:
// 修改this.data中的数据
this.setData({
text: 'changed data'
});
// 修改对象或数组字段中的子字段
this.setData({
'array[0].text': 'changed data'
});
// 修改对象的某个属性
this.setData({
'object.text': 'changed data'
});
需要注意的是,直接修改this.data而不调用setData是无法改变页面的状态的,还会造成数据不一致。因此,在小程序中应该始终使用setData来更新页面数据。
getFoodList:function(){ }
分类中
cat_id 当前选中的id
mix_kw 搜索框的值
问题1: goods: that.data.goods.concat( goods ), 是什么作用?
该段代码是在微信小程序中使用的,它的作用是将一个新的数组goods
与原数组that.data.goods
合并,并将合并后的结果赋值给that.data.goods
。具体解释如下:
that.data.goods.concat(goods)
that.data.goods
是原数组,表示已有的商品数组。goods
是一个新的数组,表示要添加的商品数组。concat()
是JavaScript中的数组方法,用于将两个或多个数组合并成一个新数组。that.data.goods.concat(goods)
将原数组that.data.goods
与新数组goods
合并成一个新的数组。- 最后,将合并后的新数组赋值给
that.data.goods
,即更新了原数组。
该段代码的作用是将新的商品数组添加到已有的商品数组中,实现了商品的追加功能。
catClick:function(e){}
当选中选择分类的时候改变它当前的分类,并设置它的选中值
currentTarget | Object | 当前组件的一些属性值集合 |
this当前对象的setData
id就是 index.wxml中的view id对象值
onReachBottom:function(){}
Page(Object object) | 微信开放文档 监听用户上拉触底事件
数据库 common/models/member/MemberCart.py
DROP TABLE IF EXISTS `member_cart`;
CREATE TABLE `member_cart` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`member_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '会员id',
`food_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品id',
`quantity` int(11) NOT NULL DEFAULT '0' COMMENT '数量',
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后一次更新时间',
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '插入时间',
PRIMARY KEY (`id`),
KEY `idx_member_id` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='购物车';
flask-sqlacodegen 'mysql://root:root@127.0.0.1/food_db' --tables member_cart --outfile "common/models/member/MemberCart.py" --flask
web/controllers/api/Food.py
# -*- coding: utf-8 -*-
from web.controllers.api import route_api
from flask import request,jsonify,g
from common.models.food.FoodCat import FoodCat
from common.models.food.Food import Food
from common.models.member.MemberCart import MemberCart
from common.models.member.MemberComments import MemberComments
from common.models.member.Member import Member
from common.libs.UrlManager import UrlManager
from common.libs.Helper import getCurrentDate,getDictFilterField,selectFilterObj
from application import app,db
from sqlalchemy import or_
@route_api.route("/food/index" )
def foodIndex():
resp = { 'code':200 ,'msg':'操作成功~','data':{} }
cat_list = FoodCat.query.filter_by( status = 1 ).order_by( FoodCat.weight.desc() ).all()
data_cat_list = []
data_cat_list.append({
'id': 0,
'name': "全部"
})
if cat_list:
for item in cat_list:
tmp_data = {
'id':item.id,
'name':item.name
}
data_cat_list.append( tmp_data )
resp['data']['cat_list'] = data_cat_list
food_list = Food.query.filter_by( status = 1 )
.order_by( Food.total_count.desc(),Food.id.desc() ).limit(3).all()
data_food_list = []
if food_list:
for item in food_list:
tmp_data = {
'id':item.id,
'pic_url':UrlManager.buildImageUrl( item.main_image )
}
data_food_list.append( tmp_data )
resp['data']['banner_list'] = data_food_list
return jsonify( resp )
@route_api.route("/food/search" )
def foodSearch():
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
req = request.values
cat_id = int( req['cat_id'] ) if 'cat_id' in req else 0
mix_kw = str(req['mix_kw']) if 'mix_kw' in req else ''
p = int( req['p'] ) if 'p' in req else 1
if p < 1:
p = 1
page_size = 10
offset = ( p - 1 ) * page_size
query = Food.query.filter_by(status=1 )
if cat_id > 0:
query = query.filter_by(cat_id = cat_id)
if mix_kw:
rule = or_(Food.name.ilike("%{0}%".format(mix_kw)), Food.tags.ilike("%{0}%".format(mix_kw)))
query = query.filter(rule)
food_list = query.order_by(Food.total_count.desc(), Food.id.desc())
.offset( offset ).limit( page_size ).all()
data_food_list = []
if food_list:
for item in food_list:
tmp_data = {
'id': item.id,
'name': "%s"%( item.name ),
'price': str( item.price ),
'min_price':str( item.price ),
'pic_url': UrlManager.buildImageUrl(item.main_image)
}
data_food_list.append(tmp_data)
resp['data']['list'] = data_food_list
resp['data']['has_more'] = 0 if len( data_food_list ) < page_size else 1
return jsonify(resp)
@route_api.route("/food/info" )
def foodInfo():
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
req = request.values
id = int(req['id']) if 'id' in req else 0
food_info = Food.query.filter_by( id = id ).first()
if not food_info or not food_info.status :
resp['code'] = -1
resp['msg'] = "美食已下架"
return jsonify(resp)
member_info = g.member_info
cart_number = 0
if member_info:
cart_number = MemberCart.query.filter_by( member_id = member_info.id ).count()
resp['data']['info'] = {
"id":food_info.id,
"name":food_info.name,
"summary":food_info.summary,
"total_count":food_info.total_count,
"comment_count":food_info.comment_count,
'main_image':UrlManager.buildImageUrl( food_info.main_image ),
"price":str( food_info.price ),
"stock":food_info.stock,
"pics":[ UrlManager.buildImageUrl( food_info.main_image ) ]
}
resp['data']['cart_number'] = cart_number
return jsonify(resp)
@route_api.route("/food/comments")
def foodComments():
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
req = request.values
id = int(req['id']) if 'id' in req else 0
query = MemberComments.query.filter( MemberComments.food_ids.ilike("%_{0}_%".format(id)) )
list = query.order_by( MemberComments.id.desc() ).limit(5).all()
data_list = []
if list:
member_map = getDictFilterField( Member,Member.id,"id",selectFilterObj( list,"member_id" ) )
for item in list:
if item.member_id not in member_map:
continue
tmp_member_info = member_map[ item.member_id ]
tmp_data = {
'score':item.score_desc,
'date': item.created_time.strftime("%Y-%m-%d %H:%M:%S"),
"content":item.content,
"user":{
'nickname':tmp_member_info.nickname,
'avatar_url':tmp_member_info.avatar,
}
}
data_list.append( tmp_data )
resp['data']['list'] = data_list
resp['data']['count'] = query.count()
return jsonify(resp)
@route_member.route( “/index” )
将数据统一构造、统一返回 resp_data={}
data是字典类型,返回数据
从数据表中取出可以展示的分类信息 food_cat表
step1: 取出可以展示的类别并进行排序
step2: 将数据统一构造再返回
step3: 条件判断: 字段查询到则进行循环展示
从数据表中取出销售排前的菜品信息 food表
step1: 取出菜品信息进行倒叙排列【将销售量最大的3个商品展示出来】
step2: 格式化该菜品信息以满足前端信息要求格式
step3:
原文地址:https://blog.csdn.net/xinzhengLUCK/article/details/135565295
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_58686.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!