写点什么

使用 APICloud AVM 多端框架开发 app 通讯录功能

作者:APICloud
  • 2022 年 3 月 22 日
  • 本文字数:2941 字

    阅读完需:约 10 分钟

一、效果展示



二、项目结构图


三、数据结构图

1、​服务端的原始好友数据结构​

2、​按字母分类排序后的好友数据结构​

3、​字母导航数据结构​

四、功能实现的思路

​​本项目基于 APICloud AVM 框架编写,因此思路要转变下比如标签的用法、CSS 样式表的写法、项目的目录结构、dom 的操作等都不一样了,完全是 Vue、React 的编程思维。​​


​​微信通讯录功能是将所有联系人根据字母首字拼音排序分类,单击右边字母滑动到相应字母分组编。本项目的核心功能是对数据按首字母进行排序,页面布局可以按照微信的布局进行设计,由于涉及到页面滚动以及、滚动到指定位置,因此我们可以选用 scroll-view 组件。​​

​​本项目的页面布局结构图如下​​


​​注意​​​scroll-view 组建必须设置高度否者不能正常显示,高度计算公式如下:​​

​​高度=页面窗口高度--状态栏高度--顶部导航高度--自定义 tab-bar 高度​​

​​代码如下​​

let top = 0;if (api.safeArea) {  top = api.safeArea.top;} else {  let res = wx.getSystemInfoSync();  top = res.statusBarHeight;}this.list_h = api.winHeight - top - 44 - 53;
复制代码


​​​nav-bar 和 tab-bar 是自定义的所以知道它的高度分别是 44 和 53px​​

​​scroll-view 组件完整属性如下​​

<scroll-view id="list" :show-scrollbar='false' :bounces='true' style={'height:'+list_h+'px'}>
复制代码

​​接下来讲解核心功能好友数据结构的转换,从服务端拿到的好友数据一般是没有按字母排序和分类的格式如下​​

[{    "id": "1",    "nick_name": "杨洋",    "avatar": "../../res/avatar/tx7.jpg" },  {    "id": "2",    "nick_name": "666",    "avatar": "../../res/avatar/tx8.jpg"}]
复制代码

​​转换后的数据格式如下​​

[{  "letter": "A",  "hasData": true,  "users": [{  "name": "abc1209",  "unicode": 97,  "avatar": "../../res/avatar/tx14.jpg",  "id": "14"  }]}, {   "letter": "B",   "hasData": false,   "users": []  }, {   "letter": "#",   "hasData": true,   "users": [{   "name": "17115719973",   "unicode": 49,   "avatar": "../../res/avatar/tx1.jpg",   "id": "1"   }]}]
复制代码

​​转换的原理就是提取 nick_name 字段第一个字符串获取拼音字母以及 unicode 码然后分组排序需要参照 pinyin 码表,网上可以下载,我这里重新封装了一下。​​


​​定义变量​​


​​用到的方法如下​​

init() {    this.initName();    this.NameIndex();},initName() {    const letterArr = this.data.letter;    for (let index = 0; index < letterArr.length; index++) {        this.data.handleData.push({            letter: letterArr[index].letter,            hasData: false,            users: []        });    }},NameIndex() {    const that = this;    for (let i = 0; i < that.data.list.length; i++) {        const NameLetter = that.getLetter(that.data.list[i].nick_name).firstletter;        const unicode = that.getLetter(that.data.list[i].nick_name).unicode;        const index = that.indexPosition(NameLetter);        if (that.data.nameIndex.indexOf(NameLetter) == -1) {            that.data.handleData[index].hasData = true;            that.data.nameIndex.push(NameLetter);        }        that.data.handleData[index].users.push({            name: that.data.list[i].nick_name,            unicode: unicode,            avatar: that.data.list[i].avatar,            id: that.data.list[i].id        });        that.paixu()//同一字母内排序    }},indexPosition(letter) {    if (!letter) { return ''; }    const ACode = 65;    return letter === '#' ? 26 : letter.charCodeAt(0) - ACode;},getLetter(str) {    return this.getFirstLetter(str[0]);},getFirstLetter(str) {    if (!str || /^ +$/g.test(str)) {        return '';    }    const result = [];    const unicode = str.charCodeAt(0);    let ch = str.charAt(0);    if (unicode >= 19968 && unicode <= 40869) {        ch = this.data.firstletter.charAt(unicode - 19968);    } else if ((unicode >= 97 && unicode <= 122) || (unicode >= 65 && unicode <= 90)) {        ch = ch.toLocaleUpperCase();    } else {        ch = '#';    }    const obj = {        unicode: unicode,        firstletter: ch    };    return obj;},paixu() {    for (let index = 0; index < this.handleData.length; index++) {        if (this.handleData[index].hasData) {            let userArr = this.handleData[index].users;            userArr = userArr.sort((a, b) => {                let value1 = a.unicode;                let value2 = b.unicode;                return value1 - value2;            });        }    }},
复制代码

​​代码执行顺序​​


​​转换后 handleData 的数据格式如下​​


​​最后就是单击字母滚动到指定区域,这里用 scroll-view 组建的 scrollTo 方法​​

​​$('#list').scrollTo({ 'view': letter })。​​

​​这里还要判断当前字母是否在 nameIndex 数组里面,如果存在就滚动到指定区域,同时字母单击后会添加绿色背景,所以这里需要改变当前字母的 active 值为 true​​

​​好友列表布局(每个字母类别设置一个 id, scrollTo 方法根据 id 滚动到指定区域)​​

<view :id="rs.letter == '#' ? 'other' : rs.letter" v-for="(rs,index) in handleData"     :key="index" v-show="rs.hasData">    <view class="list-item-title">        <text class="letter">{rs.letter}</text>    </view>    <view class="list-item" v-for="(u, uIndex) in rs.users" :key="uIndex" @click="user(u)">    <view class="list-item-left">         <view class="img">                <image class="avatar" :src="u.avatar"></image>         </view>    </view>    <view class="list-item-right">         <text class="name">{u.name}</text>    </view>    </view></view>
复制代码

​​字母列表布局​​

<view @click="letterClick(rs.letter,i)" v-for="(rs,i) in letter" :key="i">    <text class="list-right-letter active" v-if="rs.active">{rs.letter}</text>    <text class="list-right-letter" v-else>{rs.letter}</text></view>
复制代码

​​单击方法​​

letterClick(letter, key) {    this.data.letter = []//字母数组    this.data.letter = base.letter()    this.data.letter[key].active = true    for (var i = 0; i < this.data.nameIndex.length; i++) {        if (letter == this.data.nameIndex[i]) {            if (letter == '#') {                $('#list').scrollTo({ 'view': 'other' })            } else {                $('#list').scrollTo({ 'view': letter })            }        }    }},
复制代码


发布于: 刚刚阅读数: 2
用户头像

APICloud

关注

一次编码多端运行,移动应用低代码开发平台 2020.12.22 加入

用友YonBuilder移动端低代码开发平台,快速构建高性能多端应用

评论

发布
暂无评论
使用APICloud AVM多端框架开发app通讯录功能_前端开发_APICloud_InfoQ写作平台