首页
小程序框架
后台管理系统
新后台框架
部署指南
公司介绍
首页
小程序框架
后台管理系统
新后台框架
部署指南
公司介绍
  • 小程序端模板

小程序端模板

介绍

以下是小程序端模板说明

为方便快速的开发项目,我们将一些公用的组件,公用的方法,封装到小程序模板中,模板已经处理了大部分基础逻辑,并阐述了项目的基础架构逻辑。约定了参数的基本命名以及作用。方便快速的开发小程序。快速的处理各种重复逻辑

快速开始

创建项目目录并下载模板

mkdir New_Project
# 创建一个New_Project目录
cd New_Project
#切换至New_Project目录
git init
# 初始化git
git remote add origin https://gitee.com/ylsg_1/basic-applet-template.git
# 设置远程仓库地址
git pull origin master
# 拉取仓库到本地

目录架构(重要)


├─ Api
│  ├─ api.js                           //接口配置以及图片域名配置
│  ├─ cache.js                         //缓存封装
│  ├─ city.js                          //城市list本地缓存json 
│  ├─ event.js                         //封装的全局环境侦听
│  ├─ http.js                          //封装的请求方法,请求拦截器,响应拦截器
│  ├─ init.js                          //初始化以上方法,挂载到wx全局变量中
│  ├─ qqmap                            //腾讯地图SDK目录
│  │  └─ qqmap-wx.js
│  └─ util.js                          //地理位置/-时间处理-/-防抖-/
├─ app.js                              //公共app.js
├─ app.json                            //公共app.json
├─ app.wxss                            //公共样式
├─ custom-tab-bar                      //自定义taber按需引用
│  ├─ index.js
│  ├─ index.json
│  ├─ index.wxml
│  └─ index.wxss
├─ img                                //公共图标地址,当项目将上线时,应该全部将该文件夹放到服务器上
│  ├─ address.png
│  ├─ city.png
│  ├─ citydetail.png
│  ├─ close-g.png                    //登陆用的关闭icon
│  ├─ close-r.png
│  ├─ delete-icon.png
│  ├─ deletes.png
│  ├─ editquan.png
│  ├─ editquanac.png
│  ├─ gouac.png
│  ├─ red_close.png
│  ├─ register.png                  //全局登陆背景图,命名不可变动
│  ├─ right-b.png
│  ├─ right-g.png
│  └─ tab                           //tab图标,这里的文件夹长期存本地
│     ├─ center.png
│     ├─ home-active.png
│     ├─ home.png
│     ├─ my-active.png
│     ├─ my.png
│     └─ tab-box.png
├─ pages                           //页面栈
│  ├─ about-my                     //修改个人资料公共页
│  │  ├─ about-my.js
│  │  ├─ about-my.json
│  │  ├─ about-my.wxml
│  │  └─ about-my.wxss
│  ├─ cropperImage                 //原生已有新接口,此组件废弃上传图片裁剪页,多用于头像上传,指定尺寸上传
│  │  ├─ cropperImage.js
│  │  ├─ cropperImage.json
│  │  ├─ cropperImage.wxml
│  │  └─ cropperImage.wxss
│  ├─ index                       //首页必须为index
│  │  ├─ index.js
│  │  ├─ index.json
│  │  ├─ index.wxml
│  │  └─ index.wxss
│  ├─ my                          //我的页面,注意页面下的文件必须与页面命名一致,比如my,下面必须是my.js,my.json...,当然可以一个文件夹下面多个页面,但是尽量不这样写
│  │  ├─ my.js
│  │  ├─ my.json
│  │  ├─ my.wxml
│  │  └─ my.wxss
│  ├─ release                    
│  │  ├─ release.js
│  │  └─ release.wxml
│  ├─ text                       //富文本内容展示页面,支持webview和富文本
│  │  ├─ text.js
│  │  ├─ text.json
│  │  ├─ text.wxml
│  │  └─ text.wxss
│  └─ upfile                     //上传文件演示demo,上传本地目录文件与聊天中文件
│     ├─ upfile.js
│     ├─ upfile.json
│     ├─ upfile.wxml
│     └─ upfile.wxss
├─ Cpart                         //公共组件文件夹,前面C为了方便将文件夹上排
│  ├─ head                       //公共自定义头部组件,自定义头部时使用
│  │  ├─ head.js
│  │  ├─ head.json
│  │  ├─ head.wxml
│  │  └─ head.wxss
│  ├─ image-cropper              //裁剪图像组件
│  │  ├─ image-cropper.js
│  │  ├─ image-cropper.json
│  │  ├─ image-cropper.wxml
│  │  └─ image-cropper.wxss
│  ├─ impower                    //全局登陆组件,已封装好登陆授权逻辑
│  │  ├─ impower.js
│  │  ├─ impower.json
│  │  ├─ impower.wxml
│  │  └─ impower.wxss
│  ├─ mp-html                   //全局富文本组件
│  │  ├─ index.js
│  │  ├─ index.json
│  │  ├─ index.wxml
│  │  ├─ index.wxss
│  │  ├─ node
│  │  │  ├─ node.js
│  │  │  ├─ node.json
│  │  │  ├─ node.wxml
│  │  │  └─ node.wxss
│  │  └─ parser.js
│  ├─ phonePopup               //全局授权手机号解密组件,已封装好绑定用户逻辑
│  │  ├─ phonePopup.js
│  │  ├─ phonePopup.json
│  │  ├─ phonePopup.wxml
│  │  └─ phonePopup.wxss
│  └─ posterdist               //json配置海报组件,不会canvas你也能快速出海报
│     ├─ index
│     │  ├─ index.js
│     │  ├─ index.json
│     │  ├─ index.wxml
│     │  └─ index.wxss
│     └─ poster
│        ├─ index.js
│        ├─ index.json
│        ├─ index.wxml
│        ├─ index.wxss
│        └─ poster.js
├─ project.config.json
├─ project.private.config.json
├─ README.md                   //交付源码时将说明文档剔除
├─ sitemap.json
└─ wxs
   ├─ filter.js
   └─ filter.wxs

