小程序踩坑记录

前言

经历了互联网寒冬,一波面试下来。发现了学习的东西还有很多。后面也拿到了比较满意的offer。新入职的第一个项目是关于小程序的,之前我也接触小程序的,只不过是个人玩玩的项目。所以说一路踩坑过来,下面我把这段时间遇到的一些问题总结下,希望对正在小程序开发的你有所帮助,本人经验有限,以下讲的不好的欢迎指正。

1、小程序工程化开发

目前小程序开发框架有很多,mpvue、wepy。我在项目中使用的是原生小程序。下面是几个的对比。

上图可以看出原生小程序劣势很大,至于为什么我不采用其他框架呢,个人认为短时间内用其他的框架怕踩到莫名的坑。虽然原生也有很多坑。下面是我用gulp进行了细微的改造。

开发

  1. 所有小程序源码放在src目录里面,目录结构与原生的小程序基本相同,编译后的文件会自动copy到dist目录,与原生小程序不同点如下:
  • 全部使用less开发, pages目录下面的页面也使用less,程序会自动编译为wxss文件
  • 程序全局配置文件在config目录的config.js里面,程序会根据开发环境来匹配不同的配置项
  • 页面的Page构造对象需import utils目录下面的wxPage

"devDependencies": {
    "cross-env": "^5.2.0", 
    "gulp": "^4.0.0",
    "gulp-clean": "^0.4.0",     //删除文件
    "gulp-less": "^4.0.1",      //编译less
    "gulp-plumber": "^1.2.1",   
    "gulp-rename": "^1.4.0",    //重命名
    "gulp-replace": "^1.0.0"    //替换原文件
  }
复制代码

gulpfile.js

const gulp = require('gulp')
const less = require('gulp-less')
const rename = require('gulp-rename')
const clean = require('gulp-clean')
const replace = require('gulp-replace')
const plumber = require('gulp-plumber')
const fs = require('fs')
const env = process.env.NODE_ENV

const srcPath = 'src'
const outputPath = 'dist'
const lessFile = [`${srcPath}/**/*.less`, `!${srcPath}/style/*.less`]
const allLessFile = [`${srcPath}/**/*.less`]
const copyFile = [`${srcPath}/**/*.*`, `!${srcPath}/**/*.less`, `!${srcPath}/style/*.less`, `!${srcPath}/config/**/*.js`]
const replaceFile = [`${srcPath}/config/**/*.js`]
const watchOption = { events: ['add', 'change', 'unlink'], delay: 200 }

gulp.task('clean-image', function() {
  return gulp.src([`${outputPath}/images`])
    .pipe(plumber())
    .pipe(clean())
})

// 清空无关紧要的wxss
gulp.task('clean-less', function() {
  return gulp.src([`${outputPath}/template/**/*.wxss`])
    .pipe(plumber())
    .pipe(clean())
})

// 清空dist目录下面的文件
gulp.task('clean', function() {
  return gulp.src([`${outputPath}/**/*.*`, `!${outputPath}/readme.md`], { read: false })
    .pipe(plumber())
    .pipe(clean())
})

// copy项目文件到dist目录
gulp.task('copy', function() {
  return gulp.src(copyFile)
    .pipe(plumber())
		.pipe(gulp.dest(outputPath))
})

// 编译less
gulp.task('less', function() {
  return gulp.src(lessFile)
    .pipe(plumber())
    .pipe(less())
    .pipe(rename(function (path) {
      path.extname = '.wxss'
    }))
    .pipe(gulp.dest(outputPath))
})

// 替换字符串,区分开发和测试环境 dev:开发环境,build:集成环境
gulp.task('replace', function() {
  return gulp.src(replaceFile)
    .pipe(plumber())
    .pipe(replace(/{NODE_ENV}/gi, env))
    .pipe(gulp.dest(`${outputPath}/config`))
})

function fsExistsSync(path) {
  try {
    fs.accessSync(path, fs.F_OK)
  } catch(e) {
    return false
  }
  return true
}

gulp.task('watch', function() {
  gulp.watch(allLessFile, watchOption, gulp.series('less'))
  gulp.watch(copyFile, watchOption, gulp.series('copy'))
  gulp.watch(replaceFile, watchOption, gulp.series('replace'))
  // 监听文件的删除
  var watcher = gulp.watch([`${srcPath}/**`, `!${srcPath}/style/*.less`])
  watcher.on('all', function(event, p) {
    console.log(event, p)
    try {
      if (event === 'unlink') {
        const filePath = p.split('.')[0]
        const extname = p.split('.')[1]
        const fileName = extname === 'less' ? filePath + '.wxss' : p
        const file = fileName.replace(/\\/g, '/').replace(srcPath, outputPath)
        fsExistsSync(file) && gulp.src(file, { read: false }).pipe(clean())
      }
      if (event === 'unlinkDir') {
        const file = outputPath + p.split(srcPath)[1].replace(/\\/g, '/')
        fsExistsSync(file) && gulp.src(file, { read: false }).pipe(clean())
      }
    } catch (error) {
      console.log('删除文件出错!')
    }
  })
})

// gulp.task('dev', gulp.series('copy', 'replace', 'less', 'watch'))

// gulp.task('build', gulp.series('clean', 'copy', 'replace', 'less'))
gulp.task('dev', gulp.series('clean', gulp.parallel('copy', 'replace', 'less', 'watch')))

gulp.task('build', gulp.series('clean', gulp.parallel('copy', 'replace', 'less'), 'clean-image', 'clean-less'))

