打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Python 开发者的微信小程序开发实践

导读

在知乎上,有人提问“如何使用 Python 开发微信小程序”。

其实微信小程序作为一个前端的机制,Python 并不能插上边。只不过可以作为后端接口为微信小程序提供数据服务而已。

那么在本篇,我们就将结合微信小程序开发与 Python Web 开发,来完成一个朋友圈神器微信小程序的开发,这个微信小程序作为一个工具型的应用,供用户输入姓名或其他字段,生成一个带有炫耀成分的照片。

比如,移民申请表照片:

高额工资单照片:

豪车订单照片:

下面,就开干吧!

注册一个微信小程序

开发微信小程序,首先肯定需要去微信公众平台上注册一个微信小程序了,我们在微信公众平台的注册页面选择“小程序”进行注册。

接着有三个步骤:邮箱注册、邮箱激活和信息登记:

完成上述三个步骤后,就可以登录进入管理中心:

在基本设置中,我们可以设置微信小程序的名称、头像、说明等基本信息。

在开发设置中,我们可以获取到小程序的 AppID 和 AppSecret,这在后续的开发中会使用到,同时我们可以在此设置小程序服务器的域名:

安装和使用微信 Web 开发者工具

开发微信小程序需要使用到微信 Web 开发工具这一软件。我们下载并安装好。

启动之后,需要我们使用微信扫码进行登录:

之后,新建一个小程序项目:

指定小程序的项目目录、输入小程序的 AppID(管理页面中获取)、输入项目名称,之后我们就进入了微信开发工具的主界面了:

因为我们使用了快速启动的模板,所以自动生成了一个 Hello World 的 Demo。接下来,我们创建我们的票圈神器的小程序页面。

创建微信小程序页面

在创建小程序的页面之前,我们先来了解一下微信小程序的代码结构。

根据微信小程序开发文档的介绍:小程序包含一个描述整体程序的 app 和多个描述各自页面的 page。

一个小程序主体部分由以下三个文件组成,必须放在项目的根目录。

  • app.js(定义小程序的逻辑)
  • app.json(定义小程序的公共配置)
  • app.wxss(定义小程序的公共样式表)

同时,一个小程序的页面由四个文件组成:

  • JavaScript 文件(定义页面逻辑)
  • WXML 文件(定义页面结构)
  • WXSS 文件(定义页面样式)
  • JSON 文件(定义页面配置)

微信小程序的视图层负责页面的展示,由 WXML 文件描述页面结构和 WXSS 文件描述页面的样式。

WXML 和 WXSS 是什么东西呢?我们可以拿 HTML 和 CSS 来与之进行类比。虽然它们不一样,但是它们真的很相似。

WXML 是一套微信定义的可嵌套的标记语言,而 WXSS 则具备 CSS 的大部分特性,并对 CSS 进行了扩充和修改。

接下来我们来规划一下我们的小程序的页面构成:

  • 首页列表页:用于显示可用于制作照片的条目;
  • 详情表单页:用于显示照片效果以及接收用户输入信息;
  • 照片结果页:用于显示生成的照片以及提供保存按钮;

创建页面目录和文件

首先,我们在项目目录结构的 pages 路径下新建一个 detail 目录,其下包含三个同名的 JS 文件、WXML 文件、WXSS 文件;一个 result 目录,其下包含三个同名的 JS 文件、WXML 文件、WXSS 文件;最后 pages 目录下的结构如下图所示:

然后,在创建的 JS 文件中输入以下代码:

Page({  /**   * 页面的初始数据   */  data: {  },  /**   * 生命周期函数--监听页面加载   */  onLoad: function (options) {  },  /**   * 生命周期函数--监听页面初次渲染完成   */  onReady: function () {  },  /**   * 生命周期函数--监听页面显示   */  onShow: function () {  },  /**   * 生命周期函数--监听页面隐藏   */  onHide: function () {  },  /**   * 生命周期函数--监听页面卸载   */  onUnload: function () {  },  /**   * 页面相关事件处理函数--监听用户下拉动作   */  onPullDownRefresh: function () {  },  /**   * 页面上拉触底事件的处理函数   */  onReachBottom: function () {  },  /**   * 用户点击右上角分享   */  onShareAppMessage: function () {  }})

