likes
comments
collection
share

微信小程序——开发流程总结

作者站长头像
站长
· 阅读数 12

微信小程序总结

前言:

最近因项目需求,需要开发一个微信小程序(小白一个),于是就着手开发,做了大概一个月的时间(技术方案: 微信原生开发),期间也遇见很多问题,故此记录总结一下零碎的知识点和经验(主要是从一个使用vue开发者的角度,做得比较零散,如有不足,欢迎补充)。

一、环境搭建

微信小程序开发最常规的编译运行环境就是在微信开发者工具中运行,很多项目环境基础在微信小程序官方文档写的很详细。参考微信小程序官方文档:developers.weixin.qq.com/miniprogram…

1、开发者工具

关于开发工具,我都是使用微信开发者工具,安装很简单,微信开放文档下载直接傻瓜式安装即可。这里简单介绍一些开发过程中使用得方法,以及一些配置。

我们在本地开发的时候,需要将不校验合法域名这一项勾选上,这样在后面联调接口或者打开一些链接的时候在本地就不会有限制。

微信小程序——开发流程总结

2、注册

开始开发的时候可能会没有专门的账号提供给我们使用,我们可以暂时申请一个小程序测试账号进行初始开发。当有正式的小程序账号的时候,替换即可。

测试号申请:

申请小程序测试号: mp.weixin.qq.com/wxamp/wadev…

根据页面提示,然后就可以得到测试号对应的id跟密钥。

微信小程序——开发流程总结

3、页面配置

详情查阅官方文档: 微信小程序官方文档 —— 页面配置

  • 页面结构

.
├── app.js     # 小程序的逻辑文件
├── app.json   # 小程序的配置文件
├── app.wxss   # 全局公共样式文件
├── pages      # 存放小程序的各个页面
│   ├── index  # index页面
│   │   ├── index.js     # 页面逻辑
│   │   ├── index.wxml   # 页面结构
│   │   └── index.wxss   # 页面样式表
│   └── logs   # logs页面
│       ├── logs.js      # 页面逻辑
│       ├── logs.json    # 页面配置
│       ├── logs.wxml    # 页面结构
│       └── logs.wxss    # 页面样式表
├── project.config.json
└── utils
    └── util.js
  • APP.JS文件

小程序的脚本代码。我们可以在这个文件中监听并处理小程序的生命周期函数、声明全局变量

//app.js
App({
  onLaunch: function () {
    // 展示本地存储能力
    var logs = wx.getStorageSync('logs') || []
    logs.unshift(Date.now())
    wx.setStorageSync('logs', logs)
 
    // 登录
    wx.login({
      success: res => {
        // 发送 res.code 到后台换取 openId, sessionKey, unionId
      }
    })
    // 获取用户信息
    wx.getSetting({
      success: res => {
        if (res.authSetting['scope.userInfo']) {
          // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
          wx.getUserInfo({
            success: res => {
              // 可以将 res 发送给后台解码出 unionId
              this.globalData.userInfo = res.userInfo
 
              // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
              // 所以此处加入 callback 以防止这种情况
              if (this.userInfoReadyCallback) {
                this.userInfoReadyCallback(res)
              }
            }
          })
        }
      }
    })
  },
  globalData: {
    //如:可以把很多经常用的的字段设为全局变量,后面的页面可直接调用,
    userInfo: null,
    access_token: '',
    account: '',
    code: '',
    unionid: '',
    sessionKey: '',
    openId: '',
    id: '',
    username: '',
  }
})
  • pages

    "pages": [
        "pages/index/index",
        "pages/log/log"
    ]
  • 页面的.json、.js、.wxss文件必须与.wxml文件同名,否则不生效
  • 每个页面都必须pages下注册,没有注册的页面,如果不访问,编译能通过,一旦试图访问该页面则会报错
  • 可以通过在pages下添加一个选项快速新建一个页面,开发工具会自动生成对应的文件
  • window

  "window":{
    "enablePullDownRefresh": true,
    "navigationStyle": "custom"
  }

该配置项用于配置小程序的全局外观样式,具体请查阅文档。这里重点提一下两个比较实用的