API目录封装的公共方法使用说明

api.js接口配置以及图片域名配置

接口写法请严格按照get_share: 'index/get_share'接口后缀为方法名

基础接口是通用的,新项目时不管用不用得到,直接拿过去用***

//请求域名头,新项目直接换这里
const baseurl = 'https://stapi.seniorfd.com'
//腾讯地图KEY
const $qqmapKey = 'IFVBZ-3BD6V-T2OPH-UTMAR-UYNO3-UIF6Z'
//图片域名
const $domain=baseurl+'/uploads/img/'
const $api = {
    //基础接口start
    login: 'login/login', //新版登陆   [2023/2/10]
    edit_member: 'member/update_wechat_member', // 更新头像
    // edit_member: 'member/edit_member', // 更新头像
    get_banner: 'index/get_banner', //轮播图
    get_member_info: 'member/get_member_info', //个人信息
    upload_img: 'base_member/upload_img', // 上传图片
    qrcode: 'index/qrcode', // 生成二位码
    decryption: 'login/decryption', // 解密手机号
    get_show: 'index/get_show', // 获取显示配置
    get_share: 'index/get_share', // 分享图
    //基础接口end

    // 测试接口
    my_library_list: 'member/my_library_list',
    report_errors_log: 'member/report_errors_log'
}
for (let i in $api) {
    $api[i] = baseurl +'/api/'+ $api[i]
}

export {
    $api,
    $domain,
    $qqmapKey
}

使用说明 wx.$api.login //请求openid的接口地址

cache.js缓存封装

在我们的大多数项目中,经常需要频繁用到某个接口的数据,当这些接口数据短时间或一般情况下不会更新时,我们采用缓存到客户端的方式,将该数据保存,并在不同的地方可以方便快捷的调用。以下将从增删改查方面介绍下该封装的方法

存入缓存(普通用法)

wx.$cache.set(key,data)

time为可选参数,不填为永久

wx.$cache.set('a', 1)//存入缓存key为a,值为1

console.log(wx.$cache.get('a'))  //1

存入缓存(时效用法)

wx.$cache.set(key,data,time)

time为可选参数,不填为永久,当time时效过了时,无法取出值

      wx.$cache.set('a', 1, 60)//存入缓存key为a,值为1,该值将在1分钟后过期,time单位为秒

      console.log(wx.$cache.get('a'))  //1
      setTimeout(() => {
        if (wx.$cache.get('a')) {
          //缓存超过了时间,会走else
        } else {
          console.log('过期了')  //过期了
        }
      }, 60001);


读取缓存

wx.$cache.get(key)


wx.$cache.set('a', 1)//存入缓存key为a,值为1

console.log(wx.$cache.get('a'))  //1

改写缓存

wx.$cache.set(key,data,time)

重新存值就改写了,time为可选参数,不填为永久

wx.$cache.set('a', 2)//存入缓存key为a,值为2
wx.$cache.set('a', 1)//存入缓存key为a,值为1

console.log(wx.$cache.get('a'))  //1

删除指定缓存

wx.$cache.remove(key)


wx.$cache.set('a', 1)//存入缓存key为a,值为1
console.log(wx.$cache.get('a'))  //1
wx.$cache.remove('a')//清楚缓存key为a的值
console.log(wx.$cache.get('a'))  // ''

删除所有缓存

wx.$cache.clear()


