午夜91福利视频,午夜成人在线观看,午夜在线视频免费观看,午夜福利短视频,精品午夜成人免费视频APP

小程序模板網

小程序選人控件 - 仿企業微信實現多層級無規則嵌套

發布時間:2018-10-30 14:34 所屬欄目:小程序開發教程

 在很多系(xi)統中都(dou)有選(xuan)擇聯系(xi)人的(de)需求,市面上(shang)也沒什么好的(de)參照(zhao),產(chan)品(pin)經理看(kan)企業微信的(de)選(xuan)人挺好用的(de),就說參照(zhao)這個(ge)(ge)做一個(ge)(ge)吧。。。

 

 

 算了(le),還是試著做吧,企業微信的選人的確做的挺好,不得不佩(pei)服。

先看看效果(guo)圖吧,多層級無規律的嵌(qian)套都能(neng)搞定

 

 

一、設計解讀

 

 

整個界面分為三部分:

  • 最上面的返回上一層按鈕
  • 中間的顯示部門、人員的列表
  • 最下面顯示和操作已選人員的 footer。

為(wei)什么加一(yi)個返(fan)回上一(yi)層(ceng)按(an)鈕呢(ni)?

我也覺得比較丑,但小程(cheng)序無法直接控制左(zuo)(zuo)上角返回鍵(jian)(自定義(yi) Title 貌似可以,沒(mei)試過),點左(zuo)(zuo)上角的返回箭頭(tou)的話就(jiu)退(tui)出選(xuan)人控件(jian)到上個頁面了。

我們的(de)需(xu)求是(shi)點(dian)擊一個(ge)文件夾,通過刷新當前列表(biao)進入下(xia)一級目(mu)錄,感(gan)覺像是(shi)又(you)進了一個(ge)頁面,但其實并沒有,只(zhi)是(shi)列表(biao)的(de)數據變化了。由(you)此實現不定層級、無規律的(de)部門(men)和人員(yuan)嵌套的(de)支(zhi)持。

比如先點擊了首屏數(shu)據的(de)第二個(ge) item,它的(de) index 是 1 ,就將 1 存入 indexList ;返回(hui)上一層(ceng)時將最后一個(ge)元(yuan)素刪除。

當(dang)(dang)勾選(xuan)了某個人或部(bu)門(men)時(shi),會在底部(bu)的(de)框中顯示所(suo)有已選(xuan)人員或部(bu)門(men)的(de)名字(zi),當(dang)(dang)文字(zi)超過屏幕(mu)寬度時(shi)可(ke)以向(xiang)右無限滑動,底部(bu) footer 始終保持(chi)一(yi)行。

最(zui)終選擇的(de)人(ren)以底部 footer 里顯示的(de)為準,點擊確定時根(gen)據業務(wu)需要(yao)將(jiang)已選人(ren)員數(shu)據發(fa)送給(gei)需要(yao)的(de)界面(mian)。

二、功能邏輯分析

先看(kan)看(kan)數據格式

{
  id: TEACHER_ID,
  name: '教師',
  parentId: '',
  checked: false,
  isPeople: false,
  children: [
    {
      id: TEACHER_DEPARTMENT_ID,
      name: '部門',
      parentId: 'teacher',
      checked: false,
      isPeople: false,
      children: []
    },
    {
      id: TEACHER_SUBJECT_ID,
      name: '學科',
      parentId: 'teacher',
      checked: false,
      isPeople: false,
      children: []
    },
    {
      id: TEACHER_GRADECLASS_ID,
      name: '年級班級',
      parentId: 'teacher',
      checked: false,
      isPeople: false,
      children: []
    },
  ]
}

所(suo)有(you)的數據(ju)組成一個數據(ju)樹,子節點嵌(qian)套在父節點下。

 id, name 不說了,parentId 指明它(ta)的父節點,children 包含它(ta)的所有子節點,checked 用(yong)來判斷(duan)勾選狀態,isPeople 判斷(duan)是(shi)部(bu)門還(huan)是(shi)人(ren)員,因為兩者(zhe)的圖(tu)標(biao)不一樣。

注意:

