校园综合平台-微信小程序版(整整两个月暑假的成果啊 (•ิ_•ิ))

前言

        学习了一段时间的微信小程序,开始都是做零零散散的小项目,暑假借着晚上有的一点时间,决定自己写一个校园综合平台,包含二手市场、表白墙、音乐、文章、动态等一些功能,一方面可以锻炼自己的编程能力,一方面也是检验自己学习的成果。最近时间有点充足,分享一下。O(∩_∩)O~

微信小程序实现功能

  • 二手市场
  • 表白墙
  • 发布动态
  • 动态悬浮球
  • 独立swiper组件(超简洁、好看)
  • 程序版本记录
  • 文章查询
  • 天气查询
  • 音乐
  • 云开发
  • 多记录获取
  • 动态更换背景
  • 校园导航

程序运行视频

海轰Pro


视频播放地址

一、二手市场

实现功能

  1. 发布二手消息(含图片、文字)
  2. 详情页买方可以联系卖方
  3. 用户评论功能
  4. 发布信息的浏览量、点赞数、评论数
  5. 用户评论功能

模块代码
1、信息发布功能
参考海轰的往期文章–微信小程序仿QQ动态发布
2、买方联系卖方
电话联系

call: function(e) {
    console.log(e)
    wx.makePhoneCall({
      phoneNumber: this.data.phone,
    })
  },

微信联系(QQ同理,其实就是复制用户提供的微信号、QQ号)

to_weixin: function(e) {
    console.log(e.currentTarget.dataset.id)
    wx.setClipboardData({
      data: e.currentTarget.dataset.id,
      icon: "none",
      success: res => {
        wx.showToast({
          title: '已复制微信号ヽ(✿゚▽゚)ノ',
          duration: 1000,
          icon: "none",
        })
      }
    })
  }

3、点赞功能(云函数实现,每个用户都需要对数据进行操作,所以选用云函数封装一下)

// 云函数入口文件
const cloud = require('wx-server-sdk')

cloud.init()
const db = cloud.database();
const _ = db.command;
// 云函数入口函数
exports.main = async (event, context) => {
  console.log(event.name)
  try {
    return await db.collection(event.name).doc(event._id).update({
      data: {
        fabulous_num: _.inc(1)
      }
    })
  } catch (e) {
    console.error(e)
  }
}

4、评论功能

// 云函数入口文件
const cloud = require('wx-server-sdk')

cloud.init()
const db = cloud.database();

// 云函数入口函数
exports.main = async (event, context) => {
  try {
    return await db.collection("information").doc(event._id).update({
      data: {
        comment: event.comment
      }
    })
  } catch (e) {
    console.error(e)
  }
}

二、动态悬浮球

wxml

<image
 src="/images/fabu.png"
 bindtouchmove="buttonMove" catchtap="to_publish" bindtouchstart="buttonStart" bindtouchend="buttonEnd" style="top:{{buttonTop}}px;left:{{buttonLeft}}px;width:112rpx;height:92rpx;position:fixed;;line-height:50px;font-size:25pt;color:#fff;z-index:5;"></image>
</view>

js

buttonStart: function (e) {
    startPoint = e.touches[0]
  },
  buttonMove: function (e) {
    var endPoint = e.touches[e.touches.length - 1]
    var translateX = endPoint.clientX - startPoint.clientX
    var translateY = endPoint.clientY - startPoint.clientY
    startPoint = endPoint
    var buttonTop = this.data.buttonTop + translateY
    var buttonLeft = this.data.buttonLeft + translateX
    //判断是移动否超出屏幕
    if (buttonLeft + 50 >= this.data.windowWidth) {
      buttonLeft = this.data.windowWidth - 50;
    }
    if (buttonLeft <= 0) {
      buttonLeft = 0;
    }
    if (buttonTop <= 0) {
      buttonTop = 0
    }
    if (buttonTop + 50 >= this.data.windowHeight) {
      buttonTop = this.data.windowHeight - 50;
    }
    this.setData({
      buttonTop: buttonTop,
      buttonLeft: buttonLeft
    })
  },
  buttonEnd: function (e) {

  },

