乾貨分享:小程序項目實踐和經驗總結

  • 2019 年 10 月 3 日
  • 筆記

最近接觸小程序開發,我特將本次開發過程中所使用到的相關知識點進行了總結,以作為經驗的積累。希望給自己以後的開發,提供一些幫忙,同時提高解決問題的能力。如有錯誤,請大家指正。

github地址項目地址

weui:使用微信原生視覺體驗樣式庫

認識: WeUI 是一套同微信原生視覺體驗一致的基礎樣式庫,由微信官方設計團隊為微信內網頁和微信小程序量身設計,令用戶的使用感知更加統一。

官網: https://weui.io/

github地址: https://github.com/weui/weui-wxss

微信推出了一套官方樣式庫,方便大家開發,對於一些類似的UI界面我們需要引入即可,無需重複造輪子。我們只需導入weui.wxss等即可減少大量的css布局工作.

關於本地圖片資源路徑(background)

小程序只有image標籤支持本地圖片資源路徑,wxss里的background-image不支持。
如果想在css中使用背景圖,解決方法:

1、將本地圖片用線上地址轉化成base64路徑。線上轉化base64的地址:http://imgbase64.duoshitong.com/

2、url裏面的圖片來源必須填寫外鏈。如下:

area{     background: url('https://mirror-gold-cdn.xitu.io/168e088859e325b9d85?imageView2/1/w/100/h/100/q/85/format/webp/interlace/1' ) no-repeat center;  }

websocket問題

體驗版支持ws協議,需要打開調試模式
如果websocket是連接的域名非IP地址,則不能通過連接代理更改電腦的host來指定socket域名的解析地址
如果有測試環境,建議:

  1. 建一個專有的測試環境websocket域名
  2. 直接使用測試環境的IP地址訪問websocket

關於時間格式在ios中處理方法

背景: 由於ios只識別格式yyy/mm/dd格式,如"2018-10-31 20:30:00"格式無法識別;
默認情況下數據庫拿到的日期格式為「2018-08-30 12:00:00」,如果不替換「-」的話,在IOS下是不能通過getDate(datestring)獲取到日期對象的。Android下兩種格式均表現正常。

解決方法: 通過正則替換掉所有的"-",如下:

var dateStr = "2018-09-08 12:30:30"; // 後台返回的時間字符串  dateStr = dateStr.replace(/-/g, '/');  console.log(dateStr);  結果為:2018/09/08 12:30:30

小程序DOM上附屬參數,函數中獲取參數方法

view.wxml:

 // DOM上附屬參數  <view    data-id='{{fangyuanItem.id}}'    data-houseitemid='{{fangyuanItem.houseItemId}}'    catchtap='viewMendianDetail'>  </view>

view.js:

  // 函數中獲取參數    page({        data:{},        viewMendianDetail: function (e) {          var roomtypeid = e.currentTarget.dataset.id;          var houseItemId = e.currentTarget.dataset.houseitemid;        }    })

注意: 附屬參數時,data-key,key格式為小寫;

小程序 navigator 無法跳轉 tabBar上的頁面

方法一:navigator 的 open-type 設置為 switchTab

代碼如下:

<navigator url="../cart/index" open-type="switchTab">     <text>首頁</text>  </navigator>

方法二:wx.switchTab({})

代碼如下:

index.wxml:

 <text catchtap="toIndex">首頁</text>

index.js:

 page({      toIndex(){          wx.switchTab({            url: '../cart/index'          })      }   })

wx.navigateTo和wx.switchTab導航傳參

wx.navigateTo導航傳參

1.wx.navigateTo,url通過參數拼接傳參;

// 訪問房型詳情  viewMendianDetail: function (e) {    var roomtypeid = e.currentTarget.dataset.id;    var houseItemId = e.currentTarget.dataset.houseitemid;    wx.navigateTo({      url: '/pages/index/index?houseItemId=' + houseItemId + '&roomtypeid=' + roomtypeid,    })  }