本控件采用了數(shu)(shu)據(ju)分(fen)步加(jia)載(zai)(zai)(zai)的(de)(de)(de)模式,除了最上層固定的(de)(de)(de)幾個(ge)分(fen)類,其他的(de)(de)(de)每層數(shu)(shu)據(ju)都是點擊具體(ti)的(de)(de)(de)部門后才去(qu)請求服務器加(jia)載(zai)(zai)(zai)本部門下(xia)的(de)(de)(de)數(shu)(shu)據(ju)的(de)(de)(de),然后再(zai)拼接(jie)到原始數(shu)(shu)據(ju)樹上。這(zhe)樣可以提高加(jia)載(zai)(zai)(zai)速(su)度,提升用戶(hu)體(ti)驗。

我(wo)也試了一次性把所(suo)有(you)數據都拉下(xia)來,一是(shi)太(tai)慢,得三五秒,二(er)是(shi)數據量太(tai)大的話(我(wo)這里應該(gai)是(shi)超過1000,閾值多少沒測過),setData() 的時(shi)候(hou)就會報(bao)錯(cuo):

 

 

超過最大長度了。。。所以只(zhi)能分步加載數(shu)據。

當然如果你(ni)的數據量小,幾(ji)十人或(huo)幾(ji)百人,也可以選(xuan)擇一次性加載。

這個控件邏輯(ji)上還是比較復雜(za)的,要(yao)(yao)考慮(lv)的細節太(tai)多……下(xia)面梳(shu)理一(yi)下(xia)主要(yao)(yao)的邏輯(ji)點

主要邏輯點

1. 需要一個數組存儲所有被點擊的部門在當前列表的索引 index ,這里用 indexList 表示

點擊(ji)某個(ge)(ge)部門進入下一(yi)層目錄時,將被點擊(ji)部門的 index 索引 push 進 indexList 中。點擊(ji)返回上(shang)一(yi)層按鈕時,刪除 indexList 中最后一(yi)個(ge)(ge)元(yuan)素(su)。

2. 要動態的更新當前列表 currentList

每進(jin)入新的(de)一(yi)層(ceng),或(huo)返回上一(yi)層(ceng),都(dou)需要刷新 currentList 來實現頁面的(de)更新。知道下(xia)一(yi)層(ceng)數據很容易(yi),直接取被點擊 item 的(de) children 賦值給 currentList 即可。

但如何(he)還原上一層的(de)數據呢?

第一點記錄的(de) indexList 就發揮作(zuo)用了(le),原始數據樹為 originalList,循環遍歷 indexList ,根據索引依(yi)次取(qu)出(chu)每層(ceng)的(de) currentList 直(zhi)到 indexList 的(de)最后一個元素,就得到了(le)返(fan)回(hui)上一層(ceng)需要顯示的(de)數據。

3. 每一次勾選或取消選中都要更新原始的數據樹 originalList

頁面是根(gen)據每個(ge) item 的(de)(de) checked 屬性判斷是否選中的(de)(de),所以(yi)每次改變勾選狀態都要設置被(bei)改變的(de)(de) item 的(de)(de) checked 屬性,然后更(geng)新(xin)(xin) originalList。這樣即使返回上一層了,再進到當前層級選中狀態還會(hui)被(bei)保(bao)留(liu),否則(ze)刷新(xin)(xin) currentList 后已選狀態將(jiang)丟失。

4. 列表中選擇狀態的改變與底部 footer 的雙聯動

我們期望的(de)效果是,選中(zhong)currentList 列表的(de)某一項,底部 footer 會(hui)自動添加被選人的(de)名字(zi)。取消選中(zhong),底部 footer 也會(hui)自動刪除。

也可(ke)以通過 footer 來刪(shan)除已選人,點擊 footer 中(zhong)人名(ming),會將此(ci)人從(cong)已選列(lie)表中(zhong)刪(shan)除,currentList 列(lie)表中(zhong)也會自動取(qu)消勾選狀態。

嗯,這個功能(neng)比較(jiao)耗性(xing)能(neng),每(mei)一次都需(xu)要大量的計算。考(kao)慮到性(xing)能(neng)和速度因素,本(ben)次只做了從 footer 刪除只更新 currentList 的勾選(xuan)狀態(tai)。

