微信小程序踩坑指南

1. 万恶的button

由于小程序的限制,很多地方必须用到button来做,如分享按钮open-type="share",授权按钮open-type="getUserInfo"等,但是小程序对button做了很多的默认限制:

1.1 默认的padding

button默认设置了padding-left: 14rpx; padding-right: 14rpx

1.2 boder

button的上下border是通过button::after设置的,所以要去除button的boder需要设置

button::after {
  border: 0;
}
1.3 button:hover

默认的,小程序会给button加上hover时的样式,所以,如果发现点击了之后button变丑了,就要去设置button-hover样式了,或者直接设置hover-class="none",此时无点击效果,这点文档上有说明。

2. 不支持媒体查询

@media screen and (min-device-height:748px) and (max-device-height:812px) and (-webkit-min-device-pixel-ratio:3){
    html, body{
        height: 2208px;
    }
}

H5页面中做iphone X的适配可能会这么写,但是小程序中这样写不生效。
小程序中如果要针对iphone X做兼容,需要使用js,通过wx.getSystemInfo(OBJECT)获取系统信息

wx.getSystemInfo({
  success: res=> {
    this.globalData.device = JSON.stringify(res);
    let model = res.model
    // 判断是否是iPhone X
    if(model.toLowerCase().search('iphone x') != -1){
      this.globalData.isIphoneX = true;
    }else{
      this.globalData.isIphoneX = false;
    }
  }
})

3. 关于背景图片的使用

在wxss文件中,不能引用本地图片作为背景图片,否则,即便开发者工具上预览正常,真机上是读不出图片的,解决办法是:将本地图片转为base64格式,或者是使用网络图片

4. 关于scroll-view组件的使用

4.1 scroll-view横向滑动
当使用scroll-view组件作scroll-x横向滑动时,scroll-view层需要设置white-space: nowrap;,scroll-view中的子项必须使用display: inline-block;做布局,不能使用float浮动布局,否则组件会失效。
另外,默认情况下,横向滚动块底部会有一个滚动条,要隐藏滚动条,需要设置:

::-webkit-scrollbar {
  width: 0;
  height: 0;
  color: transparent;
}

这一点在官方文档中也没有提及。
scroll-view做竖向滑动时,需要给scroll-view一个固定的高度,尽量不要通过给scroll-view的父盒子使用flex布局,然后scroll-view层使用flex:1;来设置高度,否则在ios上可能会出现一些无法滑动等不可预知的问题。
4.2 scroll-view竖向滚动
scroll-view竖向滚动时绑定bindscroll="scrollHandler"滚动监听时,上拉加载数据除了要判断是否已经获取到最后一页数据后防止继续发出接口请求,还要在每次接口请求发出之时判断请求是否已经回来,在请求未回来之前禁止继续发送请求。

export default {
  data() {
    return {
      isLoadEnd: true, // 用于判断当前请求是否已完成
      isLoadAll: false // 用于判断是否已经加载了所有数据,所有数据加载完后不再发送请求
    };
  },
  methods: {
    scrollHandler() {
      if (!this.isLoadEnd || this.isLoadAll) return;
      this.isLoadEnd = false;
      // 下面是发送请求
      ajax.getData().then(res=> {
        this.isLoadEnd = true;
        // 这里根据接口返回的数据判断是否数据已经全部加载,全部加载设置 this.isLoadAll = true;
      }).catch(err=> {
        this.isLoadEnd = true;
      });
    }
  }
};

5. canvas绘制网络图片

使用canvas绘制图片时,不能使用网络图片,因此如果要绘制网络图片,需要使用downloadFilegetImageInfo将图片缓存到本地,另外还要在小程序后台配置好downloadFile安全域名,否则在真机上会出现奇怪的现象,打开调试模式图片就加载正常,关闭调试模式就加载不出来。

const ctx = wx.createCanvasContext('myCanvas')
const url = '网络图片路径'
wxGetImageInfo (url) {
    return new Promise((resolve, reject) => {
      // 获取图片信息。网络图片需先配置download域名才能生效。
      wx.getImageInfo({
        src: url,
        success: res => {
          resolve(res)
        },
        fail: e => {
          reject(e)
        }
      })
  })
}
 
const {path} = wxGetImageInfo(url)
ctx.drawImage(path, 0, 0, canvasWith, canvasHeight)
ctx.draw(fakse, () => {
    wxApi.wxCanvasToTempFilePath({
        width: 750 * dpr,
        height: 1138 * dpr,
        canvasId: 'myCanvas'
    }).then(res => {
        this.tempImg = res.tempFilePath
        wxApi.hideLoading()
    }).catch(() => {
        wxApi.hideLoading()
     })
})
  • 图片绘制成功要进行预览,则要调用 wx.canvasToTempFilePath() 将画布内容导出生成图片;
  • 图片导出成功后得到的 tempFilePath 需要放在 image 组件src中,不能用做 background-image 的 url ,否则真机下会显示不出图片;
  • 将得到的 tempFilePath 传入 wx.saveImageToPhotosAlbum() 保存到相册;
  • 保存到相册需要用户授权,因此要考虑用户拒绝授权的情况,拒绝之后需要将保存图片的按钮变为 <button open-type="openSetting"></button>打开设置页面;
  • 因为要考虑到新老用户是否授权的情况,需要两个不同的button,另外还要利用到wx.getSetting()来获取授权信息,这里会相比比较麻烦;

6. 弹窗遮罩层滚动穿透问题

弹窗最外层元素上绑定禁止滚动事件 catchtouchmove="touchmoveHandler"

<view catchtouchmove="touchmoveHandler>
  <scroll-view scroll-y>这里写弹窗的具体内容</scroll-view>
</view>

// js部分
touchmoveHandler () {
  return false;
}
  1. 针对 catchtouchmove 方法,原生小程序使用 catchtouchmove="touchmoveHandler"mpvue 中使用 @touchmove.stop="touchmoveHandler",注意 touchmoveHandler 要给个空方法,否则会报警
  2. 绑定 catchtouchmove="touchmoveHandler" 后,弹窗内部如果也有滚动区域的话,则弹窗内部的滚动也会失效,即 catchtouchmove 禁止了所有区域的滚动行为;
  3. 针对第2点,如果弹窗内还有滚动条,则不能使用catchtouchmove方法,按照H5的做法,给 页面 最外层添加height:100%;overflow:hidden;,但是会出现弹窗出来时页面会有一个返回顶部的toTop现象,交互很不友好,并且在ios(某些机型)上会有bug:先在滚动区域滚动几下,然后再在外层滚动几下,此时再回到滚动区域滑动会滑动不了;
  4. 针对第3点bug,如果一定要解决滚动穿透,按照1的方法,只是在弹窗区域内需要滚动的地方使用scroll-view进行包裹。
.noScroll {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0; 
  left: 0;
  z-index: 0;
  overflow: hidden;
}

并且需要动态获取页面当前滚动的距离,然后动态修改containerView的top值,这样做相对麻烦,因此建议此类情况允许穿透;

7. 兼容问题

7.1 onPullDownRefresh下拉刷新兼容问题
使用onPullDownRefresh下拉刷新时,如果将wx.stopPullDownRefresh()放在接口请求的回调中执行并且在请求过程中使用了小程序自带的showToastshowLoading等交互反馈时,在ios上会出现下拉之后反弹过大页面不会回弹至顶部的问题,android上正常。目前解决方法是:

onPullDownRefresh: function () {
  this.getInfo() // 发送请求
  wx.stopPullDownRefresh() // 关闭下拉刷新
}
// 或者是加个定时器
onPullDownRefresh: function () {
  this.getInfo() // 发送请求
  setTimeout(()=> {
    wx.stopPullDownRefresh() // 关闭下拉刷新
  }, 800)
}
参考: https://blog.csdn.net/weichen913/article/details/79360658

7.2 font-weight设置字体加粗的兼容问题
小程序中设置font-weight数字时,在android机上无效。只有700bold有效。

7.3 scroll-view设置height:100%引起的滑动卡顿问题
部分android机上,在scroll-view上设置height:100%会导致页面上滑时不流畅的卡顿问题,不设置自动撑开即可。

8. 摇一摇 - 加速度计

由于小程序目前没有提供摇一摇的API,因此要实现摇一摇的功能需要借助加速度计来实现,与加速度计相关的API有3个:监听加速度数据wx.onAccelerometerChange(CALLBACK)开始监听加速度数据wx.startAccelerometer(OBJECT)停止监听加速度数据wx.stopAccelerometer(OBJECT)
然后,坑来了。。。
wx.stopAccelerometer(OBJECT)停止监听,这个方法是停止了监听,再晃动手机不会走回调方法了,但是它并不移除监听
那么问题来了,在某个页面每调用一次第一个api它就会注册一个监听,第三个api并不能移除掉监听,导致你再次开启的时候就会有多个回调方法在同时进行。就好像是只提供了addEventListener,但却没有提供removeEventListener
如果小程序中有多个页面需要监听加速度,如A、B两个页面,A页面,onReady事件后wx.onAccelerometerChange,离开A页面,stopAccelerometer停止监听。到了B页面,A页面的事件还存在。在B页面摇一摇,就会触发两个页面的回调。
解决方法:
在微信小程序启动的时候就调用监听方法,在回到方法中通过getCurrentPages()获取到当前的页面,在当前页面调用你想回调的方法。

onLaunch: function () {
  wx.onAccelerometerChange((e) => {
    var pages = getCurrentPages()
    var currentPage = pages[pages.length - 1]
    if (currentPage.onAccelerometerChange) {
      currentPage.onAccelerometerChange(e)
    }
  })
}

9. video组件

  1. 在小程序中,video组件的层级跟canvas组件一样,层级是最高的,设置z-index无效;
  2. 使用 API wx.createVideoContext(videoId)seek()方法时,要求视频资源必须是网络资源,不能是本地的视频资源,否则seek()设置无效;
  3. 如果video内部设置了autoplay="{{true}}"自动播放,在 ios 下,即便设置过this.videoContext.pause(),视频一加载也会触发组件的bindplay事件,而 android 下不会;

