微笑小程序的相關知識

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

0、開發過程當中須要遵照的兩條原則css

    ①項目總體容量小於等於2M;②項目頁面棧容量5級html

    官方聲明:爲了避免讓用戶在使用小程序時形成困擾,咱們規定頁面路徑只能是五層,請儘可能避免多層級的交互方式。前端

    其餘注意事項:node

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

    2、不要在定義於 App() 內的函數中調用 getApp() ,使用 this 就能夠拿到 app 實例。程序員

    3、不要在 onLaunch 的時候調用 getCurrentPages(),此時 page 尚未生成。數據庫

    4、經過 getApp() 獲取實例以後,不要私自調用生命週期函數。json

    5、爲了方便開發者減小配置項,咱們規定描述頁面的這四個文件必須具備相同的路徑與文件名。小程序

一、項目搭建過程

    對於經驗豐富的程序員來講,項目搭建(前端框架搭建)實際上是最沒有技術含量的工做,但項目配置但是最有含金量的工做。具體項目搭建流程請參考微信小程序官方教程 ,此處略過。若果是團隊協做開發,須要將項目放在GitHub上的步驟是,先搭建項目,後放入GitHub本地倉庫後上傳。

    由於,微信小程序在建立過程當中,若是選擇的本地文件夾是個空文件夾,開發者工具會提示,是否須要建立一個 quick start 項目。選擇「是」,開發者工具會幫助咱們在開發目錄裏生成一個簡單的 demo。若是文件夾不爲空,則不會生成demo。

二、項目目錄結構和功能說明

   小程序包含一個描述總體程序的 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值進行處理

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

三、每個單頁面都是由一個文件夾和四個文件組成

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

    注意:爲了方便開發者減小配置項,咱們規定描述頁面的這四個文件必須具備相同的路徑與文件名。

四、頁面棧原理

    在小程序官方文檔 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()中包含的信息量很是大,有效利用這個對象對於開發效率事半功倍。

五、頁面傳參和參數回顯

    因爲小程序開發沒有組建的概念,所以能夠理解爲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頁面會從新請求數據,並顯示出來。

六、css樣式

    項目根目錄下的app.wxss文件是小程序公共樣式表,樣式重置、樣式初始化和公共樣式能夠放在這個文件中,這裏面的樣式屬於全局樣式,做用於任何一個頁面(即,在其餘頁面中不須要導入)。

    同時,每一個單頁面都有本身依賴的樣式文件,對於可複用的單頁面的樣式文件,如B頁面能夠複用A頁面的樣式文件,能夠在B頁面的wxss樣式文件頭部導入A頁面的樣式文件,方式以下:@import '../A/A.wxss';

七、底部標籤導航的設置

    補充頁面棧知識:微信小程序框架以棧的形式維護了當前全部頁面,當發生路由切換的時候,頁面棧的表現以下:初始化-新頁面入棧;打開新頁面新頁面入棧;頁面重定向-當前頁面出棧-新頁面入棧;頁面返回-頁面不斷出棧-直到目標返回頁-新頁面入棧;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"
      }
    ]
  },

八、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>

九、數據動態顯示

    微信的數據都存儲在js文件中的data對象中,改變數據有兩種方式:this.data.key = value;這種方法不會觸發二次渲染;this.setData({key:value});這種方法能夠觸發二次渲染;所以,對於任何須要顯示的數據或元素,發生變化時須要用第二種方法。

十、注意事項

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

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

十一、項目總體 數據接口 和封裝 公共函數 對象配置

    項目總體配置能夠在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 的格式函數

十二、表單組件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
    })
}

1三、圖片的上傳和下載顯示

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

    圖片的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數組拼接的字符串
    }
  })

})

    樣式效果實例以下圖:

 

1四、獲取用戶地理位置名稱的方案

    好比:北京市東城區和平西橋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;});

        }
      })
    }

  }

})

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

    需求,以下圖所示,實現邏輯,第一步,對頁面元素進行堆疊排列,頁面正文內容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

相關文章
相關標籤/搜索