微信小程序 【開(kāi)發(fā)】 自學(xué)總結(jié)

抖音小程序與微信小程序差異
  1. 獲取用戶(hù)信息的方式
  • 通過(guò)button按鈕,設(shè)置屬性 open-type="getUserInfo",獲取獲得用戶(hù)信息的授權(quán)
  • 兼容性,通過(guò)wx.canIUse('button.open-type.getUserInfo')的值,來(lái)判斷按鈕是否可用
  • 通過(guò)擁有上述屬性的按鈕事件bindgetuserinfo - https://developers.weixin.qq.com/miniprogram/dev/component/button.html 來(lái)獲取,事件處理函數(shù)中ev.detail.userInfo對(duì)應(yīng)的用戶(hù)信息
  • wx.getUserInfo在用戶(hù)未授權(quán)的情況下,將不再出現(xiàn)授權(quán)彈窗,所以才使用引導(dǎo)用戶(hù)點(diǎn)擊按鈕的授權(quán)方式
  • 通過(guò)onload生命周期,wx.getSetting來(lái)獲取用戶(hù)權(quán)限,并對(duì)用戶(hù)信息狀態(tài)賦值
<view wx:if="{{showLoginBtn}}">
  <button 
    class="skillbtn" 
    bindgetuserinfo="loginFn" 
    open-type="getUserInfo"
  >手動(dòng)授權(quán)登錄</button>
</view>
<view wx:else>
  <text>請(qǐng)升級(jí)微信版本</text>
</view>
...
//查看授權(quán)按鈕是否可以使用
if(wx.canIUse('button.open-type.getUserInfo')){
  _that.setData({
    'showLoginBtn': true
  });
};
...
//獲取用戶(hù)信息與請(qǐng)求服務(wù)器獲取userid
loginFn(ev){
  var _that = this;
  //獲取用戶(hù)的當(dāng)前授權(quán)設(shè)置
  wx.getSetting({
    success(res){
      //查看【獲取用戶(hù)信息】授權(quán)
      if(res.authSetting['scope.userInfo']){
        wx.getUserInfo({
          success(res){
            var _userInfo = res.userInfo;
            
            //獲得code,再進(jìn)行注冊(cè)
            _that.registerFn(function(_code){

              //請(qǐng)求后臺(tái)接口,獲取userid

            });
          },
          fail(err){
            console.log(err);
          }
        });
      }else{
        app.showPopFn({
          'title':'授權(quán)失敗',
          'icon': 'none',
          'duration': 1000
        });
      }
    }
  })
}

1-2. 如果wx:if掛載的標(biāo)簽上條件,與通過(guò)此條件來(lái)增加標(biāo)簽上的class類(lèi)名時(shí)候,不會(huì)產(chǎn)生動(dòng)畫(huà)效果
解決: 需要增加額外條件,來(lái)改變class類(lèi)名,可能的話(huà),還要增加延時(shí)定時(shí)器來(lái)進(jìn)行這個(gè)類(lèi)名條件的設(shè)置

  1. 最新官方關(guān)于 用戶(hù)信息相關(guān)接口調(diào)整 - https://developers.weixin.qq.com/community/develop/doc/000cacfa20ce88df04cb468bc52801
    【背景】:
    很多開(kāi)發(fā)者在打開(kāi)小程序時(shí)就通過(guò)組件方式喚起getUserInfo彈窗,如果用戶(hù)點(diǎn)擊拒絕,無(wú)法使用小程序,這種做法打斷了用戶(hù)正常使用小程序的流程,同時(shí)也不利于小程序獲取新用戶(hù)。

【注意】:

  • 建議多用getUserProfile,即便被拒絕,再次調(diào)用getUserProfile,仍可以拉起授權(quán)。
  • 授權(quán)被拒后,通過(guò)wx.openSetting打開(kāi)設(shè)置菜單,是無(wú)法找到被拒的授權(quán)信息的。

官方變化:


對(duì)比圖
  • 新的授權(quán)書(shū)寫(xiě)方式
    由于getUserProfile接口從2.10.4版本基礎(chǔ)庫(kù)開(kāi)始支持(覆蓋微信7.0.9以上版本),考慮到開(kāi)發(fā)者在低版本中有獲取用戶(hù)頭像昵稱(chēng)的訴求,對(duì)于未支持getUserProfile的情況下,開(kāi)發(fā)者可繼續(xù)使用getUserInfo能力
    //--wxml
<view class="container">
  <view class="userinfo">
    <block wx:if="{{!hasUserInfo}}">
      <button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 獲取頭像昵稱(chēng) </button>
      <button wx:else open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 獲取頭像昵稱(chēng) </button>
    </block>
    <block wx:else>
      <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
      <text class="userinfo-nickname">{{userInfo.nickName}}</text>
    </block>
  </view>
</view>

//--js

Page({
  data: {
    userInfo: {},
    hasUserInfo: false,
    canIUseGetUserProfile: false,
  },
  onLoad() {
    if (wx.getUserProfile) {
      this.setData({
        canIUseGetUserProfile: true
      })
    }
  },
  getUserProfile(e) {
    // 推薦使用wx.getUserProfile獲取用戶(hù)信息,開(kāi)發(fā)者每次通過(guò)該接口獲取用戶(hù)個(gè)人信息均需用戶(hù)確認(rèn)
    // 開(kāi)發(fā)者妥善保管用戶(hù)快速填寫(xiě)的頭像昵稱(chēng),避免重復(fù)彈窗
    wx.getUserProfile({
      desc: '用于完善會(huì)員資料', // 聲明獲取用戶(hù)個(gè)人信息后的用途,后續(xù)會(huì)展示在彈窗中,請(qǐng)謹(jǐn)慎填寫(xiě)
      success: (res) => {
        this.setData({
          userInfo: res.userInfo,
          hasUserInfo: true
        })
      }
    })
  },
  getUserInfo(e) {
    // 不推薦使用getUserInfo獲取用戶(hù)信息,預(yù)計(jì)自2021年4月13日起,getUserInfo將不再?gòu)棾鰪棿?,并直接返回匿名的用?hù)個(gè)人信息
    this.setData({
      userInfo: e.detail.userInfo,
      hasUserInfo: true
    })
  },
})

2-2. 區(qū)別與獲取用戶(hù)昵稱(chēng)與信息的授權(quán),有些授權(quán)拒絕后,再次調(diào)用API,不會(huì)再次彈出授權(quán)界面
如果用戶(hù)已拒絕授權(quán),則不會(huì)出現(xiàn)彈窗,而是直接進(jìn)入接口 fail 回調(diào)。需要發(fā)者兼容用戶(hù)拒絕授權(quán)的場(chǎng)景
以獲取用戶(hù)地理信息的授權(quán)為例

授權(quán)流程圖

2-3. 關(guān)于授權(quán)的過(guò)期時(shí)間

  • 在開(kāi)發(fā)者工具中,點(diǎn)擊 [ 清緩存-全部清楚 ] ,即可一次性清楚所有數(shù)據(jù)緩存與授權(quán)記錄信息
  • 借用微信文檔說(shuō)明:在真機(jī)上,一旦用戶(hù)明確同意或拒絕過(guò)授權(quán),其授權(quán)關(guān)系會(huì)記錄在后臺(tái),直到用戶(hù)主動(dòng)刪除小程序。
    直接在微信-小程序內(nèi),找到對(duì)應(yīng)的小程序?qū)⑵鋭h除,可能的話(huà),再加上(我-設(shè)置-通用-存儲(chǔ)空間-緩存-清理),更加干凈的清理對(duì)應(yīng)小程序的各種數(shù)據(jù)緩存與授權(quán)信息
  1. rpx(responsive pixel): 可以根據(jù)屏幕寬度進(jìn)行自適應(yīng)。
    規(guī)定屏幕寬為750rpx。
    如在 iPhone6 上,屏幕寬度為375px,共有750個(gè)物理像素,則750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。

  2. 獲取用戶(hù)坐標(biāo)
    在app.json中,添加獲取目標(biāo)位置的權(quán)限:

"permission": {
    "scope.userLocation": {
      "desc": "你的位置信息將用于小程序位置接口的效果展示"
    }
}

獲取用戶(hù)坐標(biāo) wx.getLocation

getUserLocalFn(){
    var that = this;
    //獲取用戶(hù)坐標(biāo)
    wx.getLocation({
      type: 'wgs84',
      success(res){
        var _userLocal = that.data.userLocal;
        _userLocal.latitude = res.latitude;
        _userLocal.longitude = res.longitude;
        that.setData({
          "userLocal": _userLocal
        });
      },
      fail(err){
        console.log(err);
      }
     });
}
  1. 圖片預(yù)加載
    app.js
//圖片預(yù)加載
loadImg(_link,sucFn,errFn,cmpFn){
  wx.getImageInfo({
    src: _link,
    success(res){
      sucFn && sucFn(res);
    },
    fail(err){
      errFn && errFn(err);
    },
    complete(res){
      cmpFn && cmpFn(res);
    }
  });
},
//加載所有圖片
loadAllImgs(imgListArr,compFn){
  //圖片預(yù)加載 相關(guān)
  var _that = this;
  var num = 0;
  
  for(var i=0; i<imgListArr.length; i++){
    ;(function(i){
      var _tempImg = imgListArr[i];
      //加載圖片
      _that.loadImg(_tempImg,function(res){
        num+=1;
        if(num==imgListArr.length){
          compFn && compFn();
        }
      },function(err){
        num+=1;
        if(num==imgListArr.length){
          compFn && compFn();
        }
      },null);  
    })(i);
  }
}

使用,pages下某個(gè)頁(yè)面:

//加載所有圖片
app.loadAllImgs([
  'https://www.xxx.net/minisoft/zhenze/everyDayPic_1.jpg',
  'https://www.xxx.net/minisoft/zhenze/everyDayPic_2.jpg',
  'https://www.xxx.net/minisoft/zhenze/everyDayPic_3.jpg'
],function(){
  _that.setData({
    allimgLoaded: true
  });
});

通過(guò)allimgLoaded這個(gè)數(shù)據(jù)變量來(lái)切換loading條和圖片
wxml結(jié)構(gòu):

<!-- 背景圖 -->
<view class="imgBox">
    <!--loadingGear 加載條 -->
    <view class="loadingGear {{allimgLoaded? '':'loadingGearAc'}}">
        <view class="inset">
            <view class="blocks"></view>
            <view class="blocks"></view>
            <view class="blocks"></view>
            <view class="blocks"></view>
            <view class="blocks"></view>
            <view class="blocks"></view>
            <view class="blocks"></view>
            <view class="blocks"></view>
        </view>
    </view>  
    <image wx:if="{{allimgLoaded}}" src="{{itemEle.picSrc}}" mode="aspectFill" />
</view>

css3 loading圖標(biāo),激活狀態(tài)運(yùn)動(dòng),否則不運(yùn)動(dòng)
wxss

/*loadingGear - 加載條2*/
.loadingGear { position:absolute; left:50%; top:50%; width:4rpx; height:4rpx; margin:-2rpx 0 0 -2rpx; 
z-index:-1;
}
.loadingGear .inset  { position:relative; z-index:2; width:100%; height:100%; visibility:hidden; }
  /*激活*/
.loadingGearAc { z-index:9999;}
.loadingGearAc .inset { visibility:visible;
-webkit-animation:gearAni linear 2s infinite;
-moz-animation:gearAni linear 2s infinite;
-ms-animation:gearAni linear 2s infinite;
-o-animation:gearAni linear 2s infinite;
animation:gearAni linear 2s infinite;
}
.loadingGear .inset .blocks { position:absolute; left:0; bottom:0; z-index:2; width:100%; height:300%; overflow:hidden; background:#006d78; font-size:0; line-height:0;
-webkit-transform-origin:center bottom; -moz-transform-origin:center bottom; transform-origin:center bottom;
}
.loadingGear .inset .blocks:nth-child(1){ -webkit-transform:rotate(0deg) translateY(-10rpx); -moz-transform:rotate(0deg) translateY(-10rpx); transform:rotate(0deg) translateY(-10rpx); }
.loadingGear .inset .blocks:nth-child(2){ -webkit-transform:rotate(45deg) translateY(-10rpx); -moz-transform:rotate(45deg) translateY(-10rpx); transform:rotate(45deg) translateY(-10rpx); }
.loadingGear .inset .blocks:nth-child(3){ -webkit-transform:rotate(90deg) translateY(-10rpx); -moz-transform:rotate(90deg) translateY(-10rpx); transform:rotate(90deg) translateY(-10rpx);  }
.loadingGear .inset .blocks:nth-child(4){ -webkit-transform:rotate(135deg) translateY(-10rpx); -moz-transform:rotate(135deg) translateY(-10rpx); transform:rotate(135deg) translateY(-10rpx);  }
.loadingGear .inset .blocks:nth-child(5){ -webkit-transform:rotate(180deg) translateY(-10rpx); -moz-transform:rotate(180deg) translateY(-10rpx); transform:rotate(180deg) translateY(-10rpx); }
.loadingGear .inset .blocks:nth-child(6){ -webkit-transform:rotate(225deg) translateY(-10rpx); -moz-transform:rotate(225deg) translateY(-10rpx); transform:rotate(225deg) translateY(-10rpx); }
.loadingGear .inset .blocks:nth-child(7){ -webkit-transform:rotate(270deg) translateY(-10rpx); -moz-transform:rotate(270deg) translateY(-10rpx); transform:rotate(270deg) translateY(-10rpx); }
.loadingGear .inset .blocks:nth-child(8){ -webkit-transform:rotate(315deg) translateY(-10rpx); -moz-transform:rotate(315deg) translateY(-10rpx); transform:rotate(315deg) translateY(-10rpx); }
/*gearAni*/
@-webkit-keyframes gearAni { 
  0% { -webkit-transform:rotate(0deg);  -moz-transform:rotate(0deg);  transform:rotate(0deg);}  
  100% { -webkit-transform:rotate(360deg);  -moz-transform:rotate(360deg);  transform:rotate(360deg);}  
}
@keyframes gearAni { 
  0% { -webkit-transform:rotate(0deg);  -moz-transform:rotate(0deg);  transform:rotate(0deg);}  
  100% { -webkit-transform:rotate(360deg);  -moz-transform:rotate(360deg);  transform:rotate(360deg);}  
}
  1. 使用微信小程序API時(shí)候,需要先要測(cè)試下兼容
compareVersion(v1, v2){
  v1 = v1.split('.')
  v2 = v2.split('.')
  const len = Math.max(v1.length, v2.length)
  while(v1.length < len){
    v1.push('0')
  }
  while(v2.length < len){
    v2.push('0')
  }
  for(let i = 0; i < len; i++){
    const num1 = parseInt(v1[i])
    const num2 = parseInt(v2[i])
    if (num1 > num2){
      return true;
    }else if(num1 < num2){
      return false;
    }
  }
}

放在app.js內(nèi),pages使用js調(diào)用
如:音頻API的兼容

var _btn = app.compareVersion(version,'1.6.0');
if(_btn){
  //基礎(chǔ)庫(kù) 1.6.0 開(kāi)始支持,低版本需做兼容處理。
  InnerAudioContext = wx.createInnerAudioContext();
}else{
  wx.showModal({
    title: '提示',
    content: '當(dāng)前微信版本過(guò)低,無(wú)法使用音頻功能,請(qǐng)升級(jí)到最新微信版本后重試。'
  });
};
  1. 跳轉(zhuǎn)到第三方小程序,需要獲知對(duì)方的小程序APPID
    也可以放在app.js內(nèi)方便,統(tǒng)一調(diào)用
