vue中基于 localeCompare 对中文首字母进行排序

我们通常在做聊天、地址、分类时都会使用对中文按照首字母来进行排序,以得到更好的视觉效果,下面我们就以此使用 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>

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值