1. 程式人生 > >微笑小程式的相關知識

微笑小程式的相關知識

現在的前端工程師職責越來越重要,很多新的技術都是從前端領域分離出來,微信小程式就是一個很好的前端技術的實踐。開發微信小程式前,總覺得神祕面紗不可及,但經過前端團隊一個月辛苦奮戰,微信小程式從此不再陌生,而變得熟悉和可控。現在,小程式終於上線了,我也終於有時間來分享一下開發過程中遇到的問題。

0、開發過程中需要遵守的兩條原則

    ①專案整體容量小於等於2M;②專案頁面棧容量5級

    官方宣告:為了不讓使用者在使用小程式時造成困擾,我們規定頁面路徑只能是五層,請儘量避免多層級的互動方式。

    其他注意事項:

    一、App() 必須在 app.js 中註冊,且不能註冊多個。

    二、不要在定義於 App() 內的函式中呼叫 getApp() ,使用 this 就可以拿到 app 例項。

    三、不要在 onLaunch 的時候呼叫 getCurrentPages(),此時 page 還沒有生成。

    四、通過 getApp() 獲取例項之後,不要私自呼叫生命週期函式。

    五、為了方便開發者減少配置項,我們規定描述頁面的這四個檔案必須具有相同的路徑與檔名。

1、專案搭建過程

    對於經驗豐富的程式設計師來說,專案搭建(前端框架搭建)其實是最沒有技術含量的工作,但專案配置可是最有含金量的工作。具體專案搭建流程請參考微信小程式官方教程 ,此處略過。若果是團隊協作開發,需要將專案放在GitHub上的步驟是,先搭建專案,後放入GitHub本地倉庫後上傳。

    因為,微信小程式在建立過程中,如果選擇的本地資料夾是個空資料夾,開發者工具會提示,是否需要建立一個 quick start 專案。選擇“是”,開發者工具會幫助我們在開發目錄裡生成一個簡單的 demo。如果資料夾不為空,則不會生成demo。

2、專案目錄結構和功能說明

   小程式包含一個描述整體程式的 app 和多個描述各自頁面的 page,專案框架搭建成功後,可以看到微信小程式的目錄結構非常簡單:根目錄結構是,一個pages資料夾,同級目錄還有三個檔案(app.js、app.json、app.wxss),pages資料夾存放所有頁面。

    對實際專案結構目錄進行改造:

    在根目錄下建立images資料夾用來存放圖片;

    建立utils資料夾用來存放公共js檔案,比如,表單驗證函式庫(還可以包含時間格式化模組formatTime,域名配置模組domainConfig,省市區三級內容模組city):

        在utils資料夾下面新建validater.js檔案,var validater = {...some function}建立物件封裝一系列函式,最後匯出module.exports.validater = validater;

        在根目錄指令碼檔案app.js中載入,letvalidater = require('utils/validater.js'); || import { validater } from 'utils/validater';兩種方式均可,並在專案的整個生命週期函式上註冊App({validater: validater});。(node的module遵循CommonJS規範,requirejs遵循AMD,seajs遵循CMD)

        在實際頁面進行呼叫,getApp().validater.isEmail(value),對具體value值進行處理

    當然,專案的整體配置可根據專案要求進行靈活搭配,目錄結構和功能可依據需求進行定製。

3、每一個單頁面都是由一個資料夾和四個檔案組成

    資料夾名稱是該單頁面的名稱,首字母大小寫均可,內容由JS、JSON,WXML和WXSS四個檔案組成,檔案功能可參考微信小程式具體說明。

    注意:為了方便開發者減少配置項,我們規定描述頁面的這四個檔案必須具有相同的路徑與檔名。

