1. 程式人生 > >縱橫開闔-微信小程式之通訊錄全攻略

縱橫開闔-微信小程式之通訊錄全攻略

Create by jsliang on 2018-11-21 20:46:36
Recently revised in 2018-11-25 00:24:14


Hello 小夥伴們,如果覺得本文還不錯,記得給個 star , 你們的 star 是我學習的動力!GitHub 地址


開篇點題
 這是一篇專研微信小程式各種功能實現的文章,例如佈局、通訊錄、元件之底部導航欄等……
 感覺不錯的小夥伴,點贊點 Star走一波;
 感覺文章有誤的小夥伴,評論區、QQ群 溜達一番。
 虛心求教,不勝感激~


專案成果圖


一 目錄

不折騰的前端,和鹹魚有什麼區別

文章篇幅甚多,請利用好目錄進行跳轉!

目錄
一 目錄
二 前言
三 功能列表
3.1 排兵佈陣 - Flex佈局
  3.1.1 樓起平地 - 基礎概念
  3.1.2 搭磚建瓦 - 左右佈局
  3.1.3 層臺累榭 - 混合佈局
3.2 沙場點兵 - 通訊錄
  3.2.1 謀定蒼生 - 整體佈局
  3.2.2 千里尋敵 - 搜尋功能
  3.2.3 遙控追蹤 - 底部導航
  3.2.4 拒敵長城 - 彈窗實現
  3.2.5 臥薪嚐膽 - 思路整理
  3.2.6 廣聚民心 - 新增功能
  3.2.7 化繁為簡 - 修改功能
  3.2.8 革新去舊 - 刪除功能
  3.2.9 兵分一路 - 正常載入
  3.2.10 兵分二路 - 拼音導航
  3.2.11 一統天下 - 歸納總結
四 專案地址

二 前言

返回目錄


 寫文章無形中也會磨鍊自己的表達能力。
 這周 (2018-11-19) 在開發微信小程式的定製 通訊錄 時,突然發現 微信小程式 bug 集中營 這篇文章不能再繼續寫了,因為它變得 臃腫醜陋難維護,就連我這個寫作人都感慨:如果沒有 Ctrl + F ,以及我的 目錄 寫得還不錯,我真心不想再翻這篇文章。
 為此,jsliang 單獨開了一篇文章:微信小程式功能清單。用來記錄小程式各種功能的實現,例如佈局、通訊錄、底部導航欄……
 然後嘛,為了能吸引小夥伴點進來瞅瞅,起個標新立異的標題吧:微信小程式之奇技淫巧


三 功能列表

返回目錄


 為了小夥伴能快速瞭解程式碼中的意思,小夥伴可以去該 專案地址 下載程式碼到本地執行檢視。

敲了再說

敲  看
一  一
遍  遍
?  ?
天  誰
差  都
地  可
別  以
!  !

 順帶附上一些資源網站:


3.1 排兵佈陣 - Flex佈局

返回目錄


 如果你發現你的 CSS 水平還處於 float 佈局,你會發現在小程式中你舉步維艱,因為單單隻用浮動佈局,在小程式中它不好用。
 所以,Flex 佈局,是你的不二選擇:佈局的傳統解決方案,基於盒狀模型,依賴 display 屬性 + position 屬性 + float 屬性。它對於那些特殊佈局非常不方便,比如,垂直居中就不容易實現。而 Flex 佈局。又稱彈性佈局,可以簡便、完整、響應式地實現各種頁面佈局。
 網上較好的教程有:

 如果你想全面瞭解 Flex,推薦去看上面的文章。
 如果你已經瞭解 Flex 佈局,點選 返回目錄 尋找更多精彩!
 如果你想快速複習瀏覽 Flex 佈局,那麼,Here we go~

Flex 最終實現效果:


3.1.1 樓起平地 - 基礎概念

返回目錄


 萬丈高樓平地起,熟悉 Flex 需要先了解下面這 7CSS 屬性:

/* 設定 Flex 模式 */
display: flex;

/* 決定元素是橫排還是豎著排,要不要倒序 */
flex-direction: column;

/* 決定元素換行格式,一行排不下的時候如何排 */
flex-wrap: wrap;

/* flex-flow = flex-direction + flex-wrap */
flex-flow: column wrap;

/* 同一排下對齊方式,空格如何隔開各個元素 */
justify-content: space-between;

/* 同一排下元素如何對齊,頂部對齊、中部對齊還是其他 */
align-items: center;

/* 多行對齊方式 */
align-content: space-between;
複製程式碼

 下面我們詳細分析這些元素的情況:

  1. flex-direction:決定主軸的方向
  • row - (預設)水平方向,起點在左端
  • row-reverse - 水平方向,起點在右端
  • column - 垂直方向,起點在上沿
  • column-reverse - 垂直方向,起點在下沿
display: flex;

flex-direction: row | row-reverse | column | column-reverse;
複製程式碼


  1. flex-wrap:一條軸線(一行)排不下時如何解決
  • nowrap - (預設)不換行
  • warp - 換行,第一行在上方
  • wrap-reverse - 換行,第一行在下方
display: flex;

flex-wrap: nowrap | wrap | wrap-reverse;  
複製程式碼


  1. flex-flow:flex-flow = flex-direction + flex-wrap。即 flex-flow 是這兩個屬性的合集
  • row nowrap - (預設)水平方向,起點在左端,不換行
display: flex;