wx.$cache.set('a', 1)//存入缓存key为a,值为1
console.log(wx.$cache.get('a'))  //1
wx.$cache.clear()//清理所有缓存
console.log(wx.$cache.get('a'))  // ''

http.js封装的请求方法,请求拦截器,响应拦截器

项目中必然会用到网络请求,我们需要通过get或者post方式从服务器获取数据,服务器收到我们的请求后会鉴权,并根据不同的情况返回不同的结果,这些请求在发出的时候可能需要本地加入鉴权key,或者其他接口必带参数,服务器端在返回的时候会告知我们操作成功或者失败,或者需要重新授权,我们为避免重复处理请求逻辑,与后端沟通后封装了该请求拦截器,这是通用的拦截器。 当然!也许新项目中有一些调整,拦截器也要针对做出响应调整。这里我们从拦截器的封装思路,使用方法,后续拓展方向做出解释 我们与服务端约定code判断请求状态结果

code值含义建议
200接口操作成功可进行下一步操作
400接口操作失败需要进行错误处理
999接口鉴权错误这时候需要重新登录拿取tokey(key),封装时已做相应处理
封装思路(2023年2月10日前)
//promise异步封装,默认请求方式为GET
function request(url, params, method = 'GET') {
    let header = null //header头
    let timeout = 10000 // 超时
    let tokenName = 'key' // token名,现已统一为key,这里是服务端的鉴权token,区分用户
    let p = new Promise((resolve, reject) => {
        // 开启头部loading,这里也可以改为showloading
        wx.showNavigationBarLoading()
        let token = wx.getStorageSync(tokenName)
        params.key = token
      
        // 请求
        wx.request({
            url: url,
            data: params,//已经处理的参数包
            timeout,
            header: header || {
                'Content-Type': 'application/json'
            },
            method,
            success: (res) => {
                if (res.statusCode == 200) {//当请求成功时,这时候请求已经得到响应
                    if (res.data.code == 200) {//服务端处理成功结果,code为200
                        resolve(res.data.datas)//将成功后的结果返回
                    } else if(res.data.code == 200){
                            let pageArr = getCurrentPages();//获取页面栈
                            let thisPage = pageArr[pageArr.length - 1]//拿到当前页面对象
                            wx.removeStorageSync(tokenName)//清除key
                            thisPage.setData({//调起授权
                                login: true,
                            })
                        } else {//这时候code为400,或者直接报错了
                             reject(res)//返回错误数据
                            wx.showToast({//提示错误原因
                                title: res.data.datas.error,
                                icon: 'none'
                            })
                        }
                      
                   
                }

            },
            fail: err => {
                reject(err)//当请求失败,返回错误原因,这时候一般检查是否是接口api文件中没写对
            },
            complete: () => {
               //关闭loading动画
                wx.hideNavigationBarLoading()
            }

        })
    })
    return p
}

function get(url, params = {}, method = 'GET') {
    return request(url, params , method)
}

function post(url, params = {}, method = 'POST') {
    return request(url, params , method)
}

function http(url, params = {}, method = 'POST') {
  
    return request(url, params, method)
}
http.get = get
http.post = post