4、頁面棧原理

    在小程式官方文件 API章節中的導航目錄中,封裝了5種導航方式,分別為wx.navigateTo、wx.redirectTo、wx.switchTab、wx.navigateBack、wx.reLaunch。由於微信的頁面路徑深度最多是五層,因此在用選擇當行方式很重要。因為,微信小程式的左上角有返回按鈕,返回按鈕的意思是回退到上一個頁面,但當導航跳轉方式選擇錯誤,第一,會導致返回的不是上一個頁面;第二,導航跳轉無法載入,由於5級頁面棧容量已經飽和。

    wx.navigateTo(OBJECT)保留當前頁面,跳轉到應用內的某個頁面,該方法會往頁面棧中增加一條記錄;

    wx.redirectTo(OBJECT)關閉當前頁面,跳轉到應用內的某個頁面,該方法會不會增加頁面棧記錄,保持頁面棧原始內容;

    wx.reLaunch(OBJECT)基礎庫 1.1.0 開始支援,低版本需做相容處理,關閉所有頁面,開啟到應用內的某個頁面,該方法會清空頁面棧全部記錄;

    wx.switchTab(OBJECT)跳轉到 tabBar 頁面,並關閉其他所有非 tabBar 頁面,該方法和和頁面棧無關;
    wx.navigateBack(OBJECT)關閉當前頁面,返回上一頁面或多級頁面,該方法會刪除頁面棧中一條記錄;

    檢視頁面棧容量的方法,以及各頁面中儲存的資料:可通過 getCurrentPages() 獲取當前的頁面棧資訊,

        let arr = getCurrentPages();//頁面棧資料陣列,儲存頁面棧中頁面js檔案中data物件

        arr[arr.length - 1]可以獲取到當前頁面的相關資訊;

        比如,獲取(重置)上一個頁面的中的某個引數,let previousThis = arr[arr.length - 2],previousThis.data.contactorList可以拿到資料,previousThis.data.setData({contactorList:[]})可以重置資料。

    頁面棧陣列物件getCurrentPages()中包含的資訊量非常大,有效利用這個物件對於開發效率事半功倍。

5、頁面傳參和引數回顯

    由於小程式開發沒有組建的概念,因此可以理解為SPA單頁面應用開發,對於一款產品,只要頁面的基本功能相同,就可以複用。因此,一款再複雜的產品,不同的單頁面也不超過十幾個。在小程式開發過程中,複用頁面是最常用的方案。比如,A頁面可以實現某個功能,這時C頁面、D頁面和F頁面都需要用A頁面的功能,就可以把A頁面當做一個模板來使用,A頁面接收父級頁面傳遞來的引數,進行處理後,可以傳遞給父級頁面需要的資料。

    頁面之間的通訊:

    A頁面跳轉到B頁面,通過URL拼接傳遞引數常用的兩種方案:

    方案一:A頁面通過新增點選事件跳轉傳參,wx.navigateTo({url:'./B/index?parameter01=one&parameter02=two'}),B頁面接收A頁面的引數,onLaunch:function(options){console.log(options.parameter01)}。A頁面通過URL地址問號?後拼接的引數,可以在B頁面的 onLaunch函式 和 onShow函式 的形參中options物件中獲取。

    注意事項:通過URL拼接的方式傳遞引數的型別是物件或者陣列,在傳遞的時候應當使用JSON.stringify(obj || array)進行json資料編碼,然後在拿到資料時應當使用JSON.parse(obj || array)進行資料解碼。

    方案二:A頁面通過導航元件navigator傳遞引數,<view><navigator url="./B/index?title=navigate">跳轉到新頁面</navigator></view>,B頁面接收引數童方案一。

getCurrenPage獲得A中的引數,可做回

    不通過URL拼接傳遞引數的方案:通過原生陣列物件 getCurrentPages() 獲取頁面棧資訊,從而拿到需要的引數。方案具體步驟如下:

    例項:A頁面 data物件 中的一個 address引數 是用來儲存使用者的住址資訊並顯示在A頁面的具體位置,當用戶點選A頁面的地址輸入框時會跳轉到儲存地址列表的B頁面,使用者可點選直接選擇獲取,選擇成功會跳轉到A頁面,並顯示使用者的選項。這個互動功能涉及到兩個知識點:

    第一,B頁面給A頁面引數賦值的方案

    var arr=getCurrentPages(),獲取頁面棧陣列;

    var previousThis=arr[arr.length - 2],獲取A頁面的this指標;

    previousThis.data.address='new address',給A頁面的資料賦值;

    第二,在A頁面中操作B頁面的顯示內容

    previousThis.setData({address:previousThis.data.address}),可在B頁面返回A頁面之前,讓A頁面正確顯示出使用者的操作內容。(可以將上述的previousThis.data.address='new address'和previousThis.setData({address:previousThis.data.address})步驟合二為一成previousThis.setData({address:'new address'}))

    在實際專案的開發過程中,一個頁面顯示的所有內容,往往是從介面直接拿到返回的資料顯示出來,在B頁面進行操作的時候,也是和後臺介面通訊,對資料庫內容進行增加和刪除,因此在做回顯處理時,不同過頁面棧資訊的方式操作回顯內容,而是通過重新請求介面的方式來重新整理並顯示最新資料。

    因此,通過wx.navigateBack(OBJECT)從B頁面返回A頁面後,保證A頁面顯示的是最新資料,需要在A頁面中做特殊處理,A頁面中所有從後臺介面拿到的作為顯示的資料,進行wx.request({url: 'test.php',data: {},header: {},success: function(res) {}})資料請求的方法必須放在onShow: function(options) {// Do something when show.}中,這樣才能保證wx.navigateBack(OBJECT)執行後從B頁面返回A頁面後,A頁面會重新請求資料,並顯示出來。

6、css樣式

    專案根目錄下的app.wxss檔案是小程式公共樣式表,樣式重置、樣式初始化和公共樣式可以放在這個檔案中,這裡面的樣式屬於全域性樣式,作用於任何一個頁面(即,在其他頁面中不需要匯入)。

    同時,每個單頁面都有自己依賴的樣式檔案,對於可複用的單頁面的樣式檔案,如B頁面可以複用A頁面的樣式檔案,可以在B頁面的wxss樣式檔案頭部匯入A頁面的樣式檔案,方式如下:@import '../A/A.wxss';

7、底部標籤導航的設定

    補充頁面棧知識:微信小程式框架以棧的形式維護了當前所有頁面,當發生路由切換的時候,頁面棧的表現如下:初始化-新頁面入棧;開啟新頁面新頁面入棧;頁面重定向-當前頁面出棧-新頁面入棧;頁面返回-頁面不斷出棧-直到目標返回頁-新頁面入棧;Tab 切換-頁面全部出棧-只留下新的 Tab 頁面;重載入-頁面全部出棧-只留下新的頁面。

    底部Tab導航的配置在app.json中tabBar物件進行設定,例項如下:

"tabBar": {
    "selectedColor": "#00B4FF",//tab 上的文字選中時的顏色
    "list": [//tab 的列表,詳見 list 屬性說明,最少2個、最多5個 tab
      {
        "pagePath": "pages/index/index",//頁面路徑,必須在 pages 中先定義
        "text": "首頁",
        "color": "",//tab 上的文字預設顏色
        "iconPath": "image/1.png",
        "selectedIconPath": "image/1_hover.png"
      },
      {
        "pagePath": "pages/message/index",
        "text": "訊息",
        "iconPath": "image/2.png",
        "selectedIconPath": "image/2_hover.png"
      },
      {
        "pagePath": "pages/my/index",
        "text": "我的",
        "iconPath": "image/3.png",
        "selectedIconPath": "image/3_hover.png"
      }
    ]
  },

8、HTML5標籤的自定義屬性data-*

    在html標籤中加入自定義屬性data-*用於儲存頁面的自定義資料,然後在元素繫結的方法中可以獲取資料

    注意事項:屬性名不能包含大寫字母,在 data- 後必須至少有一個字元;該屬性可以是任何字串;自定義屬性字首 "data-" 會被客戶端忽略。

    具體應用:

    場景一:

<View wx:for="{{contactorList}}" wx:key="unique">

    <View bindtap="reEditor" data-info="{{item}}" data-reeditIndex="{{index}}"></View>

</View>

reEditor(e){

let info = e.currentTarget.dataset.info;//js中獲取繫結的資料

let index = e.currentTarget.dataset.index;//js中獲取繫結的資料

}

    微信小程式的 列表渲染 很常用,對一個數組的資料重複渲染出該元件集合,需求:對陣列的每一個數據需要繫結事件同時獲取 資料 和 索引值,此時,可以用自定義屬性data-*在html元素上繫結資料,在函式中的e物件中獲取繫結的資料。

    注意:繫結的函式bindtap必須和data-*繫結的資料在同一個html元素上繫結,不然無法獲取資料

    場景二:

    通過獲取 html元素物件 屬性的方法getAttribute()獲取繫結的資料,也可以通過 獲取元素節點後 用 HTML5自定義屬性物件Dataset 獲得需要的資料document.getElementById('owl').dataset.animal-type

function showDetails(animal)
{
var animalType = animal.getAttribute("data-animal-type");
alert("The " + animal.innerHTML + " is a " + animalType + ".");
}
<ul>
  <li onclick="showDetails(this)" id="owl" data-animal-type="bird">Owl</li>
  <li onclick="showDetails(this)" id="salmon" data-animal-type="fish">Salmon</li>  

</ul>

9、資料動態顯示

    微信的資料都儲存在js檔案中的data物件中,改變資料有兩種方式:this.data.key = value;這種方法不會觸發二次渲染;this.setData({key:value});這種方法可以觸發二次渲染;因此,對於任何需要顯示的資料或元素,發生變化時需要用第二種方法。

10、注意事項

原型psd圖的尺寸在書寫wxss樣式檔案時,按照1px寫成2rpx的方式

<Text>標籤巢狀<View>標籤後,<View>標籤中的任何內容都不會顯示出來

11、專案整體 資料介面 和封裝 公共函式 物件配置

    專案整體配置可以在app.js的App({})方法中配置,App() 函式用來註冊一個小程式。接受一個 object 引數,其指定小程式的生命週期函式等。

App({
    HOST: ,//主機域名

    loginCode: ,//使用者身份驗證碼

    validater: ,//正則校驗物件

    formatTime:,//日期時間物件

    onLaunch: function (e) {},

    onShow: function (e) {},

    onHide: function (e) {},

    onError: function (e) {},

});

    配置好以上檔案後,在進行資料請求時的形式:

wx.request({url: getApp().HOST + '/interface/name',header: {},data: { key:value },method: 'GET',
    success: function(res) {},
    fail: function(res) {}
})

    在進行方法呼叫時的形式:getApp().formatTime.time(str);將 時間戳 轉換為 08:30 的格式函式

12、表單元件input應用

    基礎應用,一個input元件繫結一個函式:

<input  bindinput="input" value="{{inputValue}}" placeholder="" />
input: function(e) {
    this.setData({
      inputValue: e.detail.value
    })
},

    多輸入應用,一個input元件繫結一個函式看起來很繁瑣,可以採用多個input元件繫結一個函式的方案:

<input bindinput="inputFn" value="{{info.name}}" data-key="name"/>
<input bindinput="inputFn" value="{{info.age}}" data-key="age"/>
<input bindinput="inputFn" value="{{info.address}}" data-key="address"/>
<input bindinput="inputFn" value="{{info.mobile}}" data-key="mobile"/>
inputFn(e){
    var key = e.target.dataset.key;
    var value = e.detail.value
    this.data.info[key] = value;
    this.setData({
        info: this.data.info
    })
}

13、圖片的上傳和下載顯示

    前後端開發下載顯示圖片的方案:

    圖片的html容器:

<view  wx:for="{{imageArr}}" wx:key="item.id">

    <image class="slide-image" mode="scaleToFill" src="{{Item}}" data-index="{{index}}"></image>

</view>

   圖片資料的請求處理:

wx.request({
    url: url,
    success(res){
        let data = res.data.imageArr;//返回的圖片url沒有域名,只有相對路徑,需要做域名拼接處理["/1.jpg","/2.jpg","/3.jpg"]
        for(let i = 0; i < data.length; i++) {data[i] = 'http://img.wanshaobo.com' + data[i];}
        this.setData({imageArr: data});//圖片顯示操作
    }
})

    圖片的本地顯示和網路上傳方案:

    圖片的html容器,HTML結構的理解可以參考下面的例項圖片:

<view wx:for="{{imageArr}}" wx:key="id">
    <image mode="scaleToFill" src="{{item.imgUrl}}"></image>
    <icon type="clear" size="16" bindtap="deleteImg"></icon>
</view>
<view bindtap="uploadImg"><image src="../plus.png"></image></view>

    圖片的新增顯示和網路上傳:

    第一步,點選加號圖示向頁面新增並顯示圖片,呼叫微信小程式API-媒體-圖片-wx.chooseImage(OBJECT)從本地相簿選擇圖片或使用相機拍照

wx.chooseImage({
  count: 9 - imageArr.length,
  success: function (res) {
//res.tempFilePaths圖片的本地檔案路徑列表:["wxfile://tmp_1.png","wxfile://tmp_2.png","wxfile://tmp_3.png"]
//res.tempFiles圖片的本地檔案列表,每一項是一個 File 物件:[{path:"wxfile://tmp_1.png",size:1021},{path:"wxfile://tmp_2.png",size:21},{path:"wxfile://tmp_3.png",size:103}]
  this.data.imageArr.push(res.tempFilePaths)
  that.setData({imageArr:this.data.imageArr});

  }

})

    第二步,呼叫微信小程式API-網路-上傳、下載-wx.uploadFile(OBJECT)
將本地資源上傳到開發者伺服器。如頁面通過 wx.chooseImage 介面獲取到一個本地資源的臨時檔案路徑後,可通過此介面將本地資源上傳到指定伺服器。客戶端發起一個 HTTPS POST 請求,其中 content-type 為 multipart/form-data 。

    上傳圖片到自己圖片伺服器後的成功回撥函式會返回一個物件,該物件是儲存圖片的伺服器返回的資料,包含了該圖片的URL地址,這個URL地址就是以後拿到該圖片的唯一URL路徑。

imageArr.forEach((item,index)=>{
  wx.uploadFile({
    url: 'https://wsb-file.wanshaobo.com/file/simpleUpload',
    filePath: item,
    name: 'file',
    header: { 'content-type': 'multipart/form-data' },
    success: function (res) {
    //res.data:"{"msg":"上傳成功","code":200,"filePath":"/group1/M00/0A/F1/wKgGS1lfUYeAfnPLAAATCakKLos829.png"}"
    //res.errMsg:"uploadFile:ok"

    this.data.imgsArr.push(JSON.parse(res.data).filePath)//圖片成功上傳返回的URL路徑陣列,不包含主機名

    this.data.imgsStr = this.data.imgsArr.join(',')//儲存在資料庫中屬於該使用者的圖片URL陣列拼接的字串
    }
  })

})

    樣式效果例項如下圖:

 

14、獲取使用者地理位置名稱的方案

    比如:北京市東城區和平西橋58號

    需要用的的API介面:

    API-開放介面-設定-wx.getSetting(OBJECT)//獲取使用者當前設定,成功回撥res.authSetting ={

scope.userInfo": true,//使用者資訊

"scope.userLocation": true//地理位置

"scope.address": true//通訊地址

"scope.record": true//錄音功能

"scope.writePhotosAlbum": true//儲存到相簿

}

    API-開放介面-授權-wx.authorize(OBJECT)

    API-位置-獲取位置-wx.chooseLocation(OBJECT)

    具體程式碼分析:第一步,通過 wx.getSetting 查詢使用者是否授權了 "scope.userLocation" 這個 scope;第二步,通過 wx.authorize 介面開啟‘地理位置’授權介面對userLocation進行授權;第三步,通過 wx.chooseLocation 介面開啟地圖選擇位置