jumpOtherMinisoft(_appid,_path,sucFn,errFn){
  var _that = this;

  //兼容
  var version = wx.getSystemInfoSync().SDKVersion;
  var _btn = _that.compareVersion(version,'1.3.0');
  
  if(_btn){
    //基礎(chǔ)庫(kù) 1.3.0 開(kāi)始支持
    wx.navigateToMiniProgram({
      appId: _appid,
      path: _path,
      success(res){
        sucFn && sucFn(res);
      },
      fail(err){
        errFn && errFn(err);
      }
    });
  }else{
    wx.showModal({
      title: '提示',
      content: '當(dāng)前微信版本過(guò)低,無(wú)法使用該功能,請(qǐng)升級(jí)到最新微信版本后重試。'
    });
  };
}

pages頁(yè)面內(nèi)js直接使用

app.jumpOtherMinisoft('wx2c348cf579062e56','page/index/index?id=123',null,function(err){
  console.log(err);
  app.showPopFn({
    'title':'跳轉(zhuǎn)小程序失敗'
  });
});

7-2. 通過(guò)標(biāo)簽navigater跳轉(zhuǎn)

<navigator 
    target="miniProgram" 
    open-type="navigate" 
    app-id="{{detailData.AppId}}" 
    path="{{detailData.Path}}" 
    extra-data="" 
    version="release"
>查看詳情</navigator>

7-3. 獲取三方小程序的APPID以及詳細(xì)頁(yè)的path

  • 如何查看小程序的appid,
    打開(kāi)微信 - 搜索小程序 - 進(jìn)入 - 點(diǎn)擊右上角三個(gè)點(diǎn) - 點(diǎn)擊 彈出層小程序的名稱(chēng) - 更多資料 - 即可查看 APPID
  • 如何獲取詳細(xì)頁(yè)的鏈接
    登錄后臺(tái) - 工具 - 生成小程序碼 - 輸入小程序APPID - 獲取更多頁(yè)面路徑 - 添加自己微信號(hào) - 開(kāi)啟 ( 注:復(fù)制功能僅保留10分鐘,10分鐘后功能消失 )
  • 打開(kāi)小程序詳細(xì)頁(yè) - 右上三個(gè)點(diǎn) - 選擇復(fù)制鏈接 (如果不存在,則說(shuō)明上面一步時(shí)間過(guò)期了,或沒(méi)有開(kāi)發(fā)者權(quán)限)
    針對(duì)京東來(lái)說(shuō),需要將sku字段保留,其余刪除,包括".html"
  • 將復(fù)制的鏈接黏貼至上一步左側(cè)輸入框,生成小程序碼
  • 注:如果復(fù)制鏈接,提示 【網(wǎng)絡(luò)錯(cuò)誤稍后重試】, 排除斷網(wǎng)的情況,可能是微信版本過(guò)低,重新安裝最新版本微信即可

7-4. 配置跳轉(zhuǎn)三方小程序的白名單,
在app.json內(nèi),配置navigateToMiniProgramAppIdList
補(bǔ)充說(shuō)明:

  • 每個(gè)小程序可跳轉(zhuǎn)的其他小程序數(shù)量限制為不超過(guò) 10 個(gè) 從 2.4.0 版本以及指定日期(具體待定)開(kāi)始,開(kāi)發(fā)者提交新版小程序代碼時(shí),如使用了跳轉(zhuǎn)其他小程序功能,則需要在代碼配置中聲明將要跳轉(zhuǎn)的小程序名單,限定不超過(guò) 10 個(gè),否則將無(wú)法通過(guò)審核。
  • 該名單可在發(fā)布新版時(shí)更新,不支持動(dòng)態(tài)修改。
  1. 轉(zhuǎn)發(fā)以及分享到朋友圈
    轉(zhuǎn)發(fā)的觸發(fā)方式為,wxml內(nèi)放入一個(gè)button,open-type,此外在頁(yè)面的js內(nèi)要定義onShareAppMessage與onShareTimeline,分別用來(lái)定義轉(zhuǎn)發(fā)和分享到朋友圈
//用戶(hù)點(diǎn)擊右上角轉(zhuǎn)發(fā)  圖片長(zhǎng)寬比是 5:4
//基礎(chǔ)庫(kù) 1.2.0 開(kāi)始支持,低版本需做兼容處理
onShareAppMessage(res){
  //兼容
  var version = wx.getSystemInfoSync().SDKVersion;
  var _btn = app.compareVersion(version,'1.2.0');
  if(_btn){
    // 來(lái)自頁(yè)面內(nèi)轉(zhuǎn)發(fā)按鈕
    if(res.from === 'button'){};
    return {
      'title': res.target.dataset.tit  || app.globalData.shareObj.sharemes,
      'path':  res.target.dataset.path || app.globalData.shareObj.sharePath,
      'imageUrl': app.globalData.shareObj.shareSendPic
    }
  }else{
    wx.showModal({
      title: '提示',
      content: '當(dāng)前微信版本過(guò)低,無(wú)法使用該功能,請(qǐng)升級(jí)到最新微信版本后重試。'
    });
  };
},
//用戶(hù)點(diǎn)擊右上角轉(zhuǎn)發(fā)到朋友圈  query-當(dāng)前頁(yè)面路徑攜帶的參數(shù)  圖片長(zhǎng)寬比是 1:1
//從基礎(chǔ)庫(kù) 2.11.3 開(kāi)始支持 
onShareTimeline(){
  //兼容
  var version = wx.getSystemInfoSync().SDKVersion;
  var _btn = app.compareVersion(version,'2.11.3');
  if(_btn){
    return {
      'title': app.globalData.shareObj.sharemes,
      'query': null,
      'imageUrl': app.globalData.shareObj.shareFriendPic
    }
  }else{
    wx.showModal({
      title: '提示',
      content: '當(dāng)前微信版本過(guò)低,無(wú)法使用該功能,請(qǐng)升級(jí)到最新微信版本后重試。'
    });
  };
},

注: 分享的圖片比例分別為 5:4、1:1 (可以是本地文件路徑、代碼包文件路徑或者網(wǎng)絡(luò)圖片路徑。支持PNG及JPG)
在wxml內(nèi)調(diào)用,添加自定義屬性,可能會(huì)方便些

<button 
    class="insetBtn" 
    open-type="share"
    data-tit="{{listsData[nowIndex].tit}}"
    data-path="/pages/find_food_detail/index?sendindex={{nowIndex}}"
></button>
  1. 通過(guò)坐標(biāo),打開(kāi)微信小程序內(nèi)置地圖,進(jìn)行導(dǎo)航
//使用微信內(nèi)置地圖查看位置
openLocationFn(_lat,_lon,sucFn,errFn){
  if(_lat=='' || _lon==''){
    this.showPopFn({
      'title': '坐標(biāo)錯(cuò)誤'
    });
    return false;
  }else{
    wx.openLocation({
      'latitude': _lat,
      'longitude': _lon,
      'scale': 17,
      success(res){
        sucFn && sucFn(res);
      },
      fail(err){
        errFn && errFn(err);
      }
    });
  };
}

調(diào)用

goOpenLocationFn(){
  app.openLocationFn(30.91185865822398,120.50376582713723,null,function(err){
    console.log(err);
    app.showPopFn({
      'title': '調(diào)用失敗',
      'icon': 'success',
      'duration': 500
    })
  })
}
  1. 小程序音頻使用
    聲明音頻對(duì)象
var version = wx.getSystemInfoSync().SDKVersion;
var _btn = app.compareVersion(version,'1.6.0');
if(_btn){
  InnerAudioContext = wx.createInnerAudioContext();
}else{
  wx.showModal({
    title: '提示',
    content: '當(dāng)前微信版本過(guò)低,無(wú)法使用音頻功能,請(qǐng)升級(jí)到最新微信版本后重試。'
  });
};

配置音頻屬性,以及調(diào)用方法

//監(jiān)聽(tīng)播放結(jié)束后,關(guān)閉對(duì)播放結(jié)束的監(jiān)聽(tīng)
InnerAudioContext.src = _nowAudioSrc;
InnerAudioContext.play()
InnerAudioContext.onEnded(function(){
  InnerAudioContext.offEnded();
  InnerAudioContext.stop(); 
  ...業(yè)務(wù)樣式等操作...
  console.log('播放完畢');
});