flex-flow: <flex-direction> || <flex-wrap>;
複製程式碼

 詳解參考 12


  1. ustify-content:定義專案在主軸上的對齊方式
  • flex-start - 左邊對齊
  • flex-end - 右邊對齊
  • center - 居中對齊
  • space-between - 兩端對齊,空格在中間
  • space-around - 空格環繞
display: flex;

justify-content: flex-start | flex-end | center | space-between | space-around;
複製程式碼


  1. align-items:定義專案在交叉軸上如何對齊
  • flex-start - 頂部對齊,即文字圖片等頂部同一條線上
  • flex-end - 底部對其,即文字圖片等底部在同一條線上
  • center - 中間對其,即文字圖片不管多高,都拿它們的中間放在同一條線上
  • stretch - 將文字圖片充滿整個容器的高度,強制統一
  • baseline - 將每項的第一行文字做統一在一條線上對齊
display: flex;

align-items: flex-start | flex-end | center | stretch | baseline;
複製程式碼


  1. align-content:定義多根軸線的對齊方式。如果只有一根軸線(只有一行),該屬性不起作用
  • flex-start - 這幾行頂部對齊
  • flex-end - 這幾行底部對齊
  • center - 這幾行居中對齊
  • stretch - 這幾行進行擴充套件或者縮放,從而填滿容器高
  • space-between - 這幾行中間使用空格進行填充
  • space-around - 這幾行兩邊及中間進行填充
display: flex;

align-content: flex-start | flex-end | center | space-between | space-around | stretch;
複製程式碼


3.1.2 搭磚建瓦 - 左右佈局

返回目錄

 實現效果如下:

 如圖,這是我們要實現的左右佈局效果。那麼,在微信小程式要怎麼做呢?

*.wxml

<view class="left-and-right-layout">
  <view class="left-and-right-layout-floor-one">
    <text>左右佈局</text>
  </view>
  <view class="left-and-right-layout-floor-two">
    <text class="left-and-right-layout-floor-two-left">GitHub 地址</text>
    <navigator class="left-and-right-layout-floor-two-right" url="https://github.com/LiangJunrong/document-library/blob/master/other-library/WeChatApplet/WeChatAppletFunctionList.md">檢視詳情</navigator>
  </view>
</view>
複製程式碼

*.wxss

.left-and-right-layout {
  padding: 0 30rpx;
}

.left-and-right-layout-floor-one {
  font-size: 32rpx;
  line-height: 32rpx;
  font-weight: bold;
}

.left-and-right-layout-floor-two {
  /* Flex 左右佈局關鍵點 */
  display: flex;
  justify-content: space-between;

  padding: 30rpx 0;
  font-size: 30rpx;
  line-height: 30rpx;
  border-bottom: 1rpx solid #ccc;
}

.left-and-right-layout-floor-two-right {
  color: deepskyblue;
}
複製程式碼

3.1.3 層臺累榭 - 混合佈局

返回目錄

 實現效果如下:

 如圖,這是我們要實現的混合佈局效果,那麼在微信小程式中要如何程式設計呢?

*.wxml

<view class="mixed-layout">
  <view class="mixed-layout-floor-one">
    <text>混合佈局</text>
  </view>
  <view class="mixed-layout-floor-two">
    <view class="mixed-layout-floor-two-left">
      <text class="mixed-layout-floor-two-left-title">微信小程式之奇技淫巧</text>
      <text class="mixed-layout-floor-two-left-author" url="https://github.com/LiangJunrong/document-library/blob/master/other-library/WeChatApplet/WeChatAppletFunctionList.md">作者:jsliang</text>
    </view>
    <view class="mixed-layout-floor-two-right">
      <navigator>檢視詳情</navigator>
    </view>
  </view>
  <view class="mixed-layout-floor-three">
    <text>這是一篇專研小程式各種功能實現的文章,例如佈局、通訊錄、底部導航欄……如果你感覺不錯,可以點贊點 Star;如果感覺有錯,那就評論區溜達一番,虛心求教,不勝感激~ </text>
  </view>
  <view class="mixed-layout-floor-four">
    <text>2018-11-23</text>
    <text>2018閱讀</text>
    <text class="mixed-layout-floor-four-classification">#小程式功能清單#</text>
  </view>
</view>
複製程式碼

*.wxss


/* 混合佈局 */

/* 混合佈局包裹層 */
.mixed-layout {
  margin-top: 30rpx;
  padding: 0 30rpx 30rpx;
}

/* 混合佈局第一層 */
.mixed-layout-floor-one {
  font-size: 32rpx;
  line-height: 32rpx;
  font-weight: bold;
}

/* 混合佈局第二層 */
.mixed-layout-floor-two {
  /* 關鍵 Flex 佈局 */
  display: flex;
  justify-content: space-between;
  align-items: center;

  margin-top: 40rpx;
  font-size: 32rpx;
  border-bottom: 1rpx dotted #ccc;
}
.mixed-layout-floor-two-left {
  /* 左側豎行排序 */
  display: flex;
  flex-direction: column;
}
.mixed-layout-floor-two-left-title {
  font-weight: bold;
}
.mixed-layout-floor-two-left-author {
  margin-top: 10rpx;
  color: rgb(146, 138, 138);
  font-size: 30rpx;
}
.mixed-layout-floor-two-right {
  color: deepskyblue;
}

/* 混合佈局第三層 */
.mixed-layout-floor-three {
  margin-top: 20rpx;
  font-size: 30rpx;
  line-height: 36rpx;
  color: rgb(110, 108, 108);
  text-indent: 1em;
}

