address_book.vue 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. <template>
  2. <view class="">
  3. <hx-navbar leftText="查看手机通讯录" defaultBackUrl="phone" :fixed="true" >
  4. </hx-navbar>
  5. <view class="content">
  6. <input v-if="contacts.length>0 || isSearch" class="search" type="text" placeholder="搜索联系人" @input="onSearchInput" />
  7. <view v-if="contacts.length>0">
  8. <scroll-view class="contact-scroll" scroll-y :scroll-into-view="scrollViewId">
  9. <view class="box" v-for="(item,key) in contacts" :key="key">
  10. <view class="divider" :id="item.letter">
  11. <text class="divider-text">{{item.letter}}</text>
  12. </view>
  13. <view class="item" hover-class="hover" hover-start-time="20" v-for="(contact,index) in item.contacts" :key="index" @click='onSelectClick(contact)'>
  14. <image class="portrait" src="/static/img/missing-face.png" mode="aspectFill"></image>
  15. <view class="item-content">
  16. <view class="text-black"><text class="">{{contact.name}}</text></view>
  17. <view class="text-gray text-sm">
  18. {{appName}}:{{contact.name}}
  19. </view>
  20. </view>
  21. </view>
  22. </view>
  23. </scroll-view>
  24. <view class="indexBar-bg">
  25. <view class="indexBar" >
  26. <view class="indexBar-box" @touchstart="tStart" @touchend="tEnd" @touchmove="tMove">
  27. <view class="indexBar-item" v-for="(item,index) in contacts" :key="index" :id="item.letter" @touchstart="getCur"
  28. @touchend="setCur">
  29. {{item.letter}}
  30. </view>
  31. </view>
  32. </view>
  33. </view>
  34. <view v-show="!hidden" class="indexToast">{{letter}}</view>
  35. </view>
  36. <text v-else class="no-contact">通讯录暂无联系人</text>
  37. </view>
  38. </view>
  39. </template>
  40. <script>
  41. import pinyin from '@/common/pinyin/pinyin3.js'
  42. var platform = uni.getSystemInfoSync().platform
  43. export default {
  44. data() {
  45. return {
  46. /* 侧边栏选择器 */
  47. scrollViewId: "wo",
  48. letter: "",
  49. boxTop: 0,
  50. barHeight: 0,
  51. minHeight: 0,
  52. hidden: true,
  53. /* 联系人 */
  54. contacts: [],
  55. contactItems: [],
  56. isSearch: false,
  57. isShow: false,
  58. appName: ''
  59. }
  60. },
  61. onLoad() {
  62. const res = uni.getSystemInfoSync();
  63. this.barHeight = res.windowHeight / 27;
  64. //初始通讯录
  65. this.initContacts();
  66. this.appName = this.$conf.appName
  67. },
  68. methods: {
  69. /*
  70. * 滑动的侧边选择器
  71. */
  72. getCur(e) {
  73. console.log("显示");
  74. this.hidden = false
  75. this.letter = e.target.id
  76. },
  77. setCur(e) {
  78. console.log("隐藏");
  79. this.hidden = true;
  80. this.letter = e.target.id
  81. },
  82. tMove(e) {
  83. var y = e.touches[0].clientY
  84. var offsettop = this.boxTop
  85. console.log(offsettop)
  86. //判断选择区域,只有在选择区才会生效
  87. if (y > offsettop) {
  88. var num = Math.floor((y - offsettop) / this.barHeight);
  89. if (num < this.contacts.length) {
  90. this.letter = this.contacts[num].letter
  91. this.scrollViewId = this.letter
  92. }
  93. }
  94. },
  95. tStart() {
  96. this.hidden = false;
  97. let that =this;
  98. const query = uni.createSelectorQuery().in(this);
  99. query.select('.indexBar-box').boundingClientRect(data => {
  100. if (data != null) {
  101. that.boxTop = data.top
  102. }
  103. }).exec();
  104. },
  105. tEnd() {
  106. this.hidden = true;
  107. },
  108. /*
  109. * 初始化通讯录
  110. */
  111. initContacts: function() {
  112. //获取手机通讯录
  113. plus.contacts.getAddressBook(plus.contacts.ADDRESSBOOK_PHONE, (addressbook) => {
  114. // 可通过addressbook进行通讯录操作
  115. addressbook.find(["displayName", "phoneNumbers"], (contacts) => {
  116. var items = [];
  117. for (var i = 0; i < contacts.length; i++) {
  118. if (contacts[i].phoneNumbers.length > 0) {
  119. var contact = {
  120. 'name': contacts[i].displayName,
  121. 'phone': contacts[i].phoneNumbers[0].value
  122. };
  123. items.push(contact);
  124. }
  125. }
  126. this.contacts = pinyin.paixu(items)
  127. this.contacts.sort(function(o1, o2) {
  128. return o1.letter.charCodeAt(0) - o2.letter.charCodeAt(0)
  129. })
  130. this.contactItems = JSON.parse(JSON.stringify(this.contacts))
  131. }, (e) => {
  132. this.onAddressBookSetting()
  133. });
  134. }, (e) => {
  135. this.onAddressBookSetting()
  136. });
  137. },
  138. /*
  139. * 权限设置
  140. */
  141. onAddressBookSetting: function() {
  142. if (this.isShow) {
  143. return
  144. }
  145. this.isShow = true
  146. uni.showModal({
  147. title: '提示',
  148. content: 'APP通讯录权限没有开启,是否开启?',
  149. success(res) {
  150. if (res.confirm) {
  151. if (platform == 'ios') {
  152. var UIApplication = plus.ios.import("UIApplication");
  153. var NSURL2 = plus.ios.import("NSURL");
  154. var setting2 = NSURL2.URLWithString("app-settings:");
  155. var application2 = UIApplication.sharedApplication();
  156. application2.openURL(setting2);
  157. plus.ios.deleteObject(setting2);
  158. plus.ios.deleteObject(NSURL2);
  159. plus.ios.deleteObject(application2);
  160. } else {
  161. var main = plus.android.runtimeMainActivity();
  162. var bulid = plus.android.importClass("android.os.Build");
  163. var Intent = plus.android.importClass('android.content.Intent');
  164. if (bulid.VERSION.SDK_INT >= 9) {
  165. var intent = new Intent('android.settings.APPLICATION_DETAILS_SETTINGS');
  166. var Uri = plus.android.importClass('android.net.Uri');
  167. var uri = Uri.fromParts("package", main.getPackageName(), null)
  168. intent.setData(uri);
  169. intent.putExtra('android.content.Intent.setFlags', Intent.FLAG_ACTIVITY_NEW_TASK);
  170. } else if (bulid.VERSION.SDK_INT <= 8) {
  171. var intent = new Intent(Intent.ACTION_VIEW);
  172. intent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
  173. intent.putExtra("com.android.settings.ApplicationPkgName", main.getPackageName());
  174. intent.putExtra('android.content.Intent.setFlags', Intent.FLAG_ACTIVITY_NEW_TASK);
  175. }
  176. main.startActivity(intent);
  177. this.isShow = false
  178. }
  179. } else {
  180. uni.navigateBack({
  181. delta: 1
  182. })
  183. }
  184. }
  185. })
  186. },
  187. /*
  188. * 点击联系人
  189. */
  190. onSelectClick: function(contact) {
  191. uni.showActionSheet({
  192. itemList: ['电话联系'],
  193. success: (e) => {
  194. if (e.tapIndex == 0) {
  195. uni.makePhoneCall({
  196. phoneNumber: contact.phone
  197. });
  198. }
  199. }
  200. })
  201. },
  202. /*
  203. * 搜索
  204. */
  205. onSearchInput: function(e) {
  206. var searchVal = e.detail.value
  207. this.isSearch = true
  208. if (searchVal == '') {
  209. this.contacts = JSON.parse(JSON.stringify(this.contactItems))
  210. this.isSearch = false
  211. } else {
  212. var showList = []
  213. var list = []
  214. list = JSON.parse(JSON.stringify(this.contactItems))
  215. list.forEach((item, index1) => {
  216. var contacts = []
  217. item.contacts.forEach((contact, index2) => {
  218. for (var i = 0; i < searchVal.length; i++) {
  219. if (contact.name.indexOf(searchVal[i]) != -1) {
  220. var contain = false;
  221. contacts.find(function(val) {
  222. if (val.phone == contact.phone) {
  223. contain = true;
  224. }
  225. });
  226. if (!contain) {
  227. contacts.push(contact);
  228. }
  229. }
  230. }
  231. })
  232. if (contacts.length > 0) {
  233. var contacts = {
  234. letter: item.letter,
  235. contacts: contacts
  236. }
  237. showList = showList.concat(contacts)
  238. }
  239. })
  240. setTimeout(() => {
  241. this.contacts = JSON.parse(JSON.stringify(showList))
  242. }, 200)
  243. }
  244. }
  245. }
  246. }
  247. </script>
  248. <style>
  249. page{
  250. background: #ffffff;
  251. }
  252. .content {
  253. display: flex;
  254. flex-direction: column;
  255. justify-content: flex-start;
  256. align-items: center;
  257. width: 100%;
  258. height: 100%;
  259. }
  260. .search {
  261. width: 80%;
  262. height: 70upx;
  263. display: flex;
  264. flex-flow: row nowrap;
  265. justify-content: center;
  266. align-content: center;
  267. text-align: center;
  268. font-size: 30upx;
  269. background-color: #f0f0f0;
  270. border-radius: 15upx;
  271. margin-top: 10upx;
  272. margin-bottom: 10upx;
  273. }
  274. .contact-scroll {
  275. display: flex;
  276. flex-direction: column;
  277. justify-content: flex-start;
  278. align-items: center;
  279. width: 100vw;
  280. height: calc(100vh - 90upx - var(--status-bar-height) - 88upx);
  281. }
  282. .box {
  283. display: flex;
  284. flex-direction: column;
  285. justify-content: flex-start;
  286. align-items: center;
  287. width: 100%;
  288. }
  289. .divider {
  290. width: 100%;
  291. background-color: #F0F0F0;
  292. padding: 30upx;
  293. color: #000;
  294. }
  295. .divider-text {
  296. margin-left: 20upx;
  297. }
  298. .item {
  299. display: flex;
  300. flex-direction: row;
  301. flex-wrap: nowrap;
  302. justify-content: flex-start;
  303. align-items: center;
  304. width: 100%;
  305. /*border-bottom: 1px solid #f0f0f0;*/
  306. padding: 16upx 12upx;
  307. }
  308. .item-content{
  309. }
  310. .portrait {
  311. width: 96upx;
  312. height: 96upx;
  313. padding: 15upx;
  314. }
  315. .name {
  316. font-size: 35upx;
  317. }
  318. .hover {
  319. background-color: #e7e7e7;
  320. }
  321. .indexBar-bg {
  322. height: 100vh;
  323. width: 60px;
  324. position: fixed;
  325. right: 0;
  326. top: 0;
  327. z-index: 1000;
  328. }
  329. .indexBar {
  330. position: absolute;
  331. left: 50%;
  332. top: 50%;
  333. transform: translate(0, -50%);
  334. display: flex;
  335. align-items: center;
  336. z-index: 1003;
  337. }
  338. .indexBar .indexBar-box {
  339. width: 60upx;
  340. height: auto;
  341. background: #fff;
  342. display: flex;
  343. flex-direction: column;
  344. box-shadow: 0 0 20upx rgba(0, 0, 0, 0.1);
  345. border-radius: 10upx;
  346. z-index: 1004;
  347. }
  348. .indexBar-item {
  349. flex: 1;
  350. width: 60upx;
  351. height: 60upx;
  352. display: flex;
  353. align-items: center;
  354. justify-content: center;
  355. font-size: 24upx;
  356. color: #888;
  357. z-index: 1005;
  358. }
  359. .indexToast {
  360. position: fixed;
  361. top: 0;
  362. right: 80upx;
  363. bottom: 0;
  364. background: rgba(0, 0, 0, 0.5);
  365. width: 100upx;
  366. height: 100upx;
  367. border-radius: 10upx;
  368. margin: auto;
  369. color: #fff;
  370. line-height: 100upx;
  371. text-align: center;
  372. font-size: 48upx;
  373. }
  374. .no-contact {
  375. position: fixed;
  376. width: 100%;
  377. margin-top: 300upx;
  378. font-size: 35upx;
  379. color: #666666;
  380. text-align: center;
  381. }
  382. </style>