注: 上述監(jiān)聽(tīng)結(jié)束的方法,最好結(jié)束后調(diào)用stop,重置音頻

10-1. 播放進(jìn)度與獲取音頻時(shí)長(zhǎng)

//2. 監(jiān)聽(tīng)播放、并獲取音頻的時(shí)長(zhǎng)、播放位置與 進(jìn)度百分比
nowAudioObj.offPlay();
nowAudioObj.onPlay(() => {
  
  //獲取總時(shí)長(zhǎng)與當(dāng)前播放位置
  nowAudioObj.offTimeUpdate();
  nowAudioObj.onTimeUpdate(()=>{ 
    //初始化 -- 獲取音頻總時(shí)長(zhǎng)
    _listsData[_index].audio.duration = nowAudioObj.duration; 
    //實(shí)時(shí)更新 -- 獲取當(dāng)前播放的位置
    _listsData[_index].audio.startTime = nowAudioObj.currentTime;
    //實(shí)時(shí)更新 -- 進(jìn)度條百分比
    _listsData[_index].audio.nowTimePercent = Math.floor(nowAudioObj.currentTime/nowAudioObj.duration*100);

    _that.setData({
      'listsData': _listsData
    });
  });
});

//3. 播放結(jié)束監(jiān)聽(tīng)
nowAudioObj.offEnded();
nowAudioObj.onEnded(() => {
  //重置播放位置、重置樣式
  _listsData[_index].audio.startTime = 0;
  _listsData[_index].audio.nowTimePercent = Math.floor(0/nowAudioObj.duration*100);
  _listsData[_index].audio.playStatue = false;

  app.showPopFn({
    'title': '播放完畢'
  });

  //停止監(jiān)聽(tīng)
  nowAudioObj.stop();
  nowAudioObj.offPlay();
  nowAudioObj.offEnded();
  nowAudioObj.offTimeUpdate();
  _that.setData({
    'listsData': _listsData
  });
});

//4. 捕獲錯(cuò)誤
nowAudioObj.offError();
nowAudioObj.onError(function(errMsg,errCode){
  console.log(errMsg);
  var _errMes = '';
  switch(errCode){
    case 10001:
      _errMes = '系統(tǒng)錯(cuò)誤';
      break;
    case 10002:
      _errMes = '網(wǎng)絡(luò)錯(cuò)誤';
      break; 
    case 10003:
      _errMes = '文件錯(cuò)誤';
      break;
    case 10004:
      _errMes = '格式錯(cuò)誤';
      break;
    case -1:
      _errMes = '未知錯(cuò)誤';
      break;          
  };
  app.showPopFn({
    title:_errMes,
    duration:600
  });
});  

注:

  • 音頻不能使用 中文名字 ,否則不能被捕獲報(bào)錯(cuò)信息
  • 音頻在頁(yè)面之前切換不可以停止,所以在切換頁(yè)面之前,需要關(guān)閉音頻,
    onHide -- wx.navigateTo 或 底部tab切換到其他頁(yè)面觸發(fā)
    onUnload -- wx.redirectTo 或 wx.navigateBack時(shí)候觸發(fā)
  1. 輸入框表單,通過(guò)鍵盤(pán)進(jìn)行搜索,而非一個(gè)自定義按鈕
    通過(guò)bindconfirm事件,可以在鍵盤(pán)敲擊回車(chē)、在手機(jī)鍵盤(pán)輸入法觸摸完成后,即可進(jìn)行搜索
<input 
    type="text" 
    bindinput="txtFn" 
    bindconfirm="inputConfirmFn"
    value="{{txtval}}" 
    placeholder="搜索內(nèi)容..." 
/>

通過(guò)事件對(duì)象 ev.detail.value 可以完成內(nèi)容獲取

inputConfirmFn(ev){
  var _val = ev.detail.value;
  _val = _val.replace(/\s+/g,""); 
  if(_val != ''){
    console.log('提交的內(nèi)容為',_val);
  }else{
    app.showPopFn({
      'title': '內(nèi)容不能為空',
      'icon': 'none',
      'duration': 600
    });
  };
}
  1. 小程序自帶的頂部工具欄,可以通過(guò)在app.json的window內(nèi),通過(guò)"navigationStyle":"custom"關(guān)閉默認(rèn)導(dǎo)航
    只保留右上角三個(gè)點(diǎn)
"navigationStyle":"custom"

定義一個(gè)自定義狀態(tài)欄組件,可以使用的屬性與插槽,官方手冊(cè) - https://developers.weixin.qq.com/miniprogram/dev/extended/weui/navigation.html
問(wèn)題:
不同設(shè)備的狀態(tài)欄的高度不一樣,因此自定義導(dǎo)航圖標(biāo),可能會(huì)因設(shè)備不一樣而跑偏,
所以,為了統(tǒng)一這個(gè)比例,可以通過(guò)wx.getSystemInfo獲取系統(tǒng)信息,通過(guò)系統(tǒng)信息返回statusBarHeight獲得狀態(tài)欄高度( 單位px )
再通過(guò) wx.getMenuButtonBoundingClientRect()方式是獲得膠囊按鈕的空間信息,以及系統(tǒng)狀態(tài)欄的高度,之后進(jìn)行對(duì)應(yīng)的計(jì)算
【注】:getMenuButtonBoundingClientRect 部分手機(jī)有獲取設(shè)備 信息延遲 - https://developers.weixin.qq.com/community/develop/doc/0006eeb2db0ae022a098c58f85d800,所以官方建議加100MS延遲,等待信息!

具體的方法是:
app.js onLaunch聲明周期中

//獲取狀態(tài)欄高度
wx.getSystemInfo({
  success(res){
    _that.globalData.sysBarHeight = res.statusBarHeight;
    console.log(res.statusBarHeight);
  },
  fail(err){
    console.log('系統(tǒng)信息錯(cuò)誤',err);
  }
});

//獲取膠囊按鈕的空間信息
//基礎(chǔ)庫(kù) 2.1.0 開(kāi)始支持
if(_that.compareVersion(version,'2.1.0')){
  var ButtonBoundingRes = wx.getMenuButtonBoundingClientRect();
  if(ButtonBoundingRes){
    _that.globalData.ButtonBoundingHright = (ButtonBoundingRes.top - _statusBarHeight)*2 + ButtonBoundingRes.height
  };
}else{
  wx.showModal({
    title: '提示',
    content: '當(dāng)前微信版本過(guò)低,無(wú)法獲取膠囊按鈕尺寸功能,請(qǐng)升級(jí)到最新微信版本后重試。'
  });
};
截圖說(shuō)明截圖

通過(guò)上面方式計(jì)算結(jié)果 自定義導(dǎo)航欄的高度應(yīng)該為

statusBarHeight 下面的膠囊實(shí)際占位 最終自定義導(dǎo)航高度
20 (24-20)*2+32 60
20 + (24-20)*2+32 = 60

上面計(jì)算的單位為px,如果在頁(yè)面內(nèi)使用,需要使用rpx,因?yàn)閜x是固定值,不同手機(jī)設(shè)備高度不一,可能引起適配問(wèn)題:
在app.js的onLaunch生命周期內(nèi),獲取當(dāng)前設(shè)備的px與rpx比例,將px轉(zhuǎn)化為rpx,在頁(yè)面內(nèi)使用更精準(zhǔn)些

var _windowWidth = wx.getSystemInfoSync().windowWidth
var _rate = 750 / _windowWidth
_that.globalData.rateRpx = _rate;
  1. 小程序組件lifetimes 可以補(bǔ)充onload、onshow的生命周期
    js