//去掉默认的导航栏,轻松实现全面屏
"navigationStyle": "custom" , 
//开启自带的下拉刷新,减少自己写样式
"enablePullDownRefresh": ture, 

4、开发配置

通常微信小程序开发我们都是运行在微信开发者工具中,方便调试,而且微信开发者工具也可以用来编写代码,但是对于我们很多前端开发者来说,编写代码都比较喜欢使用VScode,而且我们写样式的时候都比较喜欢引入sass,这里简单介绍一些VScode开发小程序的配置。

插件在扩展里搜索 minappeasy sass并安装: 微信小程序标签、属性的智能补全(同时支持原生小程序、mpvue 和 wepy 框架,并提供 snippets)

配置:

选择“配置扩展设置”选项,进入到设置页面,点击“在setting.json中编辑”进入settings.json文件。

微信小程序——开发流程总结

将下面代码配置到配置文件中即可。

  "easysass.formats": [
    {
      "format": "expanded",//sass编译后的文件是展开的
      "extension": ".wxss"//设置编译输出的文件名
    }
  ],

微信小程序——开发流程总结

这样在我们在微信小程序中愉快的编写sass,VScode会自动帮我们转换生成为wxss文件,提高我们的开发效率。

二、与vue开发中的区别

1、技术选择

我们这次开发使用的技术方案是选用微信原生开发,起初开始考虑使用uni-app,但后来还是没有框架开发。

而选用原生开发原因大概有以下几点:

  1. 怕使用uni-app后,微信小程序里有的功能无法实现,受制于uni-app的更新
  2. 怕性能不如原生WXML
  3. 怕框架不成熟,经验丰富,跳到坑里
  4. 担心社区生态不完善,没有经验

2、与vue的区别

开发环境区分

区分小程序体验版,开发板,正式版,常规web端开发环境我们分sit,uat等,而小程序也有类似环境变量,使用 __wxConfig.envVersion,就可以获取到小程序到当前所处环境对应的值。

const envVersion = __wxConfig.envVersion
envVersion 类型为字符串
envVersion: 'develop',    //开发版
envVersion: 'trial',      //体验版
envVersion: 'release',    //正式版

数据请求

小程序有自己的生命周期,在页面加载请求数据时,两者钩子的使用有些类似, vue一般会在 created或者 mounted中请求数据,而在 小程序 ,会在 onLoad或者 onShow中请求数据。

显示与隐藏元素

开发中常用到控制元素显示与影藏

**vue中,使用 v-ifv-show**控制元素的显示和隐

**小程序**中,使用 wx-if hidden控制元素的显示和隐藏

列表渲染

直接贴代码

vue:不解释

    {{ item.message }}
var example1 = new Vue({
  el: '#example-1',
  data: {
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
   ]
  }
})

小程序:

通过 wx:for来绑定名为items的数组。效果相当于for循环,重复渲染该组件。也可以嵌套


       <block wx:for="{{bannerList}}" wx:key="index">
            <view>{{index}}:{{item.name}}</view>
        </block>

//index.js
Page({
    data:{
        items:[
            { name:"商品A"},
            { name:"商品B"},
            { name:"商品C"},
            { name:"商品D"},
            { name:"商品A"}
        ]
    }
})

数据双向绑定

1.设置值 在vue中,只需要再表单元素上加上v-model,然后再绑定data中对应的一个值,当表单元素内容发生变化时,data中对应的值也会相应改变,不需要我们手动触发。


new Vue({
  el: '#app',
  data: {
   reason:''
  }
})

但是在小程序中,却没有这个功能。当表单内容发生变化时,会触发表单元素上绑定的方法,然后在该方法中,通过this.setData({key:value})来将表单上的值赋值给data中的对应值。直接上demo:

//index.js

Page({
data:{
reason:''
},
bindReason(e) {
    this.setData({
      reason: e.detail.value
    })
  }
})    

数据绑定方式不一样: vue动态绑定一个变量的值为元素的某个属性的时候,会在变量前面加上冒号。小程序:绑定某个变量的值为元素属性时,会用两个大括号括起来,如果不加括号,为被认为是字符串。

取值

vue中,通过**this.reason**取值

小程序中,通过 this.data.reason取值

绑定事件传参