export default http
封装思路(最新)
export default class http {
    // 将 ​http​ 类作为默认导出,可以在其他文件中引入并使用该类。默认导出的类可以是一个模块的主要功能实现,或者是该模块的核心类。在这种情况下,​http​ 类封装了网络请求相关的功能,并提供了方法供其他文件调用。通过将类默认导出,其他文件可以直接引入该类并使用它的方法来进行网络请求。
    constructor() {
        // 无论创建 ​http​ 类的实例时传递了什么参数,都不会对实例对象产生影响。
        // 通常情况下,​constructor()​ 方法用于接收参数并将它们分配给实例的属性,或者进行其他与初始化相关的操作。但在这个该示例中,​constructor()​ 方法没有添加其他的功能。
        console.log("========执行了Http初始化事件=========");
    }
    //用static修饰属性
    static instance = null; // http类的单例对象
    static userTokenValue = '' //  登陆的key,如果请求失败[未登录]时等待该值后重新请求
    static isRefreshToken = false //  是否正在刷新token
    static loginUrl = "" // 登录链接
    //被static修饰的属性和方法都是静态方法和属性,只能被类名调用,不能被实例化对象调用.同时也不能被子类继承,换句话说它属于当前这个类的.
    // 获取http类的实例对象
    static getInstance(loginUrl = "") {
        if (http.instance === null) {
            http.instance = new http(); // 创建一个新的http实例
            http.userTokenValue = wx.getStorageSync('key') // 获取缓存中的登录key
            if (!loginUrl) console.error("未配置登录请求URL,请前往api.js配置、若使用老版请查看[2023/2/10]之前分支")
            http.loginUrl = loginUrl // 设置登录链接
        }
        return http.instance;
    }
    // 用static修饰发起网络请求的方法
    static request(url, params, method, isAgain = false) {
        params.key = http.userTokenValue // 在请求参数中添加登录key
        return new Promise((resolve, reject) => {
            wx.request({
                url: url,
                data: params,
                timeout: 10 * 1000,
                header: {
                    'Content-Type': 'application/json'
                },
                method,
                success: (res) => {
                    resolve(res)
                },
                fail: (e) => {
                    reject(e)
                }
            })
        }).then(res => {
            //当请求不成功时,上报错误
            if (res.data.code != 200 && isAgain) return Promise.reject(res)
            //当请求成功并服务器响应正常时,返回结果datas
            if (res.statusCode == 200 && res.data.code == 200) return Promise.resolve(res.data.datas)
            //当请求成功,但服务器响应错误码为未登录时,进行登录请求
            else if (res.statusCode == 200 && res.data.code == 999) {
                //  判断是否正在刷新Token,当正在刷新Token时开定时器,否则开始刷新Token
                if (!http.isRefreshToken) {
                    http.userTokenValue = '', http.isRefreshToken = true
                    return new Promise((resolve, reject) => {
                        wx.login({ //拉取code
                            success(res) {
                                wx.request({
                                    url: http.loginUrl,
                                    method: 'POST',
                                    data: {
                                        code: res.code,
                                        //继续判断是否有上级
                                        p_id: wx.getStorageSync('pid') || 0
                                    },
                                    success(ret) {
                                        if (!(ret.data.datas.token)) {
                                            //当刷新后发现并未获得code,提示错误结果
                                            wx.showModal({
                                                title: '温馨提示',
                                                content: ret.data.datas.error,

                                            })
                                        } else {
                                            //如果获得了token,则存储
                                            wx.setStorageSync('key', ret.data.datas.token)
                                            // 存储userInfo用户信息
                                            wx.setStorageSync('userInfo', ret.data.datas.info)
                                            //获取当前页面栈
                                            let pages = getCurrentPages();
                                            let prevPage = pages[pages.length - 1];
                                            //执行页面用户信息更新
                                            prevPage.setData({
                                                userInfo: ret.data.datas.info
                                            })
                                            //给http类中token赋值,并将刷新token状态更改为未在刷新中
                                            http.userTokenValue = ret.data.datas.token, http.isRefreshToken = false
                                            return resolve()
                                        }
                                    }
                                })
                            }
                        })
                    }).then(() => {
                        return http.request(url, params, method, true)
                    })
                } else {
                    // 在刷新Token,等待[200ms查询一次]
                    return new Promise((resolve, reject) => {
                        let timer = setInterval(() => {
                            if (http.isRefreshToken == false) {
                                timer = null;
                                resolve()
                            }
                        }, 200)
                    }).then(() => {
                        return http.request(url, params, method, true)
                    })
                }
            } else {
                //当请求成功,但是错误码不是999意思不是登录状态的问题,则直接返回错误
                wx.showModal({
                    title: '提示',
                    content: res.data.datas.error,
                    showCancel: false,
                    //   complete: () => {wx.navigateBack()}
                })
                return Promise.reject(res)
            }
        })
    }
    // 发起POST请求的方法
    post(url, params = {}, method = 'POST') {
        return http.request(url, params, method)
    }
    // 发起GET请求的方法
    get(url, params = {}, method = 'GET') {
        return request(url, params, method)
    }
}
GET请求

wx.$http.get(API,params)

params为可选参数,它是一个对象,捕获错误可不写,但是如果你需要在错误后进行一些处理就将逻辑写到.catch捕获函数中

    //请求分享图,可以获得随机分享图一张,存参数为share,不要改变参数值,所有小程序都需要请求,然后分享中使用该参数
    wx.$http.get(wx.$api.get_share).then(ress => {
     console.log(ress)//请求的结果数据
    }).catch(err=>{//捕获错误,可不写,封装已经做了报错处理
      console.error(err)
    })
    //带参数
     wx.$http.get(wx.$api.get_share,{}).then(ress => {
     console.log(ress)//请求的结果数据
    })
POST请求

params为可选参数,它是一个对象,捕获错误可不写,但是如果你需要在错误后进行一些处理就将逻辑写到.catch捕获函数中

    //请求分享图,可以获得随机分享图一张,存参数为share,不要改变参数值,所有小程序都需要请求,然后分享中使用该参数
    wx.$http.post(wx.$api.get_share).then(ress => {
     console.log(ress)//请求的结果数据
    }).catch(err=>{//捕获错误,可不写,封装已经做了报错处理
      console.error(err)
    })
    //带参数
     wx.$http.post(wx.$api.get_share,{}).then(ress => {
     console.log(ress)//请求的结果数据
    })
