今天不知道怎么的,之前拿编程浪子地作品抄过来粘上用好好的,昨天开始照片突的就不显示了。
今天不妨再耐味地细细探究一下微信小程序wxml 和flask服务器端是怎么jpg图片数据交互的。
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>
<!-- 这段代码是一个小程序中的一个视图组件,它使用了小程序的模板语法。具体来说,这段代码定义了一个视图组件,其中包含一个view标签,
该标签具有id属性和class属性,并且绑定了一个tap事件处理函数"catClick"。
在view标签内部,使用了双花括号语法来插入动态数据,其中item.id和item.name是动态的数据,根据实际情况进行渲染。-->
</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">
<!-- wx:for-items="{{goods}}" 是一个循环遍历的功能,将 goods 数组中的每个元素都渲染成一个 goods-box 组件。-->
<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>
如上例代码所示,图片的展示是通过一个image src='{{item.pic_url}}'标签引入的。通常情况下,item
是一个对象或数组,它包含了多个属性,其中pic_url
就是其中一个属性。在这个例子中,item.pic_url
表示图片的URL地址,通过该地址可以加载并显示对应的图片。
总之,image
标签是小程序中用于显示图片的组件,通过 src="{{item.pic_url}}"
绑定了图片的地址。追根溯源,找goods数组是从哪里传来的。
goods数组是通过小程序端地js文件绑定的一个getBannerAndCat()函数,并将其设置在onshow生命周期里,通过调用getFoodList(),自动进行的数据读取和刷新。
//解决切换不刷新维内托,每次展示都会调用这个方法
onShow:function(){
this.getBannerAndCat();
},
问题: 这个item对象或数组从何而来?是小程序端的js文件吗?
mina/pages/food/index.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是一个函数,它用于处理轮播图的点击事件具体的实现逻辑如下:
tapBanner: function (e) {
// 首先,通过e.currentTarget.dataset.id获取到当前点击的轮播图的id。
// 然后,判断id是否为0,如果不为0,则执行以下操作:
if (e.currentTarget.dataset.id != 0) {
// 使用wx.navigateTo函数进行页面跳转,跳转到指定的页面。
wx.navigateTo({
// 跳转的目标页面是"/pages/food/info",并且通过url参数传递了点击轮播图的id,参数名为id。
url: "/pages/food/info?id=" + e.currentTarget.dataset.id
});
// 这段代码的作用是当用户点击轮播图,如果轮播图的id不为0,则跳转到指定的页面,并将点击轮播图的id作为参数传递给标页面。
}
},
// toDetailsTap是一个函数,它是在小程序中用于点击事件的回调函数。当触发点击事件时,会执行该函数。
toDetailsTap: function (e) {
// 该函数的作用是跳转到指定的页面。在函数内部,通过调用wx.navigateTo方法来实现页面跳转。
// 其中,url参数指定了跳转的目标页面路径,通过拼接字符串的方式将参数id传递给目标页面。
// 总结一下,toDetailsTap函数的作用是在点击事件发生时,跳转到指定的页面,并将参数id传递给目标页面。
wx.navigateTo({
url: "/pages/food/info?id=" + e.currentTarget.dataset.id
});
},
getBannerAndCat: function () {
var that = this;
// 使用微信小程序的wx.request方法发送一个请求。
wx.request({
// 请求的URL是通过app.buildUrl(“/food/index”)方法构建的
url: app.buildUrl("/food/index"),
// 请求头部信息通过app.getRequestHeader()方法获取
header: app.getRequestHeader(),
// 请求成功后,会将返回的数据保存在resp变量中。
success: function (res) {
var resp = res.data;
// 如果返回的code不等于200,会通过app.alert方法弹出一个提示框显示返回的错误信息,并结束函数的执行。
if (resp.code != 200) {
app.alert({"content": resp.msg});
return;
}
// 如果返回的code等于200,会将返回的banner_list和cat_list数据分别保存在banners和categories变量中,
that.setData({
banners: resp.data.banner_list,
categories: resp.data.cat_list
});
// 并调用getFoodList方法
that.getFoodList();
}
});
},
// 这段代码是一个小程序中的一个函数,名为catClick。它的作用是在点击某个分类时,根据点击的分类id更新数据,并调用getFoodList函数获取对应分类的商品列表。
catClick: function (e) {
this.setData({
// 通过e.currentTarget.id获取点击的分类id。
activeCategoryId: e.currentTarget.id
});
// 使用setData方法更新数据,将activeCategoryId设置为点击的分类id。
this.setData({
// 将loadingMoreHidden设置为true,p设置为1(表示当前页数为1),goods设置为空数组(清空商品列表)。
loadingMoreHidden: true,
p:1,
goods:[]
});
// 调用getFoodList函数获取对应分类的商品列表。
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;
}
// 然后,函数会将processing标志设置为true,表示正在处理请求。
that.setData({
processing:true
});
// 接下来,函数会发送一个请求到服务器,请求的URL是"/food/search",并且会带上一些参数,
// 如cat_id(食品分类ID)、mix_kw(搜索关键词)、p(页码)等。
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,
},
// 当服务器返回响应时,函数会判断响应的状态码是否为200,如果不是,则弹出一个提示框显示错误信息,并返回。
success: function (res) {
var resp = res.data;
if (resp.code != 200) {
app.alert({"content": resp.msg});
return;
}
// 如果响应的状态码为200,则从响应数据中获取到食品列表,并将其与之前已有的食品列表进行合并。
var goods = resp.data.list;
that.setData({
goods: that.data.goods.concat( goods ),
p: that.data.p + 1,
//最后,函数会更新页面上的数据,包括goods(食品列表)、p(页码)和processing(处理状态),
// 并将processing标志设置为false,表示请求处理完成。
processing:false
});
// 判断变量resp.data.has_more的值是否为0。如果resp.data.has_more的值为0,
// 则执行setData方法,将loadingMoreHidden属性设置为false。
if( resp.data.has_more == 0 ){
that.setData({
loadingMoreHidden: false
});
}
}
});
}
});
那接下来,就去flask服务器端看看/food/search路由是什么情况,图片传参是怎么传的。
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 app 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)