/* 混合佈局第四層 */
.mixed-layout-floor-four {
  /* 關鍵 Flex 佈局 */
  display: flex;
  justify-content: space-between;

  margin-top: 20rpx;
  font-size: 30rpx;
  line-height: 30rpx;
}
.mixed-layout-floor-four-classification {
  color: #d0a763;
}
複製程式碼

3.2 沙場點兵 - 通訊錄

返回目錄


 不知道小夥伴們在日常開發中,有沒有碰到各種稀奇古怪的功能效果,我們覺得不可思議,但是在專案經理的眼中它卻是能 “滿足客戶需求” 的。
 所以,拿到 “奇怪的” 需求清單的時候不要恐慌,我們仔細分析,總能找到它的破綻,從而完成我們的任務。

 通訊錄功能的開發如下:
 開發時間:4 天
 實現效果:


3.2.1 謀定蒼生 - 整體佈局

返回目錄


 工欲善其事,必先利其器。

首先,我們先將該頁面命名為:addressList,並編寫它的 json 門面:

addressList.json

{
  "backgroundTextStyle": "light",
  "navigationBarBackgroundColor": "#fff",
  "navigationBarTitleText": "通訊錄",
  "navigationBarTextStyle": "black"
}
複製程式碼

接著,我們明確需要實現的功能點:

  • 搜尋功能
  • 彈窗新增功能
  • 彈窗修改功能
  • 刪除功能
  • 拼音導航功能
  • 底部導航欄

然後,我們明確下頁面佈局:

 如上圖,它主要分三大塊:頭部、內容區、底部。
最後,我們根據功能實現及頁面佈局編寫 wxml 的佈局:

wxml 骨架

<!-- part1 - 搜尋區域 -->
<view class="search"></view>

<!-- part2 - 搜尋結果 -->
<view class="search-result"></view>

<!-- part3 - 內容區域 -->
<view class="contacts-list"></view>

<!-- part4 - 拼音導航 -->
<view class="pinyin-nav"></view>

<!-- part5 - 底部導航 -->
<view class="bottom-nav"></view>

<!-- part6 - 新增彈窗 -->
<view class="add-prompt"></view>

<!-- part7 - 修改彈窗 -->
<view class="edit-prompt"></view>
複製程式碼

 如上,我們將頁面分為 7 種情況,其中:

  • 搜尋功能 - part1part2part4part5
  • 彈窗新增功能 - part1part3part4part5part6
  • 彈窗修改功能 - part1part3part4part5part7
  • 刪除功能 - part1part3part4part5
  • 拼音導航功能 - part1part3part4part5
  • 底部導航欄 - part1part3part4part5

 請注意,出現的 part 部分表明在這種模式下,頁面要顯示的 part 都有哪些,其他的則暫時隱藏,而加粗的意味著這是這個功能特有的部分。為此,我們應該在 jsdata 中定義好這些模式:

js 程式碼片段

Page({
  data: {
    /**
     * 功能模式
     * normalModel - 正常模式
     * addModel - 新增模式
     * editModel - 修改模式
     * deleteModel - 刪除模式
     * searchModel - 搜尋模式
     * pinyinNavModel - 拼音導航模式
     */
    normalModel: false,
    addModel: false,
    editModel: false,
    deleteModel: false,
    searchModel: true,
    pinyinNavModel: false,
  }
})
複製程式碼

 這樣,我們除了底部導航欄外,為其他功能定義了一個模式,正常情況下我們開啟 normalModel,其他暫時關閉。
 在下文中,我們將根據模式的開啟與關閉,顯示/隱藏某些內容,並進行資料的管理,請小夥伴們稍微理解下這種思路。


3.2.2 千里尋敵 - 搜尋功能

返回目錄


 本章節實現效果:


 實現思路、編碼及程式碼講解:

addressList.wxml

  1. wxmlwxss 結構上。

首先,我們通過 fixed 定位,將 search-form 固定在頂部。
然後,我們將 search-form 其內部分為 搜尋區 search功能區 action
接著,我們將 search 分為 假的搜尋區 search-model-one真的搜尋區 search-model-two。為什麼要分兩種情況呢?因為這樣我們就不用煩惱 inputplaceholder 一會居中一會靠邊要怎麼區分,思路不容易亂。
最後,根據功能,我們逐步完善 wxmlwxss程式碼。

返回本節開頭

<!-- part1 - 搜尋區域 -->
<view class="search-form">
  <!-- 搜尋區 -->
  <view class="search">
    <!-- 假的搜尋框 -->
    <view wx:if="{{!searchModel}}" class="search-model search-model-one" bindtap="showSearch">
      <image class="icon" src="../../public/img/icon_search.png"></image>
      <text class="search-model-one-text">搜尋</text>
    </view>
    <!-- 真的搜尋框 -->
    <view wx:if="{{searchModel}}" class="search-model search-model-two">
      <image class="icon search-model-two-icon" src="../../public/img/icon_search.png"></image>
      <!-- 多加層 view 的作用是做到 × 的定位作用 -->
      <view class="search-model-two-form">
        <input type="text" class="search-model-two-input" placeholder="搜尋" focus="{{inputFocus}}" value="{{searchVal}}" bindinput="monitorInputVal"></input>
        <text wx:if="{{searchVal.length > 0}}" class="clear-input" bindtap="clearInput">×</text>
      </view>
      <text wx:if="{{searchVal.length <= 0}}" class="search-model-two-button search-model-two-button-cancel" bindtap="showSearch">取消</text>
      <text wx:if="{{searchVal.length > 0}}" class="search-model-two-button search-model-two-button-submit" bindtap="searchSubmit">搜尋</text>
    </view>
  </view>
  <!-- 功能區 -->
  <view class="action">
    <text class="action-button action-add" bindtap="showAdd">新增</text>
    <text wx:if="{{!deleteModel}}" class="action-button action-delete" bindtap="showDelete">刪除</text>
    <text wx:if="{{deleteModel}}" class="action-button action-delete-comfirm" bindtap="showDelete">完成</text>
  </view>