简便请求(不建议)

封装该方法是为了省力,但是说实话这个写法不好看,不美观 params为可选参数,它是一个对象,捕获错误可不写,但是如果你需要在错误后进行一些处理就将逻辑写到.catch捕获函数中

    //请求分享图,可以获得随机分享图一张,存参数为share,不要改变参数值,所有小程序都需要请求,然后分享中使用该参数
    wx.$http(wx.$api.get_share).then(ress => {
     console.log(ress)//请求的结果数据
    }).catch(err=>{//捕获错误,可不写,封装已经做了报错处理
      console.error(err)
    })
    //带参数
     wx.$http(wx.$api.get_share,{}).then(ress => {
     console.log(ress)//请求的结果数据
    })

时间转换$datetype

我们项目中大多用到一些时间,一般后端会处理好传过来,但是特殊情况需要前端自己处理,$datetype方法将这些时间做出一些处理,方便我们使用 wx.$datetype(dateTime)

    console.log(wx.$datetype('2021/11/22 17:26'))
     

     ----------------------------------------
   {
    day1: "2021-11-22"
    day2: "2021年11月22日"
    day3: "2021/11/22"
    daytime1: "2021-11-22 17:26:00"
    daytime2: "2021年11月22日 17时26分00秒"
    time1: "17时26分00秒"
    time2: "17:26:00"
    time3: "17时26分"
    time4: "17:26"
    }

时间转换$getDateDiff

我们项目中大多用到一些时间,一般后端会处理好传过来,但是特殊情况需要前端自己处理,特别是对几分钟前、几小时前、几天前这样的需求。之前我们在做剧本杀的时候,封装了这样的转换方法。它的使用方法非常简单 wx.$getDateDiff(dateTime)

    console.log(wx.$getDateDiff('2021/11/22 17:26'))
     console.log(wx.$getDateDiff('2021/11/21 17:26'))
     console.log(wx.$getDateDiff('2021/11/22 23:36'))
     console.log(wx.$getDateDiff('2021/11/22 23:36:25'))

     ----------------------------------------
    6小时前
    1天前
    1分钟前
    1分钟前

自定义组件使用说明

为方便大家不再重复的封装组件,这里将一些历史封装好的组件做了一些整理,组件的引入不再做说明,基本的事件回调以及参数赋值查微信文档

自定义头部组件
参数含义建议
title页面标题-
color标题文字颜色-
bgSrc背景图片背景图片不能用本地地址,一定要用网络地址,且不要在本地用base64,太长了看个data要打人
bgColor背景颜色背景颜色优先级高于背景图片,意思是两者都具备时,会使用背景色
flexd是否占位如果为false,则导航栏位置不占位用于没有头部的页面中,如果时true,占位,用于普通自定义头部
flage是否返回首页是则默认返回到首页index
  <head title="敬请期待" color="#fff" bgSrc="{{bgsrc}}" height="{{userInfo.is_vip==2?588:400}}"></head>
图片裁剪页面(pages/cropperImage/cropperImage)
参数含义建议
cropperWidth裁剪宽度-
cropperHeight裁剪高度-
cimg裁剪图片的网路地址在上个页面不要再data中命名该参数,返回onshow时取这个参数的值,当然你也可以放到缓存中
全局登录授权/手机号授权组件(集成了)(已废弃)
参数含义建议
login是否进行授权默认为false,一般不用手动处理,请求拦截器中已经处理,需要在每个页面中定义
Authorization_type授权形式默认为user,可选值'user'😕/只授权头像昵称-'phone'😕/只授权手机号-'user_phone'😕/先授权头像昵称,接着授权手机号-'phone_user'😕/先授权手机号,接着授权头像昵称
app.json:
 //全局引入
 "impower": "/Cpart/impower/impower"

page.wxml:
//页面放入,所有页面都放入
 <impower login="{{login}}" Authorization_type='user_phone' />
全局绑定手机号组件(已废弃)

这里我们通用的处理方式是将该组件引入到登录组件中使用,登录组件中进行显示隐藏处理

参数含义建议
show是否进行授权默认为false,一般不用手动处理,请求拦截器中已经处理
app.json:
 //全局引入
 "pop": "/Cpart/phonePopup/phonePopup",

page.wxml:
//页面放入,所有页面都放入
 <pop show="{{phoneshow}}" />
时间选择器datetime

我们项目经常需要用到比如只能选以后的时间,需要选未来的几天时间诶的时间,datetime提供这样的选择方式

参数含义默认值建议
start时间选择器开始时间当前时间这是选择器出来后能选的最早时间
daynum往后推多少天7生成多少天的时间
dataid组件id0当页面有多个该组件时
changeevent值改变事件(time,day)返回值time是选择的时间,day是有两个组件时间隔天数

