uni-app 4.14~4.23首页消息页面开发

简介: uni-app 4.14~4.23首页消息页面开发


前端首页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">&#xe6e3;</text></free-icon-button>
          <free-icon-button @click="openExtend"><text class="iconfont font-md">&#xe682;</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>

页面样式是这样子的

关于功能方面,实现了置顶和取消置顶,点击加号,还有删除聊天。

好了,这就是今天的内容,感谢大家观看,我们下期再见。

目录
相关文章
|
22天前
|
移动开发 小程序
如何让uni-app开发的H5页面顶部原生标题和小程序的顶部标题不一致?
如何让uni-app开发的H5页面顶部原生标题和小程序的顶部标题不一致?
|
2月前
|
API 数据安全/隐私保护 iOS开发
利用uni-app 开发的iOS app 发布到App Store全流程
利用uni-app 开发的iOS app 发布到App Store全流程
95 3
|
2月前
|
Android开发 开发者 UED
个人开发 App 成功上架手机应用市场的关键步骤
个人开发 App 成功上架手机应用市场的关键步骤
|
2月前
|
开发工具 数据安全/隐私保护 Android开发
【教程】APP 开发后如何上架?
【教程】APP 开发后如何上架?
|
2月前
|
API
uni-app 146朋友圈列表api开发
uni-app 146朋友圈列表api开发
19 0
|
18天前
|
小程序
深入理解 uni-app 页面生命周期(四)onShareAppMessage
深入理解 uni-app 页面生命周期(四)onShareAppMessage
|
18天前
|
C++
深入理解 uni-app 页面生命周期(三):onHide vs onUnload
深入理解 uni-app 页面生命周期(三):onHide vs onUnload
|
18天前
|
JavaScript
深入理解 uni-app 页面生命周期(二):onReady()
深入理解 uni-app 页面生命周期(二):onReady()
|
18天前
|
监控 C++
深入理解 uni-app 页面生命周期(一):onLoad vs onShow
深入理解 uni-app 页面生命周期(一):onLoad vs onShow
|
22天前
|
移动开发 小程序 前端开发
使用uni-app开发(h5、小程序、app)步骤
使用uni-app开发(h5、小程序、app)步骤