</view>

<!-- part2 - 搜尋結果 -->
<view wx:if="{{searchModel}}" class="search-result">
  <view class="search-result-item" wx:for="{{searchData}}" wx:key="{{searchData.index}}">
    <view class="search-result-item-left">
      <text class="search-result-item-left-name">{{item.userName}}</text>
      <text class="search-result-item-left-phone">{{item.userPhone}}</text>
    </view>
    <view class="search-result-item-right">
      <image class="icon search-result-item-right-edit" src="../../public/img/icon_edit.png"></image>
      <image wx:if="{{deleteModel}}" class="icon search-result-item-right-delete" src="../../public/img/icon_delete.png"></image>
    </view>
  </view>
</view>
複製程式碼

addressList.wxss

返回本節開頭

/* 全域性樣式 */
view {
  box-sizing: border-box;
}
.icon {
  width: 32rpx;
  height: 32rpx;
}

/* 搜尋區域 */
.search-form {
  display: flex;
  justify-content: space-around;
  width: 100%;
  height: 100rpx;
  font-size: 32rpx;
  padding: 0 30rpx;
  /* 絕對定位 - 固定搜尋部分 */
  position: fixed;
  top: 0;
  left: 0;
  background: #fff;
}

/* 搜尋區域 - 結構 1 */
.search {
 width: 60%; 
}
.search-model {
  height: 70rpx;
  line-height: 50rpx;
  padding: 10rpx 0;
}
.search-model-one {
  margin: 15rpx 0;
  background: #f5f5f5;
  text-align: center;
  border-radius: 50rpx;
}
.search-model-one-text {
  margin-left: 30rpx;
  color: #9b9b9b;
  font-size: 30rpx;
}
.search-model-two {
  position: relative;
  display: flex;
  margin-top: 6rpx;
}
.search-model-two-icon {
  position: absolute;
  left: 20rpx;
  top: 30rpx;
  z-index: 10;
}
.search-model-two-form {
  width: 69%;
  height: 70rpx;
  background: #f5f5f5;
  position: relative;
}
.search-model-two-input {
  padding: 0 65rpx 0 65rpx;
  height: 70rpx;
  font-size: 30rpx;
}
.clear-input {
  position: absolute;
  right: 10rpx;
  top: 15rpx;
  display: inline-block;
  width: 30rpx;
  height: 30rpx;
  line-height: 30rpx;
  text-align: center;
  padding: 5rpx;
  color: #fff;
  background: #ccc;
  border-radius: 20rpx;
  z-index: 10;
}
.search-model-two-button {
  display: inline-block;
  text-align: center;
  width: 90rpx;
  height: 60rpx;
  line-height: 60rpx;
  font-size: 24rpx;
  padding: 5rpx 15rpx;
  margin-left: 10rpx;
  color: #fff;
}
.search-model-two-button-cancel {
  background: rgb(8, 202, 186);
}
.search-model-two-button-submit {
  background: rgb(8, 200, 248);
}

/* 搜尋區域 - 結構2 */
.action {
  width: 39%;
}
.action-button {
  display: inline-block;
  text-align: center;
  width: 90rpx;
  height: 60rpx;
  line-height: 60rpx;
  font-size: 24rpx;
  margin-top: 15rpx;
  padding: 5rpx 15rpx;
  border: 1rpx solid deepskyblue;
  border-radius: 40rpx;
}
.action-add, .action-delete, .action-delete-comfirm {
  margin-left: 10rpx;
}
.action-delete-comfirm {
  color: #d0a763;
  border: 1rpx solid #d0a763;
}

/* 搜尋結果 */
.search-result {
  margin-top: 100rpx;
}
.search-result-item {
  box-sizing: border-box;
  height: 120rpx;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 27rpx 60rpx 27rpx 30rpx;
  border-bottom: 1rpx solid #f3f3f3;
}
.search-result-item-left {
  display: flex;
  flex-direction: column;
}
.search-result-item-left-name {
  font-size: 30rpx;
  color: #333333;
}
.search-result-item-left-phone {
  font-size: 26rpx;
  color: #999999;
}
.search-result-item-right image {
  width: 32rpx;
  height: 32rpx;
}
.search-result-item-right-edit {
  margin-right: 30rpx;
}
.search-result-item-right-delete {
  margin-right: 30rpx;
}
複製程式碼

addressList.js

  1. js上。

 我們仔細觀察本節開頭的 GIF 圖,發現它有這幾個特點:

  • 點選假的搜尋區,進入真的搜尋區
  • 輸入內容,按鈕由【取消】變為【搜尋】
  • 點選【搜尋】按鈕,頁面顯示搜尋內容
  • 上拉載入更多資料
  • 點選 × 按鈕,輸入內容消失
  • 點選【取消】按鈕,關閉搜尋頁面

返回本節開頭

