<template> <view class="content"> <input v-if="contacts.length>0 || isSearch" class="search" type="text" placeholder="搜索联系人" @input="onSearchInput" /> <view v-if="contacts.length>0"> <scroll-view class="contact-scroll" scroll-y :scroll-into-view="scrollViewId"> <view class="box" v-for="(item,key) in contacts" :key="key"> <view class="divider" :id="item.letter"> <text class="divider-text">{{item.letter}}</text> </view> <view class="item" hover-class="hover" hover-start-time="20" v-for="(contact,index) in item.contacts" :key="index" @click='onSelectClick(contact)'> <image class="portrait" src="https://download.cheshangji.cn/app/46aeda5af72f44ba818423c6cb54799a.png" mode="aspectFill"></image> <view class="name">{{contact.name}}</view> </view> </view> </scroll-view> <view class="indexBar-bg"> <view class="indexBar" catchtouchmove> <view class="indexBar-box" @touchstart="tStart" @touchend="tEnd" @touchmove="tMove"> <view class="indexBar-item" v-for="(item,index) in contacts" :key="index" :id="item.letter" @touchstart="getCur" @touchend="setCur"> {{item.letter}} </view> </view> </view> </view> <view v-show="!hidden" class="indexToast">{{letter}}</view> </view> <text v-else class="no-contact">通讯录暂无联系人</text> </view> </template> <script> import pinyin from '@/common/pinyin/pinyin3.js' var platform = uni.getSystemInfoSync().platform export default { data() { return { /* 侧边栏选择器 */ scrollViewId: "wo", letter: "", boxTop: 0, barHeight: 0, minHeight: 0, hidden: true, /* 联系人 */ contacts: [], contactItems: [], isSearch: false, isShow: false } }, onLoad() { const res = uni.getSystemInfoSync(); this.barHeight = res.windowHeight / 27; //初始通讯录 this.initContacts() }, onReady() { var that = this uni.createSelectorQuery().select('.indexBar-box').boundingClientRect(function(e) { if (e != null) { that.boxTop = e.top } }).exec() /* uni.createSelectorQuery().select('.indexBar-item').boundingClientRect(function(e) { if(e != null){ that.barHeight = e.height } }).exec() */ }, methods: { /* * 滑动的侧边选择器 */ getCur(e) { this.hidden = false this.letter = e.target.id }, setCur(e) { this.hidden = true; this.letter = e.target.id }, tMove(e) { var y = e.touches[0].clientY var offsettop = this.boxTop //判断选择区域,只有在选择区才会生效 if (y > offsettop) { var num = Math.floor((y - offsettop) / this.barHeight); if (num < this.contacts.length) { this.letter = this.contacts[num].letter this.scrollViewId = this.letter } } }, tStart() { this.hidden = false }, tEnd() { this.hidden = true; }, /* * 初始化通讯录 */ initContacts: function() { //获取手机通讯录 plus.contacts.getAddressBook(plus.contacts.ADDRESSBOOK_PHONE, (addressbook) => { // 可通过addressbook进行通讯录操作 addressbook.find(["displayName", "phoneNumbers"], (contacts) => { var items = []; for (var i = 0; i < contacts.length; i++) { if (contacts[i].phoneNumbers.length > 0) { var contact = { 'name': contacts[i].displayName, 'phone': contacts[i].phoneNumbers[0].value }; items.push(contact); } } this.contacts = pinyin.paixu(items) this.contacts.sort(function(o1, o2) { return o1.letter.charCodeAt(0) - o2.letter.charCodeAt(0) }) this.contactItems = JSON.parse(JSON.stringify(this.contacts)) }, (e) => { this.onAddressBookSetting() }); }, (e) => { this.onAddressBookSetting() }); }, /* * 权限设置 */ onAddressBookSetting: function() { if (this.isShow) { return } this.isShow = true uni.showModal({ title: '提示', content: 'APP通讯录权限没有开启,是否开启?', success(res) { if (res.confirm) { if (platform == 'ios') { var UIApplication = plus.ios.import("UIApplication"); var NSURL2 = plus.ios.import("NSURL"); var setting2 = NSURL2.URLWithString("app-settings:"); var application2 = UIApplication.sharedApplication(); application2.openURL(setting2); plus.ios.deleteObject(setting2); plus.ios.deleteObject(NSURL2); plus.ios.deleteObject(application2); } else { var main = plus.android.runtimeMainActivity(); var bulid = plus.android.importClass("android.os.Build"); var Intent = plus.android.importClass('android.content.Intent'); if (bulid.VERSION.SDK_INT >= 9) { var intent = new Intent('android.settings.APPLICATION_DETAILS_SETTINGS'); var Uri = plus.android.importClass('android.net.Uri'); var uri = Uri.fromParts("package", main.getPackageName(), null) intent.setData(uri); intent.putExtra('android.content.Intent.setFlags', Intent.FLAG_ACTIVITY_NEW_TASK); } else if (bulid.VERSION.SDK_INT <= 8) { var intent = new Intent(Intent.ACTION_VIEW); intent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails"); intent.putExtra("com.android.settings.ApplicationPkgName", main.getPackageName()); intent.putExtra('android.content.Intent.setFlags', Intent.FLAG_ACTIVITY_NEW_TASK); } main.startActivity(intent); this.isShow = false } } else { uni.navigateBack({ delta: 1 }) } } }) }, /* * 点击联系人 */ onSelectClick: function(contact) { uni.showActionSheet({ itemList: ['电话联系'], success: (e) => { if (e.tapIndex == 0) { uni.makePhoneCall({ phoneNumber: contact.phone }); } } }) }, /* * 搜索 */ onSearchInput: function(e) { var searchVal = e.detail.value this.isSearch = true if (searchVal == '') { this.contacts = JSON.parse(JSON.stringify(this.contactItems)) this.isSearch = false } else { var showList = [] var list = [] list = JSON.parse(JSON.stringify(this.contactItems)) list.forEach((item, index1) => { var contacts = [] item.contacts.forEach((contact, index2) => { for (var i = 0; i < searchVal.length; i++) { if (contact.name.indexOf(searchVal[i]) != -1) { var contain = false; contacts.find(function(val) { if (val.phone == contact.phone) { contain = true; } }); if (!contain) { contacts.push(contact); } } } }) if (contacts.length > 0) { var contacts = { letter: item.letter, contacts: contacts } showList = showList.concat(contacts) } }) setTimeout(() => { this.contacts = JSON.parse(JSON.stringify(showList)) }, 200) } } } } </script> <style> .content { display: flex; flex-direction: column; justify-content: flex-start; align-items: center; width: 100%; height: 100%; } .search { width: 80%; height: 70upx; display: flex; flex-flow: row nowrap; justify-content: center; align-content: center; text-align: center; font-size: 30upx; background-color: #f0f0f0; border-radius: 15upx; margin-top: 10upx; margin-bottom: 10upx; } .contact-scroll { display: flex; flex-direction: column; justify-content: flex-start; align-items: center; width: 100vw; height: calc(100vh - 90upx); } .box { display: flex; flex-direction: column; justify-content: flex-start; align-items: center; width: 100%; } .divider { width: 100%; background-color: #F0F0F0; padding: 5upx 0; color: #000; } .divider-text { margin-left: 20upx; } .item { display: flex; flex-direction: row; flex-wrap: nowrap; justify-content: flex-start; align-items: center; width: 100%; border-bottom: 1px solid #f0f0f0; } .portrait { width: 80upx; height: 80upx; padding: 15upx; } .name { font-size: 35upx; } .hover { background-color: #e7e7e7; } .indexBar-bg { height: 100vh; width: 60px; position: fixed; right: 0; top: 0; z-index: 1000; } .indexBar { position: absolute; left: 50%; top: 50%; transform: translate(0, -50%); display: flex; align-items: center; z-index: 1003; } .indexBar .indexBar-box { width: 60upx; height: auto; background: #fff; display: flex; flex-direction: column; box-shadow: 0 0 20upx rgba(0, 0, 0, 0.1); border-radius: 10upx; z-index: 1004; } .indexBar-item { flex: 1; width: 60upx; height: 60upx; display: flex; align-items: center; justify-content: center; font-size: 24upx; color: #888; z-index: 1005; } .indexToast { position: fixed; top: 0; right: 80upx; bottom: 0; background: rgba(0, 0, 0, 0.5); width: 100upx; height: 100upx; border-radius: 10upx; margin: auto; color: #fff; line-height: 100upx; text-align: center; font-size: 48upx; } .no-contact { position: fixed; width: 100%; margin-top: 300upx; font-size: 35upx; color: #666666; text-align: center; } /* .search { position: fixed; width: 100vw; background-color: #FFFFFF; padding-top: 15upx; } .search .input { display: inline-block; width: 80vw; padding: 2px 0px 2px 0px; text-align: center; font-size: 30upx; background-color: #f0f0f0; margin-left: 10vw; border-radius: 15px; } .contact-scroll { position: fixed; margin-top: 90upx; } .contact-list { float: left; background-color: #FFFFFF; position: relative; width: 100%; display: flex; flex-direction: column; } .contact-list:after { position: absolute; z-index: 10; right: 0; bottom: 0; left: 0; height: 1upx; content: ''; -webkit-transform: scaleY(.5); transform: scaleY(.5); background-color: #c8c7cc; } .contact-list:before { position: absolute; z-index: 10; right: 0; top: 0; left: 0; height: 1upx; content: ''; -webkit-transform: scaleY(.5); transform: scaleY(.5); background-color: #c8c7cc; } .divider { background-color: #F0F0F0; padding: 5upx 0px 5upx 20upx; color: #000; } .item { position: relative; display: flex; flex-direction: row; align-items: center; width: 100%; float: right; border-bottom: 1px solid #f0f0f0; } .hover { background-color: #e7e7e7; } .portrait { display: inline-block; float: left; margin-left: 10upx; width: 80upx; height: 80upx; padding: 15upx; } .name { display: inline-block; float: left; margin: 0 0 0 10upx; font-size: 35upx; } .indexBar-bg { height: 100vh; width: 60px; position: fixed; right: 0px; } .indexBar { position: absolute; left: 50%; top: 50%; transform: translate(0, -50%); display: flex; align-items: center; } .indexBar .indexBar-box { width: 60upx; height: auto; background: #fff; display: flex; flex-direction: column; box-shadow: 0 0 20upx rgba(0, 0, 0, 0.1); border-radius: 10upx; } .indexBar-item { flex: 1; width: 60upx; height: 60upx; display: flex; align-items: center; justify-content: center; font-size: 24upx; color: #888; } .indexToast { position: fixed; top: 0; right: 80upx; bottom: 0; background: rgba(0, 0, 0, 0.5); width: 100upx; height: 100upx; border-radius: 10upx; margin: auto; color: #fff; line-height: 100upx; text-align: center; font-size: 48upx; } .no-contact { position: fixed; width: 100%; margin-top: 300upx; font-size: 35upx; color: #666666; text-align: center; } */ </style>