什(shen)么(me)意思呢?假如有(you)兩(liang)層(ceng),A 和 B,B 是(shi)(shi) A 的(de)下一層(ceng)數據,即 A 是(shi)(shi) B 的(de)父節點(dian)。在 A 中(zhong)(zhong)選中(zhong)(zhong)了(le)一個(ge)部(bu)門 校(xiao)長(chang)室(shi),點(dian)擊下一層(ceng)到 B,在 B 中(zhong)(zhong)又選了(le)兩(liang)個(ge)人 張(zhang)三(san)(san) 和 李(li)四,這(zhe)時(shi)(shi)底部(bu) footer 里顯示的(de)應該(gai)是(shi)(shi)三(san)(san)個(ge): 校(xiao)長(chang)室(shi)、 張(zhang)三(san)(san) 、 李(li)四。此時(shi)(shi)點(dian)擊 footer 的(de) 張(zhang)三(san)(san) , footer 會(hui)把(ba)(ba) 張(zhang)三(san)(san) 刪除(chu),中(zhong)(zhong)間列表中(zhong)(zhong) 張(zhang)三(san)(san) 會(hui)被置為(wei)未(wei)選中(zhong)(zhong)狀態,這(zhe)沒問題。但點(dian)擊 footer 的(de) 校(xiao)長(chang)室(shi) , 在 footer 中(zhong)(zhong)是(shi)(shi)把(ba)(ba) 校(xiao)長(chang)室(shi) 刪除(chu)了(le),但再(zai)返(fan)回到上一層(ceng)時(shi)(shi),中(zhong)(zhong)間列表中(zhong)(zhong)的(de) 校(xiao)長(chang)室(shi) 依然是(shi)(shi)勾(gou)選狀態,因為(wei)此時(shi)(shi)沒有(you)更新原始數據樹(shu) originalList。如果(guo)覺得這(zhe)是(shi)(shi)個(ge) bug, 可(ke)以加個(ge)更新 originalList 的(de)操(cao)作。這(zhe)樣(yang)就要(yao)遍歷 originalList 的(de)每個(ge)元(yuan)素判斷與(yu)本次刪除(chu)的(de) id 是(shi)(shi)否相等,然后(hou)改變(bian) checked 值,如果(guo)數據量很大,會(hui)非常慢。我(wo)做了(le)妥協……

關鍵的邏(luo)輯就這四塊了(le),當(dang)然還有(you)很多小細節,直接看代(dai)碼吧(ba),注釋寫的也比較詳細。

三、代碼

目(mu)錄結(jie)構:

 

 

footer 文(wen)件夾下(xia)是抽離出的 footer 組件,userSelect 是選人控件的主要(yao)邏輯。把這幾個文(wen)件復制過去就可以用(yong)了。

把 userSelect.js 里網絡請(qing)求(qiu)的(de)代碼替換為你的(de)請(qing)求(qiu)代碼,注意數據的(de)字段名是(shi)否一致。

userSelect 的代碼

userSelect.js


import API from '../../../utils/API.js'
import ArrayUtils from '../../../utils/ArrayUtils.js'
import EventBus from '../../../components/NotificationCenter/WxNotificationCenter.js'

let TEACHER_ID = 'teacher';
let TEACHER_DEPARTMENT_ID = 't_department';
let TEACHER_SUBJECT_ID = 't_subject';
let TEACHER_GRADECLASS_ID = 't_gradeclass';
let STUDENT_ID = 'student';
let PARENT_ID = 'parent'

let TEACHER = {
  id: TEACHER_ID,
  name: '教師',
  parentId: '',
  checked: false,
  isPeople: false,
  children: [
    {
      id: TEACHER_DEPARTMENT_ID,
      name: '部門',
      parentId: 'teacher',
      checked: false,
      isPeople: false,
      children: []
    },
    {
      id: TEACHER_SUBJECT_ID,
      name: '學科',
      parentId: 'teacher',
      checked: false,
      isPeople: false,
      children: []
    },
    {
      id: TEACHER_GRADECLASS_ID,
      name: '年級班級',
      parentId: 'teacher',
      checked: false,
      isPeople: false,
      children: []
    },
  ]
}
let STUDENT = {
  id: STUDENT_ID,
  name: '學生',
  parentId: '',
  checked: false,
  isPeople: false,
  children: []
}
let PARENT = {
  id: PARENT_ID,
  name: '家長',
  parentId: '',
  checked: false,
  isPeople: false,
  children: []
}
let ORIGINAL_DATA = [
  TEACHER, STUDENT, PARENT
]

