Some checks failed
Uniapp 自动化打包 CI/CD / 打包 Uniapp 项目 (push) Has been cancelled
213 lines
4.9 KiB
Vue
213 lines
4.9 KiB
Vue
<template>
|
|
<view class="page">
|
|
<!-- 搜索框 -->
|
|
<view class="search-box">
|
|
<input type="text" class="search-input" placeholder="部门、岗位、姓名" v-model="keyword"/>
|
|
</view>
|
|
|
|
<!-- 联系人列表 -->
|
|
<scroll-view
|
|
scroll-y
|
|
class="contact-list"
|
|
:scroll-into-view="currentView"
|
|
scroll-with-animation
|
|
>
|
|
<block v-for="(group, gIndex) in contacts" :key="gIndex">
|
|
<view class="group-title" :id="'group-' + group.letter">{{ group.letter }}</view>
|
|
<view class="contact-item" v-for="(item, index) in group.list" :key="index">
|
|
<image class="avatar" :src="item.avatar"></image>
|
|
<view class="contact-info">
|
|
<text class="name" :class="{'highlight': item.isHighlight}">{{ item.name }}</text>
|
|
<text class="desc">{{ item.job }} {{ item.phone }}</text>
|
|
</view>
|
|
</view>
|
|
</block>
|
|
</scroll-view>
|
|
|
|
|
|
<!-- 字母索引栏 -->
|
|
<view
|
|
class="index-bar"
|
|
@touchstart="onTouch"
|
|
@touchmove.stop.prevent="onTouch"
|
|
@touchend="onTouchEnd"
|
|
@touchcancel="onTouchEnd"
|
|
>
|
|
<view
|
|
v-for="(letter, i) in indexList"
|
|
:key="i"
|
|
class="index-item"
|
|
:style="{height: indexItemHeight + 'rpx', lineHeight: indexItemHeight + 'rpx'}"
|
|
>
|
|
{{ letter }}
|
|
</view>
|
|
</view>
|
|
|
|
|
|
<!-- 居中大字母提示 -->
|
|
<view v-if="showLetter" class="letter-toast">
|
|
{{ showLetter }}
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
keyword: "",
|
|
currentView: "",
|
|
showLetter: "",
|
|
indexList: "ABCDEFGHIJKLMNOPQRSTUVWXYZ#".split(""),
|
|
indexItemHeight: 30, // 索引单个高度 (rpx),可调整
|
|
contacts: [
|
|
{ letter: "A", list: [{ name: "张晓明", phone: "17895698899", job: "保洁", avatar: "https://img.yzcdn.cn/vant/cat.jpeg", isHighlight: true }] },
|
|
{ letter: "B", list: [
|
|
{ name: "阿俊", phone: "17895698899", job: "保洁", avatar: "https://img.yzcdn.cn/vant/dog.jpeg" },
|
|
{ name: "阿俊", phone: "17895698899", job: "保洁", avatar: "https://img.yzcdn.cn/vant/cat.jpeg" },
|
|
{ name: "阿俊", phone: "17895698899", job: "保洁", avatar: "https://img.yzcdn.cn/vant/elephant.jpeg" }
|
|
]},
|
|
{ letter: "C", list: [
|
|
{ name: "阿俊", phone: "17895698899", job: "保洁", avatar: "https://img.yzcdn.cn/vant/horse.jpeg" },
|
|
{ name: "阿俊", phone: "17895698899", job: "保洁", avatar: "https://img.yzcdn.cn/vant/lion.jpeg" }
|
|
]}
|
|
]
|
|
}
|
|
},
|
|
methods: {
|
|
// 开始/移动
|
|
onTouch(e) {
|
|
const touchY = e.touches[0].clientY
|
|
this.calcIndexByY(touchY)
|
|
},
|
|
// 松手/取消时隐藏
|
|
onTouchEnd() {
|
|
setTimeout(() => {
|
|
this.showLetter = ""
|
|
}, 300) // 0.3 秒后消失
|
|
},
|
|
|
|
// 计算位置 → 滚动 & 显示大字母
|
|
calcIndexByY(y) {
|
|
const query = uni.createSelectorQuery().in(this)
|
|
query.select('.index-bar').boundingClientRect(rect => {
|
|
if (!rect) return
|
|
const top = rect.top
|
|
const index = Math.floor((y - top) / (rect.height / this.indexList.length))
|
|
if (index >= 0 && index < this.indexList.length) {
|
|
const letter = this.indexList[index]
|
|
this.scrollTo(letter)
|
|
}
|
|
}).exec()
|
|
},
|
|
scrollTo(letter) {
|
|
const exists = this.contacts.find(item => item.letter === letter)
|
|
if (exists) {
|
|
this.currentView = "group-" + letter
|
|
}
|
|
this.showLetter = letter
|
|
}
|
|
}
|
|
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.page {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
background-color: #fff;
|
|
}
|
|
.header {
|
|
display: flex;
|
|
align-items: center;
|
|
height: 90rpx;
|
|
padding: 0 20rpx;
|
|
}
|
|
.back {
|
|
font-size: 40rpx;
|
|
}
|
|
.title {
|
|
flex: 1;
|
|
text-align: center;
|
|
font-size: 34rpx;
|
|
font-weight: bold;
|
|
}
|
|
.search-box {
|
|
padding: 20rpx;
|
|
}
|
|
.search-input {
|
|
width: auto;
|
|
height: 63rpx;
|
|
background: #F2F3F5;
|
|
border-radius: 25rpx;
|
|
padding-left: 20rpx;
|
|
font-size: 28rpx;
|
|
margin-left: 18rpx;
|
|
margin-right: 18rpx;
|
|
}
|
|
.contact-list {
|
|
flex: 1;
|
|
}
|
|
.group-title {
|
|
padding: 10rpx 20rpx;
|
|
background: #f5f5f5;
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
}
|
|
.contact-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 20rpx;
|
|
border-bottom: 1px solid #f5f5f5;
|
|
}
|
|
.avatar {
|
|
width: 80rpx;
|
|
height: 80rpx;
|
|
border-radius: 50%;
|
|
margin-right: 20rpx;
|
|
}
|
|
.contact-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
.name {
|
|
font-size: 30rpx;
|
|
}
|
|
.name.highlight {
|
|
color: orange;
|
|
}
|
|
.desc {
|
|
font-size: 24rpx;
|
|
color: #888;
|
|
margin-top: 6rpx;
|
|
}
|
|
.index-bar {
|
|
position: fixed;
|
|
right: 10rpx;
|
|
top: 200rpx;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
background-color: transparent;
|
|
user-select: none;
|
|
}
|
|
.index-item {
|
|
font-size: 22rpx;
|
|
color: #3a6ea5;
|
|
}
|
|
.letter-toast {
|
|
position: fixed;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
background: rgba(0,0,0,0.6);
|
|
color: #fff;
|
|
font-size: 80rpx;
|
|
font-weight: bold;
|
|
padding: 40rpx 60rpx;
|
|
border-radius: 20rpx;
|
|
}
|
|
</style>
|