2.定位到的組件中通過生命周期函數onLoad接收參數對象,並設置本組件中的數據

pages/index/index:

 onLoad: function (options) {      //console.log(options)      var houseItemId = options.houseItemId      var roomtypeid = options.roomtypeid      this.setData({          houseItemId: houseItemId,          roomTypeId: roomtypeid      })  }

wx.switchTab導航傳參

1.前提:app.js中有定義全局變量searchInfo,如下:

App({      globalData: {          searchInfo:{            searchInput:"",            laiyuan:0          }    }  });

2.通過app.globalData定義全局參數,如下:

a.wxml:

const app = getApp()  page({      data:{},      toZhaofang:function(e){          app.globalData.searchInfo = {            "searchInput": searchInput,            "laiyuan": 1          }          wx.switchTab({            url: '/pages/tabbar/zhaofang/index',          })     }  })

3.通過app.globalData來接收全局參數,如下:
zhaofang/index.wxml:

 const app = getApp()   page({      onLoad(){         let searchInfo = app.globalData.searchInfo         let searchInput = searchInfo.searchInput;      }   })

自定義小程序轉發功能

默認情況下,我們需要點擊小程序右上角的…才能看到轉發,這樣並不能對用戶起到引導作用,通常的做法是使用一個button,並且設置open-type為share,這樣就可以通過按鈕啟動分享。
但是原生按鈕很難看,我們可以設置一個圖片,並且調整按鈕的樣式;

效果如圖:

share.wxml:

<button open-type="share"><image src="/images/icon-share.png"></image></button>

share.wxss:

button {      padding:0;      width:70rpx;      height:70rpx;      display:block;      border:0;      background: transparent;  }  button::after {      border:0;  }

注意: 尤其是對 button::after 要進行設置,否則按鈕的邊框是無法去掉的。

通過 wx.getSystemInfo()來獲取手機信息(包括寬,高)

小程序提供的getSystemInfo()方法,該方法可以獲取到設備的常用信息,如手機型號.設備像素比.屏幕寬高等等.最常用的就是屏幕寬高了.
為了保證獲取信息的準確性,wx.getSystemInfoSync是在頁面初始化的時候就計算了。所以最好的方法是使用異步接口,並且在onReady函數中調用。

info.js:

Page({    onReady: function (options) {      this.getSystemInfo();    },    getSystemInfo:function(){      wx.getSystemInfo({        success: function (res) {           console.log("手機屏幕的寬度為:" + res.screenWidth);           console.log("手機屏幕的高度為:" + res.screenHeight);          console.log("可視網頁的寬度為:" + res.windowWidth);          console.log("可視網頁的高度為:" + res.windowHeight);          console.log("手機的系統為:" + res.system);          console.log("微信版本號為:" + res.version);        }      })    }  })

結果如圖:

模板(template)定義與傳參

定義: WXML提供模板(template),可以在模板中定義代碼片段,然後在不同的地方調用。
使用 name 屬性,作為模板的名字。如:

1.定義模板文件
baseTemplate.wxml:

<template name="msgItem">    <view>      <text> {{index}}: {{msg}} </text>      <text> Time: {{time}} </text>    </view>  </template>

2.使用模板並通過data傳遞參數
使用 is 屬性,聲明需要的使用的模板,然後將模板所需要的 data 傳入。如下:
user.wxml:

<import src="../template/baseTemplate.wxml" />   <block wx:for="{{goodlist}}" wx:key="idx">      <template is="msgItem" data="{{...item}}"></template>  </block>

注意:

1.通過data="{{…item}}"的方式傳遞參數時,被調用的模板中,不需要再寫item;

2.如果要傳多個數據到模板,用逗號分開,item 是對象,index是單個數據,要用鍵值對.

<view class="tab-list" wx:for="{{list}}" wx:key="index">     <template is="day-tab" data="{{item,index:index,target:target}}" wx:key="index"></template>  </view>

user.js,數據定義格式如下:

page({     data:{         goodlist:[             { index: 0,msg: 'this is a template',time: '2016-06-18'},             { index: 1,msg: 'this is a template1',time: '2017-06-18'},             { index: 2,msg: 'this is a template2',time: '2018-06-18'}         ]     }  })

城市選擇組件picker使用

效果如圖:


組件介紹

picker:從底部彈起的滾動選擇器。

代碼如下:

picker.wxml:

<picker      mode='selector'      range="{{region}}"      range-key="{{'cityName'}}"      value='{{indexCity}}'      bindchange="chooseCity"      >      <view class="picker">          {{region[indexCity].cityName}}      </view>  </picker>

picker.js:

page({     data:{         region:[             {"cityName":"北京市","cityId":"12345"},             {"cityName":"上海市","cityId":"67890"},             {"cityName":"武漢市","cityId":"54321"},         ]     },     chooseCity(e){       var value = e.detail.value;  // index下標     }  })

屬性介紹

mode(string):選擇器類型;mode 的合法值:

  • selector:普通選擇器;
  • multiSelector:多列選擇器;
  • time:時間選擇器;
  • date:日期選擇器;
  • region:省市區選擇器

滑動組件scroll-view

介紹: scroll-view:可滾動視圖區域。使用豎向滾動時,需要給scroll-view一個固定高度,通過 WXSS 設置 height。組件屬性的長度單位默認為px,2.4.0起支持傳入單位(rpx/px)。

詳細文檔請參考

效果如圖:

使用方法如下:

<scroll-view scroll-x="true"></scroll-view>

注意:

1.scroll-view的scroll-x失效的解決辦法

給scroll-view加上white-space: nowrap; 給scroll-view的子元素box加上display:inline-block即可。

代碼如下:

.scroll-box {     white-space: nowrap;  }  .scroll-box .box{     display:inline-block  }

2.文本數據默認顯示2行,超出部分用"…"代替:

樣式代碼如下:

line-height: 40rpx;  white-space:pre-line;  display:-webkit-box;  -webkit-box-orient:vertical;  -webkit-line-clamp:2;  overflow:hidden;

視圖容器cover-image和cover-view

使用背景:

在微信小程序經常會用到一些原生組件,比如map、video、canvas、camera,這些原生組件想讓其他元素覆蓋在其上,必須使用cover-view或者cover-image組件。

cover-view

介紹: 覆蓋在原生組件之上的文本視圖。可覆蓋的原生組件包括 map、video、canvas、camera、live-player、live-pusher。只支持嵌套 cover-view、cover-image,可在 cover-view 中使用 button。組件屬性的長度單位默認為px,2.4.0起支持傳入單位(rpx/px)。

注意: 只支持基本的定位、布局、文本樣式。不支持設置單邊的border、background-image、shadow、overflow: visible等。

1、支持background-color,不支持background-image,如果你發現你的素材在真機出不來,而且你又設置了背景圖片的話,那你可以把這些元素全部替換成cover-image。

2、不支持overflow: visible也是有點坑,這樣的話,你想超出依然顯示,就需要設置一個同級元素並提升層級才能達到效果了。

效果如圖:

示例代碼如下:

video.wxml:

<video id="myVideo" src="http://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400" controls="{{false}}" event-model="bubble">    <cover-view class="controls">      <cover-view class="play" bindtap="play">        <cover-image class="img" src="/path/to/icon_play" />      </cover-view>      <cover-view class="pause" bindtap="pause">        <cover-image class="img" src="/path/to/icon_pause" />      </cover-view>      <cover-view class="time">00:00</cover-view>    </cover-view>  </video>

video.wxss:

.controls {    position: relative;    top: 50%;    height: 50px;    margin-top: -25px;    display: flex;  }  .play,.pause,.time {    flex: 1;    height: 100%;  }  .time {    text-align: center;    background-color: rgba(0, 0, 0, .5);    color: white;    line-height: 50px;  }  .img {    width: 40px;    height: 40px;    margin: 5px auto;  }

video.js

Page({    onReady() {      this.videoCtx = wx.createVideoContext('myVideo')    },    play() {      this.videoCtx.play()    },    pause() {      this.videoCtx.pause()    }  })

cover-image

介紹: 覆蓋在原生組件之上的圖片視圖,可覆蓋的原生組件同cover-view,只支持嵌套在cover-view里。

cover-image發現了兩個問題:

1、雖說和image組件基本一樣,但是設置mode屬性也就是圖片裁剪、縮放的模式無效

2、寬度固定,高度auto,時,按照正常效果應該是圖片按比例伸縮展示,但是發現該組件高度一直為0,只能根據應用場景尋找其他替代方案了。

視圖容器swiper

介紹: 滑塊視圖容器。其中只可放置swiper-item組件,否則會導致未定義的行為。

效果如圖:

代碼如下:

swiper.wxml:

<view class="area">     <view class="fuTitle">swiper</view>     <view class="intro">        <text class="one-title">介紹:</text>        <text>滑塊視圖容器。其中只可放置swiper-item組件,否則會導致未定義的行為。</text>     </view>     <view class="item">        <swiper          indicator-dots="{{indicatorDots}}"          indicator-color="{{indicatorColor}}"          indicator-active-color="{{indicatorActiveColor}}"          previous-margin="{{previousMargin}}"          next-margin="{{nextMargin}}"          display-multiple-items="{{itemsNum}}"          autoplay="{{autoplay}}"          interval="{{interval}}"          duration="{{duration}}"          bindchange="bindchange"          easing-function="{{easing}}"          >          <block wx:for="{{imgUrls}}" wx:key="{{index}}">            <swiper-item item-id="{{index}}">              <image src="{{item}}" class="slide-image" width="355" height="150"/>            </swiper-item>          </block>        </swiper>     </view>  </view>

swiper.js

Page({      data: {           imgUrls:[             "../../images/bo1.jpg",             "../../images/bo2.jpg",             "../../images/bo3.jpg",             "../../images/bo4.jpg"           ],           indicatorDots: true,    // 是否顯示滾動圓點圖標          indicatorColor: "#07c160", // 指示點顏色          indicatorActiveColor: "#28d3ee", // 當前選中的指示點顏色          previousMargin: "10rpx", // 前邊距,可用於露出前一項的一小部分,接受 px 和 rpx 值          nextMargin: "10rpx",     // 後邊距,可用於露出後一項的一小部分,接受 px 和 rpx 值          itemsNum:1,              // 同時顯示的滑塊數量          easing: "default",       // 指定 swiper 切換緩動動畫類型          autoplay: true,         // 是否自動播放          interval: 5000,         // 自動切換時間間隔          duration: 1000          // 滑動的動畫時長      }  })

rich-text實現富文本解析

介紹: 富文本。主要用來解析服務端傳遞過來的富文本html格式的數據,進行展示在頁面上。類似於vue的v-html指令;

效果如圖:

代碼如下:

richText.wxml:

<view class="rich-area">        <rich-text nodes="{{article_content}}" bindtap="tapRichText"></rich-text>  </view>

richText.js:

Page({     data: {       article_content: '<p>自我介紹1</p><p><img src="https://mirror-gold-cdn.xitu.io/168e088859e325b9d85?imageView2/1/w/100/h/100/q/85/format/webp/interlace/1" width="100" height="100"/></p><p>自我介紹2</p><p><img src="https://mirror-gold-cdn.xitu.io/168e088859e325b9d85?imageView2/1/w/100/h/100/q/85/format/webp/interlace/1" width="100" height="100"/></p><p>自我介紹3</p><p><img src="https://mirror-gold-cdn.xitu.io/168e088859e325b9d85?imageView2/1/w/100/h/100/q/85/format/webp/interlace/1" width="100" height="100"/></p>',     }  });

小程序中運用高德地圖繪製靜態圖

功能背景

在小程序的頁面中,需要顯示某個位置的具體地理坐標並做好標記;如果直接使用map組件,無法滿足功能需求,同時會存在頁面層級重疊的問題;所有就選擇了高德地圖微信小程序sdk,繪製靜態圖來呈現。

效果如圖:

開發步驟

1.獲取高德Key

點我獲取Key>>
點我查看申請高德Key的方法>>

2.繪製靜態圖

簡介:
由於微信內無法運行第三方地圖,高德對廣大開發者提供了靜態地圖功能,可快速生成一張地圖圖片,可以指定顯示的地圖區域、圖片大小、以及在地圖上添加覆蓋物,如標籤、標註、折線、多邊形。 可用於快速生成一張個性化塗鴉的靜態地圖用於查看和分享。

靜態圖上繪製點

1、在頁面的 js 文件中,實例化 AMapWX 對象,請求顯示靜態地圖。

首先,引入 amap-wx.js 文件(amap-wx.js 從相關下載頁面下載的 zip 文件解壓後得到)。

xinxi.js:

var amapFile = require('path/to/amap-wx.js');//如:..­/..­/libs/amap-wx.js

然後,構造 AMapWX 對象,並調用 getStaticmap 方法。
其中,注意: 把百度地圖坐標轉換成高德,騰訊地圖坐標

var zuobiaoArr = network.bMapTransQQMap(lng,lat)
Page({    data: {      pointObj:{        lng:'您的坐標經度值',        lat:'您的坐標緯度值'      },      src: ''    },    onLoad: function() {      var that = this;      var myAmapFun = new amapFile.AMapWX({key:"您的Key"});      wx.getSystemInfo({        success: function(data){          var height = data.windowHeight;          var width = data.windowWidth;          var size = width + "*" + height;          myAmapFun.getStaticmap({            zoom: 8,            size: size,            scale: 2,            markers: "mid,0xFF0000,A:"+pointObj.lng+","+pointObj.lat",            success: function(data){              that.setData({                src: data.url              })            },            fail: function(info){              wx.showModal({title:info.errMsg})            }          })        }      })    }  })

注意:
data.windowHeight,data.windowWidth獲取的是整個窗口的高度和寬度,這裡可以根據需求自己設定地圖要顯示的寬高。
markers: "mid,0xFF0000,A:"+pointObj.lng+";"+pointObj.lat",用於設置地圖上要顯示的標記坐標;如果要顯示多個標記,格式為:

markers: "mid,0xFF0000,A:116.37359,39.92437;116.47359,39.92437"; // 多個坐標點以";"分割;

2、編寫頁面的 wxml 文件,搭建頁面結構。

xinxi.wxml:

<view class="img_box">    <img src="{{src}}">  </view>

3、編寫頁面的 wxss 文件,設置頁面樣式。

xinxi.wxss:

.img_box{    position: absolute;    top: 0;    bottom: 0;    left: 0;    right: 0;  }  .img_box image{    width: 100%;    height: 100%;  }  ……

4.注意細節:

如果你提供的 pointObj:{lng:’您的坐標經度值’,lat:’您的坐標緯度值’}數據對象為百度地圖的坐標值,我們需要將其轉換為高德地圖坐標值(它們的坐標計算方式不同);

轉換方法如下:

//百度地圖坐標轉為高德,騰訊地圖坐標  function bMapTransQQMap(lng, lat) {      let x_pi = 3.14159265358979324 * 3000.0 / 180.0;      let x = lng - 0.0065;      let y = lat - 0.006;      let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);      let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);      let lngs = z * Math.cos(theta);      let lats = z * Math.sin(theta);      return {          lng: lngs,          lat: lats      }  }  let pointObj = bMapTransQQMap(lng,lat); // 轉換之後的坐標值;

結束:

如果你也一樣喜歡前端開發,歡迎加入我們的討論/學習群,群內可以提問答疑,分享學習資料;

歡迎添加群主微信和qq群答疑: