
下面pySegSort函数代码中的localeCompare在小程序中似乎不兼容安卓,但是兼容苹果手机,就,挺懵的。
初步解决方案:安装pinyin-pro,地址:pinyin-pro - npm
pinyin(item.name, { pattern: 'first', type: 'array' })[0].toUpperCase()
最近是用智能小程序开发的项目,所以就贴一下智能小程序实现的代码,大家可以根据自己的需要更改样式或者逻辑。
首先是一个函数,这个函数是实现,把中文开头的拼音的首字母提出,比如上面图片里的S;把英文开头的首字母提出;把数字等归为"#"。
这里我当时卡壳了半天,思维有所受限,还是带我的导师分分钟搞定的,哈哈,夸张了一下。
pySegSort(arr, dataIndex) {
if (!String.prototype.localeCompare) return null;
let letters = '#ABCDEFGHJKLMNOPQRSTWXYZ'.split('');
let zh = '阿八嚓哒妸发旮哈讥咔垃痳拏噢妑七呥扨它穵夕丫帀'.split('');
let segs = [];
let zh_arr = [];
let en_arr = [];
arr.forEach((item) => {
let name = dataIndex ? item[dataIndex] : item;
if (/[a-zA-Z]/.test(name.charAt(0))) {
en_arr.push(item);
} else {
zh_arr.push(item);
}
})
letters.forEach((letter, i) => {
let curr = { letter, data: [] };
zh_arr.forEach(item => {
let name = dataIndex ? item[dataIndex] : item;
if ((!zh[i - 1] || zh[i - 1].localeCompare(name) <= 0) && name.localeCompare(zh[i]) === -1) {
curr.data.push(item);
}
});
if (curr.data.length) {
segs.push(curr);
curr.data.sort((a, b) => (dataIndex ? a[dataIndex].localeCompare(b[dataIndex]) : a.localeCompare(b)));
}
});
en_arr.forEach((item) => {
let name = dataIndex ? item[dataIndex] : item;
let en = name.charAt(0).toUpperCase();
let index = segs.findIndex(({ letter }) => letter === en)
if (index > -1) {
segs[index].data.push(item);
} else {
segs.push({
letter: en, data: [item]
})
}
})
return segs.sort((a, b) => a.letter < b.letter ? -1 : 1);
},
然后我mock了一堆假数据,复制到 js 里又改了改,并传入函数中执行,如下是我的假数据和函数执行后打印出来的结果。
let arr = [
{
"name": "12345678989"
},
{
"name": "hhh"
},
{
"name": "地这究图选由"
},
{
"name": "42245678989"
},
{
"name": "支高动经可接"
},
{
"name": "www"
},
{
"name": "革百看回压采"
},
{
"name": "然场干总每起"
},
{
"name": "d切"
},
{
"name": "知再议速看青"
},
{
"name": "哈哈"
},
{
"name": "术着白治志接"
},
{
"name": "斗用重从水品"
},
{
"name": "入治说约开图"
},
{
"name": "道与需走应任"
},
{
"name": "程中标以县林"
},
{
"name": "器者红北门正"
},
{
"name": "准果素造展内"
},
{
"name": "区线志反从说"
},
{
"name": "见题通般行越"
},
{
"name": "间此代之委准"
},
{
"name": "用何极段织林"
},
{
"name": "阶都实快极共"
},
{
"name": "都京米应今下"
},
{
"name": "开车也观车算"
},
{
"name": "已入金本无划"
},
{
"name": "压取它应便关"
},
{
"name": "当无农快品导"
},
{
"name": "起公维业等民"
},
{
"name": "命素府利华新"
},
{
"name": "教想适治器该"
},
{
"name": "查需国价政增"
},
{
"name": "管起来西毛般"
},
{
"name": "广资接最更千"
},
{
"name": "来命确两界地"
},
{
"name": "政团铁层状很"
},
{
"name": "长西信两效加"
},
{
"name": "般则就级好示"
},
{
"name": "方际出产党满"
},
{
"name": "思革青许龙所"
},
{
"name": "从加月引成支"
},
{
"name": "立此验解包众"
},
{
"name": "受器整广速物"
},
{
"name": "已记却界六明"
},
{
"name": "么所指往通情"
},
{
"name": "型界新习此满"
},
{
"name": "争算原究感府"
},
{
"name": "求米当标得任"
},
{
"name": "西响所酸即和"
},
{
"name": "最具展小量目"
},
{
"name": "类再复际方也"
},
{
"name": "到手了议常入"
}
];
console.log(this.pySegSort(arr, "name"));
然后可以把数据更新到data里的list里,再根据数据格式去.swan文件渲染数据,这里我是用了智能小程序的scroll-view组件来实现滑动和字母定位,先粘一下代码:
index.wxml
<view class="container">
<scroll-view
class="scroll-view"
scroll-y
scroll-top="{= scrollTop =}">
<block s-for="item,index in list">
<view class="letter">{{item.letter}}</view>
<view id="{{item.letter}}" s-for="c,i in item.data">
<view class="part">{{c.name}}</view>
</view>
</block>
</scroll-view>
<view class="navigation">
<text s-for="item,index in letters" bindtap="scrollToTop" data-id="{{item}}">{{item}}</text>
</view>
</view>
其中有一个scrollToTop点击事件,可以通过这个事件更改scrollTop中的值,进而达到点击右侧字母时,左侧内容定位到同样字母开头的位置,如下:
scrollToTop(e) {
let arr = [...this.data.list];
let l = [];
let count = 0;
let len = 0;
for (let i = 0; i < arr.length; i++) {
l.push(arr[i].letter);
if (arr[i].letter === "#" && e.target.dataset.id === "#") {
count = len = 0;
} else if ((arr[i].letter < e.target.dataset.id) || (arr[i].letter === "#" && e.target.dataset.id !== "#")) {
count += arr[i].data.length;
len++;
} else {
break;
}
}
//注意这里的50.5是我一条数据的高度,37.5是字母的高度
if (l.indexOf(e.target.dataset.id) !== -1) {
this.setData({
scrollTop: count * 50.5 + 37.5 * len
})
}
},
这样就ok了,下面粘贴一下效果图:

