前端首页index.nvue
<template> <view> <free-nav-bar title="微信" :noreadnum="totalNoreadnum"> </free-nav-bar> <!-- 置顶列表 --> <block v-for="(item,index) in list" v-if="item.istop === true" :key="index"> <free-media-list :item="item" :index="index" @long="long"></free-media-list> </block> <!-- 非置顶列表 --> <block v-for="(item,index) in list" v-if="item.istop === false" :key="index"> <free-media-list :item="item" :index="index" @long="long"></free-media-list> </block> <!-- 弹出层 --> <free-popup ref="extend" maskColor bottom :bodyWidth="240" :bodyHeight="geMenusHeight"> <view class="flex flex-column" style="width:240rpx;" :style="getMenusStyle"> <view v-for="(item,index) in menus" :key="index" class="flex-1 flex align-center" hover-class="bg-light" @click="clickEvent(item.event)"> <text class="font-md pl-3">{{item.name}}</text> </view> </view> </free-popup> </view> </template> <script> import freeNavBar from '@/components/free-ui/free-nav-bar.vue'; import freeMediaList from '@/components/free-ui/free-media-list.vue'; import freePopup from '@/components/free-ui/free-popup.vue'; export default { components: { freeNavBar, freeMediaList, freePopup }, data() { return { propIndex:-1, totalNoreadnum:10, menus:[ { name:'设为置顶', event:"setTop" }, { name:'删除该聊天', event:"delChat" } ], list:[ { avatar:"/static/images/demo/demo6.jpg", nickname:"昵称", update_time:1628069958, data:"你好啊,哈哈哈", noreadnum:1, istop:false }, { avatar:"/static/images/demo/demo6.jpg", nickname:"昵称", update_time:1628069958, data:"你好啊,哈哈哈", noreadnum:12, istop:false }, { avatar:"/static/images/demo/demo6.jpg", nickname:"昵称", update_time:1628069958, data:"你好啊,哈哈哈", noreadnum:2, istop:false }, { avatar:"/static/images/demo/demo6.jpg", nickname:"昵称", update_time:1628069958, data:"你好啊,哈哈哈", noreadnum:10, istop:true } ] } }, onLoad() { }, computed:{ // 动态获取菜单高度 geMenusHeight(){ let H = 100; return this.menus.length * H; }, // 获取菜单的样式 getMenusStyle(){ return `height:${this.geMenusHeight}rpx;`; } }, methods: { openExtend(){ this.$refs.extend.show(100,100); }, long(e){ this.propIndex = e.index; // 拿到当前对象 let item = this.list[e.index] // 判断之前是否处于置顶状态 this.menus[0].name = item.istop ? '取消置顶' : '设为置顶'; this.$refs.extend.show(e.x,e.y); }, //分发菜单事件 clickEvent(event){ switch(event){ case "setTop": this.setTop(); break; // 删除当前会话 case "delChat": this.delChat(); break; } this.$refs.extend.hide(); }, // 删除当前会话 delChat(){ this.list.splice(this.propIndex,1); }, // 置顶取消置顶 setTop(){ let item = this.list[this.propIndex] this.list[this.propIndex].istop = !this.list[this.propIndex].istop; } }, } </script> <style> </style>
插件free-media-list.vue
<template> <view hover-class="bg-light"> <div class="flex align-stretch" :class="item.istop ? 'bg-light' : 'bg-white'" @longpress="long"> <view class=" flex align-center justify-center position-relative" style="width: 145rpx;" @click="onClick" > <free-avatar :src="item.avatar" size="92"></free-avatar> <!-- 角标 --> <free-badge badgeClass="position-absolute" bageStyle="top:15rpx;right:15rpx;" :num="item.noreadnum" v-if="item.noreadnum>0"></free-badge> </view> <view class="flex flex-column border-bottom flex-1 py-3 pr-3 border-light-secondary"> <view class="flex align-center justify-between mb-1"> <text class="font-md">{{item.nickname}}</text> <text class="font-sm text-light-muted">{{item.update_time|formateTime}}</text> </view> <text class="font text-ellipsis text-light-muted">{{item.data}}</text> </view> </div> </view> </template> <script> import freeBase from '@/common/mixin/free-base.js'; import freeAvatar from './free-avatar.vue'; import freeBadge from "./free-badge.vue"; export default{ mixins:[freeBase], components:{ freeAvatar, freeBadge }, props:{ item:Object, index:Number, }, methods:{ long(e){ let x=0,y=0; // #ifdef APP-PLUS-NVUE if(Array.isArray(e.changedTouches) && e.changedTouches.length>0){ x = e.changedTouches[0].screenX; y = e.changedTouches[0].screenY; } // #endif // #ifdef MP x = e.detail.x; y = e.detail.y; // #endif this.$emit('long',{x,y,index:this.index}); }, onClick(){ this.$emit('click'); } } } </script> <style> </style>
插件free-navbar-list.vue
<template> <view> <view class="bg-light" :class="fixed?'fixed-top':''"> <!-- 状态栏 --> <view :style="'height:'+statusBarHeight+'px;'"></view> <!-- 导航 --> <view class="w-100 flex align-center justify-between" style="height: 90rpx;"> <!-- 左边 --> <view class="flex align-center"> <!-- 标题 --> <text v-if="title" class="font-md ml-3" >{{getTitle}}</text> </view> <!-- 右边 --> <view class="flex align-center"> <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> </view> <!--\ue6e3 \ue682 --> </view> </view> <!-- 站位 --> <view v-if="fixed" :style="fixedStyle"></view> <!-- 扩展菜单 --> <free-popup 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: { title: { type: String, default: '' }, fixed:{ type:Boolean, default:false }, noreadnum:{ type:Number, default:0 } }, 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; } }, methods:{ openExtend(){ this.$refs.extend.show(uni.upx2px(415),uni.upx2px(150)); } } } </script> <style> </style>
插件free-popup.vue
<template> <div style="z-index:9999;overflow:hidden;" v-if="status"> <!-- 蒙版 --> <view v-if="mask" class="position-fixed top-0 left-0 right-0 bottom-0" :style="getMaskColor" @click="hide"></view> <!-- 弹出框内容 --> <div ref="popup" class="position-fixed free-animated" :class="getBodyClass" :style="getBodyStyle"> <slot></slot> </div> </div> </template> <script> // #ifdef APP-PLUS-NVUE const animation = weex.requireModule('animation'); // #endif export default { props: { // 是否开启蒙版颜色 maskColor: { type: Boolean, default: false }, // 是否开启蒙版 mask:{ type:Boolean, default:true }, // 是否处于底部 fixedBottom:{ type:Boolean, default:false }, // 弹出层内容高度 bodyHeight:{ type:Number, default:0 }, // 弹出层内容宽度 bodyWidth:{ type:Number, default:0 }, bodyBgColor:{ type:String, default:'bg-white' }, transformOrigin:{ type:String, default:'left top' } }, data() { return { status: false, x:-1, y:1, maxX:0, maxY:0 } }, mounted() { try { const res = uni.getSystemInfoSync(); this.maxX = res.windowWidth - uni.upx2px(this.bodyWidth) this.maxY = res.windowHeight - uni.upx2px(this.bodyHeight) } catch (e) { // error } }, computed: { getMaskColor() { let i = this.maskColor ? 0.5 : 0 return `background-color: rgba(0,0,0,${i});` }, getBodyClass(){ if(this.center){ return 'left-0 right-0 bottom-0 top-0 flex align-center justify-center'; } let bottom = this.bottom ? 'left-0 right-0 bottom-0' : 'rounded border' return `${this.bodyBgColor} ${bottom}`; }, getBodyStyle(){ let left = this.x > -1 ? `left:${this.x}px;` : '' let top = this.y > -1 ? `top:${this.y}px;` : '' return left + top } }, methods:{ show(x=-1,y=-1){ this.x = (x > this.maxX) ? this.maxX : x; this.y = (y > this.maxY) ? this.maxY : y; this.status = true // #ifdef APP-PLUS-NVUE this.$nextTick(()=>{ animation.transition(this.$refs.popup,{ styles:{ transform:'scale(1,1)', transformOrigin:this.transformOrigin, opacity:1 }, duration:100, //ms timingFunction:'ease', },()=>{ console.log('动画执行结束'); }) }) // #endif }, hide(){ // #ifdef APP-PLUS-NVUE this.$nextTick(()=>{ animation.transition(this.$refs.popup,{ styles:{ transform:'scale(0,0)', transformOrigin:this.transformOrigin, opacity:0 }, duration:100, //ms timingFunction:'ease', },()=>{ this.status = false; }) }) // #endif } } } </script> <style scoped> .free-animated{ /* #ifdef APP-PLUS-NVUE */ /* transform: scale(0,0); opacity: 0; */ /* #endif */ } .z-index{ /* #ifndef APP-NVUE */ z-index: 9999; /* #endif */ } </style>
页面样式是这样子的
关于功能方面,实现了置顶和取消置顶,点击加号,还有删除聊天。
好了,这就是今天的内容,感谢大家观看,我们下期再见。