这一块主要讲了,微信通讯录右边的音文字母的联动效果
mail.nvue
<template> <view> <!-- 导航栏 --> <free-nav-bar title="通讯录"></free-nav-bar> <!-- 通讯录列表 --> <scroll-view scroll-y="true" :style="'height:'+scrollHeight+'px;'" :scroll-into-view="scrollInto"> <free-list-item v-for="(item,index) in topList" :key="index" :title="item.title" :cover="item.cover" @click=""></free-list-item> <view v-for="(item,index) in list" :key="index" v-if="item.data.length>0" :id="'item-'+item.letter"> <view class="py-2 px-3 border-bottom bg-light"> <text class="font-md text-dark">{{item.letter}}</text> </view> <free-list-item v-for="(item2,index2) in item.data" :key="index2" :title="item2" cover="/static/images/mail/friend.png" @click=""></free-list-item> </view> </scroll-view> <!-- 侧边导航条 --> <view class="position-fixed right-0 bottom-0 flex flex-column" :style="'top:'+top+'rpx;'" style="width: 50rpx;" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend" > <view class="flex-1 flex align-center justify-center" v-for="(item,index) in list" :key="index"> <text class="font-sm text-muted">{{item.letter}}</text> </view> </view> <!-- <block v-if="current"> --> <view class="position-fixed rounded-circle bg-light border flex align-center justify-center" style="width: 150rpx;height: 150rpx; left: 300rpx;" :style="'top:'+modalTop+'px;'" v-if="current!=''"> <text class="font-lg" >{{current}}</text> </view> <!-- </block> --> </view> </template> <script> import freeNavBar from "@/components/free-ui/free-nav-bar.vue"; import freeListItem from '@/components/free-ui/free-list-item.vue'; export default { components:{ freeNavBar, freeListItem }, computed:{ modalTop(){ return (this.scrollHeight-uni.upx2px(150))/2; }, itemHeight(){ let count = this.list.length; if(count<1){ return 0; } return this.scrollHeight/count; } }, onLoad() { let res = uni.getSystemInfoSync(); this.top = res.statusBarHeight + uni.upx2px(90); this.scrollHeight = res.windowHeight-this.top; }, data() { return { scrollInto:'', top:0, scrollHeight:0, current:'', topList:[ { title:"新的朋友", cover:"/static/images/mail/friend.png", event:"" }, { title:"群聊", cover:"/static/images/mail/group.png", event:"" }, { title:"标签", cover:"/static/images/mail/tag.png", event:"" } ], list:[{ "letter":"A", "data":[ "阿苏", "阿拉", "阿拉", "阿拉", "阿拉", "阿拉", "阿拉", "阿拉", "阿拉", "阿拉" ] },{ "letter":"B", "data":[ "baba", "霸占", "吧拉" ] }, { "letter":"C", "data":[ "吃好", "车霸占", "才吧拉" ] }, { "letter":"D", "data":[ "Dd", "dd", "滴滴滴" ] }] } }, methods: { touchstart(e){ this.changeScrollInto(e); }, touchmove(e){ this.changeScrollInto(e); }, touchend(){ this.current = ''; }, // 联动 changeScrollInto(e){ // let Y = e.touches[0].pageY; // let index = Math.floor(Y / this.itemHeight); // let item = this.list[index]; // if(item){ // this.scrollInto = 'item-'+item.letter; // this.current = item.letter; // } let Y = e.touches[0].pageY // #ifdef MP Y = Y - this.top // #endif let index = Math.floor(Y / this.itemHeight) let item = this.list[index] if(item){ this.scrollInto = 'item-'+item.letter this.current = item.letter } } } } </script> <style> </style>
所用到的插件
// free-nav-bar.vue <template> <view> <view :class="getClass"> <!-- 状态栏 --> <view :style="'height:'+statusBarHeight+'px;'"></view> <!-- 导航 --> <view class="w-100 flex align-center justify-between" style="height: 90rpx;"> <!-- 左边 --> <view class="flex align-center"> <!-- 返回按钮 --> <free-icon-button v-if="showBack" @click="back"><text class="iconfont font-md"></text></free-icon-button> <!-- 标题 --> <text v-if="title" class="font-md ml-3" >{{getTitle}}</text> </view> <!-- 右边 --> <view class="flex align-center" v-if="showRight"> <slot name="right"> <free-icon-button @click="search"><text class="iconfont font-md"></text></free-icon-button> <free-icon-button @click="openExtend"><text class="iconfont font-md"></text></free-icon-button> </slot> </view> <!--\ue6e3 \ue682 --> </view> </view> <!-- 站位 --> <view v-if="fixed" :style="fixedStyle"></view> <!-- 扩展菜单 --> <free-popup v-if="showRight" ref="extend" maskColor bottom :bodyWidth="320" :bodyHeight="525" bodyBgColor="bg-dark" transformOrigin="right top"> <view class="flex flex-column" style="width:320rpx;height: 525rpx;"> <view v-for="(item,index) in menus" :key="index" class="flex-1 flex align-center" hover-class="bg-hover-dark" @click="clickEvent(item.event)"> <text class="pl-3 pr-2 iconfont font-md text-white">{{item.icon}}</text> <text class="font-md text-white">{{item.name}}</text> </view> </view> </free-popup> </view> </template> <script> import freeIconButton from './free-icon-button.vue'; import freePopup from './free-popup.vue'; export default { components: { freeIconButton, freePopup }, props: { showBack:{ type:Boolean, default:false }, title: { type: String, default: '' }, fixed:{ type:Boolean, default:false }, noreadnum:{ type:Number, default:0 }, bgColor:{ type:String, default:"bg-light" }, showRight:{ type:Boolean, default:true } }, data() { return { statusBarHeight: 0, navBarHeight: 0, menus:[ { name:'发起群聊', event:"", icon:"\ue633" }, { name:'添加好友', event:"", icon:"\ue65d" }, { name:'扫一扫', event:"", icon:"\ue614" }, { name:'收付款', event:"", icon:"\ue66c" }, { name:'帮助与反馈', event:"", icon:"\ue61c" } ], } }, mounted() { // 获取任务栏高度 // #ifdef APP-PLUS-NVUE this.statusBarHeight = plus.navigator.getStatusbarHeight() // #endif this.navBarHeight = this.statusBarHeight + uni.upx2px(90) }, computed: { fixedStyle() { return `height:${this.navBarHeight}px`; }, getTitle(){ let noreadnum = this.noreadnum>0 ? '('+this.noreadnum+')' : ''; return this.title + noreadnum; }, getClass(){ let fixed = this.fixed?"fixed-top":""; return `${fixed} ${this.bgColor}`; } }, methods:{ openExtend(){ this.$refs.extend.show(uni.upx2px(415),uni.upx2px(150)); }, // 返回 back(){ uni.navigateBack({ delta:1 }) } } } </script> <style> </style> // free-list-item.vue <template> <view class="bg-white flex align-stretch" hover-class="bg-light" @click="$emit('click')"> <view class="flex align-center justify-center py-2 pl-3" v-if="showLeftIcon"> <slot name="icon"></slot> <image :src="cover" v-if="cover" style="width: 75rpx;height: 75rpx;" mode="widthFix" :style="coverStyle"></image> </view> <view class="flex-1 flex align-center justify-between py-3 pl-3" :class="border ? 'border-bottom' : ''"> <slot> <text class="font-md text-dark">{{title}}</text> </slot> <view class="flex align-center pr-3" v-if="showRight"> <slot name="right"></slot> <!-- 右 --> <text class="iconfont text-light-muted font-md" v-if="showRightIcon" ></text> </view> </view> </view> </template> <script> export default{ props:{ // 是否开启下边线 border:{ type:Boolean, default:true }, // 封面 cover:{ type:String, default:"" }, // 标题 title:{ type:String, default:"" }, // 显示右边 showRight:{ type:Boolean, default:false }, // 封面大小 coverSize:{ type:[String,Number], default:75 }, // 显示左边图标 showLeftIcon:{ type:Boolean, default:true }, showRightIcon:{ type:Boolean, default:true } }, computed:{ coverStyle(){ return `width:${this.coverSize}rpx;height:${this.coverSize}rpx;`; } } } </script> <style> </style>
界面是酱紫的
感谢大家观看,我们下期见。