Page({
  data: {
    currentList: [], //當前展示的列表
    selectList: [],  //已選擇的元素列表
    originalList: [], //最原始的數據列表
    indexList: [],  //存儲目錄層級的數組,用于準確的返回上一層
    selectList: [],  //已選中的人員列表
  },

  onLoad: function (options) {
    wx.setNavigationBarTitle({
      title: '選人控件'
    })
    this.init();
  },

  init(){
    //用戶的單位id
    this.unitId = getApp().globalData.userInfo.unitId;
    //用戶類型
    this.userType = 0;
    //上次選中的列表,用于判斷是不是取消選中了
    this.lastTimeSelect = []

    this.setData({
      currentList: ORIGINAL_DATA, //當前展示的列表
      originalList: ORIGINAL_DATA, //最原始的數據列表
    })
  },

  clickItem(res){
    console.log(res)
    let index = res.currentTarget.id;
    let item = this.data.currentList[index]

    console.log("item", item)

    if (!item.isPeople) {
      //點擊教師,下一層數據是寫死的,不用請求接口
      if (item.id === TEACHER_ID) {
        this.userType = 2;
        this.setData({
          currentList: item.children
        })
      } else if (item.id === TEACHER_SUBJECT_ID) {
        if (item.children.length === 0){
          this._getTeacherSubjectData()
        }else{
          //children的長度不為0時,更新 currentList
          this.setData({
            currentList: item.children
          })
        }
      } else if (item.id === TEACHER_DEPARTMENT_ID) {
        if (item.children.length === 0) {
          this._getTeacherDepartmentData()
        } else {
          //children的長度不為0時,更新 currentList
          this.setData({
            currentList: item.children
          })
        }
      } else if (item.id === TEACHER_GRADECLASS_ID) {
        if (item.children.length === 0) {
          this._getTeacherGradeClassData()
        } else {
          //children的長度不為0時,更新 currentList
          this.setData({
            currentList: item.children
          })
        }
      } else if (item.id === STUDENT_ID) {
        this.userType = 1;
        if (item.children.length === 0) {
          this._getStudentGradeClassData()
        } else {
          //children的長度不為0時,更新 currentList
          this.setData({
            currentList: item.children
          })
        }
      } else if (item.id === PARENT_ID) {
        this.userType = 3;
        if (item.children.length === 0) {
          this._getParentGradeClassData()
        } else {
          //children的長度不為0時,更新 currentList
          this.setData({
            currentList: item.children
          })
        }
      } else{
        //children的長度為0時,請求服務器
        if(item.children.length === 0){
          this._getUserByGroup(item)
        }else{
          //children的長度不為0時,更新 currentList
          this.setData({
            currentList: item.children
          })
        }
      }

      //將當前的索引存入索引目錄中。索引多一個表示目錄多一級
      let indexes = this.data.indexList
      indexes.push(index)
      //是目錄不是具體的用戶
      this.setData({
        indexList: indexes
      })
      //清空上次選中的元素列表,并設置上一層的選中狀態給lastTimeSelect
      this.setLastTimeSelectList();
    }
  },


  //返回按鈕
  goBack() {
    let indexList = this.data.indexList
    if (indexList.length > 0) {
      //返回時刪掉最后一個索引
      indexList.pop()
      if (indexList.length == 0) {
        //indexList長度為0說明回到了最頂層
        this.setData({
          currentList: this.data.originalList,
          indexList: indexList
        })
      } else {
        //循環將當前索引的對應數組賦值給currentList
        let list = this.data.originalList
        for (let i = 0; i < indexList.length; i++) {
          let index = indexList[i]
          list = list[index].children
        }
        this.setData({
          currentList: list,
          indexList: indexList
        })
      }
      //清空上次選中的元素列表,并設置上一層的選中狀態給lastTimeSelect
      this.setLastTimeSelectList();
    }
  },

  //清空上次選中的元素列表,并設置上一層的選中狀態給lastTimeSelect
  setLastTimeSelectList(){
    this.lastTimeSelect = []
    this.data.currentList.forEach(item => {
      if (item.checked) {
        this.lastTimeSelect.push(item)
      }
    })
  },

  //獲取教師部門數據
  _getTeacherDepartmentData() {
    this._commonRequestMethod(2, 'department')
  },

  //請求教師的學科數據
  _getTeacherSubjectData(){
    this._commonRequestMethod(2, 'subject')
  },

  //請求教師的年級班級
  _getTeacherGradeClassData() {
    this._commonRequestMethod(2, 'gradeclass')
  },

  //請求學生的年級班級
  _getStudentGradeClassData() {
    this._commonRequestMethod(1, 'gradeclass')
  },

  //請求家長的年級班級
  _getParentGradeClassData() {
    this._commonRequestMethod(3, 'gradeclass')
  },

  //根據部門查詢人
  _getUserByGroup(item){
    let params = {
      userType: this.userType,
      unitId: this.unitId,
      groupType: item.type,
      groupId: item.id
    }
    console.log('params', params)
    getApp().get(API.selectUserByGroup(), params, result => {
      console.log('result', result)
      let list = this.transformData(result.data.data, item.id)
      this.setData({
        currentList: list
      })
      this.addList2DataTree()
      //清空上次選中的元素列表,并設置上一層的選中狀態給lastTimeSelect。寫在這里防止異步請求時執行順序問題
      this.setLastTimeSelectList();
    })
  },

  //通用的請求部門方法
  _commonRequestMethod(userType, groupType){
    wx.showLoading({
      title: '',
    })
    let params = {
      userType: userType,
      unitId: this.unitId,
      groupType: groupType
    }
    console.log('params', params)
    getApp().get(API.selectUsersByUserGroupsTree(), params, result => {
      console.log('result', result)
      wx.hideLoading()
      let data = result.data.data
      this.setData({
        currentList: data
      })
      this.addList2DataTree();
      //清空上次選中的元素列表,并設置上一層的選中狀態給lastTimeSelect。寫在這里防止異步請求時執行順序問題
      this.setLastTimeSelectList();
    })
  },

  //將請求的數據轉化為需要的格式
  transformData(list, parentId){
    //先將數據轉化為固定的格式
    let newList = []
    for(let i=0; i<list.length; i++){
      let item = list[i]
      newList.push({
        id: item.id,
        name: item.realName,
        parentId: parentId,
        checked: false,
        isPeople: true,
        userType: item.userType,
        gender: item.gender,
        children: []
      })
    }
    return newList;
  },

  //將當前列表掛載在原數據樹上, 目前支持5層目錄,如需更多接著往下寫就好
  addList2DataTree(){
    let currentList = this.data.currentList;
    let originalList = this.data.originalList;
    let indexes = this.data.indexList
    switch (indexes.length){
      case 1: 
        originalList[indexes[0]].children = currentList
        break;
      case 2:
        originalList[indexes[0]].children[indexes[1]].children = currentList
        break;
      case 3:
        originalList[indexes[0]].children[indexes[1]].children[indexes[2]].children = currentList
        break;
      case 4:
        originalList[indexes[0]].children[indexes[1]].children[indexes[2]].children[indexes[3]].children = currentList
        break;
      case 5:
        originalList[indexes[0]].children[indexes[1]].children[indexes[2]].children[indexes[3]].children[indexes[4]].children = currentList
        break;
    }

    this.setData({
      originalList: originalList
    })
    console.log("originalList", originalList)
  },

  //選框變化回調
  checkChange(res){
    console.log(res)
    let values = res.detail.value
    let selectItems = []
    //將值取出拼接成 id,name 格式
    values.forEach(value => {
      let arrs = value.split(",")
      selectItems.push({id: arrs[0], name: arrs[1]})
    })
    console.log("selectItems", selectItems)
    console.log("lastTimeSelect", this.lastTimeSelect)
    
    //將本次選擇的與上次選擇的比對,本次比上次多說明新增了,本次比上次少說明刪除了,找出被刪除的那條數據,在footer中也刪除
    if (selectItems.length > this.lastTimeSelect.length){
      //將 selectList 與 selectItems 拼接并去重
      let newList = this.data.selectList.concat(selectItems)
      newList = ArrayUtils.checkRepeat(newList)
      this.setData({
        selectList: newList
      })
    }else{
      //找出取消勾選的item,從selectList中刪除
      //比對出取消勾選的是哪個元素
      let diffItem = {}
      this.lastTimeSelect.forEach(item => {
        let flag = false;
        selectItems.forEach(item2 => {
          if(item.id === item2.id){
            flag = true
          }
        })
        if(!flag){
          diffItem = item
          console.log("diff=", item)
        }
      })
      //找出被刪除的元素在 selectList 中的位置
      let list = this.data.selectList
      let delIndex = 0;
      for(let i=0; i<list.length; i++){
        if (list[i].id === diffItem.id){
          delIndex = i;
          break;
        }
      }
      //從list中刪除這個元素
      list.splice(delIndex, 1)
      this.setData({
        selectList: list
      })
    }
    console.log("selectList", this.data.selectList)
    //更新 currentList 選中狀態并重新掛載在數據樹上,以保存選擇狀態
    this.updateCurrentList(this.data.currentList, this.data.selectList)
  },

  //footer點擊刪除回調
  footerDelete(res){
    console.log(res)
    this.setData({
      selectList: res.detail.selectList
    })

    console.log('selectList', this.data.selectList)
    this.updateCurrentList(this.data.currentList, res.detail.selectList)
  },

  //點擊 footer 的確定按鈕提交數據
  submitData(res){
    let selectList = this.data.selectList
    //通過 WxNotificationCenter 發送選擇的結果通知
    EventBus.postNotificationName("SelectPeopleDone", selectList)
    //將選擇結果存入 app.js 的 globalData
    getApp().globalData.selectPeopleList = selectList
    //返回
    wx.navigateBack({
      delta: 1
    })
    console.log("selectdone", selectList)
  },

  //更新 currentList 并將更新后的列表掛載在數據樹上
  updateCurrentList(currentList, selectList){
    let newList = []
    currentList.forEach(item => {
      let flag = false;
      selectList.forEach(item2 => {
        if (item.id === item2.id) {
          flag = true
        }
      })
      if (flag) {
        item.checked = true
      } else {
        item.checked = false
      }
      newList.push(item)
    })
    this.setData({
      currentList: newList
    })
    this.addList2DataTree()
    this.setLastTimeSelectList()
  }
})
復制代碼

userSelect.wxml

<view class='container'>
  <view class='btn-wrapper'>
    <button bindtap='goBack'>返回上一層</button>
  </view>

  <view class='people-wrapper'>
    <scroll-view scroll-y class='scrollview'>
      <checkbox-group bindchange="checkChange">
        <view class='item' wx:for='{{currentList}}' wx:key='{{item.id}}'>
          <checkbox checked='{{item.checked}}' value='{{item.id + "," + item.name}}'>
          </checkbox>
          <view id='{{index}}' class='item-content' bindtap='clickItem'>
            <image class='img' wx:if='{{!item.isPeople}}' src='../../../assets/file.png'></image>
            <image class='avatar' wx:if='{{item.isPeople}}' src='../../../assets/avatar.png'></image>
            <text class='itemtext'>{{item.name}}</text>
          </view>
        </view>
      </checkbox-group>
      <view class='no-data' wx:if='{{currentList.length===0}}'>暫無數據</view>
    </scroll-view>
  </view>
  <view class='footer'>
    <footer list='{{selectList}}' binddelete='footerDelete' bindsubmit="submitData"/>
  </view>
</view>
復制代碼
userSelect.wxss

.container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  padding: 20rpx;
  overflow-x: hidden;
  box-sizing: border-box;
  background-color: #fff;
}