Page({

  /**
   * 頁面的初始資料
   */
  data: {
    /**
     * 功能模式
     * normalModel - 正常模式
     * addModel - 新增模式
     * editModel - 修改模式
     * deleteModel - 刪除模式
     * searchModel - 搜尋模式
     * pinyinNavModel - 拼音導航模式
     */
    normalModel: true,
    addModel: false,
    editModel: false,
    deleteModel: false,
    searchModel: false,
    pinyinNavModel: false,

    /**
     * 搜尋功能
     * inputFocus - 搜尋框聚焦
     * searchVal - 搜尋內容
     * searchData - 搜尋結果
     */
    inputFocus: false,
    searchVal: '',
    searchData: [],
  },

  /**
   * 搜尋功能
   * showSearch - 顯示搜尋框
   * monitorInputVal - 監聽搜尋框的值
   * searchSubmit - 提交搜尋
   * clearInput - 清除搜尋
   */
  showSearch(e) {
    this.setData({
      normalModel: !this.data.normalModel,
      searchModel: !this.data.searchModel,
      searchData: [],
      inputFocus: true
    })
  },
  monitorInputVal(e) {
    this.setData({
      searchVal: e.detail.value
    })
  },
  searchSubmit(e) {
    console.log("\n【API - 確認搜尋】");
    console.log("搜素欄位:" + this.data.searchVal);
    
    // 原資料
    let searchData = this.data.searchData;

    // 搜尋資料 - 假設搜尋資料是這個,實際應該是介面返回資料
    let newSearchData = [
      {
        userName: '阿狸',
        userPhone: '18811111111',
        pinyin: 'ali'
      },
      {
        userName: '貝吉塔',
        userPhone: '18822222222',
        pinyin: 'beijita'
      },
      {
        userName: '楚怡',
        userPhone: '18833333333',
        pinyin: 'chuyi'
      },
      {
        userName: '鄧婕',
        userPhone: '18844444444',
        pinyin: 'dengjie'
      },
      {
        userName: '爾康',
        userPhone: '18855555555',
        pinyin: 'erkang'
      },
      {
        userName: '福狸',
        userPhone: '18866666666',
        pinyin: 'fuli'
      },
      {
        userName: '古狸',
        userPhone: '18877777777',
        pinyin: 'guli'
      },
      {
        userName: '哈狸',
        userPhone: '18888888888',
        pinyin: 'hali'
      },
      {
        userName: 'i狸',
        userPhone: '18899999999',
        pinyin: 'ili'
      },
      {
        userName: '激狸',
        userPhone: '18800000000',
        pinyin: 'jli'
      },
    ]

    // 拼接新舊資料
    searchData.push(...newSearchData);

    console.log("\搜尋後資料:");
    console.log(searchData);

    this.setData({
      searchData: searchData
    })

  },
  clearInput(e) {
    console.log("\n清除搜尋");
    this.setData({
      searchVal: ''
    })
  },

  /**
   * 刪除功能
   */
  showDelete(e) {
    this.setData({
      deleteModel: !this.data.deleteModel
    })
  },

  /**
   * 生命週期函式--監聽頁面載入
   */
  onLoad: function (options) {
    console.log("\n通訊錄");
  },

  /**
   * 頁面上拉觸底事件的處理函式
   */
  onReachBottom: function () {
    if (this.data.normalModel) { // 正常模式上拉
      console.log("\n正常模式上拉")
    } else if (this.data.searchModel) { // 搜尋模式上拉

      console.log("\n搜尋模式上拉:");

      // 新資料
      let newSearchData = [
        {
          userName: '克狸',
          userPhone: '18811121112',
          pinyin: 'keli'
        },
      ]

      // 原資料
      let searchData = this.data.searchData;

      // 拼接新舊資料
      searchData.push(...newSearchData);

      console.log("\上拉載入後資料:");
      console.log(searchData);

      this.setData({
        searchData: searchData
      })

    } else if (this.data.pinyinNavModel) { // 拼音模式上拉
      console.log("\n拼音模式上拉");
    }
  },
})
複製程式碼

 到此,我們就實現了搜尋功能。儘管它還有點小 bug,就是不停上拉的時候,它會重複地載入一條資料。
 在實際專案中,jsliang 會定義一個 searchNoData 來判斷介面是否還在返回資料,如果它不再返回資料,那麼通過判斷 searchNoData == true 來禁止繼續載入。
 這樣,我們就完美搞定了搜尋功能的實現。


3.2.3 遙控追蹤 - 底部導航

返回目錄


 本章節實現效果:

 眾所周知,微信小程式的子頁面(除了設定 tabBar 的頁面)是沒有底部導航欄的。那麼,我們要如何設計,才能編寫一個 自定義的底部導航欄 呢?
 在日常開發中,我們通過 fixed 佈局,在頁面實現一個 自定義的底部導航欄 是很容易的。
 但是,考慮到其他頁面可能也需要使用這個底部導航欄,我們就需要想辦法將其封裝成元件了:

 微信小程式 - 自定義元件

 是的,微信小程式官方文件中是存在這個東西的。當然,僅有官方文件,是滿足不了我的,至於過程中我百度了幾篇文章來輔助寫出下面的程式碼,你猜?

 下面貼出實現程式碼及如何使用:

  1. 建立目錄。

首先,在根目錄中新建 component 目錄,用來存放我們專案的元件。
然後,我們新建 navBar 目錄,用來存放我們的元件 navBar
最後,我們新建 ComponentnavBar


  1. 進行元件程式碼編寫。