page.js:

Page({
  /**
   * 页面的初始数据
   */
  data: {
    checkInDate:'',//开始时间
    checkInDate2:'',//开始时间戳
  },
  bindDateChange(e){
    let {id} = e.target
  // console.log(e)
    if(id==1){
      this.setData({
        checkInDate:e.detail.day.day3,
        checkInTime:e.detail.day.time4,
        checkInDate2:e.detail.lotterytime
      })
    }else{
      this.setData({
        checkOutDate:e.detail.day.day3,
        checkOutTime:e.detail.day.time4,
        checkOutDate2:e.detail.lotterytime
      })
    }
    this.setData({
      timenum:parseInt((this.data.checkOutDate2 - this.data.checkInDate2)/86400000)
    })
  },
})

page.json:

{
  "usingComponents": {
    "datetime": "Cpart/datetime/datetime"
   
  }
}

page.wxml:

 <datetime value="{{checkInDate2}}"  bindchange="bindDateChange" dataid="1" id="1">
          <view class="haotime">{{f.time2(checkInDate)}}</view>
          <view class="haotime1">{{checkInTime}}</view>
          </datetime>
全局海报生成器组件

这里是直接引用大佬的一个组件,这里查看使用说明,这里阐述了封装思路 担心git地址上文章可能会被删除,所以我将方法再次做了一遍整理,如下

使用之前

使用 wxa-plugin-canvas 前,请确保你已经学习过微信官方的 小程序简易教程 和 自定义组件介绍。

安装
方式一.通过 npm 安装 (推荐)

小程序已经支持使用 npm 安装第三方包,详见 npm 支持

# npm
npm i wxa-plugin-canvas -S --production

# yarn
yarn add wxa-plugin-canvas --production
方式二.下载代码

直接通过 git 下载 wxa-plugin-canvas 源代码,并将miniprogram_dist目录拷贝到自己的项目组件目录中

使用组件
{
  "usingComponents": {
	"poster": "wxa-plugin-canvas/poster",
  }
}

接着就可以在 wxml 中直接使用组件

<poster id="poster" config="{{posterConfig}}" bind:success="onPosterSuccess" bind:fail="onPosterFail">
    <button>点击生成海报</button>
</poster>
使用注意事项
  1. 图片的域名务必添加到downloadFile合法域名中(开发设置-服务器域名-downloadFile合法域名)
  2. 如果要使用异步生成海报的方法,务必组件要加上 id="poster"
组件参数解释
config字段
字段类型必填描述
widthNumber(单位:rpx)是画布宽度
heightNumber(单位:rpx)是画布高度
backgroundColorString否画布颜色
debugBoolean否false隐藏canvas,true显示canvas,默认false
pixelRatioNumber否1为一般,值越大越清晰
preloadBoolean否true:图片资源预下载 默认false
hide-loadingBoolean否true:隐藏loading 默认false
blocksObject Array(对象数组)否看下文
textsObject Array(对象数组)否看下文
imagesObject Array(对象数组)否看下文
linesObject Array(对象数组)否看下文
blocks字段
字段名类型必填描述
xNumber(单位:rpx)是块的坐标
yNumber(单位:rpx)是块的坐标
widthNumber(单位:rpx)否如果内部有文字,由文字宽度和内边距决定
heightNumber(单位:rpx)是
paddingLeftNumber(单位:rpx)否内左边距
paddingRightNumber(单位:rpx)否内右边距
borderWidthNumber(单位:rpx)否边框宽度
borderColorString否边框颜色
backgroundColorString否背景颜色
borderRadiusNumber(单位:rpx)否圆角
textObject否块里面可以填充文字,参考texts字段解释
zIndexInt否层级,越大越高
texts字段
字段名类型必填描述
xNumber(单位:rpx)是坐标
yNumber(单位:rpx)是坐标
textString|Object是当Object类型时,参数为text字段的参数,marginLeft、marginRight这两个字段可用(示例请看下文)
fontSizeNumber(单位:rpx)是文字大小
colorString否颜色
opacityInt否1为不透明,0为透明
lineHeightNumber(单位:rpx)否行高
lineNumInt否根据宽度换行,最多的行数
widthNumber(单位:rpx)否没有指定为画布宽度
marginLeftNumber(单位:rpx)否当text字段为Object可以使用,用来控制多行文字间距
marginRightNumber(单位:rpx)否当text字段为Object可以使用,用来控制多行文字间距
textDecorationString否目前只支持 line-through(贯穿线),默认为none
baseLineString否top| middle|bottom基线对齐方式
textAlignString否left|center|right对齐方式
zIndexInt否层级,越大越高
fontFamilyString否小程序默认字体为'sans-serif', 请输入小程序支持的字体,例如:'STSong'
fontWeightString否'bold'加粗字体,目前小程序不支持 100 - 900 加粗
fontStyleString否'italic'倾斜字体
images字段
字段类型必填描述
xNumber(单位:rpx)是右上角的坐标
yNumber(单位:rpx)是右上角的坐标
urlString是图片url(需要添加到下载白名单域名中)也支持本地图片
widthNumber(单位:rpx)是宽度(会根据图片的尺寸同比例缩放)
heightNumber(单位:rpx)是高度(会根据图片的尺寸同比例缩放)
borderRadiusNumber(单位:rpx)否圆角,跟css一样
borderWidthNumber(单位:rpx)否边框宽度
borderColorString否边框颜色
zIndexInt否层级,越大越高
lines字段
字段类型必填描述
startXNumber(单位:rpx)是起始坐标
startYNumber(单位:rpx)是起始坐标
endXNumber(单位:rpx)是终结坐标
endYNumber(单位:rpx)是终结坐标
widthNumber(单位:rpx)是线的宽度
colorString否线的颜色
zIndexInt否层级,越大越高
事件
success