在vue中,绑定事件传参挺简单,只需要在触发事件的方法中,把需要传递的数据作为形参传入就可以了,例如:

<button  @click="say('明天不上班')"></button>
new Vue({
  el: '#app',
  methods:{
    say(arg){
    consloe.log(arg)
    }
  }
})

在小程序中,不能直接在绑定事件的方法中传入参数,需要将参数作为属性值,绑定到元素上的data-属性上,然后在方法中,通过e.currentTarget.dataset.*的方式获取,从而完成参数的传递,麻烦...

<button data-id='{{id}}'  @click="say()"></button>
Page({
data:{
    reason:''
},
toApprove(e) {
    let id = e.currentTarget.dataset.id;
  }
})

父子组件通信

1.子组件的使用

在vue中:编写子组件,在需要使用的父组件中通过import引入,在vue的components中注册,在模板中使用

// 父组件 foo.vue

// 子组件bar.vue

<template>
  <div class="search-box">
    <div :title="title"></div>
  </div>
</template>


<script>
export default{
props:{
    title:{
       type:String,
       default:''
      }
    }
}
</script>


子组件和父组件通信可以通过this.$emit将方法和数据传递给父组件。

在小程序中 父组件向子组件通信和vue类似,但是小程序没有通过v-bind,而是直接将值赋值给一个变量,如下

tab-bar

此处, “index”就是要向子组件传递的值,在子组件properties中,接收传递的值

properties: {
    // 弹窗标题
    currentpage: {      // 属性名
      type: String,     // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object,         Array, null    (表示任意类型)
      value: 'index'     // 属性初始值(可选),如果未指定则会根据类型选择一个
    }
  }
  

子组件向父组件通信和vue也很类似,代码如下:

//子组件中
methods: {   
    // 传递给父组件
    cancelBut: function (e) {
      var that = this;
      var myEventDetail = { pickerShow: false, type: 'cancel' } // detail对象,提供给事件监听函数
      this.triggerEvent('myevent', myEventDetail) //myevent自定义名称事件,父组件中使用
    },
}

//父组件中 bar

// 获取子组件信息
toggleToast(e){
    console.log(e.detail)
}

如果父组件想要调用子组件的方法 vue会给子组件添加一个ref属性,通过this.$refs.ref的值便可以获取到该子组件,然后便可以调用子组件中的任意方法,例如:

//子组件
bar

//父组件
this.$ref.bar.子组件的方法
小程序是给子组件添加id或者class,然后通过this.selectComponent找到子组件,然后再调用子组件的方法,示例:

//子组件
bar

// 父组件
this.selectComponent('#id').syaHello()

小程序父组件改变子组件样式

  1. 父组件将style传入子组件
  2. 父组件传入变量控制子组件样式
  3. 在父组件样式中,在子组件类名前面加上父组件类名

.share-button-container .button--btn-navigator__hover{
  background: #fff;
}

data私有数据修改

和vue中的data不同的是,小程序不允许直接修改data的数据,修改了也不会不会实时更新,想要实时更新就要使用setData来实现

  onLoad: function () {
  //  可以更改值,但是页面不会变化
  this.firstLoad = true 
  //  正确操作
    this.setData({
      firstLoad: true,
    });
  },

三、开发中的总结

1、微信小程序登录与授权

1.1 登录:

下图的介绍是微信小程序登录的过程,开发过程中也是采用的这个逻辑。

微信小程序——开发流程总结

  • 登录步骤

  1. 通过调用wx.login() API,成功后会拿到用户的code信息
  2. 将code信息通过接口,传给自己的后台(不是微信的后台),在服务端发起对微信后台的请求,成功后拿到用户登录态信息,包括openid、session_key等。也就是通常所说的拿code换openid,这个openid是用户的唯一标识。
  3. 自己的后台,拿到openid、session_key等信息后,通过第三方加密,生成自己的session信息,返回给前端。
  4. 前端拿到第三方加密后的session后,通过wx.setStorage()保存在本地,以后的请求都需要携带这个经过第三方加密的session信息
  5. 之后如果需要用户重新登录,先去检查本地的session信息,如果存在,再用wx.checkSession()检查是否在微信的服务器端过期。如果本地不存在或者已过期,则重新从步骤1开始走登录流程。