navBar.wxml

返回本節開頭

<!-- 底部導航條 -->
<view class="navBar">
  <!-- 首頁 -->
  <view class="navBar-item navBar-home" bindtap='goHome'>
    <image wx:if="{{homeActive}}" src="../../public/img/tabBar_home.png"></image>
    <image wx:if="{{!homeActive}}" src="../../public/img/tabBar_home_nor.png"></image>
    <text class="{{homeActive ? 'active-text' : 'nor-active-text'}}">首頁</text>
  </view>
  <!-- 探索 -->
  <view class="navBar-item navBar-explore" bindtap='goExplore'>
    <image wx:if="{{exploreActive}}" src="../../public/img/tabBar_explore.png"></image>
    <image wx:if="{{!exploreActive}}" src="../../public/img/tabBar_explore_nor.png"></image>
    <text class="{{exploreActive ? 'active-text' : 'nor-active-text'}}">探索</text>
  </view>
  <!-- 我的 -->
  <view class="navBar-item navBar-user" bindtap='goUser'>
    <image wx:if="{{userActive}}" src="../../public/img/tabBar_user.png"></image>
    <image wx:if="{{!userActive}}" src="../../public/img/tabBar_user_nor.png"></image>
    <text class="{{userActive ? 'active-text' : 'nor-active-text'}}">我的</text>
  </view>
</view>
複製程式碼

navBar.wxss

返回本節開頭

/* 底部導航條 */
.navBar {
  display: flex;
  justify-content: space-around;
  box-sizing: border-box;
  width: 100%;
  height: 97rpx;
  padding: 5rpx 0;
  border-top: 1rpx solid #cccccc;
  position: fixed;
  bottom: 0;
  background: #F7F7FA;
}
.navBar image {
  width: 55rpx;
  height: 55rpx;
}
.navBar-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-size: 20rpx;
  color: #999999;
}
.nor-active-text {
  padding-top: 5rpx;
}
.active-text {
  padding-top: 5rpx;
  color: #d0a763;
}
複製程式碼

navBar.js

返回本節開頭

Component({
  /**
   * 元件的屬性列表
   */
  properties: {
    homeActive: {
      type: Boolean,
      value: false
    },
    exploreActive: {
      type: Boolean,
      value: false
    },
    userActive: {
      type: Boolean,
      value: false
    }
  },

  /**
   * 元件的初始資料
   */
  data: {

  },

  /**
   * 元件的方法列表
   */
  methods: {
    // 返回首頁
    goHome: function (e) {
      wx.switchTab({
        url: '../index/index',
      })
    },
    // 返回探索頁
    goExplore: function (e) {
      wx.switchTab({
        url: '../explore/explore',
      })
    },
    // 返回我的
    goUser: function (e) {
      wx.switchTab({
        url: '../user/user',
      })
    }
  }
})
複製程式碼

navBar.json

返回本節開頭

{
  "component": true,
  "usingComponents": {}
}
複製程式碼

  1. 在需要引用的介面引用該元件

addressList.wxml

<!-- part5 - 底部導航 -->
<view class="bottom-nav">
  <navBar homeActive="{{homeActive}}"></navBar>
</view>
複製程式碼

addressList.json

{
  "backgroundTextStyle": "light",
  "navigationBarBackgroundColor": "#fff",
  "navigationBarTitleText": "通訊錄",
  "navigationBarTextStyle": "black",
  "usingComponents": {
    "navBar": "../../component/navBar/navBar"
  }
}
複製程式碼

addressList.js

Page({
  data: {
    // 引用底部導航
    homeActive: true,
  }
})
複製程式碼

 下次我們還需使用該底部導航欄的時候,我們只需要重複在 addressList 的步驟就行了。
 當然,我們需要根據需要活躍的位置,進行 homeActiveexploreActiveuserActive 這三個活躍狀態與否的設定。
 這樣,我們就實現了底部導航欄元件的開發及引用。


3.2.4 拒敵長城 - 彈窗實現

返回目錄


 本章節實現效果:


 彈窗?微信小程式就有啊,為啥不用它的呢?

型別 說明 地址
模態彈窗 wx.showModal(Object) - 模態彈窗可以給你選擇【取消】或者【確定】 連結
<modal> <modal>是可以提供使用者填寫 連結
訊息彈窗 wx.showToast(Object) - 訊息彈窗就是操作成功或者操作失敗的那一刻,系統的提示彈窗,無需使用者操作,可設定幾秒自動關閉 連結
操作選單 wx.showActionSheet(Object) - 操作選單類似於彈出的下拉選單,提供你選擇其中某項或者【取消】 連結

 然而,逐一嘗試,你會發現,上面辣麼多彈窗,沒有一種符合你的需求的!所以,咱要畫一個屬於自己的彈窗:

首先,咱在 part6 中新增兩個層:遮罩層 jsliang-mask 和彈窗內容 jsliang-alert
然後,往彈窗內容中編寫我們需要的標題、 input 輸入框以及 text 按鈕。
最後,我們逐一細化編寫程式碼。

addressList.wxml

返回本節開頭