.btn-wrapper {
  width: 100%;
  padding: 0 20rpx;
  box-sizing: border-box;
}

.btn {
  font-size: 24rpx;
  width: 100%;
}

.people-wrapper {
  width: 100%;
  margin-top: 10rpx;
  margin-bottom: 100rpx;
}

.scrollview {
  width: 100%;
  display: flex;
  flex-direction: column;
}

.item {
  width: 100%;
  display: flex;
  flex-direction: row;
  align-items: center;
  padding: 30rpx 0;
  margin: 0 20rpx;
  border-bottom: 1rpx solid rgba(7, 17, 27, 0.1);
}

.item-content {
  width: 100%;
  display: flex;
  flex-direction: row;
  align-items: center;
  margin-left: 20rpx;
}

.itemtext {
  font-size: 36rpx;
  color: #333;
  margin-left: 20rpx;
  text-align: center;
}

.img {
  width: 50rpx;
  height: 40rpx;
}

.avatar {
  width: 50rpx;
  height: 50rpx;
}

.footer {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
}

.no-data{
  width: 100%;
  font-size: 32rpx;
  text-align: center;
  padding: 40rpx 0;
}

userSelect.json

{
  "usingComponents": {
    "footer": "footer/footer"
  }
}

footer 的代碼

footer.js


