微信小程序开发的胡言乱语|项目复盘

我心飞翔 分类:微信小程序

最近接了个新项目,做一个微信小程序。虽然很久很久以前有做过一个小程序,但真的是很久之前了,大概是小程序元年那会。就在前两天接到了上个小程序被搜索降权的通知😅,大概已经很长时间不维护了。所以这次大概或许可能得从头开始思考一些问题。开发文档上有的东西呢,就不在这里讨论了,还有具体的业务逻辑也不说了,我们来胡言乱语一些乌七八糟的东西吧。hhh

1. 设置合理的目录结构

这应该是我最先想到的问题,怎么才能让项目各个模块比较有秩序呢?
项目大概包括了pages,components,resource,utils,env,还有就是需要用到的置于根目录下的一些脚本文件。如下图:

WechatIMG162.jpeg

  • 先来说下最关键的模块pages和components的组织方式,首先得根据具体的业务逻辑,拆分出不同功能模块,比如个人中心,课程,博客等。每一个模块设置一个文件夹。比如像下图这样

WechatIMG163.png

/pages/course文件夹下面包含了课程模块的所有页面,以及一个/pages/course/components文件夹(只存放用于课程模块的组件文件)。一些公共的组件,当然得放到最外层的/components文件夹下面。

  • /utils 主要存放一些工具文件,比如常量文件,请求封装文件,参数加密方法封装文件,常用函数文件等等。如下图

WechatIMG164.png

  • /resource 顾名思义,是一些静态资源文件,比如一些图片,字体,音频等。
  • /env 用来存放环境变量文件的文件夹,这个在第4小节会细讲,这里就不多赘述了。

小结: 到这里大概已经讲清楚了我的目录结构设置,顺便说下我期间的一些思考。

  • 资源文件夹设置,本来有考虑在每个模块目录下设置一个资源文件夹,但是后来实际写代码的时候,发现这样做很不方便。比如到最后的时候我把所有的资源文件都做了压缩处理,想象下如果分散在不同功能目录下的话,那真的要裂开了。还好我意识到了这个问题,及时改过来了。当然/resource里面的目录结构也和/pages相似。方便快速查找。
  • 组件目录的设置,方案一每个模块下设置一个组件文件夹,方案二只在跟目录设置组件文件夹。首先方案一与上一条资源文件夹是一样的问题,而且考虑到很多组件在同一功能模块下是通用的,所以方案一不合适。方案二只在根目录设置组件文件夹,考虑到很多组件都是只在某个具体的功能模块才会被使用到,所以方案二也不合适。最终选择了中颗粒度方案,在每个功能模块下设置一个components文件夹。

2.登录功能的封装

具体的微信登录流程就不说了,主要说下登录模块的封装吧。大概有以下两种方式:
方式一 注册一个behavior,然后在需要用到登录的地方引入这个behaviorbehavior只解决了js代码的复用问题,而且要在需要登录的模块(甚至是父子组件)重复引入。而微信授权依赖原生button组件,所以就要在每个需要登录的组件都设置一个弹窗放置这个button,当然这样可以实现功能,但是很不优雅。
方式二 注册一个公共的登录页面。在所有需要登录的模块,在没有登录的情况下都navigateTo到这个页面,在这个页面做用户信息授权,登录,存储token等操作,再nagivateBack到之前页面,当然之前页面的接口请求最好写在onShow这个生命周期钩子里面。
小结: 最后当然选择了方案二咯,目前使用下来没有什么问题。想清楚了还是挺简单的,但当时确实花了点时间思考。

3.如何在微信开发者工具里使用scss

在vscode里用当然就很简单,安装一下Easy Sass,配置下setting.json就OK了。然后保存一下就可以在同目录生成.wxss文件了。但能不能在微信开发者工具里也这么香呢,于是我就翻了文档,果然开发者工具早就支持扩展工具了。具体步骤如下,
1.vscode安装Easy Scss

WechatIMG166.jpeg
2.找到扩展文件夹
其解包后的文件夹可以在 ~/.vscode/extensions (macOS系统) 或 C:\Users\用户名\.vscode\extensions (Windows系统) 下找到

WechatIMG167.jpeg
3.复制扩展文件夹到开发者工具的扩展文件夹中(设置-扩展设置-编辑自定义扩展-打开扩展文件夹),下图所示

WechatIMG170.jpeg

WechatIMG169.jpeg
4.配置setting.json

WechatIMG171.jpeg

WechatIMG175.jpeg
小结: 到这里应该就可以在微信开发者工具里愉快的使用scss了。这里再说个小问题吧,就是在mac上不太好找具体的文件位置,所以我是先把vscode的扩展插件先cp到桌面然后再拖到开发者工具的扩展文件夹里面。听起来像是反向代理hhh。

4.如何设置环境变量的小技巧

微信小程序目前为止还没有提供API或者具体的配置方式,给我们设置环境变量,所以还得自己想办法。大概的想法就是设置一个配置文件(/utils/baseData.js),在需要的地方引入,然后在不同的情况下用node处理配置文件。具体步骤如下:

  • 设置一个baseData.js文件

WechatIMG176.jpeg

  • 在需要的地方引入

image.png
这样就完成了第一步,把配置文件引入到项目中

  • 在根目录新建/env文件夹

