【微信小程序】踩坑指南(持续更新)

前言 

说明:

  • 基于mpvue框架:mpvue官方文档
  • 语法同vue框架:vue官方文档
  • 小程序中会有一些坑点,这里会就工作中遇到的坑一一列举出来
  • 无说明时请直接看代码注释

v-show无法使用在小程序中

<!-- 下面这行代码无法正常工作 -->
<img v-show="IDcard" :src="IDcard" alt="">

<!-- 替代方案 -->
<img v-if="IDcard" :src="IDcard" alt="">

input标签的type无法动态赋值

<!-- 下面的inputType的值可能为:number|text|tel -->
<!-- 下面的代码无法得到正确结果 -->
<input class="value" :type="inputType" v-model="value">

<!-- 替代方案 -->
<input v-if="inputType === 'text'" class="value" v-model="value" type="text">
<input v-else-if="inputType === 'number'" class="value" v-model="value" type="number">
<input v-else class="value" v-model="value" type="tel">

img标签的src内不可使用三元运算符

<!-- 下面的写法导致src拿不到bg_identity.png -->
<img :src="IDcard?IDcard:'../../../static/images/bg_identity.png'" alt="">

<!-- 替代方案 -->
<img v-if="IDcard" :src="IDcard" alt="">
<img v-else src="../../../static/images/bg_identity.png" alt="">

详情页跳转旧数据不销毁处理办法

场景:

  • 从商品列表点击一件商品进详情,返回列表页,选择另一件商品进详情,会出现上一件商品的数据后再渲染新商品的数据 
// 解决方案
onUnload () {
  Object.assign(this.$data, this.$options.data())
}

解释:

  • 在小程序的页面卸载生命钩子onUnload中添加以上代码,可让data对象里的属性重新初始化 

原生组件的层级问题

官方说明文档原生组件说明

举例说明:

  • 如果想让一个按钮定位在canvas内容层级上面,直接使用z-index是无效的。

解决办法:

  • 使用小程序提供的cover-view 与 cover-image组件可覆盖在部分原生组件上面。

实际例子:

  • button组件定位在canvas组件上面

注意事项:

  • 使用了cover-view组件后,cover-view容器内不能使用常规的div,a,span等等,可嵌套cover-view 、 cover-image和button
  • 可覆盖的原生组件包括map、video、canvas、camera、live-player、live-pusher

onLoad与onShow的区别

页面路由

说明:

  • onLoad:页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打开当前页面路径中的参数。 
  • 例:从分享的消息卡片中带参数到指定页,如:pages/index/main?id=123
  • onShow:页面显示/切入前台时触发。不可带参数,但是可以动态更新当前页

 

onLoad (e) {
  console.log(e.id) // 123
},

onShareAppMessage: function (res) {
  return {
    title: '邀请您填简历',
    path: `/pages/index/main?id=${this.id}`
  }
}

textarea原生组件相关问题

  • 解决textarea组件为原生组件层级最高,穿透弹窗或遮罩层。
<textarea v-model="desc" class="inp" placeholder="" auto-focus v-if="focusFlag" @blur="hideTextarea"></textarea>
<p v-else-if="!focusFlag && desc" class="textarea-replace" @click="showTextarea">{{desc}}</p>
<p v-else class="textarea-replace no-desc" @click="showTextarea">请介绍一下自己的性格特点、工作经历,描述下自己擅长做的事情</p>
export default {
  data () {
    desc: '',
    focusFlag: true
  },
  methods: {
    hideTextarea () {
      this.focusFlag = false
    },
    showTextarea () {
      this.focusFlag = true
    }
  }
}

解释

  • auto-focus很重要,不加的话,每次输入文字都得聚焦(点击)两次;
  • placeholder可以通过增减p标签的class名来实现,即class="no-desc"
  • @blur事件是失去焦点时触发

 new Date()设置日期在IOS的兼容问题

说明:

  • new Date(date).getTime(),用这个方法来获取时间戳时,iphone手机上打印出的时间戳为NaN
  •  例:日期为2019-08-27 16:11:02时使用new Date(date).getTime()方法无法在iphone手机上获取到对应的时间戳
  • 安卓手机不管是‘-’还是‘/’都能正确转成时间戳

解决方案:

const time = '2019-08-27 16:11:02'
const newTime = new Date(time.replace(/-/g, '/')).getTime()

关于小程序中计时器的正确使用

先看实例

讲解:

  • 每个需求详情对应一组倒计时
  • 每次进详情页,希望数据都是初始化的状态
  • 离开页面即销毁数据,下次进详情重新获取新数据 

坑点:

  • 每次进详情页都会生成一个计时器
  • 如果页面销毁时不手动清除计时器的话会导致再次进入详情页会有两个计时器在运行,重复动作,会有越来越多的计时器存在于详情页中
  • 如何销毁,计时器如何定义?

解决方案

data () {
  return {
    timer: null
  }
},
onLoad (e) {
  this.demandId = e.id
  this.getDemandDetail()
},
onUnload () {
  clearInterval(this.timer)
  Object.assign(this.$data, this.$options.data())
},
methods: {
  getDemandDetail() {
    // axios请求拿到详情数据后
    getDetail(this.demandId).then(res => {
      // 在接口中获取到截止时间和服务器的当前时间
      this.runTimer(res.data.deadline, res.data.systemDate)
    })
  },

  runTimer (deadline, systemDate) {
    deadline = deadline.replace(/-/g, '/')
    systemDate = systemDate.replace(/-/g, '/')
    let totalSeconds = parseInt((new Date(deadline).getTime() - new Date(systemDate).getTime()) / 1000)
    this.timer = setInterval(() => {
      const hours = parseInt(totalSeconds / 60 / 60) > 0 ? parseInt(totalSeconds / 60 / 60) : 0
      const minutes = parseInt((totalSeconds - hours * 3600) / 60) > 0 ? parseInt((totalSeconds - hours * 3600) / 60) : 0
      const seconds = parseInt(totalSeconds - hours * 3600 - minutes * 60) > 0 ? parseInt(totalSeconds - hours * 3600 - minutes * 60) : 0
      // 计算出时分秒并赋值给显示区域
      this.countTime.hours = hours < 10 ? '0' + hours : hours
      this.countTime.minutes = minutes < 10 ? '0' + minutes : minutes
      this.countTime.seconds = seconds < 10 ? '0' + seconds : seconds
      // 当秒数小于零时销毁计时器,否则秒数-1
      if (totalSeconds <= 0) {
        this.countdownEnd = true
        clearInterval(this.timer)
        this.timer = null
      } else {
        totalSeconds--
      }
    }, 1000)
  }
}

关键代码:

onUnload () {
  // 必须执行clearInterval操作才能销毁计时器,简单的null赋值无法销毁
  clearInterval(this.timer)
  // 前面有介绍过,负责页面销毁后再次回到页面时初始化数据
  Object.assign(this.$data, this.$options.data())
}
posted @ 2019-11-19 14:57  宝贝QY  阅读(479)  评论(0编辑  收藏  举报