一、成果展现
二、我的项目结构图
三、数据结构图
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})
}
}
}
},