lifetimes: {
  attached: function() {
    // 在組件實(shí)例進(jìn)入頁(yè)面節(jié)點(diǎn)樹(shù)時(shí)執(zhí)行
    ...
  },
  detached: function() {
    // 在組件實(shí)例被從頁(yè)面節(jié)點(diǎn)樹(shù)移除時(shí)執(zhí)行
    ...
  },
},
  1. 通過(guò)分享進(jìn)來(lái),沒(méi)有返回主頁(yè)入口的困局
    問(wèn)題:
    如果分享頁(yè)面是詳細(xì)頁(yè)面,通過(guò)分享點(diǎn)擊進(jìn)來(lái),無(wú)法通過(guò)常規(guī)后退按鈕返回,因此需要一個(gè)返回首頁(yè)的按鈕
    但是需要一個(gè)判斷的條件,即 如何判斷此時(shí)頁(yè)面是否為分享點(diǎn)擊進(jìn)來(lái)的。
    方案:
    在app.js內(nèi),可以在App的onLaunch和onShow,或wx.getLaunchOptionsSync中獲取上述場(chǎng)景值,
    來(lái)獲取 scene (小程序的場(chǎng)景值)
    官方的場(chǎng)景值對(duì)應(yīng)表 - https://developers.weixin.qq.com/miniprogram/dev/reference/scene-list.html
    通過(guò)將獲取的scene來(lái)判斷是否顯示一個(gè)返回主頁(yè)的入口,與表格對(duì)比可知,
1007  --  是分享給朋友,朋友通過(guò)鏈接點(diǎn)擊過(guò)來(lái)的
1008  --  群聊會(huì)話(huà)中的小程序消息卡片

app.js