登录的代码如下:

//添加事件结束,有时候微信版本过低使用finally会报错,
Promise.prototype.finally = function (callback) {
  let Promise = this.constructor;
  return this.then(
    (value) => Promise.resolve(callback()).then(() => value),
    (reason) =>
      Promise.resolve(callback()).then(() => {
        throw reason;
      })
  );
};

let queryTokening = false;

function setLoginActionReady(param) {
  if (!queryTokening) {
    queryTokening = true;

    loginActionReady = new Promise((resolve, reject) => {
      const action = () => {
        const request = (data) => {
          wx.request({
            url: `${baseURL}/blade-auth/oauth/token`,
            method: POST,
            data: data, // 如果param有值
            header: {
              'Content-Type': 'application/x-www-form-urlencoded',
              'tenant-Id': '121971',
              Authorization: 'Basic aXN0YXJ0dXA6aXN0YXJ0dXBfc2VjcmV0',
              'Blade-Auth': '',
            },
            success({ data: res }) {
              if (res.access_token) {
                const access_token = res.token_type + ' ' + res.access_token;
                const app = getApp();
                app.globalData.checkLogin = true;
                app.globalData.access_token = access_token;
                wx.setStorageSync('access_token', access_token);
                console.log('获取token成功==', access_token);
                resolve(res);
              } else {
                const { error_description } = res;
                // 在onLaunch里拿当前page的信息是拿不到的,需要等一会
                reject();
                console.log('获取token失败==res===', res);

                if (error_description === 'Unbound mobile phone number') {
                  const url = getCurrentPageUrlWithArgs();
                  wx.setStorageSync('logging', true);
                  wx.redirectTo({
                    url: `/pages/log/log?url=${url}`,
                  });
                } else {
                  wx.showToast({
                    title: error_description,
                    icon: 'none',
                  });
                }
              }
            },
            fail: reject,
          });
        };
        if (param) {
          request(param);
        } else {
          wx.login({
            success: (res) => {
              console.log('获取微信code==', res);
              // 发送 res.code 到后台换取 openId, sessionKey, unionId
              const { code } = res;
              const app = getApp();
              app.globalData.code = code;
              wx.setStorage({
                key: 'code',
                data: code,
              });
              const parame = {
                code,
                grant_type: 'wechat',
                scope: 'all',
                type: 'account',
              };
              // 调用接口获取openid
              request(parame);
            },
            fail: reject,
          });
        }
      };
      action();
    }).finally(() => {
      queryTokening = false;
    });
  }

  return loginActionReady;
}

1.2 授权:

这里以获取用户个人信息为例

之前获取用户信息直接用 wx.getUserInfo即可,但微信为了优化用户体验,后来被限制,不允许开发者主动弹出授权框。必须使用button按钮的 open-type="getUserInfo" ,通过bindgetuserinfo事件获取用户信息,现在叒限制。现在使用API: wx.getUserProFile获取用户信息。

微信小程序——开发流程总结