Page() 函数用来注册一个页面。接受一个 object 参数,以指定页面的初始数据、生命周期函数、事件处理函数等。

使用微信开发者工具的智能提示可以快速生成这些代码:

完成这一步之后,我们打开项目根目录的 app.json 文件:

在pages列表中添加如下代码:

"pages/detail/detail","pages/result/result",

最后 app.json 文件中 pages 列表的值应该为:

[    "pages/index/index",    "pages/detail/detail",    "pages/result/result",    "pages/logs/logs"  ],

编辑列表页面

首先,我们在列表页面放置一个轮播图,让我们的页面不显单调。准备三张图片:

在项目根路径下新建一个名为 imgs 的目录,将三张轮播图片复制进去:

在 index.js 文件的 Page 实例中,在 data 字典添加一个键值对,用于指定本地轮播图片的位置:

删除 index.wxml 文件中的所有代码,输入以下代码以创建一个轮播图:

<swiper class="swiper" indicator-dots="true" autoplay="true" interval="5000" duration="1000">     <block wx:for="{{headimg}}" wx:for-index="index">      <swiper-item>       <image src="{{item.url}}" class="slide-image" mode="aspectFill"/>      </swiper-item>     </block>  </swiper>

其中:

  • swiper 标签表示滑块视图容器;
  • swiper-item 标签则表示滑块的条目;
  • block 标签表示一个标签块

我们可以看到,在 block 标签中,我们为其设置了 wx:for 属性,这个属性用于列表渲染,绑定了 Page 的 data 中的 headimg 数组(在微信小程序中,WXML 中的动态数据都来自于对应 JS 文件 Page 中的 data 数据)。

接着,调整轮播图的样式,在 index.wxss 文件中输入以下代码:

.swiper { height: 400rpx; width: 100%;}.swiper image { height: 100%; width: 100%;}

最后保存文件,在微信开发者工具中可以预览到我们的轮播图已经创建成功:

创建完轮播图之后,我们继续编辑创建图片列表结构。

<view class="temp_box">  <block wx:for="{{templist}}">    <view class="temp_item">      <navigator url="../detail/detail?tid={{item.id}}">        <image src="https://www.huabandata.com/{{item.icon}}"></image>        <view class="content">          <text>{{item.name}}</text>        </view>      </navigator>    </view>  </block></view>

在页面的列表结构中,我们使用一个 view 标签作为外部容器,里面定义了一个 block 标签用于遍历图片模板数据生成多个图片信息,定义渲染的数组为 templist,这个我们将在 index.js 文件中进行定义和声明。

同时使用了 navigator 标签,用于页面的跳转,设置一个参数 tid 并将模板的 id 作为值,使其能够跳转到具体模板的详情页面。

然后在 index.wxss 文件中添加以下样式:

/* 模板图片列表 */.temp_box {    margin: 3px;    width: 100%;}.temp_item {    display: inline-block;    width: 48%;    margin: 0.5%;    background-color: white;}.temp_item image {    width: 100%;    height: 160px;}.temp_item .content {    width: 100%;    height: 32px;    margin: 5px;}.temp_item .content text {    font-size: 12px;    line-height: 16px;    overflow: hidden;    text-overflow: ellipsis;    display: -webkit-box;    -webkit-line-clamp: 2;    -webkit-box-orient: vertical;}

如果 templist 数组有合适的数据,那么其渲染出来的页面应该是下面这样的:

编辑详情页面

详情页面相较于列表页面简单很多,由两个结构组成:

  • 图片模板;
  • 表单输入框;
  • 提交按钮;

所以我们的详情页面 detail.wxml 的结构为:

<view class='temp'>  <image src='https://www.xxx.com/{{tempData.img}}'></image></view><form bindsubmit='generate'>  <view class="form">    <view class='li'>      <image class='icon' src='http://www.xxx.com/media/resume/icon_user.png'></image>      <input class='input' placeholder='请输入{{tempData.hint}}' name='content'></input>    </view></view><button class="button" form-type='submit'>立刻生成照片</button></form>

在这里,我们通过 <view> 标签包裹着 <image> 标签来显示图像,然后用一个 form 表单标签包裹着 input 输入框和 button 提交按钮。

在 button 按钮中,我们通过设置 form-type 属性为 submit,使得点击这个按钮时会提交表单。

表单的提交处理由 <form> 标签的 bindsubmit 属性来控制,在此我们指定了处理函数为 generate,我们将在 detail.js 中对 generate 函数进行定义。

然后,在 detail.wxss 中对其进行样式设计:

page{background-color: #efeff4}.temp{  background-color: white;  border: #e5e5e5 solid 1px;   display: flex;   align-items: center;  justify-content:center;}.temp image{   height: 320px;}.form{  margin-top: 20rpx;   background-color: white;  border: #e5e5e5 solid 1px;   border-right: none;    border-left: none;  }.li{  height: 100rpx;   border-bottom: #e5e5e5 solid 1px;   width: 90%;   margin: auto;   display: flex;   align-items: center }.input{padding-left: 20rpx;  width: 94%; color: black}.icon{  width: 50rpx;  height: 50rpx;}.button{    background-color: #09bb07;     margin: auto;     margin-top:20rpx;    margin-bottom: 20rpx;      width: 90%;     color: white }

如果 tempData 数组中有正确的数据,那么详情页面的显示效果如下所示:

编辑结果页面

结果页面与详情页面类似,同样是显示一个图片,和一个按钮(用于保存照片至本地),所以将 detail 页面的结构和样式稍作修改即可。

result.wxml:

<view class='temp'>  <image src='https://www.xxx.com/{{imgurl}}'></image></view><button class="button" form-type='submit' bindtap='savePhoto'>保存照片</button>

reault.wxss:

page{background-color: #efeff4}.temp{  background-color: white;  border: #e5e5e5 solid 1px;   display: flex;   align-items: center;  justify-content:center;}.temp image{   height: 320px;}.button{    background-color: #09bb07;     margin: auto;     margin-top:20rpx;    margin-bottom: 20rpx;      width: 90%;     color: white }

如果 imgurl 数组有正确的数据,那么结果页面的显示效果如下所示:

创建 Django 应用

在小程序的页面创建和设计好之后,我们需要创建一个 API 数据接口,供小程序请求获取,以生成供 WXML 页面进行渲染的数组。

因为本篇讲的是《Python 开发者的微信小程序开发实践》,自然使用的是 Python 语言,而我对 Django 相对比较熟悉,所以我们使用的是 Django 框架来对小程序提供 API 接口。

我已经有一个 Django 项目在运行,所以在此直接在此项目下创建 Django App:

python3 manage.py startapp pyq_tool

通过 PIL 模块合成一张装 X 照片

要生成一张那样可用来炫耀的图片,其实很简单,利用图像处理模块,在图片上添加相应字体的文字即可。

在 Python 中,我们使用 PIL 模块对图像进行处理,其可以通过 pip 命令进行安装:

pip install pillow

下面我们介绍一下使用 PIL 库生成一张装 X 图片的过程:

(1)引入核心模块:

from PIL import Image,ImageDraw,ImageFont

其中,Image 是图像类的包装器,ImageDraw 用于对图片界面进行操作,ImageFont 用于进行光栅字体管理。

(2)根据图片大小,创建一个新的图像:

bg = Image.new("RGB",(640,853))

(3)打开图片:

im = Image.open(r"toutu3.jpg")

(4)合并两个图片为一个新的图像:

draw2 = Image.blend(bg,im,1.0)

(5)创建一个图像绘制对象:

draw = ImageDraw.Draw(draw2)

(6)添加一个字体并指定字体大小:

ttfont = ImageFont.truetype(r"gb.ttf",30)

(7)在图像绘制对象中添加文字:

draw.text((230,120),'州的现实', fill=(20,20,20),font=ttfont)

(8)最后显示图像:

draw2.show()

这样,我们就使用 Python 的 PIL 模块完成了图像的操作从而制作出了一个新的图像,结果为:

如果我们需要保存图像,则第8步改成:

draw2.save()

创建应用数据模型、视图函数和 URL路由

创建数据模型

根据上面生成照片的代码,我们可以发现不同照片之间共同的部分和不同的部分,共同的部分就是代码的结构和图像处理的逻辑,不同的部分则是图片、图片的大小,字体的类型和大小,文本的内容和颜色等。

将这些不同之处,提取出来,我们可以创建一个数据模型用于保存不同模板图片的信息,以根据不同的模板,使用同一台代码生成不同的照片。所以,我们在 pyq_tool 目录下的 models.py 文件中创建一个数据模型来保存不同模板图片的数据:

from django.db import models# Create your models here.class Tempinfo(models.Model):    name = models.CharField(max_length=20,verbose_name="模板名称")    font = models.CharField(max_length=5,verbose_name='字体代码')    fontsize = models.IntegerField(verbose_name="字体大小")    img = models.ImageField(upload_to='pyq_tool',verbose_name="模板图片")    imgsize = models.CharField(max_length=10,verbose_name='图片大小')    icon = models.ImageField(upload_to='pyq_tool',verbose_name="图标")    hint = models.CharField(max_length=10,verbose_name="输入提示")    textcolor = models.CharField(max_length=15,verbose_name='文本颜色')    textplace = models.CharField(max_length=10,verbose_name='文本位置')    text2 = models.CharField(max_length=15,verbose_name='日期文本',null=True,blank=True)    text2hint = models.CharField(max_length=10,verbose_name="文本2提示",null=True,blank=True)    text2place = models.CharField(max_length=10,verbose_name='日期位置',null=True,blank=True)    def __str__(self):        return self.name    class Meta:        verbose_name = '票圈神器'        verbose_name_plural = verbose_name

然后将 pyqtool 添加进 settings.py 文件中的 INSTALLEDAPPS 列表中,使用 makemigrations 和 migrate 命令生成数据模型。最后,每一个图片模板的信息如下图所示:

根据收集好的装 X 图片模板,向数据库中添加几条数据:

创建视图函数

在数据库中有了数据之后,我们来创建视图函数,在创建具体视图函数之前,我们先引入需要使用到的模块:

from django.shortcuts import renderfrom django.http import JsonResponsefrom django.views.decorators.csrf import csrf_exemptfrom .models import Tempinfofrom dss.Serializer import serializerfrom django.views.generic import ListViewfrom dss.Mixin import MultipleJsonResponseMixinfrom PIL import Image,ImageDraw,ImageFontimport datetimeimport os

为了简单快捷的序列化模型数据,在此我们使用一个第三方的 Django 序列化模块——Django Simple Serializer,一个由国人开发的 Django 数据快速序列化方案。

首先是模板列表视图,用于返回一个多条数据组成数组供小程序的首页列表页进行渲染 WXML:

# 获取模板列表class GetTempList(MultipleJsonResponseMixin,ListView):    model = Tempinfo    queryset = Tempinfo.objects.all()    paginate_by = 6

创建一个基于类的视图,借助 Django Simple Serializer 生成一个分页接口,每页6条数据。

然后是模板详情视图,根据模板 id 查询并返回模板的数据:

@csrf_exemptdef get_temp_detail(request):    if request.method == 'POST':        id = request.POST.get('tid','')        if id is not '':            try:                detail = Tempinfo.objects.get(id=id)                detail = serializer(detail,datetime_format='string')                return JsonResponse({'sucess':True,'data':detail})            except Exception as e:                return JsonResponse({'success':False,'data':str(e)})        else:            return JsonResponse({'success':False,'data':'没有数据'})

最后是照片的生成视图:

@csrf_exemptdef generate_photo(request):    if request.method == 'POST':        id = request.POST.get('tid','')        content = request.POST.get('content','')        if id != '' and content != '':            try:                temp = Tempinfo.objects.get(id=id)                fontpath = os.path.join(BASE_DIR,'media/pyq_font/{font}.ttf'.format(font=temp.font))                ttfont = ImageFont.truetype(fontpath,int(temp.fontsize))                # 图片大小                imgsize = temp.imgsize.split(",")                try:                    bg = Image.new("RGB",(int(imgsize[0]),int(imgsize[1])))                except Exception as e:                    return JsonResponse({'success':False,'data':'图片大小出错:'+str(e)})                im = Image.open(temp.img)                draw2 = Image.blend(bg,im,1.0)                draw = ImageDraw.Draw(draw2)                try:                    textplace = temp.textplace.split(",")                    textcolor = temp.textcolor.split(",")                    draw.text((int(textplace[0]), int(textplace[1])),content, fill=(int(textcolor[0]), int(textcolor[1]), int(textcolor[2])),font=ttfont)                except Exception as e:                    return JsonResponse({'success':False,'data':'文字颜色位置出错:'+str(e)})                if temp.text2 != '':                    text2place = temp.text2place.split(",")                    draw.text((int(text2place[0]), int(text2place[1])),                              datetime.date.strftime(datetime.date.today(),"%Y-%m-%d"),                              fill=(int(textcolor[0]), int(textcolor[1]), int(textcolor[2])),                              font=ttfont)                filename = str(datetime.datetime.today()).replace(':','-').replace(' ','-').replace('.','')                photoname = os.path.join(BASE_DIR,'media/pyq_photo/{0}.jpg'.format(filename))                draw2.save(photoname)                return JsonResponse({'success':True,'data':'media/pyq_photo/{0}.jpg'.format(filename)})            except Exception as e:                return JsonResponse({'success':False,'data':str(e)})        else:            return JsonResponse({'success':False,'data':'不能为空'})

我们的小程序目前只需要使用到这三个视图函数。接下来创建 URL 路由。

创建 URL 路由

在 views.py 同级目录下新建一个 pqy_tool 应用的 urls.py 文件,将以下代码写入:

from django.conf.urls import url, includefrom . import viewsurlpatterns = [    url(r'^templist/',views.GetTempList.as_view()),    url(r'^tempdetail/',views.get_temp_detail),    url(r'^generate/',views.generate_photo),]

然后,再在 settings.py 文件同级目录下的 urls.py 中,将 pyq_tool 应用的 urls.py 包含进项目的 URl 路由中:

# 票圈神器    url(r'^pyq/',include('pyq_tool.urls')),

完成这一步,我们的 Django API 接口就完成了。测试一下列表接口,结果显示正常:

微信小程序请求 Django 接口

在完成后台 API 数据接口的创建之后,我们需要做的就是让微信小程序请求这些接口并解析数据。这些步骤,都分别在 index.js、detai.js 和 result.js 中完成。

列表页面数据请求

在 index.js 文件中,我们在 data 字典中定义两个空的变量:

  data: {    headimg: [      { url: '/imgs/head1.png' },      { url: '/imgs/head2.png' },      { url: '/imgs/head3.png' },    ],    templist:[],    next:''  },

templist 用于填充模板列表数据,next 用于标识分页。

然后在 onload() 函数中,使用小程序的网络请求接口 wx.request() 方法对模板列表的 API 进行请求,将获取到的数据赋值给 templist 和 next:

onLoad: function () {    var that = this;    //获取模板列表    wx.request({      url: 'https://www.huabandata.com/pyq/templist/',      method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT      header: { 'content-type': 'application/x-www-form-urlencoded' }, // 设置请求的 header      success: function (res) {        console.log(res)        // success        if (res.data) {          that.setData({            templist: res.data.tempinfo_list,            next: res.data.page_obj.next          })          console.log(that.data)        } else {          wx.showToast({            title: '服务器开了小差,下拉刷新一下',            icon: 'waring',            duration: 3000          })        }      },      fail: function (res) {        // fail        wx.showToast({          title: '服务器开了小差,下拉刷新一下',          icon: 'waring',          duration: 3000        })      },      complete: function (res) {        // complete      }    })  },

完成这一步,我们就可以在首页看到通过 wx.request 请求、经由 WXML 的 wx:for 属性渲染后的数据了:

这样,列表页面的功能基本实现了,我们还需要添加一个下拉刷新和上拉加载下一页的功能。首先在 app.json 中的 window 字典中添加:

"enablePullDownRefresh": true

以开启下拉刷新的功能。然后在 index.js 的 onPullDownRefresh 函数中添加下拉刷新的代码,与 onLoad() 函数的代码类似:

  onPullDownRefresh: function (i) {    var that = this;    wx.request({      url: 'https://www.huabandata.com/pyq/templist/',      method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT      header: { 'content-type': 'application/x-www-form-urlencoded' }, // 设置请求的 header      success: function (res) {        console.log(res)        // success        if (res.data) {          that.setData({            templist: res.data.tempinfo_list,            next: res.data.page_obj.next          })          console.log(that.data)        } else {          wx.showToast({            title: '服务器开了小差,下拉刷新一下',            icon: 'waring',            duration: 3000          })        }      },      fail: function (res) {        // fail        wx.showToast({          title: '服务器开了小差,下拉刷新一下',          icon: 'waring',          duration: 3000        })      },      complete: function (res) {        // complete      }    })    wx.showToast({      title: '刷新成功',      icon: 'success',      duration: 2000    })    console.log('刷新')  },

再是上拉加载下一页的 onReachBottom() 函数,通过 next 来判断是否存在下一次,如果存在则传入页面参数并请求,如果不存在则提示“没有更多了”:

  onReachBottom: function (i) {    var that = this;    if (that.data.next != null) {      wx.request({        url: 'https://www.huabandata.com/pyq/templist/',        data: {          'page': that.data.next        },        method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT        header: { 'content-type': 'application/x-www-form-urlencoded' }, // 设置请求的 header        success: function (res) {          console.log(res)          // success          if (res.data.is_paginated) {            that.setData({              templist: that.data.templist.concat(res.data.tempinfo_list),              next: res.data.page_obj.next            })            console.log(that.data)          } else {            wx.showToast({              title: '服务器开了小差,下拉刷新一下',              icon: 'waring',              duration: 3000            })          }        },        fail: function (res) {          // fail          wx.showToast({            title: '服务器开了小差,下拉刷新一下',            icon: 'waring',            duration: 3000          })        },        complete: function (res) {          // complete        }      })    } else {      wx.showToast({        title: '没有更多了',        icon: 'info',        duration: 2000      })    }    console.log('加载下一页')  },})

完成这两个函数的编写,那么效果将如下所示:

详情页面数据请求

详情页面在 detail.js 中主要有两个函数进行数据请求:

  • 获取从列表页跳转来模板 id,对 id 请求具体的模板数据;
  • 传递模板 id 和表达文本内容以生成照片。

第一个请求我们直接可以在 onLoad() 函数中完成:

  onLoad: function (options) {    var that = this;    var tid = options.tid    //获取模板详情    wx.request({      url: 'https://www.huabandata.com/pyq/tempdetail/',      data:{        'tid':tid      },      method:'POST',      header: { 'content-type': 'application/x-www-form-urlencoded' },      success:function(res){        console.log(res)        that.setData({          tempData:res.data.data        })      },fail:function(res){        //fail      },complete:function(res){        //complete      }    })  },

对表单数据的提交,我们在 detail.wxml 文件的 form 标签中绑定了 generate 函数,所以,我们在 detail.js 文件的 Page() 中新建一个 generate() 函数,将模板 id 和表达内容传递给照片生成的 URL,如果请求成功获取到了照片的 URL,那么使用小程序的重定向方法 wx.wx.redirectTo() 附带上照片的 URL 跳转到结果页面,如果请求失败则提示生成出错:

  generate:function(e){    var that = this;    console.log('提交的表单信息为', e)    console.log('当前数据为:', that.data)    var tid = that.data.tempData.id;    var content = e.detail.value.content;    //显示加载框    wx.showLoading({      title: '照片制作中',    })    wx.request({      url: 'https://www.huabandata.com/pyq/generate/',      method:'POST',      data:{'tid':tid,'content':content},      header: { 'content-type': 'application/x-www-form-urlencoded' },      success: function (res) {        console.log(res)        if(res.data.success){          wx.hideLoading()          wx.redirectTo({            url: '../result/result?imgurl=' + res.data.data          })        }else{          wx.hideLoading()          wx.showToast({            title: '生成出错'          })        }      }, fail: function (res) {        //fail        wx.hideLoading()        wx.showToast({          title: '生成出错'        })      }, complete: function (res) {        //complete      }    })  },

详情页面最后呈现为:

结果页面

结果页面相对比较简单,获取到页面跳转过来附带的照片 URL 将其赋值给imgURL,就可以完成生成后的照片的显示:

  onLoad: function (options) {    var that = this    console.log(options)    console.log('点击某个模板跳转到', options.imgurl)    const imgurl = options.imgurl    that.setData({ imgurl: imgurl })  },

接着,定义保存照片的函数 savePhoto(),在微信小程序中,保存一个图片需要两个步骤:

  1. 使用 wx.getImageInfo() 方法传递一个图片文件路径(相对路径、临时文件路径、存储文件路径、网络图片路径)获取图片的信息,其结果会返回图片的本地路径;
  2. 再使用 wx.saveImageToPhotosAlbum() 方法传递一个图片文件路径(不支持网络图片路径)以保存图片到系统相册

所以,我们的 savePhoto() 函数为:

  savePhoto:function(i){    var that = this;    // wx.authorize({    //   scope: 'scope.writePhotosAlbum',    // })    wx.getImageInfo({      src: 'https://www.huabandata.com/'+that.data.imgurl,      success:function(i){        var path = i.path;        wx.saveImageToPhotosAlbum({          filePath: path,          success(result){            console.log(result)            wx.showToast({              title: '保存成功',              icon: 'success',              duration: 2000            })          }        })      }    })  },

其效果如下所示:

上架

到了这一步,我们的票圈神器小程序就开发完成了,接下来可以进行上传和上架了。

点击微信开发者工具工具栏的“上传”按钮:

其会提示我们上传成功后,需要将本次上传的版本设置为体验版:

接着输入此次上传的版本信息:

提示上传成功后,我们就可以在微信小程序管理后台的“开发管理”栏目下看到了:

我们可以直接提交审核,或者是将其选为体验版本,供指定的体验者进行前提体验测试。

我们直接提交审核,会要求我们填写相关的信息:

接着点击“提交审核”按钮即可。完成提交后,我们就可以在“开发管理”的审核版本中看到我们刚刚提交的版本了:

耐心等待审核通过吧。

如果不通过怎么办?嗯,改内容呗,毕竟:


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
【AI番外】今天说微信小程序开发,不能上线的AI,都是纸老虎
微信小程序云开发一路走来所遇到的坑
【微信小程序开发•系列文章二】视图层
第2章 微信小程序开发基础
岁寒之松柏:小程序skyline渲染引擎初尝试 | 微信开放社区
微信小程序<span style="color: rgb(0, 0, 0); font-size: 14px; font-weight: 400;">麦当劳点餐)+爬虫</span>
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服