我们通常在做聊天、地址、分类时都会使用对中文按照首字母来进行排序,以得到更好的视觉效果,下面我们就以此使用 vue 在前端 使用 localeCompare 进行原生中文首字母的排序与展示。
话不多说,先直接上效果图
简单排序版
// 按照姓氏排序 data 需要为数组
fristSort (data) {
return data.sort(function (x, y) {
return x['nickname'].localeCompare(y['nickname'])
})
}
附加首字母信息的排序
原始数据
{
"myFriendsList": [
{
"id": 2,
"nickname": "赵小云",
"avatar": "https://game.gtimg.cn/images/yxzj/img201606/heroimg/107/107.jpg",
"signature": "心怀不惧,方能翱翔于天际。",
"roomId": "1-2"
},
{
"id": 3,
"nickname": "韩小信",
"avatar": "https://game.gtimg.cn/images/yxzj/img201606/heroimg/150/150.jpg",
"signature": "必将百倍奉还。",
"roomId": "1-3"
},
{
"id": 4,
"nickname": "诸小亮",
"avatar": "https://game.gtimg.cn/images/yxzj/img201606/heroimg/190/190.jpg",
"signature": "运筹帷幄之中,决胜千里之外。",
"roomId": "1-4"
},
{
"id": 5,
"nickname": "羞花",
"avatar": "https://game.gtimg.cn/images/yxzj/img201606/heroimg/176/176.jpg",
"signature": null,
"roomId": "1-5"
}
]
}
最终数据格式
"friendList": [
{
"letter": "H",
"data": [
{
"id": 3,
"nickname": "韩小信",
"avatar": "https://game.gtimg.cn/images/yxzj/img201606/heroimg/150/150.jpg",
"signature": "必将百倍奉还。",
"roomId": "1-3"
}
]
},
{
"letter": "X",
"data": [
{
"id": 5,
"nickname": "羞花",
"avatar": "https://game.gtimg.cn/images/yxzj/img201606/heroimg/176/176.jpg",
"signature": null,
"roomId": "1-5"
}
]
},
{
"letter": "Z",
"data": [
{
"id": 2,
"nickname": "赵小云",
"avatar": "https://game.gtimg.cn/images/yxzj/img201606/heroimg/107/107.jpg",
"signature": "心怀不惧,方能翱翔于天际。",
"roomId": "1-2"
},
{
"id": 4,
"nickname": "诸小亮",
"avatar": "https://game.gtimg.cn/images/yxzj/img201606/heroimg/190/190.jpg",
"signature": "运筹帷幄之中,决胜千里之外。",
"roomId": "1-4"
}
]
}
]
展示部分代码
<div v-for="(friends,index) in friendList" :key="index" class="friend-group">
<div class="group-info">
<span class="secondary-font" style="margin-left:5px">{{ friends.letter }}</span>
</div>
<friend-item
v-for="item in friends.data"
:key="item.id"
:friendInfo="item"
/>
</div>
对姓氏进行排序
然后就是我们的重点了,对姓氏进行排序,首先我们简单介绍一下大概过程
-
传入原始数据
-
初始化
- 校验是否支持
localeCompare
方法 letters
:首字母数组zh
:中文数组arrList
:拷贝原始数据数组result
:最终结果数组curr
:当前分组变量
- 校验是否支持
-
遍历 26 个字母
- 对拷贝的数组遍历,获取要进行排序字段的首字符
- 然后判断首字符类型
- 英文则直接放入当前分组
- 是中文,且符合当前类别才放入当前分组
-
最后对不是字母也不是中文的数据进行归类
-
最终组成分组
初始化
- 校验是否支持
localeCompare
方法 letters
:首字母数组zh
:中文数组arrList
:拷贝原始数据数组result
:最终结果数组curr
:当前分组变量
var $this = this
if (!String.prototype.localeCompare) { return null }
var letters = 'ABCDEFGHJKLMNOPQRSTWXYZ'.split('')
var zh = '阿八嚓哒妸发旮哈讥咔垃痳拏噢妑七呥扨它穵夕丫帀'.split('')
var arrList = []
for (var m = 0; m < arr.length; m++) {
arrList.push(arr[m])
}
var result = []
var curr
遍历 26 个字母,最终组成分组
for (var i = 0; i < letters.length; i++) {
curr = {letter: letters[i], data: []}
if (i !== 26) {
for (var j = 0; j < arrList.length; j++) {
// 截取第一个字符
var initial = arrList[j].nickname.charAt(0)
// 首字符是英文的
if (arrList[j].nickname.charAt(0) === letters[i] || arrList[j].nickname.charAt(0) === letters[i].toLowerCase()) {
curr.data.push(arrList[j])
// 判断是否是无汉字,是否是中文
} else if (zh[i] !== '*' && $this.isChinese(initial)) {
// 判断中文字符在哪一个类别
if (initial.localeCompare(zh[i]) >= 0 && (!zh[i + 1] || initial.localeCompare(zh[i + 1]) < 0)) {
curr.data.push(arrList[j])
}
}
}
}
}
...
对不是字母也不是中文的数据进行归类
for (var k = 0; k < arrList.length; k++) {
// 截取第一个字符
var ini = arrList[k].nickname.charAt(0)
if (!$this.isChar(ini) && !$this.isChinese(ini)) {
curr.data.push(arrList[k])
}
}
其中判断字符和中文的函数
isChinese (temp) {
var re = /[^\u4E00-\u9FA5]/
if (re.test(temp)) { return false }
return true
},
isChar (char) {
var reg = /[A-Za-z]/
if (!reg.test(char)) { return false }
return true
}
最终加入该分组
if (empty || curr.data.length) {
result.push(curr)
}
排序部分代码
pySort (arr, empty) {
var $this = this
if (!String.prototype.localeCompare) { return null }
var letters = 'ABCDEFGHJKLMNOPQRSTWXYZ'.split('')
var zh = '阿八嚓哒妸发旮哈讥咔垃痳拏噢妑七呥扨它穵夕丫帀'.split('')
var arrList = []
for (var m = 0; m < arr.length; m++) {
arrList.push(arr[m])
}
var result = []
var curr
for (var i = 0; i < letters.length; i++) {
curr = {letter: letters[i], data: []}
if (i !== 26) {
for (var j = 0; j < arrList.length; j++) {
// 截取第一个字符
var initial = arrList[j].nickname.charAt(0)
// 首字符是英文的
if (arrList[j].nickname.charAt(0) === letters[i] || arrList[j].nickname.charAt(0) === letters[i].toLowerCase()) {
curr.data.push(arrList[j])
// 判断是否是无汉字,是否是中文
} else if (zh[i] !== '*' && $this.isChinese(initial)) {
// 判断中文字符在哪一个类别
if (initial.localeCompare(zh[i]) >= 0 && (!zh[i + 1] || initial.localeCompare(zh[i + 1]) < 0)) {
curr.data.push(arrList[j])
}
}
}
} else {
for (var k = 0; k < arrList.length; k++) {
// 截取第一个字符
var ini = arrList[k].nickname.charAt(0)
if (!$this.isChar(ini) && !$this.isChinese(ini)) {
curr.data.push(arrList[k])
}
}
}
if (empty || curr.data.length) {
result.push(curr)
}
}
console.log('result:', result)
return result
},
isChinese (temp) {
var re = /[^\u4E00-\u9FA5]/
if (re.test(temp)) { return false }
return true
},
isChar (char) {
var reg = /[A-Za-z]/
if (!reg.test(char)) { return false }
return true
}
全部代码
<template>
<div>
<div class="search-header">
<el-row class="search-row">
<el-col :span="20" style="margin-top:12px">
<el-input
size="medium"
placeholder="搜索"
v-model="keyword"
style="width: 96%;"
>
<i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-input>
</el-col>
<el-col :span="3" style="margin-top:12px">
<el-dropdown @command="handleCommand" trigger="click">
<el-button icon="el-icon-plus" size="medium" circle></el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="0">加入群聊</el-dropdown-item>
<el-dropdown-item command="1">添加好友</el-dropdown-item>
<el-dropdown-item command="2">发起群聊</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-col>
</el-row>
</div>
<div class="friend-list">
<div class="new-info" @click="newsVisible = true">
<div class="wrapper">
<el-badge :is-dot="newsListStatus">
<div class="new-avatar">
<el-avatar shape="square" icon="el-icon-bell" style="background:#f48058"></el-avatar>
</div>
</el-badge>
<span style="margin-left: 10px;">新的消息</span>
</div>
</div>
<div v-for="(friends,index) in friendList" :key="index" class="friend-group">
<div class="group-info">
<span class="secondary-font" style="margin-left:5px">{{ friends.letter }}</span>
</div>
<friend-item
v-for="item in friends.data"
:key="item.id"
:friendInfo="item"
/>
</div>
</div>
<el-dialog title="验证消息" :visible.sync="newsVisible" width="40%">
<el-table :data="newsList" :show-header="false" height="250">
<el-table-column width="60">
<template slot-scope="scope">
<div class="block"><el-avatar :size="50" :src="scope.row.senderAvatar"></el-avatar></div>
</template>
</el-table-column>
<el-table-column property="senderName" width="120" show-overflow-tooltip></el-table-column>
<el-table-column width="118">
<template slot-scope="scope">
<span v-if="scope.row.validateType===0">邀请你加入群聊</span>
<span v-if="scope.row.validateType===1">请求添加为好友</span>
</template>
</el-table-column>
<el-table-column property="additionMessage" width="120" show-overflow-tooltip>
</el-table-column>
<el-table-column width="148">
<template slot-scope="scope">
<el-button
v-if="scope.row.status===0"
size="mini"
type="success"
@click="agree(scope.row)">添加
</el-button>
<el-button
v-if="scope.row.status===0"
size="mini"
type="danger"
@click="disagree(scope.row)">拒绝
</el-button>
<el-button
v-if="scope.row.status===1"
size="mini"
type="success"
disabled>已添加
</el-button>
<el-button
v-if="scope.row.status===2"
size="mini"
type="danger"
disabled>已拒绝
</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
<add-group @changeAddGroupVisible="changeAddGroupVisible" :addGroupVisible="addGroupVisible" />
<add-friend @changeAddFriendVisible="changeAddFriendVisible" :addFriendVisible="addFriendVisible" />
<new-group @changeNewGroupVisible="changeNewGroupVisible" :newGroupVisible="newGroupVisible" />
</div>
</template>
<script>
import friendApi from '@/api/'
import friendItem from '@/views/friend/FriendItem'
import addFriend from '@/components/AddFriend'
import addGroup from '@/components/AddGroup'
import newGroup from '@/components/NewGroup'
export default {
name: 'AddressBook',
components: { friendItem, addFriend, addGroup, newGroup },
data () {
return {
keyword: '',
friendList: [],
addGroupVisible: false,
addFriendVisible: false,
newGroupVisible: false,
newsVisible: false,
newsList: []
}
},
created () {
this.getMyFriendsList()
this.getNewsList()
},
computed: {
userInfo () {
return this.$store.state.user.userInfo
},
newsListStatus () {
return this.$store.state.friend.newsListStatus
}
},
mounted () {
this.$eventBus.$on('getMyFriends', () => {
this.getMyFriendsList()
})
},
beforeDestroy () {
this.$eventBus.$off('getMyFriends')
},
sockets: {
// 收到好友请求就将消息存入请求列表
receiveValidateMessage (validateMessage) {
this.newsList = [validateMessage, ...this.newsList]
let newsListStatus = this.newsList.filter(item => item.status === 0).length > 0
this.$store.dispatch('friend/SET_NEWS_STATUS', {status: newsListStatus})
},
// 同意好友请求
receiveAgreeFriendValidate () {
this.getMyFriendsList()
}
},
methods: {
// 获取验证消息列表
getNewsList () {
friendApi.getNewsList(this.userInfo.id).then(res => {
this.newsList = res.data.newsList
let newsListStatus = res.data.newsList.filter(item => item.status === 0).length > 0
// console.log('getNewsList', newsListStatus)
this.$store.dispatch('friend/SET_NEWS_STATUS', {status: newsListStatus})
})
},
// 同意好友请求
agree (validateMessage) {
this.$socket.emit('sendAgreeFriendValidate', validateMessage)
this.getMyFriendsList()
this.getNewsList()
},
// 拒绝好友请求
disagree (validateMessage) {
this.$socket.emit('sendDisAgreeFriendValidate', validateMessage)
this.newsVisible = false
this.getNewsList()
},
changeAddFriendVisible (val) {
this.addFriendVisible = val
},
changeAddGroupVisible (val) {
this.addGroupVisible = val
},
changeNewGroupVisible (val) {
this.newGroupVisible = val
},
handleCommand (command) {
if (command === '0') {
console.log('加入群聊≡ω≡')
this.addGroupVisible = true
} else if (command === '1') {
console.log('添加好友︿( ̄︶ ̄)︿')
this.addFriendVisible = true
} else if (command === '2') {
console.log('发起群聊( ̄▽ ̄)~■干杯□~( ̄▽ ̄)')
this.newGroupVisible = true
} else {
this.$message.error('错了哦,这是一条错误消息╮(╯▽╰)╭')
}
},
// 获取好友列表
getMyFriendsList () {
friendApi.getMyFriendsList(this.$store.state.user.userInfo.id).then(res => {
if (res.data.myFriendsList != null) {
// this.friendList = this.fristSort(res.data.myFriendsList)
this.friendList = this.pySort(res.data.myFriendsList)
if (this.$store.state.friend.friendList != null) {
console.log('friendList:' + this.$store.state.friend.friendList)
this.$store.state.friend.friendList.forEach(item => {
console.log('加入房间:', item.roomId)
this.$socket.emit('join', item.roomId)
})
}
}
})
},
// 按照姓氏排序
fristSort (data) {
return data.sort(function (x, y) {
return x['nickname'].localeCompare(y['nickname'])
})
},
pySort (arr, empty) {
var $this = this
if (!String.prototype.localeCompare) { return null }
var letters = 'ABCDEFGHJKLMNOPQRSTWXYZ'.split('')
var zh = '阿八嚓哒妸发旮哈讥咔垃痳拏噢妑七呥扨它穵夕丫帀'.split('')
var arrList = []
for (var m = 0; m < arr.length; m++) {
arrList.push(arr[m])
}
var result = []
var curr
for (var i = 0; i < letters.length; i++) {
curr = {letter: letters[i], data: []}
if (i !== 26) {
for (var j = 0; j < arrList.length; j++) {
// 截取第一个字符
var initial = arrList[j].nickname.charAt(0)
// 首字符是英文的
if (arrList[j].nickname.charAt(0) === letters[i] || arrList[j].nickname.charAt(0) === letters[i].toLowerCase()) {
curr.data.push(arrList[j])
// 判断是否是无汉字,是否是中文
} else if (zh[i] !== '*' && $this.isChinese(initial)) {
// 判断中文字符在哪一个类别
if (initial.localeCompare(zh[i]) >= 0 && (!zh[i + 1] || initial.localeCompare(zh[i + 1]) < 0)) {
curr.data.push(arrList[j])
}
}
}
} else {
for (var k = 0; k < arrList.length; k++) {
// 截取第一个字符
var ini = arrList[k].nickname.charAt(0)
if (!$this.isChar(ini) && !$this.isChinese(ini)) {
curr.data.push(arrList[k])
}
}
}
if (empty || curr.data.length) {
result.push(curr)
}
}
console.log('result:', result)
return result
},
isChinese (temp) {
var re = /[^\u4E00-\u9FA5]/
if (re.test(temp)) { return false }
return true
},
isChar (char) {
var reg = /[A-Za-z]/
if (!reg.test(char)) { return false }
return true
}
}
}
</script>
<style>
.search-header {
position: sticky;;
height: 60px;
top: 0px;
z-index: 999;
}
.search-row {
height:60px;
background-color: #f7f7f7;
}
.el-dropdown-link {
cursor: pointer;
color: rgb(187, 187, 187);
}
.el-icon-arrow-down {
font-size: 12px;
}
.friend-list {
background-color: #e6e6e6;
}
.friend-list .new-info {
height: 50px;
line-height: 50px;
padding: 0 10px;
background-color: #e6e6e6;
}
.friend-list .new-info:hover {
height: 50px;
padding: 0 10px;
line-height: 50px;
background-color: #cfcfcf;
}
.friend-list .new-info .wrapper {
display: flex;
height: 50px;
padding: 0 5px;
align-items: center;
border-radius: 10px;
overflow: hidden;
}
.friend-list .new-avatar {
width: 40px;
height: 40px;
}
.friend-list .friend-group {
border-top: 1px solid #cacaca;
}
.friend-list .friend-group .group-info {
padding: 0 10px;
background: #e6e6e6;
text-align: left;
margin: 5px 0;
}
</style>