wx.getSetting({

  success(res) {

    if (!res['scope.userLocation']) {

      wx.authorize({
        scope: 'scope.userLocation',
        success() {

          wx.chooseLocation({success: function (res) {res.address;res.longitude;res.longitude;});

        }
      })
    }

  }

})

15、自定義頁面的滾動選擇器

    需求,如下圖所示,實現邏輯,第一步,對頁面元素進行堆疊排列,頁面正文內容z-index:0;半透明蒙層z-index=1,寬高佔據滿屏;滾動選擇器z-index=2:第二步,對選擇器樣式進行設計,需要用到<picker-view><picker-view-column></picker-view-column></picker-view>元件;第三步,對透明蒙層區域、取消按鈕、確定按鈕新增事件處理函式。

 

    微信小程式的原生滾動選擇器僅有三種類型,普通選擇器,時間選擇器,日期選擇器,但現在的選擇器需求是:年月日時分秒。

    HTML結構如下:

<view class="mask" bindtap="clickMask"></view>

<view class="datePicker">

  <view class="pickerBtn"><text bindtap="cancel">取消</text><text bindtap="confirm">確定</text></view>

  <picker-view  value="{{dateValue}}" bindchange="dateChange">

    <picker-view-column><view wx:for="{{years}}">{{item}}年</view></picker-view-column>

    <picker-view-column><view wx:for="{{months}}">{{item}}月</view></picker-view-column>

    <picker-view-column><view wx:for="{{days}}">{{item}}日</view></picker-view-column>

    <picker-view-column><view wx:for="{{hours}}" >{{item}}時</view></picker-view-column>

    <picker-view-column><view wx:for="{{minutes}}">{{item}}分</view></picker-view-column>

    <picker-view-column><view wx:for="{{seconds}}">{{item}}秒</view></picker-view-column>

  </picker-view>

</view>

    資料繫結方案:

    資料初始化,定義初始化顯示的資料是當前的日期時間:

this.setData({dateValue: ['0',date.getMonth(),date.getDate()-1,date.getHours(),date.getMinutes()]})

    年份列表顯示當前年份到後三十年,對於具體月份顯示的天數列表需要做特殊處理,1-3-5-7-8-10-12每月31天,4-6-9-11每月30天,2月的天數最為特殊,閏年2月份為29天,平年2月份為28天,每月天數處理如下:

var date = new Date();

var year = date.getFullYear();//獲取當前年份

var month = date.getMonth() + 1;//獲取當前月份

var days ;//定義當月的天數;

if(month == 2){

    days= ((year % 4 == 0 && year % 100 != 0) || year % 400 ==0) ? 29 : 28;//閏年29天,還是平年

}else if(month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12){

    days= 31;//月份為:1,3,5,7,8,10,12 時,大月.天數為31

}else{

    days= 30;//其他月份,小月,天數為30.

}
for (let i = 1 ; i <= days; i++) {

    daysArr.push(i)

}

    月份列表滾動選擇器發生變化時,天數選擇器的天數陣列也需要做響應式實時變化,當滾動選擇,value 改變時觸發 change 事件,event.detail = {value: value};value為陣列,表示 picker-view 內的 picker-view-column 當前選擇的是第幾項(下標從 0 開始):

dateChange(e){//月份發生變化時需要改變響應的天數

  var date = new Date(),days = []

  var year = date.getFullYear() + e.detail.value[0];//獲取年份

  var month = e.detail.value[1] + 1;//獲取月份

  var days ;//定義當月的天數;


  if(month == 2){

    days= ((year % 4 == 0 && year % 100 != 0) || year % 400 ==0) ? 29 : 28;//閏年29天,還是平年

  }else if(month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12){

    days= 31;//月份為:1,3,5,7,8,10,12 時,大月.天數為31

  }else{

    days= 30;//其他月份,小月,天數為30.

  }

  this.setData({days: days})

  var dateArr = e.detail.value

  this.setData({

    year: this.data.years[dateArr[0]],

    month: this.data.months[dateArr[1]],

    day: this.data.days[dateArr[2]],

    hour: this.data.hours[dateArr[3]],

    minute: this.data.minutes[dateArr[4]]

  })

}
---------------------
作者:FEBruce
來源:CSDN
原文:https://blog.csdn.net/wanshaobo888/article/details/74452402
版權宣告:本文為博主原創文章,轉載請附上博文連結!