App({
  onLaunch(option){
    //可以查看scene值
    if(option.scene==1007 || option.scene==1008){
      _that.globalData.formShare = true;
    };
    ...

pages/xx/xx.wxml內(nèi)

<!-- 后退 -->
<view 
    wx:if="{{!homeBackBtn}}"
    bindtap="backFn" 
    class="backIcon"
>
    <view class="icoInset iconTag backIco"></view>
</view>
<!-- 返回首頁(yè) -->
<view 
    wx:else
    bindtap="backHomeFn" 
    class="backIcon"
>
    <view class="icoInset iconTag homeIco"></view>
</view>

pages/xx/xx.js內(nèi)

onLoad:function(option){
  //是否顯示返回主頁(yè)按鈕
    if(app.globalData.formShare){
      _that.setData({
        'homeBackBtn': true
      })
    };
},
backHomeFn(){
    //重置狀態(tài)
    app.globalData.formShare = false;
    this.setData({
      'homeBackBtn': false
    });
    //完成跳轉(zhuǎn)
    app.returnHomeFn();
}
  1. wx.navigateTo 與 wx.redirectTo 的使用差異
    不同點(diǎn):
    wx.navigateTo 用于頁(yè)面流程為串行的操作,最多紀(jì)錄10層歷史路徑,可以通過(guò)wx.navigateBack進(jìn)行后退,
    如果超過(guò)10層,會(huì)進(jìn)行報(bào)錯(cuò)。
navigateTo webview cont limit exceed

wx.redirectTo 可以用來(lái)代替上頁(yè)面跳轉(zhuǎn)的問(wèn)題,但是無(wú)法使用歷史路徑。
相同點(diǎn):
都不能跳到 tabbar 頁(yè)面

  1. 復(fù)雜數(shù)據(jù)的修改,通過(guò)字符串拼接好數(shù)據(jù),包裹上[ ]來(lái)進(jìn)行解析
    推薦的方式:
var _nowIndex = this.data.nowIndex;
this.setData({
    ['listsData['+_nowIndex+'].sonIndex']: 新的數(shù)據(jù)
});

var _dataStr = "mapDatas.tabLists["+_mapDatas.tabIndex+"].sonLists";
 _that.setData({
    [_dataStr]: _tempArr
});

引起問(wèn)題的方式:

var _sonIndex = ev.detail.current;
var _listsData = this.data.listsData;
var _nowIndex = this.data.nowIndex;

_listsData[_nowIndex].sonIndex = _sonIndex;
this.setData({
  'listsData': _listsData
});

出現(xiàn)的具體問(wèn)題是:

  • listsData下某個(gè)無(wú)需修改數(shù)據(jù),重新覆蓋,會(huì)引起undefined的渲染錯(cuò)誤,比如地圖組件的經(jīng)緯度;
  • 此外對(duì)局部的數(shù)據(jù)修改,是被建議的
  • 渲染大小的建議
由于小程序運(yùn)行邏輯線(xiàn)程與渲染線(xiàn)程之上,setData的調(diào)用會(huì)把數(shù)據(jù)從邏輯層傳到渲染層,數(shù)據(jù)太大會(huì)增加通信時(shí)間。
**得分條件:`setData`的數(shù)據(jù)在`JSON.stringify`后不超過(guò) 256KB**
  1. scroll-view組件內(nèi),存在子元素,包裹一個(gè)swiper組件和同級(jí)增加一個(gè)浮層,滾動(dòng)scroll-view時(shí)候,浮層會(huì)消失
    解決方法:
    將浮層從swiper同級(jí)提取到更高一層,可以解決問(wèn)題。

  2. wx.navigateTo跳轉(zhuǎn),會(huì)出現(xiàn)重復(fù)跳轉(zhuǎn)
    原因:如 wx.navigateTo、wx.redirectTo跳轉(zhuǎn)官方?jīng)]有做節(jié)流
    具體操作:

//修復(fù)BUG、節(jié)流timer
var navigaterTimer = null;
var redirectTimer = null;

App({
onLaunch(option){
var _that = this;
  ...
//跳轉(zhuǎn) wx.navigateTo 小程序中頁(yè)面棧最多十層
jumpLink(_link,sucFn,errFn){
clearTimeout(navigaterTimer);
navigaterTimer = setTimeout(function(){
  wx.navigateTo({
    url: _link,
    success(res){
      sucFn && sucFn(res);
    },
    fail(err){
      errFn && errFn(err);
    }
  })
},600);
},
//跳轉(zhuǎn)
jumpLink2(_link,sucFn,errFn){
clearTimeout(redirectTimer);
redirectTimer = setTimeout(function(){
  wx.redirectTo({
    url: _link,
    success(res){
      sucFn && sucFn(res);
    },
    fail(err){
      errFn && errFn(err);
    }
  });
},500);
},

注:延遲時(shí)間越久,修復(fù)效果越好,如果延遲時(shí)間設(shè)置300ms,在模擬器上仍可能出現(xiàn)重復(fù)跳轉(zhuǎn)的情況,理解可能是設(shè)備性能來(lái)不及反應(yīng)?

  1. text標(biāo)簽內(nèi)如果要添加長(zhǎng)文本,為了方便用戶(hù)瀏覽時(shí)copy可以,為text添加user-select屬性,
    此外,首行縮進(jìn)(text-indent:2em;)不能添加到父級(jí)標(biāo)簽,否則會(huì)溢出屏幕

  2. 針對(duì)富文本,處理帶有HTML標(biāo)簽的文案

<rich-text nodes="{{itemEle.backMes.detmes}}" user-select></rich-text>
  1. 獲取rpx與px的轉(zhuǎn)化比例值
    已知:小程序規(guī)定屏幕寬為750rpx,這個(gè)無(wú)關(guān)機(jī)型(rpx(responsive pixel): 可以根據(jù)屏幕寬度進(jìn)行自適應(yīng))
    未知:當(dāng)前設(shè)備的寬度
let windowWidth = wx.getSystemInfoSync().windowWidth
let rate = 750 / windowWidth
  1. 小程序加載分頁(yè)的格式


    小程序分頁(yè)流程圖

22-2. 分頁(yè)代碼格式
js:

'commentLists':{
  'list':[],
  'loaded': false,
  'isLoading': false, 
  'noMore': false,
  'totalcount':0,
  'pageindex': 0
}

wxml:

<!--加載完畢-->
<view 
    class="commentLists"
    wx:if="{{isLoaded}}"
>
    <!-- 有數(shù)據(jù) -->
    <view
        wx:if="{{commentLists.list.length>0}}"
    >
        <!--數(shù)據(jù)列表-->
        <view class="listBox">
            <!-- ele -->
            <view 
                class="ele"
                wx:for="{{commentLists.list}}" 
                wx:for-index="idx" 
                wx:for-item="itemEle"
                wx:key="idx"
            >
                <view class="phootBox borderR">
                    <image src="{{itemEle.userPhoto}}" mode="aspectFill" />
                </view>
                <view class="say">
                    <text>{{itemEle.mes}}</text>
                </view>
            </view>
        </view>
        <!-- 暫無(wú)更多數(shù)據(jù) -->
        <view wx:if="{{noMore}}" class="noDataTxt">
            <text>暫無(wú)更多評(píng)論</text>
        </view> 
    </view>
    <!-- 無(wú)數(shù)據(jù) -->
    <view wx:if="{{commentLists.noMore}}">
        <view class="noDataTxt">
            <text>暫無(wú)任何數(shù)據(jù)</text>
        </view> 
    </view>
</view>
<!--加載中-->
<view wx:else>
    <view class="noDataTxt">
        <text>加載中...</text>
    </view> 
</view>
  1. 小程序跳轉(zhuǎn)第三方小程序中某個(gè)頁(yè)面
    具體流程:
  • 配置app.json ---(已經(jīng)廢棄)
    小程序限定不超過(guò)10個(gè),否則將無(wú)法通過(guò)審核。
    此名單可在發(fā)布新版時(shí)更新,不支持動(dòng)態(tài)修改。
"navigateToMiniProgramAppIdList": [
    "wx91d27dbf599dff74",
    "wx0e6ed4f51db9d078"
]

備注:
從2020年4月24日起,使用跳轉(zhuǎn)其他小程序功能將無(wú)需在全局配置中聲明跳轉(zhuǎn)名單 ,跳轉(zhuǎn)其他小程序?qū)⒉辉偈軘?shù)量限制

  • 獲取跳轉(zhuǎn)小程序的appid
    微信 - 搜索小程序 京東 - 打開(kāi)小程序 - 右上角三個(gè)點(diǎn) - 點(diǎn)擊浮層內(nèi)小程序名稱(chēng) - 更多資料 - 點(diǎn)擊即可查看AppID
  • 查看該商品是否可以獲取詳情地址,
    打開(kāi)要跳轉(zhuǎn)的小程序目標(biāo)頁(yè)面,右上角三個(gè)點(diǎn),發(fā)送給朋友,
    如果點(diǎn)擊這個(gè)鏈接可以達(dá)到目前鏈接,則繼續(xù)后續(xù)步驟。
    如果僅能跳轉(zhuǎn)至目標(biāo)小程序的首頁(yè),那么說(shuō)明無(wú)法獲取商品詳情地址,則可以停止后續(xù)流程了
  • 打開(kāi)微信公眾平臺(tái),登錄賬號(hào)后,頂部菜單 工具-生成小程序碼,將上面獲取的appid輸入,搜索小程序;
    然后將自己的小程序賬號(hào)放進(jìn)去,點(diǎn)擊"開(kāi)啟"即可顯示復(fù)制鏈接按鈕;
    【注】: 這個(gè)"開(kāi)啟"按鈕有一個(gè)有效時(shí)間,過(guò)了時(shí)間就不顯示復(fù)制鏈接按鈕了,需要再次這一步開(kāi)啟


    配置微信的截圖

    上面開(kāi)啟有時(shí)間限制,如果過(guò)了一段時(shí)間,跳轉(zhuǎn)的小程序內(nèi),點(diǎn)擊右上角三個(gè)點(diǎn),彈出層內(nèi)可能會(huì)不顯示"復(fù)制鏈接"

  • 編輯鏈接地址
    點(diǎn)擊這個(gè)分享的圖文框,再點(diǎn)擊右上角的三個(gè)點(diǎn),浮層內(nèi),點(diǎn)擊復(fù)制鏈接;
    將復(fù)制的鏈接,在記事本內(nèi)編輯,刪除.html與id參數(shù)之后的內(nèi)容;
    例如:
pages/gs/sight/newDetail.html?sightId=25603&mktshare=eyJhbGxpYW2IjNyojIklWZj5ODQsInNpZCI6NzExNDY1LCJvdWlkIjoiIiwic291cmNlaWQiOjU1NTUyNjg5LCJmcm9tYWxsaWFuY2VpZCI6MCwiZnJvbXNpZCI6MCwiZnJvbW91aWQiOiIiLCJmcm9tc291cmNlaWQiOjAsImZyb21vcGVuaWQiOiIyMTVhZGVhZi1lMmRiLTQ3YWUtODRiZC1hMWU2ZWViMWNlMTAifQ()()KY&allianceid=262684&sid=711465&ouid=&sourceid=55552689

處理鏈接為:

pages/gs/sight/newDetail?sightId=25603

wxml標(biāo)簽內(nèi)使用,方式為:

<navigator 
    target="miniProgram" 
    open-type="navigate" 
    app-id="{{pageDetail.appid}}" 
    path="{{pageDetail.path}}" 
    extra-data="" 
    version="release"
>查看詳情</navigator>
  1. pinker針對(duì)數(shù)組包裹對(duì)象的形式,需要處理一份用于展示的pinker數(shù)據(jù)
  • 原始數(shù)據(jù):
deptData:{
  indexnum:0,
  list: [
    { id:1, name:'服裝藝術(shù)與工程學(xué)院' },
    { id:2, name:'材料設(shè)計(jì)與工程學(xué)院' }
  ]
}
  • 處理后數(shù)據(jù):
deptData:{
  indexnum:0,
  list: [
    { id:1, name:'服裝藝術(shù)與工程學(xué)院' },
    { id:2, name:'材料設(shè)計(jì)與工程學(xué)院' }
  ],
  pinkerlist: [
    '服裝藝術(shù)與工程學(xué)院','材料設(shè)計(jì)與工程學(xué)院'
  ]
}

結(jié)構(gòu):

--wxml--
<picker 
    class="pickerBox"
    bindchange="changeDeptFn" 
    range="{{deptData.pinkerlist}}"
    value="{{deptData.indexnum}}" 
>
    <view class="mes">
        <text class="tit">選擇學(xué)院:</text>
        <text class="pinkmes">{{deptData.pinkerlist[deptData.indexnum]}}</text>
    </view>
</picker>

--js--
changeDeptFn(ev){
    var _that = this;
    var _indexnum = ev.detail.value;
    _that.setData({
      ['deptData.indexnum']: _indexnum
    });
    //根據(jù)學(xué)院,加載專(zhuān)業(yè)
    _that.getSpecDataFn();
}
  1. 組件的使用
    組件目錄位置:同pages相同目錄的components文件夾
  • 設(shè)置組件
    配置組件目錄下的 .json文件
{
  "usingComponents": {},
  "component": true
}
  • 使用組件
    配置組件目錄下的 .json文件
{
  "usingComponents": {
    "workDetail": "/components/workdetail/index"
  }
}

引入組件

<workDetail
    userCollect="{{userCollect.data}}"
    userData="{{userData}}"
    worksid="{{worksid}}"
    bind:addCollectFn="addCollectFn"
    bind:delCollectFn="delCollectFn"
></workDetail>

25-1. 組件內(nèi)通信 官方鏈接 - https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html

  • 父組件 -> 子組件
    通過(guò)掛載屬性的方式實(shí)現(xiàn),數(shù)據(jù)掛載
//--wxml
<workDetail
  bind:addCollectFn="addCollectFn"
></workDetail>
//--js
addCollectFn(e){
  console.log(e.detail);
}
  • 子組件 -> 父組件
//--js
this.triggerEvent('addCollectFn', _addObj);

25-2. 父組件使用子組件內(nèi)的方法

//--wxml
<workDetail id="workDetailCmp"></workDetail>
//--js
onReady(){
  this.selectComponent('#workDetailCmp').fn1();
}
  1. 通過(guò)option設(shè)置數(shù)值,并將數(shù)據(jù)掛載至組件上,子組件內(nèi)通過(guò)properties獲取數(shù)據(jù),
    在子組件的生命周期 lifetimes 的attached內(nèi)調(diào)用,存在延遲問(wèn)題
  • 問(wèn)題產(chǎn)生的原因:
    lifetimes 生命周期 - https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/lifetimes.html 內(nèi),attached調(diào)用,父組件掛載的數(shù)據(jù)還沒(méi)過(guò)來(lái),等父組件的數(shù)據(jù)更新后,attached內(nèi)方法不會(huì)再執(zhí)行
lifetimes: {
    attached: function() {
      // 在組件實(shí)例進(jìn)入頁(yè)面節(jié)點(diǎn)樹(shù)時(shí)執(zhí)行
      //初始化菜單索引位置
      this.getProductDetFn();
    },
    detached: function(){
      // 在組件實(shí)例被從頁(yè)面節(jié)點(diǎn)樹(shù)移除時(shí)執(zhí)行
      
    }
}
  • 解決:
    掛載的方法,可以對(duì)數(shù)據(jù)設(shè)置數(shù)據(jù)開(kāi)關(guān),等數(shù)據(jù)加載完畢后,打開(kāi)開(kāi)關(guān)進(jìn)行組件數(shù)據(jù)掛載
    如:
'userCollect': {
  'data': [],
  'loaded': false
}
<view wx:if="{{worksid && userCollect.loaded}}">
    <workDetail
        userCollect="{{userCollect.data}}"
        userData="{{userData}}"
        worksid="{{worksid}}"
        bind:addCollectFn="addCollectFn"
        bind:delCollectFn="delCollectFn"
    ></workDetail>
</view>
  1. 設(shè)置數(shù)據(jù) setData 中的問(wèn)題
  • 設(shè)置數(shù)據(jù)時(shí)候,如果下面書(shū)寫(xiě)會(huì)報(bào)錯(cuò)
data:{
   'userCollect': {
      'data': [],
      'loaded': false
    }
},
fn1(e){
        //錯(cuò)誤
    //var _userCollect = _that.data.userCollect;
    //_userCollect.data.push(_tempAddObj);
    //正確
    var _userCollect = _that.data.userCollect.data;
    _userCollect.push(_tempAddObj);
    _that.setData({
    ['userCollect.data']: _userCollect
    });
}
  1. webview相關(guān)
  • 創(chuàng)建小程序,使用企業(yè)身份申請(qǐng),完成轉(zhuǎn)賬等身份驗(yàn)證
  • 配置開(kāi)發(fā)管理-開(kāi)發(fā)設(shè)置-業(yè)務(wù)域名,下載驗(yàn)證文件,上傳至業(yè)務(wù)域名服務(wù)器的根下
  • wxml添加 <web-view src="業(yè)務(wù)域名的H5文件"></web-view>
  • 查看 官方文檔 - https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html, 下載 JSSDK 1.3.2 - https://res.wx.qq.com/open/js/jweixin-1.3.2.js,以便在H5頁(yè)面內(nèi)使用小程序的API(如返回路由)
  1. 點(diǎn)擊事件,阻止冒泡之 catchtap
  • bindtap是冒泡的
  • catchtap是非冒泡的
  1. 監(jiān)聽(tīng)用戶(hù)上拉觸底事件
  • 可以在app.json的window選項(xiàng)中或頁(yè)面配置中設(shè)置觸發(fā)距離onReachBottomDistance。
  • 在觸發(fā)距離內(nèi)滑動(dòng)期間,本事件只會(huì)被觸發(fā)一次。
  • onReachBottom生命周期內(nèi)處理事件
  1. 地圖API、組件
  • 地圖組件 <map>
<map
    id="myMap"
    latitude="{{mapDatas.tabLists[mapDatas.tabIndex].wxMapDataList[mapDatas.sonindex].latitude}}"
    longitude="{{mapDatas.tabLists[mapDatas.tabIndex].wxMapDataList[mapDatas.sonindex].longitude}}"
    markers="{{mapDatas.tabLists[mapDatas.tabIndex].wxMapDataList}}"
    show-location
    show-compass
    show-scale
    bindmarkertap="bindmarkerFn"
></map>
  • 地圖屬性
latitude -- 地圖中心緯度 (-90 ~ 90) - 【特別注意都是數(shù)字類(lèi)型】
longitude -- 地圖中心經(jīng)度 (-180 ~ 180) - 【特別注意都是數(shù)字類(lèi)型】
  • 地圖遮蓋物點(diǎn)擊事件:bindmarkertap
  • 地圖獲取上下文方法: wx.createMapContext(string mapId, Object this) -- 版本要求:1.9.6
  • 地圖移動(dòng)地圖中心點(diǎn)的方法
_that.mapCtx.moveToLocation({
    longitude: Number(新的中心點(diǎn)經(jīng)度),
    latitude: Number(新的中心點(diǎn)緯度),
    success(){},
    fail(err){
      console.log(err);
    }
});
  • 地理位置授權(quán) app.json
"permission": {
    "scope.userLocation": {
      "desc": "你的位置信息將用于小程序位置接口的效果展示"
    }
  },
  1. 監(jiān)聽(tīng)組件上的參數(shù)變化
//--wxml
<workDetail
    userCollect="{{userCollect.data}}"
    userData="{{userData}}"
    worksid="{{worksid}}"
    onlyRead="{{onlyRead}}"
    bind:addCollectFn="addCollectFn"
    bind:delCollectFn="delCollectFn"
></workDetail>

//--js
lifetimes:{
...
},
observers:{
//基礎(chǔ)庫(kù)版本 2.6.1 開(kāi)始支持
'worksid': function(newV) {
  var version = wx.getSystemInfoSync().SDKVersion;
  var _btn = app.compareVersion(version,'2.6.1');
  if(_btn){
    // console.log(newV);
    //加載作品詳情
    this.getProductDetFn();
  }else{
    wx.showModal({
      title: '提示',
      content: '當(dāng)前微信版本過(guò)低,無(wú)法使用該功能,請(qǐng)升級(jí)到最新微信版本后重試。'
    });
  };
}
}
  1. 頁(yè)面渲染截?cái)嗟那闆r
  • 產(chǎn)生原因:
    setData接口的調(diào)用涉及邏輯層與渲染層間的線(xiàn)程通信,通信過(guò)于頻繁可能導(dǎo)致處理隊(duì)列阻塞,界面渲染不及時(shí)而導(dǎo)致卡頓,應(yīng)避免無(wú)用的頻繁調(diào)用。
  • 解決方案:
    每秒調(diào)用setData的次數(shù)不超過(guò) 20 次
  1. 小程序頁(yè)面性能監(jiān)測(cè) 官方地址 - https://developers.weixin.qq.com/miniprogram/dev/framework/audits/best-practice.html
    小程序開(kāi)發(fā)工具 在調(diào)試器區(qū)域切換到 Audits 面板,
    點(diǎn)擊”開(kāi)始“按鈕,然后自行操作小程序界面,運(yùn)行過(guò)的頁(yè)面就會(huì)被“體驗(yàn)評(píng)分”檢測(cè)到。

    性能分析工具截圖

  2. 小程序獲取用戶(hù)信息 新要求
    推薦使用 wx.getUserProfile ,不推薦使用getUserInfo
    具體范例:

  • 不推薦使用getUserInfo獲取用戶(hù)信息,預(yù)計(jì)自2021年4月13日起,getUserInfo將不再?gòu)棾鰪棿?,并直接返回匿名的用?hù)個(gè)人信息
    如下:
<button wx:else open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 獲取頭像昵稱(chēng) </button>
  • 推薦使用wx.getUserProfile獲取用戶(hù)信息,開(kāi)發(fā)者每次通過(guò)該接口獲取用戶(hù)個(gè)人信息均需用戶(hù)確認(rèn)
    //--wxml
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 獲取頭像昵稱(chēng) </button>

//--js

onLoad() {
    if (wx.getUserProfile) {
      this.setData({
        canIUseGetUserProfile: true
      })
    }
},
getUserProfile(e) {
    // 推薦使用wx.getUserProfile獲取用戶(hù)信息,開(kāi)發(fā)者每次通過(guò)該接口獲取用戶(hù)個(gè)人信息均需用戶(hù)確認(rèn)
    // 開(kāi)發(fā)者妥善保管用戶(hù)快速填寫(xiě)的頭像昵稱(chēng),避免重復(fù)彈窗
    wx.getUserProfile({
      desc: '用于完善會(huì)員資料', // 聲明獲取用戶(hù)個(gè)人信息后的用途,后續(xù)會(huì)展示在彈窗中,請(qǐng)謹(jǐn)慎填寫(xiě)
      success: (res) => {
        this.setData({
          userInfo: res.userInfo,
          hasUserInfo: true
        })
      }
    })
},
  1. 一個(gè)兩列的瀑布流如何實(shí)現(xiàn),(支持分頁(yè))
  • 原理:
    第一步,將一個(gè)數(shù)據(jù)列表,拆為兩個(gè)數(shù)據(jù)列表,并定義兩個(gè)列表的初始高度
    第二步,每次請(qǐng)求后臺(tái)獲取過(guò)來(lái)的數(shù)據(jù),對(duì)比一下兩列累積高度,哪一側(cè)小,就優(yōu)先將數(shù)據(jù)插入至哪一側(cè),并將對(duì)應(yīng)側(cè)的高度累加
    第三步,將更新后的兩列數(shù)據(jù)以及累加后的兩個(gè)高度值,返回
    第四步,與后臺(tái)接口開(kāi)發(fā)人員,提前告知返回圖片寬、高 字段(如例子中的ImgWidth,ImgHeight),用于計(jì)算列表高度使用