返回生成海报图片的本地url,一般做法是使用wx.previewImage预览海报,如下

onPosterSuccess(e) {
	const { detail } = e;
	wx.previewImage({
        current: detail,
        urls: [detail]
    })
}
fail

返回错误信息

异步生成海报

有些场景可能需要发起ajax请求后才能获取生成海报的数据,这里提供了异步生成海报的方式。

只需要引入组件中的poster/poster.js,如下调用就行了

import Poster from '../../miniprogram_dist/poster/poster';
Page({
    /**
     * 异步生成海报
     */
    onCreatePoster() {
    	// setData配置数据
    	this.setData({ posterConfig: {...} }, () => {
        	Poster.create(); 
    	});
    }
})
自定义组件异步生成海报

有些场景可能需要发起ajax请求后才能获取生成海报的数据,这里提供了异步生成海报的方式。

只需要引入组件中的poster/poster.js,如下调用就行了,与page不同的是,需要在Poster.create中加入this。

import Poster from '../../miniprogram_dist/poster/poster';
Component({
    /**
     * 自定义组件异步生成海报
     */
    onCreatePoster() {
    	// setData配置数据
    	this.setData({ posterConfig: {...} }, () => {
        	Poster.create(true, this); 
    	});
    }
})

app.js应用启动

import init from './Api/init' //引入封装方法
let util = require('./Api/util') //
import './util/mp-weixin'
App({
    onLaunch() {

        init() //初始化封装函数,请勿在此之前调其他wx自定义函数,会是undefined
        // 透明头部start
        let system = wx.getSystemInfoSync();
        let rect = wx.getMenuButtonBoundingClientRect();
        let spacing = rect.top - system.statusBarHeight; // 状态栏与胶囊之间的间距
        this.globalData.width = system.screenWidth;
        this.globalData.height = system.screenHeight;
        let bili = 375 / system.screenWidth;
        this.globalData.statusBarHeight = system.statusBarHeight / bili * 2;
        this.globalData.titleBarHeight = (rect.height + spacing * 2) / bili * 2;
        this.globalData.navigationBarHeight = this.globalData.statusBarHeight + this.globalData.titleBarHeight;
        let customBar = rect.bottom + rect.top - system.statusBarHeight;
        this.globalData.customBar = customBar / bili * 2;
        // 透明头部 end
        //参见文献https://blog.csdn.net/yanxiaomu/article/details/116357712
        // 通过mp-weixin全局注入一个store对象,更改使用  this.setData({})  即可同步全局数据
        // 当注入store时,组件内的生命周期需写到 [lifetimes] 中,Component->lifetimes->attached()
        const mixin = {
            store: {
                userInfo: wx.$cache.get("userInfo") || {
                    "test": true
                }
            }
        }
        wx.mixin(mixin)
        //拉取应用全局配置
        wx.$http.post(wx.$api.get_show).then(res => {
            //全局参数为can
            wx.$cache.set('can', res)
            if (res.edition == 1) {
                /*如果显示配置中版本为过审版本,小程序上线有诸多限制,
                为保证上线顺畅,我们与后端约定了两个版本切换,
                一个过审版edition == 1一个运营版为edition == 2,
                当运营版时项目已经上线,可以展示一些资质不限定的内容*/
                if (system.platform == 'ios') { //当前系统为ios时
                    wx.$IOS = true //ios为true,这里主要用来做虚拟支付判定,非虚拟支付的板块继续用配置中的edition判断显示隐藏
                }
            }
        })



    },
    onShow(e) {
        //请求分享图,可以获得随机分享图一张,存参数为share,不要改变参数值,所有小程序都需要请求,然后分享中使用该参数
        wx.$http.post(wx.$api.get_share).then(ress => {
            wx.$cache.set('share', ress)
            this.overShare() //全局配置分享图,谨慎使用
            //不要在 App.onLaunch 的时候调用该方法,因为方法中有 getCurrentPages(),此时 page 还没有生成。
        }).catch(err => {
            console.error(err)
        })
        if (e.query.pid) {
            if (wx.$cache.get('member_id') == e.query.pid) {} else {
                wx.$cache.set('pid', e.query.pid)
            }
        }
        /*
    非测试账号时,为避免之前的测试体验账号存有key,故而进行清空,默认请求key为1
    */
        if (wx.$cache.get('key') == 1) {
            wx.$cache.set('key', '')
        }
        /*
        当新项目拿到后,由于这时候客户可能还没有小程序账号,为方便开发,我们与后端约定,key=1为测试通用key。同样作为有效凭证返回数据
        */
        // wx.$cache.set('key',1)//设置默认key为1,此为测试操作
        // wx.$cache.set('member_id',1)//设置默认用户id为1,此为测试操作

        //  console.log(wx.$datetype(new Date().getTime()))

    },
    overShare() {
        //当你想偷懒不写分享方法时,但是当你看不懂这些代码时,不要偷懒
        wx.onAppRoute(function (res) {
            console.log(res)
            let pages = getCurrentPages(),
                view = pages[pages.length - 1],
                data;
            if (view) {
                data = view.data;
                console.log(!!(view.onShareAppMessage == undefined || (!view.onShareAppMessage())));
                if (view.onShareAppMessage == undefined || (!view.onShareAppMessage())) {
                    view.onShareAppMessage = view.onShareTimeline = function () {
                        return {
                            title: '测试标题' || wx.$cache.get('share').title,
                            imageUrl: wx.$cache.get('share').img,
                            path: `pages/splash/splash?pid=` + wx.$cache.get('member_id')
                        };
                    }
                }
            }
        })
    },

    globalData: {


    }
})

