開發(fā)那點事(十)組件化開發(fā)微信小程序案例

開發(fā)背景
最近在優(yōu)化一個兩三年的老項目柏蘑,奈何UI小姐姐出的圖太高大上喊儡,用了好久的微信自帶網(wǎng)絡加載api,沒法滿足需求瓦胎,但是在每個頁面上寫太多相同的setData太low,于是下定決心封裝一個尤揣。

插件實現(xiàn)功能

  • 1 網(wǎng)絡加載框
  • 2 選擇對話框
  • 3 吐司對話框

本文要點

  • 1 插件效果演示(amazing)
  • 2 插件集成使用(import)
  • 2 小程序插件的開發(fā)與使用(component)
  • 3 基于插件相關(guān)功能Util類封裝(loadToastUtil)
  • 4 總結(jié)(summary)

上干貨

插件效果演示(amazing)

效果演示.gif

插件集成使用(import)

插件下載地址在文末搔啊,歡迎下載,歡迎star??????
在小程序頁面的json文件中引入該插件

home.json

{
  "usingComponents": {
    "jkDialog": "../../view/jk-dialog/jk-dialog"
  }
}

在js文件中引入jkDialogUtil北戏,注意構(gòu)造方法中的三個參數(shù)

home.js

import {
  jkDialogUtil
} from "../../view/jk-dialog/dialogUtil";
let dialogUtil;
//三個參數(shù)分別對應page對象,網(wǎng)絡請求基礎(chǔ)url,對應插件id
dialogUtil = new jkDialogUtil(this, 'https://www.baidu.com', '#loadToast');
//調(diào)用吐司對話框
dialogUtil.showToast('提示用戶\n換行');
//調(diào)用選擇對話框
dialogUtil.showSelectDialog({
      selectTip: '測試',
      selectContent: '測試選擇對話框\njust soso',
    }, (res) => {
      dialogUtil.showToast(res == 'confirm' ? '確認操作' : '取消操作');
    });
//顯示隱藏網(wǎng)絡加載框
dialogUtil.showLoading();
dialogUtil.hiddenLoading();

原理分析

小程序插件的開發(fā)與使用(component)
在項目文件中定義view文件夾负芋,用來存放自定義組件
右鍵新建Component,以我的為例取名為jk-dialog
這個時候開發(fā)者工具就會生成四個相應的文件
話不多說嗜愈,直接上代碼

jk-dialog.json
json文件旧蛾,這里需要注意的就是component字段,聲明這個模塊是一個插件

{
  "component": true, //聲明組件
  "usingComponents": {}
}

jk-dialog.wxml
wxml文件蠕嫁,插件頁面文件锨天,這個分成三個部分,網(wǎng)絡加載框 選擇對話框 吐司對話框剃毒,分別用三個boolean變量控制顯隱

<view wx:if="{{showLoading}}" class="load-container">
    <image src="./img/loading.png"></image>
</view>

<view wx:if="{{showSelect}}" class="pop-container">
    <view class="delay-con column-center">
        <view class="delay-title">
            {{selectTip}}
        </view>
        <view class="delay-content column-center">
            <text>{{selectContent}}</text>
        </view>
        <view class="delay-bottom row-center">
            <view data-state="confirm" bindtap="hiddeenSelectDialog" style="border-right:1px solid #d6d6d6">{{confirmText}}</view>
            <view data-state="cancel" bindtap="hiddeenSelectDialog">{{cancelText}}</view>
        </view>
    </view>
</view>

<view wx:if="{{showToast}}" style="background: transparent;" class="load-container">
    <view class="toast-con">
        <text>{{toastContent}}</text>
    </view>
</view>

jk-dialog.wxss
wxss文件病袄,頁面樣式,其中用到了一些動畫效果赘阀,有想法的可以看看益缠,雖然我也是在網(wǎng)上找的代碼。??????

.load-container {
  pointer-events: auto;
  color: #000;
  font-size: 20px;
  z-index: 9999;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.3);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.load-container image {
  width: 50px;
  height: 50px;
  animation: loading-rotate 1s linear infinite;
}

@keyframes loading-rotate {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

.pop-container {
  pointer-events: auto;
  color: #000;
  font-size: 20px;
  z-index: 10;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.3);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.row-center {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
}

.delay-con {
  width: 80%;
  border-radius: 25rpx;
  background: white;
  font-size: 32rpx;
  margin-bottom: 200rpx;
  -webkit-animation: fadeleftIn .4s;
  animation: fadeleftIn .4s;
  -webkit-animation-name: popIn;
  animation-name: popIn;
}


.delay-title {
  padding-top: 30rpx;
  padding-bottom: 20rpx;
}

.column-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.delay-content {
  padding-bottom: 30rpx;
  line-height: 45rpx;
  text-align: center;
}

.delay-bottom {
  width: 100%;
  border-top: 1px solid #d6d6d6;
  color: #027bfe;
}

.delay-bottom view {
  width: 50%;
  padding-top: 25rpx;
  padding-bottom: 25rpx;
  text-align: center;
}

.toast-con {
  width: calc(85% - 60px);
  padding-top: 20px;
  padding-bottom: 20px;
  padding-left: 30px;
  padding-right: 30px;
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.8);
  margin-bottom: 200px;
  color: white;
  text-align: center;
  font-size: 17px;
  -webkit-animation: fadelogIn .2s;
  animation: fadelogIn .2s;
}