css样式可以根据自己需要去写哈。比如字母那加个粘性定位啥的。
js文件的详细代码如下,在实际项目开发,list数据可以调用后端接口获取一下再用this.setData更新。
index.js
Page({
data: {
list: [],
//字母导航表
letters: ['#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],
scrollTop: 0,
},
/**
* 将汉字转为字母
*/
pySegSort(arr, dataIndex) {
if (!String.prototype.localeCompare) return null;
let letters = '#ABCDEFGHJKLMNOPQRSTWXYZ'.split('');
let zh = '阿八嚓哒妸发旮哈讥咔垃痳拏噢妑七呥扨它穵夕丫帀'.split('');
let segs = [];
let zh_arr = [];
let en_arr = [];
arr.forEach((item) => {
let name = dataIndex ? item[dataIndex] : item;
if (/[a-zA-Z]/.test(name.charAt(0))) {
en_arr.push(item);
} else {
zh_arr.push(item);
}
})
letters.forEach((letter, i) => {
let curr = { letter, data: [] };
zh_arr.forEach(item => {
let name = dataIndex ? item[dataIndex] : item;
if ((!zh[i - 1] || zh[i - 1].localeCompare(name) <= 0) && name.localeCompare(zh[i]) === -1) {
curr.data.push(item);
}
});
if (curr.data.length) {
segs.push(curr);
curr.data.sort((a, b) => (dataIndex ? a[dataIndex].localeCompare(b[dataIndex]) : a.localeCompare(b)));
}
});
en_arr.forEach((item) => {
let name = dataIndex ? item[dataIndex] : item;
let en = name.charAt(0).toUpperCase();
let index = segs.findIndex(({ letter }) => letter === en)
if (index > -1) {
segs[index].data.push(item);
} else {
segs.push({
letter: en, data: [item]
})
}
})
return segs.sort((a, b) => a.letter < b.letter ? -1 : 1);
},
/**
* 右侧字母表点击字母滑动到对应首字母开头的数据位置
*/
scrollToTop(e) {
let arr = [...this.data.list];
let l = [];
let count = 0;
let len = 0;
for (let i = 0; i < arr.length; i++) {
l.push(arr[i].letter);
if (arr[i].letter === "#" && e.target.dataset.id === "#") {
count = len = 0;
} else if ((arr[i].letter < e.target.dataset.id) || (arr[i].letter === "#" && e.target.dataset.id !== "#")) {
count += arr[i].data.length;
len++;
} else {
break;
}
}
//注意这里的50.5是我一条数据的高度,37.5是字母的高度
if (l.indexOf(e.target.dataset.id) !== -1) {
this.setData({
scrollTop: count * 50.5 + 37.5 * len
})
}
},
onLoad: function (options) {
let arr = [
{
"name": "12345678989"
},
{
"name": "hhh"
},
{
"name": "地这究图选由"
},
{
"name": "42245678989"
},
{
"name": "支高动经可接"
},
{
"name": "www"
},
{
"name": "革百看回压采"
},
{
"name": "然场干总每起"
},
{
"name": "d切"
},
{
"name": "知再议速看青"
},
{
"name": "哈哈"
},
{
"name": "术着白治志接"
},
{
"name": "斗用重从水品"
},
{
"name": "入治说约开图"
},
{
"name": "道与需走应任"
},
{
"name": "程中标以县林"
},
{
"name": "器者红北门正"
},
{
"name": "准果素造展内"
},
{
"name": "区线志反从说"
},
{
"name": "见题通般行越"
},
{
"name": "间此代之委准"
},
{
"name": "用何极段织林"
},
{
"name": "阶都实快极共"
},
{
"name": "都京米应今下"
},
{
"name": "开车也观车算"
},
{
"name": "已入金本无划"
},
{
"name": "压取它应便关"
},
{
"name": "当无农快品导"
},
{
"name": "起公维业等民"
},
{
"name": "命素府利华新"
},
{
"name": "教想适治器该"
},
{
"name": "查需国价政增"
},
{
"name": "管起来西毛般"
},
{
"name": "广资接最更千"
},
{
"name": "来命确两界地"
},
{
"name": "政团铁层状很"
},
{
"name": "长西信两效加"
},
{
"name": "般则就级好示"
},
{
"name": "方际出产党满"
},
{
"name": "思革青许龙所"
},
{
"name": "从加月引成支"
},
{
"name": "立此验解包众"
},
{
"name": "受器整广速物"
},
{
"name": "已记却界六明"
},
{
"name": "么所指往通情"
},
{
"name": "型界新习此满"
},
{
"name": "争算原究感府"
},
{
"name": "求米当标得任"
},
{
"name": "西响所酸即和"
},
{
"name": "最具展小量目"
},
{
"name": "类再复际方也"
},
{
"name": "到手了议常入"
}
];
this.setData({
list: this.pySegSort(arr, "name"),
})
}
});
来源:https://blog.csdn.net/qq_43652492/article/details/123231963