10. mpvue中关于data的值不会重置的问题

mpvue中,放在data中的数据,在页面没有销毁(点击左上角或手机返回键返回上一层,再进入页面)的情况下,data的数据不会进行重置,因此在小程序onUnload的时候要将数据进行一次重置,也可以在onLoad或onShow生命周期数据操作之前使用Object.assign(this.$data, this.$options.data());将所有的数据重置为初始值;

11. ad组件 - Banner广告

小程序的banner广告会存在加载失败的情况,应该在监听到加载成功的时候再将广告显示出来,否则即便失败的情况,广告也会在页面中占位,显示的 暂无广告 的样式。并且需要将isLoadAd放在父容器上,不能直接在ad组件上使用v-if做判断,否则不生效。

<view :class="{hide: !isLoadAd}">
  <ad unit-id="adunit-****" @load="adLoadSuccess" @error="adLoadFail"></ad>
</view>

data() {
  return {
    isLoadAd: true
  };
}
// 广告加载成功监听
adLoadSuccess() {
  this.isLoadAd = true;
},
// 广告加载失败监听
adLoadFail() {
  this.isLoadAd = false;
}

12. 激励视频

wx.createRewardedVideoAd(Object object)
创建一个激励式视频广告,返回一个单例对象,该对象仅对单个页面有效,不允许跨页面使用。多次创建,将返回同一个激励式视频广告对象(RewardedVideoAd)。该方法在基础库 2.6.0 开始支持,开发者需做兼容处理。

注意:
激励视频会存在加载失败的情况,因此所有观看视频相关的操作必须是在视频加载成功后(isLoadedVideoAd=true)才执行。

export default {
  data() {
    this.videoAd = null;
    return {
      isLoadedVideoAd: false // 激励视频是否加载成功,默认不展示
    };
  },
  onLoad() {
    this.createVideoAd(); // 创建激励视频
  },
  onUnload() {
    this.destoryVideoAd(); // 销毁激励视频及相关视频监听事件
  },
  methods: {
    // 创建激励视频
    createVideoAd() {
      if (wx.createRewardedVideoAd && !this.videoAd) {
        this.videoAd = wx.createRewardedVideoAd({
          adUnitId: '你的视频广告id'
        });
        this.videoAdLoadHandler();
        this.videoAdErrorHandler();
        this.videoAdCloseHandler();
      },
      // 监听激励视频是否加载成功
      videoAdLoadHandler() {
        this.videoAd.onLoad(()=> {
          this.isLoadedVideoAd = true;
        });
      },
      // 监听视频加载出错
      videoAdErrorHandler() {
        this.videoAd.onError(()=> {
          // 视频加载出错,请稍后重试
          this.deleteVideoAd();
        });
      },
      // 监听视频的播放完成事件
      videoAdCloseHandler() {
        this.videoAd.onClose(status=> {
          // 2.1.0以前的版本兼容,status是一个undefined
          if ((status && status.isEnded) || status === undefined) {
            // 正常播放结束-观看完成的逻辑写在这里
          } else {
            // 播放中途退出-相应的处理逻辑写在这里
          }
        });
      },
      // 销毁激励视频广告组件
      destoryVideoAd() {
        if (this.videoAd) {
            this.videoAd.offLoad();
            this.videoAd.offClose();
            this.videoAd.offError();
            this.videoAd = null;
            this.isLoadedVideoAd = false;
        }
      },
      // 显示激励视频广告
      videoAdShow() {
        if (this.videoAd && this.videoAd.show && typeof this.videoAd.show === 'function') {
            this.videoAd.show().catch(()=> {
                // 失败后重试
                this.videoAd.load().then(()=> {
                    this.videoAd.show(); // 加载成功重新显示视频广告
                }).catch(()=> {
                    // 视频加载失败,请稍后重试
                    this.deleteVideoAd();
                  });
                });
            }
      }
    }
  }
};

参考:https://wximg.qq.com/wxp/pdftool/get.html?post_id=851

13. webView - 小程序跳H5

web-view组件: 承载网页的容器。会自动铺满整个小程序页面。
由于web-view组件会自动铺满整个小程序页面,因此每个小程序要跳H5的链接,都需要一个中间页来承载。
而如果一个小程序中如果有多个要跳H5的链接,是不是就需要创建多个承载页?
当然不需要,否则就太麻烦了。因此,建立一个承载页,然后将web-view的src传入即可。

<template>
  <div class="webv-container">
    <web-view :src="webSrc"></web-view>
  </div>
</template>

<script>
export default {
    data() {
        return {
            webSrc: ''
        };
    },
    onLoad() {
        const rootQuery = this.$root.$mp.query || {};

        this.webSrc = decodeURIComponent(rootQuery.src);
    }
};
</script>

tip:

  1. 父级页面传入src时一定要进行encodeURIComponent,然后在webView页面中进行decodeURIComponent;
参考:

http://www.iamaddy.net/2017/07/wxapp-accelerometer/
https://blog.csdn.net/frankkay/article/details/80485095

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345