三、独立swiper组件

参考海轰的往期文章–简洁好看的轮播图组件

四、音乐

这里我使用的GitHub上一个音乐UI为模板,按照自己想法,改成了一个属于自己的音乐播放器。
wxml

  <view class="player" v-show="playlist.length>0">
    <view class="normal-player" wx:if="fullScreen">
      <view class="background">
      </view>
      <view class="top">
        <view class="title">{{song.music_name || '暂无正在播放歌曲'}}</view>
        <view class="subtitle">{{song.singer_name}}</view>
      </view>
      <swiper class="middle" style="height: 700rpx" bindchange="changeDot">
        <swiper-item class="middle-l" style="overflow: visible">
          <view class="cd-wrapper" ref="cdWrapper">
            <view class="cd {{cdCls}}">
              <image src="{{song.singer_img}}" alt="" class="image"/>
            </view>
          </view>
          <view class="currentLyricWrapper">{{currentText}}</view>
        </swiper-item>
        <swiper-item class="middle-r">
          <scroll-view class="lyric-wrapper" scroll-y scroll-into-view="line{{toLineNum}}" scroll-with-animation>
            <view v-if="currentLyric">
              <view ref="lyricLine"
                    id="line{{index}}"
                    class="text {{currentLineNum == index ? 'current': '' }}"
                    wx:for="{{currentLyric.lines}}">{{item.txt}}
              </view>
            </view>
            <view wx:if="{{!currentLyric}}">
              <view class="text current">暂无歌词</view>
            </view>
          </scroll-view>
        </swiper-item>
      </swiper>
      <view class="dots-wrapper">
        <view class="dots {{currentDot==index?'current':''}}" wx:for="{{dotsArray}}"></view>
      </view>
      <view class="bottom">
        <view class="progress-wrapper">
          <text class="time time-l">{{currentTime}}</text>
          <view class="progress-bar-wrapper">
            <progress-bar percent="{{percent}}"></progress-bar>
          </view>
          <text class="time time-r">{{duration}}</text>
        </view>
        <view class="operators">
          <view class="icon i-left">
            <i bindtap="changeMod"
               class="{{playMod==1? 'icon-sequence':''}}{{playMod==2? ' icon-random':''}}{{playMod==3?' icon-loop':''}}"></i>
          </view>
          <view class="icon i-left">
            <i class="icon-prev" bindtap="prev"></i>
          </view>
          <view class="icon i-center" bindtap="togglePlayings">
            <i class="{{playIcon}}" ></i>
          </view>
          <view class="icon i-right">
            <i class="icon-next" bindtap="next"></i>
          </view>
          <view class="icon i-right" bindtap="openList">
            <i class="icon-playlist"></i>
          </view>
        </view>
      </view>
    </view>
    <view class="content-wrapper {{translateCls}}">
      <view class="close-list"  bindtap="close"></view>
      <view class="play-content">
        <view class="plyer-list-title">播放队列({{songs.length}})</view>
        <scroll-view class="playlist-wrapper" scroll-y scroll-into-view="list{{currentIndex}}">
          <view class="item {{index==currentIndex ? 'playing':''}}" wx:for="{{songs}}" id="{{index}}"
                data-index="{{songs.music_path}}" bindtap="playthis" wx:key="{{index}}">
            <view class="name" style='text-white'>{{item.music_name}}</view>
            <view class="play_list__line">-</view>
            <view class="singer">{{item.singer_name}}</view>
            
          </view>
        </scroll-view>
        <view class="close-playlist" bindtap="close">关闭</view>
      </view>
    </view>
  </view>


<view class='cu-load load-modal' wx:if="{{loadModal}}">
  <!-- <view class='cuIcon-emojifill text-orange'></view> -->
  <image src='/images/T1.jpg' class='png' mode='aspectFit'></image>
  <view class='text-red'>加载中...</view>