获取用户信息。页面产生点击事件(例如 buttonbindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo。该接口用于替换 wx.getUserInfo,详情参考文档:developers.weixin.qq.com/community/d…

1.将授权登陆获取用户信息的接口调整了,新增了一个 wx.getUserProfile 。特说明一下授权登陆的注意事项:

2.原授权登陆流程不变,依旧是 wx.login >>> code >>> 请求接口换取openid >>> openid >>> 自定义请求态 >>> uid 只是获取用户信息的地方发生改变了,获取用户信息必须通过wx.getUserProfile获取,

3. wx.getUserProfile返回的加密数据中不包含 openIdunionId 字段。通过wx.login接口获取的登录凭证可直接换取unionID

使用方面注意事项:

wx.getUserProfile这个API必须写在事件的最上面,只能事件触发

下面是官方示例直接复制即可实现简单的授权获取信息:

view
  view
    block
      
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
<button wx:else="" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
    block
      ![]({{userInfo.avatarUrl}})
      text{{userInfo.nickName}}

Page({
  data: {
    userInfo: {},
    hasUserInfo: false,
    canIUseGetUserProfile: false,
  },
  onLoad() {
    if (wx.getUserProfile) {
      this.setData({
        canIUseGetUserProfile: true
      })
    }
  },
  getUserProfile(e) {
    // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
    // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
    wx.getUserProfile({
      desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
      success: (res) => {
        this.setData({
          userInfo: res.userInfo,
          hasUserInfo: true
        })
      }
    })
  },
  getUserInfo(e) {
    // 不推荐使用getUserInfo获取用户信息,预计自2021年4月13日起,getUserInfo将不再弹出弹窗,并直接返回匿名的用户个人信息
    this.setData({
      userInfo: e.detail.userInfo,
      hasUserInfo: true
    })
  },
})

2、开发注意事项

2.1 接口访问

本地启服务,如何通过localhost访问服务端接口?

微信小程序默认都是https请求,如果本地开发联调,需要在开发者工具 -> 项目设置里,勾选上【不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书】,这样就可以愉快的使用localhost访问服务端了。

2.2 跳转

navigateTo层级不能超过5级

文档上说明: 为了不让用户在使用小程序时造成困扰,我们规定页面路径只能是五层,请尽量避免多层级的交互方式。 使用wx.navigateTo()的时候,规定层级不能超过5级。如果超过5级,页面就出错了。 但wx.redirectTo()则无此限制。 注意: wx.navigateTo()是保留当前页面,跳转到应用内的某个页面,使用 wx.navigateBack 可以返回到原页面 wx.redirectTo()是关闭当前页面,跳转到应用内的某个页面。

2.3 封装请求

统一封装请求,在header中携带session信息

wx.request()是发送请求的api,如果每个request请求都在header中重新一份session信息,一定很麻烦。所以基本上前端都会封装一个新的请求函数,包括携带session信息,处理错误接口等功能。具体代码如下:

const httpRequest = data => {
    return new Promise(function(resolve, reject) {
        console.log("http request", data.url);
        let code = "";
        wx.getStorage({
            key: "code",
            success: res => {
                code = res.data;
                console.log("http request success", code);
                //发起网络请求
                wx.request({
                    url: data.url,
                    data: { ...data.data },
                    method: data.method,
                    header: {
                        code: code,
                        "content-type": "application/x-www-form-urlencoded"
                    },
                    success: function(res) {
                        if (res.data.success) {
                            resolve(res.data);
                        } else {
                            // console.log(JSON.stringify(res));
                            if (res.data.errorCode == 100) {
                                goBackIndex();
                            }
                            reject(res.data);
                        }
                    },
                    fail: function(res) {
                        console.log(JSON.stringify(res));
                        if (res.data.errorCode == 100) {
                            goBackIndex();
                        }
                        reject(res);
                    }
                });
            },
            fail: res => {
                console.log("http request failed", code);
                console.log("not found code in storage");
                goBackIndex();
            }
        });
    });
};
  • 有关图片的引用问题

给页面添加背景是,如果通过background属性来添加,抱歉,那你不能引用本地的图片,只能引用经过base64转码的或者网上的图片。 小程序的文档上有说,本地资源是无法通过css获取的。但是通过image的src属性引用的图片,则没有这个限制。

  • 表单数据双向绑定

一般我们在使用Vuejs以及reactjs等MVVM框架的使用,是支持数据双向绑定的 , 也就是我们input输入数据的时候,是实时反应在data字段数据中的 ,但是微信小程序并不支持这样 , 那么问题来了, 在微信小程序中如何获取用户输入的数据呢 ,有2种方式 , input提供bindinput和bindblur事件,可以监听input输入的数据以及当鼠标离开input框时候获取到他的数据,bindinput输入监听事件,使用时如果只有一两个表单还好,但是如果有很多表单那肯定不行,需要监听每一个input的输入事件bindblur事件鼠标离开input框事件 , 使用它时必须要主动离开输入框,但是会存在用户输入完之后直接点击提交按钮,这种情况也不能正常获取到用户输入的数据, 所以也不可行 。后来,才发现, 微信给我们提供了form表单提交的方式, 简言之,就是点击提交按钮后 ,可以获取到全部的input数据

2.4 日期格式

在微信小程序中,时间显示需要注意的是,ios不支持‘2020-10-23’这种后端返回的时间格式,转换的时候需要特殊处理一些,会显示为NaN,,只支持2010/10/23着各种格式的时间。

解决办法---替换

const time = '2020-10-23'
let dateTime = time.replace(/-/g, '/');
const date = new Date(dateTime);

3、重点介绍几个组件

3.1 web-view

当我们想在小程序中打开其他外部页面的时候,微信官方提供了web-view组件,让小程序和H5网页之前的跳转成为了可能。通过把H5页面放置到web-view中,可以让H5页面在小程序内运行。同时在H5页面中也可以跳转回小程序页面。可以说是带来了很大的便利,但同时由于web-view的诸多限制,用起来也不是很舒服。

下面是使用的注意事项:

  1. 需要打开的H5页面必须在后台业务页面中配置,这其中还有个服务校验。另外H5页面必须是https协议,否则无法打开,如果打开跟小程序时同一主体账号的公众号时,没有限制条件,可直接打开

  2. web-view中无法在页面中调起分享,如果需要分享,比如跳回小程序原生页面

  3. 小程序与web-view里H5通信问题。小程序向web-view传递,不敏感信息可以通过页面url传递。如果是敏感信息比如用户token等,可以让服务端重定向,比如请求服务端一个地址,让他把敏感信息写在cookie中,再重定向到我们的H5页面。之后H5页面就可以通过在cookie中拿这些敏感数据了,或者http-only,发送请求时直接带上。

  4. 每次web-view中src值有变化就会重新加载一次页面。所以个src拼接参数时,需要先赋值给个变量拼接好再一次性setData给web-view的src,防止页面重复刷新。

  5. 从微信客户端6.7.2版本开始,navigationStyle: custom对组件无效。也就意味着使用web-view时,自带的导航栏无法去掉。

  6. 因为导航栏无法去掉,这里就出现了一个巨大的坑。实现全屏效果问题。如果想要实现H5页面全屏,就是不滑动,全屏显示完所有内容。这时如果你使用width:100%;height:100%,你会发现,你页面底部可能会缺失一段。上图:

微信小程序——开发流程总结

因为web-view是默认铺满全屏的,也就是web-view宽高和屏幕宽高一样。然后H5页面这是高度100%,这是相对web-view的高度,也是屏幕高度。但是关键问题:web-view里H5页面是从导航栏下开始渲染的。这就导致了H5页面溢出了屏幕,无法达到全屏效果。

解决方法

通过拼接宽高参数在H5页面url上,这个宽高是在web-view外层计算好的。H5页面直接读取url上的宽高,动态设置页面的宽高。页面高度的计算,根据上图,很显然就是屏幕高度减去导航栏高度。宽度都是一样的,直接是屏幕宽度。

但问题又来了,貌似没有途径获取导航栏高度。而且对于不同机型的手机,导航栏高度不同。经过了对多个机型导航栏跟屏幕高度的比较。发现了一个规律,导航栏高度与屏幕高度、屏幕宽高比有一定的关系。所以根据多个机型就计算出了这个比例。这解决了95%以上手机的适配问题,只有少数机型适配不是很好。到基本实现了全屏效果。具体代码如下:

onLoad (options) {
    //同步获取屏幕信息,现在用到的是屏幕宽高
    var res = wx.getSystemInfoSync();
    if (res) {
        var widHeight = res.screenHeight;
        //对于大多数手机,屏幕高度/屏幕宽度 = 1.78。此时导航栏占屏幕高度比为0.875
        var raito = 0.875;
        if (res.screenHeight / res.screenWidth > 1.95) {
            //对于全屏手机,这个占比会更高些
            raito = 0.885;
        } else if (res.screenHeight / res.screenWidth > 1.885) {
            raito = 0.88;
        }
        //做兼容处理,只有微信版本库高于6.7.2,有导航栏才去兼容,否则可以直接使用高度100%。res.statusBarHeight是手机顶部状态栏高度
        //如果微信版本号大于6.7.2,有导航栏
        if (util.compareVersion(res.version, "6.7.2") > 0) {
            widHeight = Math.round(widHeight * raito) + (res.statusBarHeight || 0);
        }
        this.setDate({
            //将H5页面宽高拼接在url上,赋值给web-view的src即可加载出H5页面
            webview_src: util.joinParams(h5_src, {
                "height": widHeight, 
                "width": res.screenWidth
            })
        })
    }
}

3.2 scroll-view

在vue中,当我们要实现一个区域内滑动效果时,在H5页面中我们设置overflow-y: scroll即可。但在小程序中,没有该属性。需要用到scroll-view标签。具体操作实现我们可以查看文件scroll-view

锚点定位在前端开发中会经常用到,在H5页面中,我们会在url后面加上#来实现锚点定位效果。但是在小程序中这样是不起作用的,因为小程序内渲染页面的容易不是一个浏览器,无法实时监听Hash值得变化。但是使用scroll-view,我们可以实现锚点点位效果。主要是使用scroll-into-vie属性具体实现我们直接上代码

scroll-into-view | String | 值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素

wxml文件

    <!--toView的值动态变化,当toView为luckydraw时,会定位到id为luckydraw的view
    需要注意的是,这里需要设置高度为屏幕高度-->
    <scroll-view scroll-y scroll-into-view="{{toView}}" 
    scroll-with-animation = "true" style="height: 100%; white-space:nowrap">
        <view id="top"></view>
        <view id="luckydraw"></view>
        <view id="secskill"></view>
    <scroll-view>

3.3 rich-text---组件

有时候我们需要赞详情页面呈现出多样性,渲染富文本相关的东西,微信小程序专门给我们提供了这样的一个组件。该组件能解析几乎所有的html标签,其中tableimg标签支持width,问题就出现了,设定了固定的width,除非是百分比,否则还能自适应各个屏幕吗?另外img只支持网络图片,这个大家可以理解,毕竟代码不可能连图片资源一起带过来。

考虑到多张图片的话,图片之间会有间隙,不希望有间隙可以加上display:block,而微信小程序自己的图片标签是有默认宽高的,有时候我们在拿到富文本内容的时候前端也可以通过正则处理以下数据。

 that.setData({
          content: res.data.content.replace(/<img/gi, '<img style="max-width:100%;height:auto;display:block;"')
        })
 
//或
 
 that.setData({
          content: res.data.contents.replace('<img ', '<img style="max-width:100%;height:auto;display:block;"')          
        })

3.4 Painter 2.0海报

微信小程序-海报生成工具分享

微信小程序自己带有分享功能,而很多时候满足不了我们的业务,比如分享海报,而微信自带的Canv生产的方法又有很多坑,新手小白确实非常头疼。下就分享一个微信小程序画海报的插件。GitHub地址:github.com/Kujiale-Mob…。下面是注意事项:

  1. 网络图片真机显示空白请检查 微信公众平台 服务器域名里面的安全域名有没有添加
  2. 微信头像显示空白 请添加 thirdwx.qlogo.cn; 添加域名后重新启动项目就可以成功显示了。
  3. 确保在图片加载完再生成海报。

使用:

首先在项目把painter当作一个自定义组件引入,这里采用的是自己把相关插件放到component文件中

微信小程序——开发流程总结

然后在需要使用的页面的.JSON文件中引入该组件:

微信小程序——开发流程总结

画海报:重点来了,我们的难点也是这里,我们自己手动创建一个海报, 然后在用的页面将这个海报引入进去,传入我们需要的数据,生成海报。

组件接收 palette 字段作为画图数据的数据源, 图案数据以 json 形式存在,推荐使用“皮肤模板”的方法进行传递。你可以通过设置 widthPixels 来强制指定生成的图片的像素宽度,否则,会根据你画布中设置的大小来动态调节,比如你用了 rpx,则在 iphone 6 上会生成 0.5 倍像素的图片。由于 canvas 绘制的图片像素直接由 Canvas 本身大小决定,此处通过同比例放大整个画布来实现对最后生成的图片大小的调节。

微信小程序——开发流程总结

数据传入后,则会自动进行绘图。绘图完成后,你可以通过绑定 imgOK 或 imgErr 事件来获得成功后的图片 或失败的原因。

因为 text 的特殊性,此处对 text 进行单独说明。

微信小程序——开发流程总结

当文字设置 width 属性后,则文字布局的最大宽度不会超过该 width 。如果内容超过 width,则会进行换行,如果此时未设置 maxLines 属性,则会把所有内容进行换行处理,行数由内容和 width 决定。如果此时设置了 maxLines 属性,则最大展示所设置的行数,如果还有多余内容未展示出来,则后面会带上 ... 。

Tips

1,目前 Painter 中支持两种尺寸单位,px 和 rpx,代表的意思和小程序中一致,此处就不多说。

2,目前子 view 的 css 属性支持 object 或 array。所以意味着,你可以把几个子 view 共用的 css 属性提取出来。做到让 Palette 更加简洁。

3,因为我们的 palette 是以 js 承载的 json,所以意味着你可以在每一个属性中很方便的加上自己的逻辑。也可以把某些属性单独提取出来,让多个 palette 共用,做到模块化。

4、ui组件引入(vant)

参考:vant-contrib.gitee.io/vant-weapp/…

项目开发用的很多ui组件,小程序自己也有一些ui组件,文档上面也有介绍,项目中直接可以使用,有时候还想用一些其他的ui组件。这里就简单介绍在小程序中使用vant的组件

安装:

通过 npm 安装

npm i @vant/weapp -S --production

步骤二 修改 app.json

将 app.json 中的 "style": "v2" 去除,小程序的新版基础组件强行加上了许多样式,难以覆盖,不关闭将造成部分组件样式混乱。

步骤三 修改 project.config.json

开发者工具创建的项目,miniprogramRoot 默认为 miniprogrampackage.json 在其外部,npm 构建无法正常工作。

需要手动在 project.config.json 内添加如下配置,使开发者工具可以正确索引到 npm 依赖的位置。

{
  "setting": {
    "packNpmManually": true,
    "packNpmRelationList": [
      {
        "packageJsonPath": "./package.json",
        "miniprogramNpmDistDir": "./miniprogram/"
      }
    ]
  }
}

微信小程序——开发流程总结

注意: 由于目前新版开发者工具创建的小程序目录文件结构问题,npm构建的文件目录为miniprogram_npm,并且开发工具会默认在当前目录下创建miniprogram_npm的文件名,所以新版本的miniprogramNpmDistDir配置为'./'即可

步骤四 构建 npm 包

首先将微信开发者工具配置项勾选上:

微信小程序——开发流程总结

步骤: 打开微信开发者工具,点击 工具 -> 构建 npm,并勾选 使用 npm 模块 选项,构建完成后,即可引入组件。

微信小程序——开发流程总结

这样就引入完毕。

微信小程序——开发流程总结

组件的使用:

引入组件

以 Button 组件为例,只需要在app.jsonindex.json中配置 Button 对应的路径即可。

所有组件文档中的引入路径均以 npm 安装为例,如果你是通过下载源代码的方式使用 @vant/weapp,请将路径修改为项目中 @vant/weapp 所在的目录。

// 通过 npm 安装
// app.json
"usingComponents": {
  "van-button": "@vant/weapp/button/index"
}

然后就可以在页面中使用

<van-button type="primary">vant按钮</van-button>

四、项目上线

项目上线的时候基本流程很简单,开发者在开发者工具中将代码提交到微信官方后台,管理员在后台将提交的版本提交即可,等待微信官方审核通过后即可发布。

开发版本: 使用开发者工具,可将代码上传到开发版本中,开发版本只保留每人最新的一份上传的代码。点击提交审核,可将代码提交审核,开发版本可删除,不影响线上版本和审核中版本的代码。

审核中版本: 只能有一份代码处于审核中,有审核结果后可以发布到线上,也可直接重新提交审核,覆盖原审核版本。

线上版本: 线上所有用户使用的代码版本,该版本代码在新版本代码发布后被覆盖更新。

注意事项:

这里简单讲述以下代码提交审核过程中遇见的问题。

1、测试数据未清除,需要清除我们的后台测试数据。

微信小程序——开发流程总结

2、有敏感信息,不能包含一些敏感的信息。

微信小程序——开发流程总结

3、获取用户信息交互不友好,获取用户授权方式要友好。

微信小程序——开发流程总结

有时候很奇怪,相同版本审核结果有时候也不一样,我们猜测审核的人员标准不一样。