/env文件夹下创建dev.jsonprod.json两个json文件,分别用于存放开发环境和生产环境的常量。
image.png

  • 在package.json的script下新增两条命令,用来启动不同的环境

根据命令行参数,选择/env下的对应的配置文件
image.png

  • 在根目录新建switch.js文件,利用node处理配置信息。
* 根据命令行运行参数,修改/config.js 里面的项目配置信息,
*/
const fs = require('fs')
const path = require('path')
//源文件
const sourceFiles = {
  prefix: '/env/',
  dev: 'dev.json',
  prod: 'prod.json'
}
//目标文件
const targetFiles = [{
  prefix: '/utils/',
  filename: 'baseData.js'
}]
const preText = 'module.exports = '
// 获取命令行参数
const cliArgs = process.argv.splice(2)
const env = cliArgs[0]
// 判断是否是 prod 环境
const isProd = env.indexOf('prod') > -1 ? true : false
// 根据不同环境选择不同的源文件
const sourceFile = isProd ? sourceFiles.prod : sourceFiles.dev
// 根据不同环境处理数据
fs.readFile(__dirname + sourceFiles.prefix + sourceFile, (err, data) => {
  if (err) {
    throw new Error(`Error occurs when reading file ${sourceFile}.nError detail: ${err}`)
    process.exit(1)
  }
  // 获取源文件中的内容
  const targetConfig = JSON.parse(data)
  // 将获取的内容写入到目标文件中
  targetFiles.forEach(function(item, index) {
    let result = null
    if (item.filename === 'baseData.js') {
      result = preText + JSON.stringify(targetConfig, null, 2)
    }
    console.log(result)
    // 写入文件(这里只做简单的强制替换整个文件的内容)
      fs.writeFile(__dirname + item.prefix + item.filename, result, 'utf8', (err) => {
        if (err) {
          throw new Error(`error occurs when reading file ${sourceFile}. Error detail: ${err}`)
        process.exit(1)
        }
      })
    })
})
 

当我们执行不同的命令时,switch.js会动态的将相应的环境配置写入配置文件(/utils/baseData.js)中。所以到这里基本完成我们的目标了。但每次切换环境都要运行npm脚本,也不是很方便。

  • 所以最后一步很关键,就是配置我们的开发者工具,让它在预览和上传等操作前自动执行对应的npm脚本。

在开发者工具本地设置中,可以勾选启用自定义处理命令,如下图

image.png
小结: 这样之后,基本就实现了不同环境,使用不同的变量。每次只要更新对应环境的json文件,可以说是很方便了。

5.选择合适的UI框架

这个就不具体展开了,参考文章很多 👀汇总9款优秀的开源小程序UI框架
我最后选的vant。因为我对vant比较熟,但是此vant非彼vant啊,和web版本比起来,简直就是丐中丐了,要啥没啥。唉,如果再给我一次机会,我想...

7.其它细节

7.1 页面初始化请求 onLoad or onShow

本来呢基于减少请求次数,减轻服务器压力的考虑。我准备把请求都写在onload里。但开发中发现有些接口数据依赖于登录状态和其它一些状态,比如vip状态,那这些时候呢,放在onshow里更合适些(主要考虑到这些状态会不定时的发生改变)。

7.2 修改数据不一定要setData

下面是开发文档中最佳实践部分摘抄的一段话:

setData操作会引起框架处理一些渲染界面相关的工作,一个未绑定的变量意味着与界面渲染无关,传入setData会造成不必要的性能消耗。

得分条件:setData传入的所有数据都在模板渲染中有相关依赖

所以有些时候修改数据🦆不必使用setData,比如分页参数page,直接this.data.page++就可以了。

7.3 网络请求的封装

微信提供了发起网络请求的api——wx.request(),并且提供了各种回调函数。这很容易用着用着就回调地狱了。所以封装大概就有以下三点原因:

  • promise化
  • 设置统一的请求头
  • 获得统一的接口回调处理能力

具体代码如下:

import baseData from './baseData'

// 请求封装
const baseUrl = baseData.apiBaseUrl
const timeout = 20000 ////请求超时时间
const header = {
  'content-type': 'application/x-www-form-urlencoded'
}

function fetch(options) {
  if (options.loading) {
    wx.showLoading({
      title: '加载中',
      mask: true
    })
  }
  return new Promise(function(resolve, reject) {
    wx.request({
      url: `${baseUrl}${options.url}`,
      method: options.method || 'GET',
      data: getParams(options.data),
      header: header,
      timeout: timeout,
      success (res) {
        if(res.data.return_code === '2003') { ///token失效
          wx.removeStorageSync('accessToken')
        }
        resolve(res)
      },
      fail (err) {
        reject(err)
      },
      complete () {
        if (options.loading) {
          wx.hideLoading()
        }
      }
    })
  })
}

export function post(url, params, loading=false) {
  let options = {
    method: 'POST',
    url: url,
    data: params,
  }
  return fetch(options)
}
 

总结:终于用了两天的碎片时间给胡言乱语完了。再结合开发文档,应该是可以进行流畅的开发了。水分我就不挤了,大哥们自己挑着看吧。

本文正在参与「掘金 2021 春招闯关活动」, 点击查看活动详情

作者:掘金-微信小程序开发的胡言乱语|项目复盘

回复

我来回复
  • 暂无回复内容