小程序的项目架构

2021-02-24  本文已影响0人  人猿Jim
Nam form Pixiv

目前项目用到的小程序项目架构,比较特殊的是store和behaviors,有个清晰的目录架构可以加快开发的效率,便于维护


小程序的项目架构

behavior

存放小程序需要用到的混合文件,类似vue的mixin

// page-a.js
// var myBehavior = require('./my-behavior.js')
// Page({
//   behaviors: [myBehavior],
//   onLoad: function() {
//     this.data.sharedText === 'This is a piece of data shared between pages.'
//   }
// })
const app = getApp()
module.exports = Behavior({
  data: {
    userInfo: null,
    hasUserInfo: false,
    canIUse: wx.canIUse('button.open-type.getUserInfo')
  },
  methods: {
    // 1.通过button来授权获取 用户信息
    getUserInfo: function(e) {
      console.log('--getUserInfo--')
      app.globalData.userInfo = e.detail.userInfo
      this.setData({
        userInfo: e.detail.userInfo,
        hasUserInfo: true
      })
    },

    // 2.通过静默授权的方式来获取 用户信息(为了兼容旧版本)
    silentGetUserInfo: function() {
      return new Promise((resolve, reject) => {
        console.log('--silentGetUserInfo--', app.globalData.userInfo)
        if (app.globalData.userInfo) {
          this.setData({
            userInfo: app.globalData.userInfo,
            hasUserInfo: true
          })
          // 已登录
          resolve(app.globalData.userInfo)
        } else if (this.data.canIUse) {
          // 获取用户信息 ( 如果授权过以后直接获取用户信息 )
          wx.getSetting({
            success: res => {
              console.log('scope.userInfo=', res.authSetting['scope.userInfo'])
              if (res.authSetting['scope.userInfo']) {
                // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
                wx.getUserInfo({
                  success: res => {
                    // 可以将 res 发送给后台解码出 unionId
                    app.globalData.userInfo = res.userInfo
                    console.log('res.userInfo', res.userInfo)
                    // 已登录
                    resolve(res.userInfo)
                  },
                  fail: () => {
                    // 没登录
                    reject(null)
                  }
                })
              } else {
                // 没登录
                reject(null)
              }
            },
            fail: () => {
              // 没登录
              reject(null)
            }
          })
        } else {
          // 在没有 open-type=getUserInfo 版本的兼容处理
          wx.getUserInfo({
            success: res => {
              app.globalData.userInfo = res.userInfo
              this.setData({
                userInfo: res.userInfo,
                hasUserInfo: true
              })
              // 已登录
              resolve(res.userInfo)
            },
            fail: () => {
              // 没登录
              reject(null)
            }
          })
        }
      })
    },
    // 3.退出登录
    loginOut() {
      // 清除page的登录的数据
      this.setData({
        userInfo: null,
        hasUserInfo: false,
        isLogin: false
      })
      // 清除app的登录数据
      app.globalData.userInfo = null
    }
  }
})

config

用于定义环境与接口地址,方便切换与维护

// config.dev.js
// 开发环境
module.exports = {
  isDebug: true,
  baseUrl: 'http://192.168.1.120',
  storageUrl: 'http://192.168.1.120'
}

// index.js
// 1.开发环境
// const conf = require('./config.dev.js')
// 1.测试环境
const conf = require('./config.pro.js')
// 1.正式环境
// const conf = require('./config.real.js')

module.exports = {
  isDebug: conf.isDebug,
  baseUrl: conf.baseUrl,
  storageUrl: conf.storageUrl
}

service

用于存放接口地址

var http = require('../../utils/http.js')

const api_report = {
  foo: '/aaa, 
  boo: '/bbb'
}

const reportList = (payload) => {
  return http.post(api_report.foo, payload) // 返回的是 promise
}
const reportSubmit = (payload) => {
  return http.post(api_report.boo, payload) // 返回的是 promise
}
// 对外暴露
module.exports = {
  reportList,
  reportSubmit
}

store

类似vue的vuex作用,用于存储全局变量

// store.js
import { observable, action } from 'mobx-miniprogram'

export const store = observable({

  // 数据字段( 相当于data的fields )
  numA: 1,
  numB: 2,

  // 计算属性( 相当于data的fields )
  get sum() {
    return this.numA + this.numB
  },

  // actions
  update: action(function() {
    const sum = this.sum
    this.numA = this.numB
    this.numB = sum
  })

})

util

网络方面:需要注意的是小程序的登录功能因为需要存储token和用户信息,而用户信息是存在小程序的Storage中,在http中会处理到用户的信息