Component({
  /**
   * 組件的屬性列表
   */
  properties: {
    list: {
      type: Array
    }
  },

  /**
   * 組件的初始數據
   */
  data: {
    
  },

  /**
   * 組件的方法列表
   */
  methods: {
    delete(res){
      console.log(res)
      let index = res.currentTarget.id
      let list = this.data.list
      list.splice(index,1)
      this.setData({list: list})
      this.triggerEvent("delete", {selectList: list})
    },

    /**
     * 點擊確定按鈕
     */
    confirm(){
      this.triggerEvent("submit", "")
    }
  }
})
復制代碼

footer.wxml

<view class='container'>
  <view class='scroll-wrapper'>
    <scroll-view scroll-x style='scroll'>
      <text id='{{index}}' class='text' wx:for='{{list}}' wx:key='{{index}}' bindtap='delete'>{{item.name}}</text>
    </scroll-view>
  </view>
  <text class='btn' bindtap='confirm'>確定</text>
</view>

footer.wxss

.container {
  width: 100%;
  height: 100rpx;
  display: flex;
  flex-direction: row;
  padding: 20rpx;
  box-sizing: border-box;
  background-color: #fff;
  align-items: center;
  overflow-x: hidden;
  white-space: nowrap;
  border-top: 2rpx solid rgba(7, 17, 27, 0.1)
}

.scroll-wrapper {
  flex: 1;
  overflow-x: hidden;
  white-space: nowrap;
}

.scroll {
  width: 100%;

}

.text {
  font-size: 32rpx;
  color: #333;
  padding: 40rpx 20rpx;
  margin-right: 10rpx;
  background-color: #f5f5f5;
}

.btn {
  padding: 10rpx 20rpx;
  background-color: rgb(26, 173, 25);
  border-radius: 10rpx;
  font-size: 32rpx;
  color: #fff;
}
復制代碼

footer.json

{
  "component": true,
  "usingComponents": {}
}
復制代碼

再補一(yi)個用到的 ArrayUtils 的代碼

export default{

  /**
     * 給數組去重
     */
  checkRepeat(list) {
    let noRepList = [list[0]]
    for (let i = 0; i < list.length; i++) {
      let repeat = false
      for (let j = 0; j < noRepList.length; j++) {
        if (noRepList[j].id === list[i].id) {
          repeat = true
          break
        }
      }
      if (!repeat) {
        noRepList.push(list[i])
      }
    }
    return noRepList
  },

  //刪除list中id為 delId 的元素
  deleteItemById(list, delId){
    for (let i = 0; i < list.length; i++) {
      if (list[i].id == delId) {
        list.splice(i, 1)
        return list;
      }
    }
    return list;
  }

}
復制代碼

由于時間(jian)緊張,還(huan)沒有把(ba)這(zhe)個控件單獨從項目(mu)中抽出來寫個 Demo,有時間(jian)了會給 github 地址的。

代碼(ma)還(huan)有很多可以(yi)優化的(de)地方,比(bi)如有幾個方法太長(chang)了(le),不符合單一(yi)職責(ze)原則等等,不想改(gai)了(le),以(yi)后再優化吧。。

水(shui)平(ping)有限,各(ge)位(wei)大俠請輕噴~

有問(wen)題或(huo)發(fa)現 Bug 請(qing)在評論區留言(yan),畢竟剛寫完就(jiu)分享(xiang)出(chu)來了,還沒經過(guo)嚴格(ge)的測試(shi)。不過(guo)應該沒什么大的問(wen)題。。。有些細節可能沒注意到。



易優小程序(企業版)+靈活api+前后代碼開源(yuan) 碼云倉庫:
本文地址://www.jinyoudianli.com/wxmini/doc/course/24921.html 復制鏈接 如需定(ding)制請聯系易優客服咨詢:

工作日 8:30-12:00 14:30-18:00
周六及部分(fen)節假(jia)日提(ti)供值班服務

易小優(you)
轉人工 ×