@-webkit-keyframes popIn {
  0% {
    -webkit-transform: scale3d(0, 0, 0);
    transform: scale3d(0.5, 0.5, 0.5);
    opacity: 0;
  }

  50% {
    -webkit-animation-timing-function: cubic-bezier(0.47, 0, 0.745, 0.715);
    animation-timing-function: cubic-bezier(0.47, 0, 0.745, 0.715);
  }

  100% {
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
    -webkit-animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
    animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
    opacity: 1;
  }
}

@keyframes popIn {
  0% {
    -webkit-transform: scale3d(0, 0, 0);
    transform: scale3d(0.5, 0.5, 0.5);
    opacity: 0;
  }

  50% {
    -webkit-animation-timing-function: cubic-bezier(0.47, 0, 0.745, 0.715);
    animation-timing-function: cubic-bezier(0.47, 0, 0.745, 0.715);
  }

  100% {
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
    -webkit-animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
    animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
    opacity: 1;
  }
}

@keyframes fadelogIn {
  0% {
    -webkit-transform: translate3d(0, 100%, 0);
    -webkit-transform: translate3d(0, 100%, 0);
    transform: translate3d(0, 100%, 0);
    transform: translate3d(0, 100%, 0);
  }

  100% {
    -webkit-transform: none;
    transform: none;
  }
}

@-webkit-keyframes fadelogIn {
  0% {
    -webkit-transform: translate3d(0, 100%, 0);
  }

  100% {
    -webkit-transform: none;
  }
}

jk-dialog.js
js文件基公,封裝了三個對話框的顯示隱藏

let systemInfo, selectCallBack;
import {
  selectLabel
} from './config'
Component({
  /**
   * 組件的屬性列表
   */
  properties: {
    toastText: {
      type: String,
    }
  },

  /**
   * 組件的初始數(shù)據(jù)
   */
  data: {
    statusBarHeight: 0,
    showLoading: false,
    showToast: false,
    toastContent: '',
    showSelect: false,
    selectTip: '提示',
    selectContent: '該操作不可逆\n是否繼續(xù)',
    confirmText: '確認',
    cancelText: '取消'
  },
  ready: function () {
    let that = this;
    that.initData();
  },
  /**
   * 組件的方法列表
   */
  methods: {
    /*用戶提示對話框
    \n表示換行
     */
    showToast: function (content, duration) {
      let that = this;
      that.setData({
        showLoading: false,
        showSelect: false,
        showToast: true,
        toastContent: content
      });
      let timer = setTimeout((res) => {
        that.setData({
          showToast: false,
        });
        clearTimeout(timer);
      }, duration == undefined ? 1500 : duration)
    },
    /* 展示自定義加載框
     */
    showLoading: function () {
      this.setData({
        showSelect: false,
        showToast: false,
        showLoading: true,
      })
    },
    /* 隱藏自定義加載框
     */
    hiddenLoading: function () {
      this.setData({
        showLoading: false,
      })
    },
    /* 初始化數(shù)據(jù)
     */
    initData: function () {
      let that = this;
      wx.getSystemInfo({
        success: function (res) {
          console.log(res, 'system');
          if (res.errMsg === 'getSystemInfo:ok') {
            that.setData({
              statusBarHeight: res.statusBarHeight
            });
            res.lang = res.language.indexOf('zh') !== -1 ? 'zh' : 'en';
            systemInfo = res;
          }
        },
      });
    },
    /* 展示選擇對話框
     */
    showSelectDailog: function (params, callBack) {
      let that = this;
      that.setData({
        showToast: false,
        showLoading: false,
        showSelect: true,
        selectTip: params.selectTip != undefined ? params.selectTip : selectLabel[systemInfo.lang]['selectTip'],
        selectContent: params.selectContent != undefined ? params.selectContent : selectLabel[systemInfo.lang]['content'],
        confirmText: params.confirmText != undefined ? params.confirmText : selectLabel[systemInfo.lang]['confirmText'],
        cancelText: params.cancelText != undefined ? params.cancelText : selectLabel[systemInfo.lang]['cancelText'],
      });
      selectCallBack = callBack;
    },

    hiddeenSelectDialog: function (e) {
      let that = this;
      that.setData({
        showSelect: false
      });
      selectCallBack(e.currentTarget.dataset.state);
    }
  }
})

基于插件相關(guān)功能Util類封裝(loadToastUtil)
插件頁面基本已經(jīng)好了幅慌,還差一個工具類,調(diào)用比較方便轰豆。
dialogUtil.js
我是直接封裝成了一個class類胰伍,在構(gòu)造方法中傳入小程序Page對象,baseUrl以及插件id,簡單暴露了一些方法供每一個頁面調(diào)用酸休。
需要注意的是小程序中的一個api selectComponent喇辽。
通過這個獲取到插件對象,以此來調(diào)用插件js文件中寫好的方法