注:
第一,由于列表高度考量因素是圖片高度,如果列表單元,是一個(gè)圖文配,那么需要將文字部分設(shè)置統(tǒng)一高度,文字溢出省略號(hào),才可以(單行省略號(hào)或多行省略號(hào))
目的還是將判斷哪一列插入數(shù)據(jù)的考量,縮小為圖片高度一個(gè)判斷依據(jù)
第二,瀑布流中兩列的寬度必須一致(如列中:375屏寬下,單列162rpx寬),否則兩列寬度不統(tǒng)一,通過(guò)圖片(widthFix模式)獲取的等比高度,將不能用于判斷

  • 數(shù)據(jù)結(jié)構(gòu):
'mainNews':{
      'loaded': false,
      'isLoading': false,
      'noMore': false,
      'totalcount':0,
      'pageindex': 0,
      /*變量名代表:左側(cè)數(shù)據(jù)列表,右側(cè)數(shù)據(jù)列表,左側(cè)列表累積高度,右側(cè)列表累積高度*/
      'listL': [],
      'listR': [],
      'leftNowH':0,
      'rightNowH':0
},
  • 全局app.js內(nèi),工具函數(shù)
/*瀑布流排序 - 計(jì)算高度,重新排序
* 如果存在分頁(yè) 
* 傳入值: datalist- 待處理數(shù)據(jù) | oldLeftH- 舊的左側(cè)高度 | oldRightH- 舊的右側(cè)高度
* 輸出值: leftArr- 左側(cè)數(shù)據(jù) | rightArr- 右側(cè)數(shù)據(jù) | leftNowH - 左側(cè)累積值 | rightNowH - 右側(cè)累計(jì)值
*/
sortListFn(datalist,oldLeftH,oldRightH){
  var _leftH = oldLeftH || 0;
  var _rightH = oldRightH || 0;
  var _leftArr = [];
  var _rightArr = [];

  datalist.forEach(function(item,index){
    //162(rpx)為一個(gè)頁(yè)面布局寬度,計(jì)算值為布局寬度內(nèi)的圖片高度,僅比大小,不用那么精細(xì)
    var _layoutH = Math.ceil((item.ImgHeight*162)/item.ImgWidth);
    if(_leftH>_rightH){
      _rightArr.push(datalist[index]);
      _rightH+=_layoutH;
    }else{
      _leftArr.push(datalist[index]);
      _leftH+=_layoutH;
    };
  });
  //每次更新后的,兩側(cè)累積高度:
  //console.log(_leftH,_rightH);
  return {
    leftArr: _leftArr,
    rightArr: _rightArr,
    leftNowH: _leftH,
    rightNowH: _rightH
  };
}
  • 如何使用工具函數(shù)
... 某事件回調(diào)內(nèi)
var _that = this;
_that.getDataFn(function(res){
    var _mainNews = _that.data.mainNews;
    var _sortRes = app.sortListFn(res.data.list,_mainNews.leftNowH,_mainNews.rightNowH);
    var _listL = _mainNews.listL.concat(_sortRes.leftArr);
    var _listR = _mainNews.listR.concat(_sortRes.rightArr);
    //有無(wú)更多數(shù)據(jù)
    var _totalcount = res.data.totalcount;
    //設(shè)置數(shù)據(jù)
    _that.setData({
        ["mainNews.listL"]: _listL,
        ["mainNews.listR"]: _listR,
        ["mainNews.leftNowH"]: _sortRes.leftNowH,
        ["mainNews.rightNowH"]: _sortRes.rightNowH,
        ["mainNews.loaded"]: true,
        ["mainNews.totalcount"]: _totalcount
    });
    //有無(wú)更多數(shù)據(jù)
    if((_listL.length+_listR.length) == _totalcount){
      _that.setData({
        ["mainNews.noMore"]: true
      });
    }else{
      _that.setData({
        ["mainNews.noMore"]: false
      });
    };
},function(err){
    console.log(err);
});
...
  1. 通過(guò)微信生成小程序二維碼,然后掃碼進(jìn)入小程序,并傳遞參數(shù)的實(shí)現(xiàn)
    后端:
{
 "page": "pages/index/index",
 "scene": "a=1",
 "check_path": true,
 "env_version": "release"
} 

注意:

  • 開(kāi)發(fā)環(huán)境要對(duì)應(yīng)上 env_version 正式版為 "release",體驗(yàn)版為 "trial",開(kāi)發(fā)版為 "develop"。默認(rèn)是正式版。
  • 踩坑,不要在連接地址上使用下劃線(xiàn)'_',否則會(huì)獲取不到參數(shù),如:'pages/index/index',不能寫(xiě)成 'pages/abc_index/index'

前端:
在掃碼對(duì)應(yīng)的頁(yè)面內(nèi),onload聲明周期中獲取參數(shù),參數(shù)在scene中,這個(gè)scene不是app.js的onlunch的場(chǎng)景值,而是一個(gè)掃碼進(jìn)入某個(gè)頁(yè)面的參數(shù)載體

Page({
  onLoad (query) {
    // scene 需要使用 decodeURIComponent 才能獲取到生成二維碼時(shí)傳入的 scene
    const scene = decodeURIComponent(query.scene)
  }
})

此外,調(diào)試的時(shí)候,可以通過(guò)開(kāi)發(fā)者工具,掃描為了開(kāi)發(fā)板生成的二維碼,實(shí)現(xiàn)本地調(diào)試功能


本地開(kāi)發(fā)環(huán)境掃碼調(diào)試
  1. 小程序內(nèi)調(diào)用掃一掃功能
wx.scanCode({
  // 只允許從相機(jī)掃碼
  onlyFromCamera: true,
  // 掃碼類(lèi)型 - 二維碼
  scanType: qrCode,
  success (res.path) {
    var _resPath = decodeURIComponent(res.path);
    console.log(_resPath );
  }
})

開(kāi)發(fā)者工具,通過(guò)上面API,可以直接上傳掃碼的圖片,完成掃碼,數(shù)據(jù)格式如下:


掃一掃返回?cái)?shù)據(jù)格式

占坑....

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容