复制代码

2、登陆与授权问题

登陆首先看下官网的泳道图其实讲的很清楚

  • 调用 wx.login() 获取 临时登录凭证code ,并回传到后端提供的接口。
  • 调用 auth.code2Session 接口,换取 用户唯一标识 OpenID 和 会话密钥 session_key。

授权

最新的api,获取一些用户授权信息是要用户主动去触发(有些产品不清楚这一点交互方面)。通过button组件配置不一样的open-type,获取手机号信息需要企业认证。

3、自定义遮罩层在真机下遮不住map、video、canvas、camera、live-player、live-pusher

cover-view了解下

还有种场景就是textarea,如果上面的提示层不是用cover-view。那么真机下会出现问题

另一种解决思路 提交的时候用view替换textarea。

<textarea class="beizhu" value="{{txtContent}}" bindinput='txtInput'  wx:if="{{!isSure}}" maxlength="20"/>
<!-- 这是用于模拟 textarea的替代元素 -->
<view class='beizhu' wx:else>
    <rich-text nodes="{{txtRealContent}}"></rich-text>
</view>
js
txtInput(e) {
    this.setData({ txtContent: e.detail.value })
},
const txtRealContent = this.data.txtContent.replace(/\n/g, '<br/>')
this.setData({ txtRealContent })

复制代码

4、微信上传图片到腾讯云并且返回加速地址

预警深坑腾讯云,腾讯云api看得真是混乱 ... 下面是采用SDK形式调用下载地址cos-wx-sdk-v5.js


 let COS = require('../../utils/cos-wx-sdk-v5.js')
 // 调用后端提供的接口获取对应的桶 域...
 // 注意此接口要在new COS之前调用
 
    getAuthorization(options, callback) {
      let _this = this
      callback({
        TmpSecretId: _this.data.cosParam.tmpSecretId,
        TmpSecretKey: _this.data.cosParam.tmpSecretKey,
        XCosSecurityToken: _this.data.cosParam.sessionToken,
        ExpiredTime: _this.data.cosParam.expiredTime, // SDK 在 ExpiredTime 时间前,不会再次调用 getAuthorization
      });
    },

    requestCallback(err, data) {
      let _this = this
      console.log(err || data);
      if (err && err.error) {
        wx.showModal({
          title: '返回错误',
          content: '请求失败:' + (err.error.Message || err.error) + ';状态码:' + err.statusCode,
          showCancel: false
        });
      } else if (err) {
        wx.showModal({
          title: '请求出错',
          content: '请求出错:' + err + ';状态码:' + err.statusCode,
          showCancel: false
        });
      } else {
        let region = this.data.cosParam.region
        let urls = `https://${data.Location}`
        let url = urls.replace(region,'file') // 切换加速CDN地址
        // wx.showToast({
        //   title: '上传成功',
        //   icon: 'success',
        //   duration: 3000
        // });
      }
    },
    
    ajax.get('/common/qcloud/getQcloudTempTokenInfo', {}, false).then(res => {
        let credentials = res.data;
        _this.setData({
            cosParam: credentials
        })
     });
     wx.chooseImage({
            count: 1, // 默认9
            sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
            sourceType, // 可以指定来源是相册还是相机,默认二者都有
            success: (res) => {
              let size = res.tempFiles[0].size;
              console.log(res)
              const filePath = res.tempFiles[0].path;
              const filename = filePath.substr(filePath.lastIndexOf('/') + 1);
              console.log(filename)
              if (size < 10000000) {
    
                _this.setData({ showVisible: false })
    
                const cos = new COS({
                  // path style 指正式请求时,Bucket 是在 path 里,这样用途相同园区多个       bucket 只需要配置一个园区域名
                    getAuthorization: _this.getAuthorization.bind(_this),
                });
             
                cos.postObject({
                  Bucket: _this.data.cosParam.bucket,
                  Region: _this.data.cosParam.region.split('.')[1],
                  Key: _this.data.cosParam.fileFolder+filename,
                  FilePath: filePath
                  // Body: file[0]
                  // 在小程序里,putObject 接口只允许传字符串的内容,不支持 TaskReady 和 onProgress,上传请使用 cos.postObject 接口
                }, _this.requestCallback.bind(_this));
            }
    })
复制代码

5、页面传值

a页面 -> b页面

 // a.js
 wx.navigateTo({ url: `../industry/industry?formData=${queryBean}` });
 // b.js 取值
 onLoad(option){
     console.log(option.formData)
 }
复制代码

a页面 <- b页面

// b.js
const pages = getCurrentPages()             // 获取微信页面栈
const prevPage = pages[pages.length - 2];   // a页面
const index = prevPage.data.selectIndex;    
const placeholder = `formList[${index}].placeholder`
prevPage.setData({
    [placeholder]: '已上传',                  // 设置a页面数据
    selectIndex: 1 
})
wx.navigateBack({
    delta: 1                                  //返回的页面数,如果 delta 大于现有页面数,则返回到首页,
});
复制代码

6、动态改变底部tabBar

考虑到项目中后续需要多个角色,每个角色展示的不一样的底部。

方法一:首先隐藏原始的tabBar,然后使用标签自定义布局可以实现。但是缺点是每次切换都需要重新加载底部的页面。

方法二:官方给了一个,这里具体就不再写了,给个传送门

后续持续更新...

转载于:https://juejin.im/post/5cd0142ee51d453b560f2d50

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值