<!-- part6 - 新增彈窗 -->
<view wx:if="{{addModel}}" class="add-prompt">
  <!-- 遮罩層 -->
  <view class="jsliang-mask" bindtap='showAdd'></view>
  <!-- 彈窗內容 -->
  <view class="jsliang-alert">
    <!-- 標題 -->
    <view class="jsliang-alert-title">
      <text>新增成員</text>
      <text class="jsliang-alert-title-close" bindtap='showAdd'>×</text>
    </view>
    <!-- 輸入內容 -->
    <view class="jsliang-alert-content">
      <input type="text" placeholder='請輸入姓名' placeholder-class='jsliang-alert-content-user-name-placeholder'></input>
      <input type="text" placeholder='請輸入電話號碼' placeholder-class='jsliang-alert-content-user-phone-placeholder'></input>
    </view>
    <!-- 確定 -->
    <view class="jsliang-alert-submit">
      <text bindtap='addConfirm'>新增</text>
    </view>
  </view>
</view>
複製程式碼

addressList.wxss

返回本節開頭

/* 彈窗-新增成員 */
.jsliang-mask {
  z-index: 998;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: #404040;
  filter: alpha(opacity=90);
  -ms-filter: "alpha(opacity=90)";
  opacity: 0.9;
}
.jsliang-alert {
  z-index: 999;
  position: fixed;
  top: 15%;
  left: 9%;
  width: 620rpx;
  height: 580rpx;
  box-shadow: 2rpx 2rpx 4rpx #A0A0A0, -2rpx -2rpx 4rpx #A0A0A0;
  background-color: #fff;
  border-radius: 15rpx;
}

/* 彈窗標題 */
.jsliang-alert-title {
  height: 120rpx;
  line-height: 120rpx;
  color: #333333;
  background: #f8f0e3;
  font-size: 40rpx;
  font-weight: bold;
  text-align: center;
  position: relative;
  border-radius: 15rpx;
}
.jsliang-alert-title-close {
  display: inline-block;
  color: #999999;
  position: absolute;
  font-size: 50rpx;
  right: 40rpx;
}
/* 彈窗內容 */
.jsliang-alert-content {
  padding: 0 70rpx;
}
.jsliang-alert-content input {
  height: 120rpx;
  line-height: 120rpx;
  font-size: 30rpx;
  border-bottom: 1rpx solid #e6e6e6;
}
.jsliang-alert-content-user-name-placeholder, .jsliang-alert-content-user-phone-placeholder {
  font-size: 30rpx;
  color: #b6b6b6;
}
.jsliang-alert-content-user-phone {
  color: rgb(238, 227, 227);
}
.jsliang-alert-submit {
  font-size: 30rpx;
  margin: 60rpx auto;
  text-align: center;
  width: 400rpx;
  height: 90rpx;
  line-height: 90rpx;
  color: #fff;
  background: deepskyblue;
  border-radius: 50rpx;
}
複製程式碼

 這樣,我們就可以通過控制 addModeltrue 或者 false,來顯示隱藏新增彈窗。
 同理,我們可以依法炮製通過 editModel 控制修改彈窗。


3.2.5 臥薪嚐膽 - 思路整理

返回目錄


 文章寫到這裡,我們需要整理下我們都完成了什麼,還缺什麼?


 如上,我們實現了:

  • 搜尋功能
  • 底部導航
  • 彈窗顯示

 那麼,我們還缺少:

  • 新增成員功能
  • 修改成員功能
  • 刪除成員功能
  • 拼音導航功能

 很好!我們實現了一半功能了!但是,小夥伴有沒有發現,我們的主內容區是空白的。
 所以,為了剩下的功能實現,我們應該編寫下 內容區域,並進行頁面的資料載入:

addressList.wxml

返回本節開頭

<!-- part3 - 內容區域 -->
<view class="contacts-list">
  <!-- 每組字母資料 -->
  <view class="contacts-item" wx:for="{{contactsData}}" wx:for-item="contactsDataItem" wx:key="{{contactsDataItem.index}}">
    <!-- 字母標題 -->
    <view wx:if="{{!contactsDataItem.users.length < 1}}" class="contacts-list-title">
      <text>{{contactsDataItem.groupName}}</text>
    </view>
    <!-- 該組字母的成員 -->
    <view class="contacts-list-user" wx:for="{{contactsDataItem.users}}" wx:for-item="usersItem" wx:key="{{usersItem.index}}">
      <!-- 成員資訊展示 -->
      <view class="contacts-list-user-left">
        <text class="contacts-list-user-left-name">{{usersItem.userName}}</text>
        <text class="contacts-list-user-left-phone">{{usersItem.userPhone}}</text>
      </view>
      <!-- 成員操作 -->
      <view class="contacts-list-user-right">
        <image class="icon contacts-list-user-right-edit" src="../../public/img/icon_edit.png"></image>
        <image wx:if="{{deleteModel}}" class="icon contacts-list-user-right-delete" src="../../public/img/icon_delete.png"></image>
      </view>
    </view>
  </view>
</view>

            
           

相關推薦

縱橫-程式通訊錄

Create by jsliang on 2018-11-21 20:46:36 Recently revised in 2018-11-25 00:24:14  Hello 小夥伴們,如果覺得本文還不錯,記得給個 star , 你們的 star 是我學習的動力!GitHub 地址  開

程式物流狀態時間軸

一個月左右沒更新部落格了,最近有點懶了哈(工作上真的忙),很多工作上學習到的東西都沒有及時分享出來,有點愧疚,不過自己最近一直在收集資料和學習一些新技術,最主要是想要構建自己的前端技術體系和自定義一個前端規範文件,哈哈哈。說重點啦,微信小程式裡面開發的商城模組還挺多的,剛好寫了一個物流狀態的時間軸,簡單分享一

程式登陸 —— 程式教程系列(20)