</view>

wxss

.player .normal-player {
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    z-index: 150;
    background: #222;
}
.player .normal-player .background {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    z-index: -1;
    background-image: url(https://wx3.sinaimg.cn/mw690/006cV2kkly1g6e0w1wb20j30yi22oacu.jpg);
  background-size: cover;
}
.player .normal-player .top {
    position: relative;
    margin-bottom: 50rpx;
}
.player .normal-player .top .title {
    width: 70%;
    margin: 50rpx auto;
    line-height: 80rpx;
    text-align: center;
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
    font-size: 36rpx;
    color: #fff;
}
.player .normal-player .top .subtitle {
    line-height: 40rpx;
    text-align: center;
    font-size: 28rpx;
    color: #fff;
}
.player .normal-player .middle {
    position: fixed;
    width: 100%;
    top: 360rpx;
    bottom: 200rpx;
    white-space: nowrap;
    font-size: 0;
}
.player .normal-player .middle .middle-l {
    display: inline-block;
    vertical-align: top;
    position: relative;
    width: 100%;
    height: 0!important;
    padding-top: 80%!important;
}
.player .normal-player .middle .middle-l .cd-wrapper {
    position: absolute;
    left: 15%;
    top: 0;
    width: 70%;
    height: 90%;
}
.player .normal-player .middle .middle-l .cd-wrapper .play {
    -webkit-animation-play-state: running !important;
    animation-play-state: running !important;
}
.player .normal-player .middle .middle-l .cd-wrapper .pause {
    -webkit-animation-play-state: paused!important;
    animation-play-state: paused!important;
}
.player .normal-player .middle .middle-l .cd-wrapper .cd {
  width: 100%;
  height: 100%;
  border: 10rpx solid rgba(255,255,255,0.1);
  border-radius: 50%;
    -webkit-animation: rotate 20s linear infinite;
    animation: rotate 20s linear infinite;
}
.player .normal-player .middle .middle-l .cd-wrapper .cd .image {
    position: absolute;
    left: 0rpx;
    top: 0rpx;
    width: 100%;
    height: 100%;
    border-radius: 50%;
}
.player .normal-player .bottom {
    position: absolute;
    bottom: 50rpx;
    width: 100%;
}
.player .normal-player .bottom .progress-wrapper {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    width: 80%;
    margin: 0rpx auto;
    padding: 20rpx 0;
}
.player .normal-player .bottom .progress-wrapper .time.time-l {
    text-align: left;
}
.player .normal-player .bottom .progress-wrapper .time.time-r {
    text-align: right;
}
.player .normal-player .bottom .progress-wrapper .time {
  color: #fff;
  font-size: 24rpx;
  -webkit-box-flex: 0;
  -ms-flex: 0 0 60rpx;
  flex: 0 0 60rpx;
  line-height: 60rpx;
  width: 60rpx;
}
.player .normal-player .bottom .operators {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    height: 200rpx;
}
.player .normal-player .bottom .operators .icon {
    -webkit-box-flex: 1;
    -ms-flex: 1;
    flex: 1;
    color: #ffcd32;
}
.player .normal-player .bottom .operators .i-left {
    text-align: right;
}
.player .normal-player .bottom .operators .icon i {
    font-size: 80rpx;
}
.player .normal-player .bottom .operators .i-center {
    padding: 0 40rpx;
    text-align: center;
}
.player .normal-player .bottom .operators .i-right {
    text-align: left;
}
.player .normal-player .top .back .icon-back {
    display: block;
    padding: 18rpx;
    font-size: 44rpx;
    color: #ffcd32;
    -webkit-transform: rotate(-90deg);
    transform: rotate(-90deg);
}
.content-wrapper {
    position: fixed;
    top: 100%;
    height: 100%;
    width: 100%;
    z-index: 150;
    transition: all 0.5s;
}
.close-list {
    position: absolute;
    top: 0;
    height: 100%;
    width: 100%;
}
.playlist-wrapper {
    height: 660rpx;
    width: 100%;
    padding:15rpx 30rpx;
    box-sizing: border-box;
}
.playlist-wrapper .item {
    display: flex;
    position: relative;
    height: 90rpx;
    line-height: 90rpx;
    margin-left: 30rpx;
    padding-right: 30rpx;
    border-bottom: 1rpx dashed rgba(255,255,255,.3);
}
.playlist-wrapper .playing ,.playlist-wrapper .playing .singer, .playlist-wrapper .playing .play_list__line{
    color: #ff9900!important;
}

.playlist-wrapper .item .name {
    max-width:350rpx;
    overflow:hidden;
    white-space:nowrap;
    text-overflow:ellipsis;
    font-size: 14px;
    color: white
}
.playlist-wrapper .item .play_list__line {
    display: block;
    margin: 0 5px;
    color: rgba(255,255,255,.5);
}
.playlist-wrapper .item .singer {
    max-width:200rpx;
    overflow:hidden;
    white-space:nowrap;
    text-overflow:ellipsis;
    font-size: 12px;
    color: rgba(255,255,255,.5);
}
.playlist-wrapper .item .playing-img {
    width: 24rpx;
    height: 24rpx;
    position: absolute;
    top: 32rpx;
    right: 0;
}
.play-content {
    position: absolute;
    /*//bottom: -860rpx;*/
    bottom: 0;
    /*transform: translateY(860rpx);*/
    left: 0;
    right: 0;
    height: 860rpx;
    width: 100%;
    background: rgba(0,0,0,.9);
    z-index: 200;
    transition: all 0.5s;
}
.uptranslate {
    transform: translateY(-100%)!important;
}
.downtranslate {
    transform: translateY(100%)!important;
}
.close-playlist {
    height: 100rpx;
    width: 100%;
    text-align: center;
    line-height: 100rpx;
    border-top: 1px solid rgba(255,255,255,.3);
    font-size: 16px;
}
.plyer-list-title{
    height: 100rpx;
    width: 100%;
    color: white;
    text-align: center;
    line-height: 100rpx;
    border-bottom: 1px solid rgba(255,255,255,.3);
    font-size: 16px;
}
.player .normal-player .bottom .progress-wrapper .progress-bar-wrapper {
    -webkit-box-flex: 1;
    -ms-flex: 1;
    flex: 1;
}
@keyframes rotate{
    0% {
        transform: rotate(0)
    }
    100% {
        transform: rotate(360deg)
    }
}

.middle-r {
    display: inline-block;
    vertical-align: top;
    width: 100%;
    height: 100%;
    overflow: hidden;
}
.lyric-wrapper{
    width: 80%;
    margin: 0 auto;
    overflow: hidden;
    text-align: center;
    height: 100%;
}
.text{
    line-height: 32px;
    color: rgba(255, 255, 255, 0.5);
    font-size: 14px;
}
.current {
    color: #ffcd32;
}
.currentLyricWrapper {
    height:70rpx;
    font-size:12px;
    position:absolute;
    bottom:-80rpx;
    line-height: 70rpx;
    text-align: center;
    width: 100%;
    color: #ffcd32;
}
.dots-wrapper {
    position: absolute;
    bottom: 210rpx;
    height: 20rpx;
    line-height: 20rpx;
    text-align: center;
    width: 100%;
}
.dots-wrapper .dots {
    width: 20rpx;
    height: 20rpx;
    border-radius: 10rpx;
    background: rgba(255, 255, 255, 0.5);
    display: inline-block;
    margin: 10rpx;
    margin-top: 0;
}
.dots-wrapper .current {
    width: 40rpx;
    background: rgba(255,255,255,.8);
}

更多

模块实在太多,有需要项目完整源码的伙伴可以去海轰的微信公众号:海轰Pro
回复:海轰
O(∩_∩)O哈哈~

发布了155 篇原创文章 · 获赞 110 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_44225182/article/details/103691495
今日推荐