今天不知道怎么的,之前拿编程浪子地作品抄过来粘上用好好的,昨天开始照片突的就不显示了。
今天不妨再耐味地细细探究一下微信小程序wxml 和flask服务器端是怎么jpg图片数据交互的。
mina/pages/food/index.wxml
XML
<!--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(),自动进行的数据读取和刷新。
javascript
//解决切换不刷新维内托,每次展示都会调用这个方法
onShow:function(){
this.getBannerAndCat();
},
问题: 这个item对象或数组从何而来?是小程序端的js文件吗?
mina/pages/food/index.js
javascript
//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
python
@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)
common/libs/UrlManager.py
python
# -*- coding: utf-8 -*-
import time
from app import app
class UrlManager(object):
def __init__(self):
pass
@staticmethod
def buildImageUrl( path ):
app_config = app.config['APP']
url = app_config['domain'] + app.config['UPLOAD']['prefix_url'] + path
return url