这就是个模糊查询,我们平常做的都是直接输入汉字去把对应的值过滤出来,但我还真是第一次通过拼音去查询(当然不只是拼音,汉字也是可以的),以前还真没注意这个。唉,这可咋搞,我怎么知道某个汉字(字符串)的拼音的首字母是什么呢?正当我愁眉苦脸的时候,哎,一个库被我发现了,hhhhh~。就是pinyin-match。下面介绍该包的使用,这个包也不大,四百多kb。蛮高效的。下面介绍一下该库的使用
npm官方:https://www.npmjs.com/package/pinyin-match
1. 首先说下功能:
它能够使用拼音快速检索目标。当然也可以使用汉字
- 简体版27KB (gzip ≈ 19KB),繁体版86KB (gzip ≈ 60KB)
- 支持多音字、繁体字、拼音首字母匹配,具备分词功能
- 返回位置信息,可用于高亮匹配字符
- 在长多音字串下依然有高性能
在线演示:http://laosep.top/pinyin-match/
2. 安装:
npm install pinyin-match --save
3. 引入:
简体版:
import PinyinMatch from 'pinyin-match'; // es
const PinyinMatch = require('pinyin-match'); // commonjs
繁体版:
import PinyinMatch from 'pinyin-match/es/traditional.js'; // es
const PinyinMatch = require('pinyin-match/lib/traditional.js'); // commonjs
当然也可以script引入
// 简体:
<script src="pinyin-match/dist/main.js"></script>
// 繁体:
<script src="pinyin-match/dist/traditional.js"></script>
4. API:
.match(input, keyword) //查询匹配拼音的数据。
只向外提供暴露了这么一个方法,这一个方法足够我们使用了,也很方便
参数:
- input
{string}
目标字符串 - keyword
{string}
输入的拼音或其他关键词
返回:
Array | Boolen
5. 简单使用测试示例:
let test = '123曾经沧海难为水除却巫山不是云'
PinyinMatch.match(test, '23曾'); // [1, 3]
PinyinMatch.match(test, 'cjc') // [3, 5]
PinyinMatch.match(test, 'cengjingcanghai') // [3, 6]
PinyinMatch.match(test, 'cengjingcangha') // [3, 6]
PinyinMatch.match(test, 'engjingcanghai') // false
PinyinMatch.match(test, 'zengjingcang') // [3, 5]
PinyinMatch.match(test, 'sdjkelwqf') // false
PinyinMatch.match(test, 'zengji ng cang') // [3, 5]
PinyinMatch.match(test, 'zengji ng cangsdjfkl') // false
PinyinMatch.match(' 我 爱你 中 国 ', 'nzg') // [6, 12]
PinyinMatch.match(' 我 爱你 中 国 ', '爱你中') // [5, 8]
PinyinMatch.match('發', 'fa') // [0, 0]
6. 具体案例:
就是平常的列表展示加模糊搜索。所用的人员列表测试数据都是下面这种格式,章末会把完整测试数据附上。
// 模拟后端返回的数据
export default [
{
name: '管理员',
no: 'FT00000'
},
//...
]
其实很简单的了,主要是实现拼音的搜索过滤的功能,所以我案例里面样式也没调,主要是功能
闲话不说了,直接上完整代码,大家看下里面的逻辑都明白了,就这么一个组件:
<template>
<div class="main">
<input type="text" v-model="serchValue" placeholder="输入搜索">
<div class="user" v-for="(user, index) in users" :key="user.no">{{ index }}# : {{ user.name }}</div>
</div>
</template>
<script>
import userList from './data/user'
import PinyinMatch from 'pinyin-match'
let timer = null
export default {
data() {
return {
serchValue: '',
userListAll: [], // 所有数据
users: [] // 展示的数据
}
},
watch: {
serchValue() {
this.debounce(this.selectUser, 200)
}
},
mounted(){
this.getUserList()
},
methods:{
// 模拟请求
getUserList() {
setTimeout(() => {
this.userListAll = userList
this.selectUser()
}, 100)
},
// 防抖
debounce(fn, wait) {
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.call(this)
timer = null
}, wait)
},
// 模糊查询条件
selectUser() {
this.users = []
// 如果搜索框有值的话再去过滤,因为PinyinMatch.match第二个参数是空字符串的话会匹配不到,返回false,这不符合我们的预期
// 搜索框没有值,我们要展示所有数据
if(this.serchValue) {
this.userListAll.forEach(user => {
let matchIndexs = PinyinMatch.match(user.name, this.serchValue) // 如果匹配到返回 首尾的索引数组,如果匹配不到则返回false
if(matchIndexs) {
this.users.push(user)
}
})
} else {
this.users = this.userListAll
}
}
}
}
</script>
<style scoped>
.main {
width: 100vw;
height: 100vh;
padding: 200px 0 0 200px;
box-sizing: border-box;
}
.main input {
margin-bottom: 5px;
}
</style>
接下来看下效果:
接下来!我们可以把上面的示例再提高点儿难度,因为让我想起了通讯录,所以在展示的时候我们就像通讯录那样展示
首先将拿到的人员列表进行分组,根据什么分呢?就是根据字母,a、b、c...这样,难道我们要把26个英文字母全都列出来吗?当然这个也分需求,但如果是通讯录的话,我们只需要百家姓中所有的拼音的首字母就可以了,也就是:abcdefghjklmnopqrstwxyz 这些。
在上面示例的基础上进行修改,在拿到人员数据之后,先处理一下,然后再进行过滤模糊查询
完整代码:
<template>
<div class="main">
<input type="text" v-model="serchValue" placeholder="输入搜索">
<div class="users" v-for="user in users" :key="user.key">
<div>{{ user.key }}</div>
<div class="user-name" v-for="o in user.data" :key="o.no">{{ o.name }}</div>
</div>
</div>
</template>
<script>
import userList from './data/user'
import PinyinMatch from 'pinyin-match'
let timer = null
export default {
data() {
return {
serchValue: '',
userListAll: [], // 所有数据
users: [] // 展示的数据
}
},
watch: {
serchValue() {
this.debounce(this.selectUser, 200)
}
},
mounted(){
this.getUserList()
},
methods:{
// 模拟请求
getUserList() {
setTimeout(() => {
this.userListAll = this.handlerData(userList)
this.selectUser()
}, 100)
},
// 处理数据
handlerData(userList) {
// 这是百家姓中所有的拼音的首字母
const surnameLetters = 'abcdefghjklmnopqrstwxyz'.split('')
const userListAll = []
surnameLetters.forEach(letter => {
let o = { key: letter, data: [] }
userList.forEach(user => {
let matchIndexs = PinyinMatch.match(user.name.slice(0, 1), letter) // 匹配姓氏的拼音的首字母
if(matchIndexs) {
o.data.push(user)
}
})
if(o.data.length) {
userListAll.push(o)
}
})
return userListAll
},
// 防抖
debounce(fn, wait) {
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.call(this)
timer = null
}, wait)
},
// 模糊查询条件
selectUser() {
this.users = []
if(this.serchValue) {
this.userListAll.forEach(user => {
let o = { key: user.key, data: [] }
user.data.forEach(item => {
let matchIndexs = PinyinMatch.match(item.name, this.serchValue)
if(matchIndexs) {
o.data.push(item)
}
})
if(o.data.length) {
this.users.push(o)
}
})
} else {
this.users = this.userListAll
}
}
}
}
</script>
<style scoped>
.main {
width: 100%;
height: 100%;
padding: 0 0 0 200px;
box-sizing: border-box;
}
.main input {
margin-bottom: 5px;
}
.user-name {
padding-left: 10px;
}
</style>
最后看下修改后的效果:
接下来是上面测试用的数据
export default [
{
"name": "管理员",
"no": "FT00000"
},
{
"name": "朱大锤",
"no": "FT00001"
},
{
"name": "郝大锤",
"no": "FT00002"
},
{
"name": "宋大锤",
"no": "FT00003"
},
{
"name": "杨大锤",
"no": "FT00004"
},
{
"name": "石大锤",
"no": "FT00005"
},
{
"name": "郑大锤",
"no": "FT00006"
},
{
"name": "刘大锤",
"no": "FT00007"
},
{
"name": "赵大锤",
"no": "FT00008"
},
{
"name": "李大锤",
"no": "FT00009"
},
{
"name": "牛二",
"no": "FT00010"
},
{
"name": "张大锤",
"no": "FT00011"
},
{
"name": "王大锤",
"no": "FT00012"
},
{
"name": "冯大锤",
"no": "FT00013"
},
{
"name": "李大锤",
"no": "FT00014"
},
{
"name": "邓大锤",
"no": "FT00015"
},
{
"name": "孙大锤",
"no": "FT00016"
},
{
"name": "袁大锤",
"no": "FT00017"
},
{
"name": "康大锤",
"no": "FT00018"
},
{
"name": "武大锤",
"no": "FT00019"
},
{
"name": "蔡大锤",
"no": "FT00020"
},
{
"name": "戴大锤",
"no": "FT00021"
},
{
"name": "鄂大锤",
"no": "FT00022"
},
{
"name": "封大锤",
"no": "FT00023"
},
{
"name": "盖大锤",
"no": "FT00024"
},
{
"name": "景大锤",
"no": "FT00025"
},
{
"name": "麻大锤",
"no": "FT00026"
},
{
"name": "那大锤",
"no": "FT00027"
}
]