1. Effect display

2. Project structure diagram

3. Data structure diagram

1. The original friend data structure of the server

2. Friends data structure sorted by alphabetical order

3. Alphabet Navigation Data Structure

Fourth, the idea of function realization

This project is written based on the APICloud AVM framework, so the thinking needs to be changed, such as the usage of tags, the way of writing CSS style sheets, the directory structure of the project, and the operation of dom. It is completely the programming thinking of Vue and React.

The WeChat address book function is to sort and classify all contacts according to the first letter of the alphabet, click the letter on the right and slide to the corresponding letter grouping. The core function of this project is to sort the data according to the first letter, and the page layout can be designed according to the layout of WeChat. Since it involves page scrolling and scrolling to a specified position, we can use the scroll-view component.

The page layout structure of this project is as follows

Note that the scroll-view component must be set to a height or it cannot be displayed normally. The height calculation formula is as follows:

height=page window height--status bar height--top navigation height--custom tab-bar height

code show as below

 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 and tab-bar are custom so know its height is 44 and 53px respectively

The complete properties of the scroll-view component are as follows

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

Next, I will explain the conversion of the core function friend data structure. The friend data obtained from the server is generally not in alphabetical order and the format is as follows

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

The converted data format is as follows

 [{
    "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"
     }]
}]

The principle of conversion is to extract the first string of the nick_name field to obtain pinyin letters and unicode codes, and then grouping and sorting needs to refer to the pinyin code table, which can be downloaded from the Internet. I repackage it here.

define variable

The method used is as follows

 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;
            });
        }
    }
},

code execution order

The data format of handleData after conversion is as follows

The last is to click the letter to scroll to the specified area, here the scrollTo method formed by scroll-view

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

It is also necessary to judge whether the current letter is in the nameIndex array. If it exists, scroll to the specified area. At the same time, a green background will be added after the letter is clicked, so it is necessary to change the active value of the current letter to true.

Friends list layout (set an id for each letter category, scrollTo method scrolls to the specified area according to the 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>

alphabetical list layout

 <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>

click method

 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 })
            }
        }
    }
},

海的尽头
18 声望340 粉丝