关于全局挂载的封装思路:

我们都知道在微信小程序中官方api可以通过wx点出来,而wx是不需要定义的,那我们大胆想一下,按照js一切接对象的特点,wx肯定是一个全局对象。故而我们继续在全局对象上挂载其他方法和变量函数是可以全局应用的。都不用考虑作用域和生命周期的问题。简直是perfect。所以我们将公共方法封装到一个对象后,通过init()在应用启动时,将方法挂载。从而得到了上面我们看到的各种全局api

通用缓存参数名及含义

参数含义建议
can全局配置当你有些参数找不到接口时,基本都在这里的
key用户凭证有用户凭证不代表是有用户信息,用户凭证可以鉴权用户数据
share分享图用于页面分享中
userInfo用户资料用户资料,是否vip都在这里的
member_id用户id当前用户的id,可以在分享时带出去
p_id上级id应用中如果分享一定要带上用户id,哪怕不分销
wx.$cityInfo(废弃)获取的位置对象可以在里面取到位置信息

项目开发思路以及注意事项

  1. 拿到项目如果有appid可以直接开发,如果没有,就用测试号,并在app.js中打开key=1
  2. 每个项目启动第一个接口必然要有分享图和全局配置,特别是全局配置,他是一个公共数据接口,里面有你项目中用到的各种杂项。当你发现页面中有数据接口并未提供时,他多半在全局配置中,你用wx.$cache.get('can')就能取出使用
  3. 当你发现你的接口不通,并未请求时,请检查是否域名指向不对
  4. 一个项目的首页必须命名index,如果有登录页一定要命名login
  5. 当项目用到地图时,请一定要注意地图请求为异步,并将需要回调的接口放到页面的对应函数中
  6. 当你封装一个组件且这个组件在全局都会用到时,请使用页面栈对数据进行操作
  7. 当你在写静态页面时,请先在页面data中定义domain,并引用api中的$domain进行全局地址配置,避免后期图片上到服务器时丢失地址
  8. 请一定要再页面命名app全局变量,不管你用与不用
  9. 一定尽量不要用绝对定位,相对定位写页面
  10. 页面中遇到蓝湖上标注宽高,左右边距为单数时,请写双数,这样可以减少视觉误差
  11. 当无必要用自定义头部或者自定义taber时,不要自定义
  12. 页面方法都要有注释,data中配参有相应的说明
  13. 避免频繁调用setData,并不要在其他地方调用生命周期onshow外方法
  14. 当你封装好一个方法或者一个组件觉得使用会比较频繁时,请按照此文档写入组件开发文档
最近更新: 2025/8/4 23:49
Contributors: litaipingwy, 印留时光