簡介: 微信登陸,在新建一個微信小程式Hello World專案的時候,就可以看到專案中出現了我們的微信頭像,其實這個Hello World專案,就有一個簡化版的微信登陸。只不過是,還沒有寫入到咱們自家的後臺中而已。 新建一個Hello World專案,找到a

程式swiper限制迴圈滑動

最近接的一個單子是使用swiper來達到頁面之間完美滑動的效果的。也就三個頁面首頁、內容頁、尾頁。 但是客戶要求首頁不能滑到尾頁,尾頁不能滑到首頁。 在官方文件中沒有找到方法,因此只能繞彎路了。  wxml頁面程式碼:重點在於 current='{{show_index}}'

11.程式canvas生成圖片並儲存到手機

在小程式中,會有這樣一種需求,儲存某一個頁面並將其分享到朋友圈。一般的做法是:將這個頁面用canvas繪製出來,通過wx.canvasToTempFilePath,把當前畫布指定區域的內容匯出生成指定大小的圖片。然後再通過wx.saveImageToPhotosAlbum,儲存圖片到系統相簿。由

程式介面互動反饋

互動反饋就是在使用者觸發某事件之後,給使用者一個反饋資訊。 在小程式中是通過以下幾種方式實現的: 1.wx.showToast()方法 showToast: function (postscollected, postcollected) {

程式側邊欄滑動實現(附完整原始碼)

目錄 一、效果圖 二、原理解析 三、原始碼 四、專案下載 同類文章推薦: 更多幹貨關注公眾號: 一、效果圖 講什麼都不如直接上效果圖好,所以我們先來看下實現效果如何。 通過滑動螢幕,或者點選左上角的圖示按鈕,都能實現側邊欄的劃出效果。   &nb

Android 分享程式圖片優化

      小菜上週接入了微信分享小程式的入口,基本功能實現都沒問題,有需要的朋友可以瞭解一下 Android 分享微信小程式失敗二三事,雖然功能都正常,但整體測試發現圖片展示效果不佳。於是小菜整理了一個簡單的小方法處理一下圖片!  

程式踩坑textarea 元件的 bug

微信小程式公測也有段時間了,但是裡面的坑踩了一個又一個,心也是夠累的。本文說說關於 textarea 元件的 bug。(注:本文提及的 bug,至少在 2016-12-1日還存在) 上一篇:微信小程式之踩坑之旅一,wx.request 和 wx.uploadFile 測試時使用到:

程式:雲開發初體驗--致我的第一個程式

背景:一直關注微信小程式的發展,看著小程式一步步完善,一步步壯大,心裡癢癢,也想做一個自己的微信小程式,但是苦於只會前端,不會服務端,所以想法一直被卡著。現在小程式有了雲開發,很輕鬆實現後端功能,寫後端跟寫前端沒啥區別,真的是前端小夥伴們的福音啊。 經過幾個晚上的熬夜奮戰,我的第一個微信小程式正式

程式1--頁面跳轉錯誤

而檢視app.json的時候,是正常的,頁面寫進入了app.json. 那麼就只能是url的問題了, 先看一下目錄: 這時候寫的跳轉url為,當前頁面為login,由login 頁面跳轉mailList頁面 url: '../usion/mailList/mailList',

程式事件繫結冒泡

事件繫結格式: bind+evnetType catch+eventType 假如存在三個view盒子,分別為outer(bindtap=""),middle(catchtap),inner(bindtap); 1:當點選inner盒子的時候,inner,middle盒子繫結的函式會

程式canvas畫圖生成圖片下載

要實現的功能:點選朋友圈按鈕彈出分享圖片:點選儲存分享圖片儲存到手機實現程式碼:1.分享按鈕點選事件 /** * 分享 */ weixinShare:function(){ var that = this; console.log(111); share.canvas

程式view動態佈局

wxml <view class='main'> <view wx:for="{{long}}" wx:key="*this" class='items'> <view class='il'>{{item[0].acmonth}}</

程式父子間元件傳參

1.建立元件 開啟微信開發者工具,建立元件,會生成四個檔案:wxml,wxss,js,json 在wxml中: <view>我是元件A</view> 在js中: Component({ behaviors: [], properti

程式地理位置授權 wx.getLocation

1. 授權地理位置 點選按鈕,彈出授權彈窗,點選允許後,在以後的操作中可以隨時獲取到使用者地理位置 點選拒絕後,將無法獲取到地理位置,也無法再次點選彈出彈窗。 <button bindtap='onAuthLocation' >授權位置</button> onAut

程式使用者資訊授權 wx.getUserInfo

使用者授權 <button open-type="getUserInfo" bindgetuserinfo='getUser'>授權使用者資訊</button> getUser(e) { console.log(e); wx.getUserInfo({

程式路由

1. 路由方式 路由方式 觸發時機 路由前頁面 路由後頁面 初始化 小程式開啟的第一個頁面 onLoad, onShow 開啟新頁面 呼叫 API wx.naviga

程式快取——不同頁面傳遞資料

1. 新增快取 單個金鑰允許儲存的最大資料長度為1MB,所有資料儲存上限為10MB。 // 儲存資訊到storage // 非同步儲存 set() { wx.setStorage({ key: 'user', data: 'cck', succe

程式 動畫 —— 自定義底部彈出層

wxml: <view class='buy' bindtap='showBuyModal'>立即購買</view> <!-- 點選立即購買 彈出購買遮罩層 --> <view class="cover_screen" bindtap="hideBuyModal"