const app = getApp();
export class jkDialogUtil {
  /* 
  構(gòu)造方法 
  that:page對象
  baseUrl:網(wǎng)絡請求基礎(chǔ)url
  loadToast:對應插件id
  */
  constructor(that, baseUrl, loadToast) {
    this.that = that;
    this.baseUrl = baseUrl;
    this.loadToast = that.selectComponent(loadToast);
    if (this.loadToast != null)
      console.log('插件加載成功');
    else
      console.log('插件加載失敗');
  }

  /*展示網(wǎng)絡加載框  */
  showLoading() {
    if (this.loadToast != null)
      this.loadToast.showLoading();
  }
  /*隱藏網(wǎng)絡加載框  */
  hiddenLoading() {
    if (this.loadToast != null)
      this.loadToast.hiddenLoading();
  }
  /**
   * 網(wǎng)絡請求
   *let params = {
              url: '/authorization/v1/token/decode',
              data: data,
              method: 'POST',
              isCommon: true,
              isLoad: true
            }
          successCallback:成功回調(diào)
          errorCallback:失敗回調(diào)
   */
  baseRequest(params, successCallback, errorCallback) {
    if (this.loadToast == null) {
      return;
    }
    let that = this;
    let realUrl = that.baseUrl + params.url;
    if (params.type == 'realUrl') {
      realUrl = params.realUrl;
    }
    if (params.isLoad) {
      that.loadToast.showLoading();
    };
    let token = wx.getStorageSync('accessToken');
    let header = {
      'Authorization': 'Bearer ' + token,
      'X-TrackingId': that.getXTrackingId() + ''
    };
    if (params.header != undefined) {
      header = Object.assign({}, params.header, header);
    }
    wx.request({
      url: realUrl,
      method: params.method,
      header: header,
      data: params.data,
      success: res => {
        if (params.isLoad) {
          that.loadToast.hiddenLoading();
        }
        if (res.data.responseCode === undefined) {
          that.baseToast('未知錯誤');
          return;
        }
        if (res.data.responseCode === -2) {
          wx.login({
            success: res => {
              jKLogin(res.code, function () {
                that.baseRequest(params, successCallback, errorCallback)
              })
            }
          });
          return;
        }
        if (!params.isCommon) {
          successCallback(res.data);
          return;
        }
        if (res.data.responseCode != undefined) {
          if (res.data.responseCode === 0) {
            successCallback(res.data.data);
            return;
          } else {
            that.baseToast(res.data.responseMessage);
            errorCallback == undefined ? '' : errorCallback(res.data);
          }

          return;
        }

        baseToast('未知錯誤');
      },
      error: res => {
        that.loadToast.hiddenLoading();
        console.log(res, 'error');
        that.baseToast('未知錯誤')

      }
    })

  }
  /*展示選擇對話框  */
  showSelectDialog(params, callBack) {
    if (this.loadToast != null)
      this.loadToast.showSelectDailog(params, callBack);
  }
  /* 展示吐司對話框 */
  showToast(content) {
    if (this.loadToast != null)
      this.loadToast.showToast(content);
  }
  baseToast(content) {
    wx.showToast({
      title: content,
      icon: 'none',
      duration: 3000
    })
  }

  getXTrackingId() {
    let chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    let XTrackingId = "";
    for (let i = 0; i < 32; i++) {
      let id = parseInt(Math.random() * 61);
      XTrackingId += chars[id];
    }
    return XTrackingId;
  }

}

源碼地址點我前往
總結(jié)(summary)
在工具類中其實還封裝了baseRequest的網(wǎng)絡請求方法雨席,大家可以按照具體需求自行修改菩咨。
沒bug 祝好運 ~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子抽米,更是在濱河造成了極大的恐慌特占,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件云茸,死亡現(xiàn)場離奇詭異是目,居然都是意外死亡,警方通過查閱死者的電腦和手機标捺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門懊纳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人亡容,你說我怎么就攤上這事嗤疯。” “怎么了闺兢?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵茂缚,是天一觀的道長。 經(jīng)常有香客問我屋谭,道長脚囊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任桐磁,我火速辦了婚禮悔耘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘我擂。我一直安慰自己淮逊,他們只是感情好,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布扶踊。 她就那樣靜靜地躺著,像睡著了一般郎任。 火紅的嫁衣襯著肌膚如雪秧耗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天舶治,我揣著相機與錄音分井,去河邊找鬼。 笑死霉猛,一個胖子當著我的面吹牛尺锚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惜浅,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼瘫辩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起伐厌,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤承绸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后挣轨,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體军熏,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年卷扮,在試婚紗的時候發(fā)現(xiàn)自己被綠了荡澎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡晤锹,死狀恐怖摩幔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抖甘,我是刑警寧澤热鞍,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站衔彻,受9級特大地震影響薇宠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜艰额,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一澄港、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柄沮,春花似錦回梧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拯欧,卻和暖如春详囤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背镐作。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工藏姐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人该贾。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓羔杨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親杨蛋。 傳聞我的和親對象是個殘疾皇子兜材,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容