utils.js

// rpx 转换为 px
const rpxTopx  =(rpx)=>{
  let deviceWidth = wx.getSystemInfoSync().windowWidth; //获取设备屏幕宽度
  let px = (deviceWidth/750)*Number(rpx);
  return px;
}
// px 转换为 rpx ,传参类型是数字(Number)
const pxTorpx = (px) => {
    let deviceWidth = wx.getSystemInfoSync().windowWidth;   //获取设备屏幕宽度
    let rpx = (750 / Number(px)) * deviceWidth;
    return rpx;
}
const getAuthToken = () => {
  return wx.getStorageSync('session_key')
}

// 清除登录的数据(退出登录)
const loginOut = () => {
  setAuthToken(null)
}
module.exports = {
  rpxTopx,
  pxTorpx,
  getAuthToken,
  loginOut 
}

http.js

// const baseUrl = '' // 基本路径
const config = require('../config/index')
const utils = require('../utils/util.js')
// 请求方法
function request(url, method, data, header, hasLoading = true) {
  data = data || {}
  header = header || {}

  // // 判断 是否有登录 token
  const auth_token = utils.getAuthToken() // 同步
  // 对接时候写死token
  if (auth_token) {
    header['auth_token'] = auth_token
  } else {
    // 测试 auth_token
    header['auth_token'] = 'abc'
  }

  // 加载动画
  if (hasLoading) {
    wx.showLoading({
      title: '加载中'
    })
  }

  // 创建 promise 对象
  const promise = new Promise((resolve, reject) => {
    wx.request({
      url: config.baseUrl + url, // 地址
      header: header,
      data: data,
      method: method,
      success: function(res) {
        console.log( res)
        if (hasLoading) {
          wx.hideLoading() // 隐藏加载动画
        }
        // 判断是否成功(res的数据需要看接口返回的数据做判断)
        if (typeof res.data === 'object') {
          // console.log(res)
          if (res.data.code === -1 || res.data.code === '1001') {
            // 判断是否有登录 请求未登录
            // {code: -1
            //  data: "401"
            //  msg: "未登录"}
            if (res.data.data === '401') {
              // 清除登录数据,重新登录
              utils.loginOut()
              setTimeout(() => {
                // 跳转到登录页面
                wx.redirectTo({
                  url: '/pages/mine/mine' //  跳转登录页
                })
              }, 500)
              wx.showToast({
                title: '请重新登录!',
                icon: 'none',
                duration: 2000
              })
              reject(res)
            // 请求失败
            } else {
              wx.showToast({
                title: res.data.msg || '请求失败',
                icon: 'none',
                duration: 2000
              })
              reject(res)
            }
          } else if (res.data.code === 200 || res.data.code === 0) {
            resolve(res)
          } else {
            reject(res)
          }
        } else {
          reject(res)
        }
      },

      // 接口调用失败的回调函数
      fail: function(res) {
        console.log('x=', config.baseUrl + url)
        if (hasLoading) {
          wx.hideLoading()
        }
        wx.showToast({
          title: '网络错误!',
          icon: 'none',
          duration: 2000
        })
        reject(res)
      }

    })
  })
  return promise
}

// 对外暴露
module.exports = {
  get: function(url, data, header) {
    return request(url, 'GET', data, header)
  },
  post: function(url, data, header) {
    return request(url, 'POST', data, header)
  }
}

template

小程序提供模板功能,可自定义几个"暂无数据"的模板进行复用

// 使用模板
<import src="../../templates/no-data/no-data.wxml"/>
<!-- 没有数据 -->
<view
   class="report-list-page no-data"
   wx:if="{{dataList.length === 0}}">
     <template is="noData"></template>
</view>

// 定义模板
<!--templates/no-login/no-data.wxml-->
<template name="noData">
  <view style="text-align: center;">
    <image 
      src="../../images/mine/no-find-bg.png"
      style="width:506rpx;height:239rpx;margin-top:107rpx"
    >
    </image>
    <view style="color:#8E919C;font-size:28rpx">暂无数据</view>
  </view>
</template>

其它

小程序有个坑点需要注意,就是css中background-image引用图片时会无法显示,需要把图片转为base64,这个转换可以在onload生命周期上进行

  data:{
    bannerBg:'../../images/banner.png'
  },
  onLoad: function(options) {
    const bannerBg = wx.getFileSystemManager().readFileSync(this.data.bannerBg, 'base64')
    that.setData({
      'bannerBg': 'data:image/jpg;base64,' + bannerBg,
    })
  },
上一篇 下一篇

猜你喜欢

热点阅读