0

    你的心事我全知晓——心情日记小程序丨实战

    2023.05.10 | admin | 145次围观

    1. class="bg_music" @tap="audioPlay">

    2. src="../../static/images/music_icon.png" class="musicImg" :class="isPlay?'music_icon':''"/>

    3. src="../../static/images/music_play.png" class="music_play" :class="isPlay?'pauseImg':'playImg'"/>

  • id="myAudio" :src="audioUrl" autoplay loop>

    1. data () {

    2. return {

    3. isPlay: true,

    4. audioCtx: ''

    5. }

    6. },

    7. onLoad () {

    8. const that = this

    9. that.audioCtx = wx.createAudioContext('myAudio')

    10. that.getMusicUrl()

    11. },

    12. methods: {

    13. getMusicUrl () {

    14. const that = this

    15. const db = wx.cloud.database()

    16. const music = db.collection('music')

    17. music.get().then(res => {

    18. that.audioUrl = res.data[0].musicUrl

    19. that.audioCtx.loop = true

    20. that.audioCtx.play()

    21. })

    22. },

    23. audioPlay () {

    24. const that = this

    25. if (that.isPlay) {

    26. that.audioCtx.pause()

    27. that.isPlay = !that.isPlay

    28. tools.showToast('您已暂停音乐播放~')

    29. } else {

    30. that.audioCtx.play()

    31. that.isPlay = !that.isPlay

    32. tools.showToast('背景音乐已开启~')

    33. }

    34. }

    35. }

    1. .bg_music

    2. position fixed

    3. right 0

    4. top 20rpx

    5. width 100rpx

    6. z-index 99

    7. display flex

    8. justify-content flex-start

    9. align-items flex-start

    10. .musicImg

    11. width 60rpx

    12. height 60rpx

    13. .music_icon

    14. animation musicRotate 3s linear infinite

    15. .music_play

    16. width 28rpx

    17. height 60rpx

    18. margin-left -10rpx

    19. transform-origin top

    20. -webkit-transform rotate(20deg)

    21. .playImg

    22. animation musicStop 1s linear forwards

    23. .pauseImg

    24. animation musicStart 1s linear forwards

    25. #myAudio

    26. display none

    1、通过wx.createInnerAudioContext()获取实例 ,安卓机上音乐能正常播放,IOS上不行,具体原因感兴趣的可以去深究一下;

    2、由于前面邀请函小程序相关文章发出后,问的最多的问题依然是音乐无法播放这块,所以这个demo中就再给大家讲解了下实现的原理。

    这里日历使用了小程序插件,之所以在首页放一个日历是为了页面不显的太单调。下面讲解下插件是如何使用的:

    1、登录微信公众平台>设置>第三方设置>添加插件>搜索相关插件的名字(使用appId搜索更好)>点击某个插件右侧的查看详情,进入插件详情页添加插件,一般都能立马添加通过;

    2、插件详情里面一般都有使用文档,或git地址,插件的具体属性事件都会在文档里有介绍;

    3、下面讲解下如何在项目中使用插件:

    (1)找到src根目录下的app.json文件,添加如下内容:

    1. // "cloud": true,

    2. "plugins": {

    3. "calendar": {

    4. "version": "1.1.3",

    5. "provider": "wx92c68dae5a8bb046"

    6. }

    7. }

    (2)在需要引用该插件的页面的.json文件中加入如下内容:

    1. {

    2. // "navigationBarTitleText": "媳妇的心情日记",

    3. // "enablePullDownRefresh": true,

    4. "usingComponents": {

    5. "calendar": "plugin://calendar/calendar"

    6. }

    7. }

    (3)在页面中直接使用如下(具体属性方法的意思根据对应插件有所不同):

    1. :class="showCalendar?'':'hide_right'"

    2. class="right"

    3. weeks-type="en"

    4. cell-size="20"

    5. :header="showHeader"

    6. show-more-days=true

    7. calendar-style="demo4-calendar"

    8. board-style="demo4-board"

    9. :days-color="demo4_days_style"

    10. @dayClick="dayClick"

    11. />

    1、这里我借助的是高德微信小程序SDK;

    2、首先获取使用相关api需要的key值,如下:

    3、下载对应SDK(.js文件)并引入到项目中;

    4、通过相关api获取天气和地址:

    1. getWeather () {

    2. const that = this

    3. let myAmapFun = new amapFile.AMapWX({key: '你申请的key'})

    4. myAmapFun.getWeather({

    5. success (res) {

    6. // 成功回调

    7. that.address = res.liveData.city

    8. that.weather = res.liveData.weather + ' '

    9. that.temperature = res.liveData.temperature + '℃'

    10. that.winddirection = res.liveData.winddirection + '风' + res.liveData.windpower + '级'

    11. },

    12. fail (info) {

    13. // 失败回调

    14. console.log(info)

    15. }

    16. })

    17. },

    这里涉及到发表文字图片内容,在个人小程序提交审核后很大可能是不会被通过的qq空间日志音乐要什么插件,虽然第一次提交我的个人小程序通过审核了,后面几次审核均未通过,虽然我这里只限制了我和媳妇两个人能发日记,其他人压根看不到右下角的发布加号,但是审核人员会查代码,代码中一旦被他们发现有类似发表相关的内容或字样就会导致审核不通过,好在已经通过了一次,媳妇能正常写点东西,也算基本符合要求,遗憾的是后面实现点赞相关的功能都没有更新到线上。

    1、通过唯一的openId来判断是否显示首页右下角的发布加号;

    2、后面会具体讲解页面里上传图片到云开发及存储到数据库相关功能。

    1、这里点赞功能借助的小程序云开发的云函数来实现的,结合代码:

    1. class="list">

    2. class="item" v-for="(item, index) in diaryList" :key="item._id" @tap="toDetail(item)">

    3. class="like" src="../../static/images/like_active.png" v-if="likeList[index] === '2'" @tap.stop="toLike(item._id, '1', item.like)"/>

    4. class="like" src="../../static/images/like.png" v-if="likeList[index] === '1'" @tap.stop="toLike(item._id, '2', item.like)"/>

    5. class="img" :src="item.url" mode="aspectFill"/>

    6. class="desc">{{item.desc}}

    7. class="name-weather">

    8. class="name">{{item.name}}

    9. class="weather">{{item.weather}}

  • class="time-address">

  • class="time">{{item.time}}

  • class="dialog" v-if="showDialog">

  • class="box">

  • 提示

  • 是否授权使用点赞功能?

  • class="bottom">

  • class="cancel" @tap="hideDialog">取消

  • class="confirm" lang="zh_CN" open-type="getUserInfo" @getuserinfo="login">确认

    1. // 获取日记列表

    2. getDiaryList () {

    3. const that = this

    4. wx.cloud.callFunction({

    5. name: 'diaryList',

    6. data: {}

    7. }).then(res => {

    8. that.getSrcFlag = false

    9. that.diaryList = res.result.data.reverse()

    10. that.likeList = []

    11. that.diaryList.forEach((item, index) => {

    12. item.like.forEach(itemSecond => {

    13. if (itemSecond.openId === that.openId) {

    14. that.likeList.push(itemSecond.type)

    15. }

    16. })

    17. if (that.likeList.length < index + 1) {

    18. that.likeList.push('1')

    19. }

    20. })

    21. wx.hideNavigationBarLoading()

    22. wx.stopPullDownRefresh()

    23. })

    24. },

    25. // 点赞或取消点赞

    26. toLike (id, type, arr) {

    27. const that = this

    28. that.tempObj = {

    29. id: id,

    30. type: type,

    31. like: arr

    32. }

    33. wx.getSetting({

    34. success (res) {

    35. if (res.authSetting['scope.userInfo']) {

    36. // 已经授权,可以直接调用 getUserInfo 获取头像昵称

    37. wx.getUserInfo({

    38. success: function (res) {

    39. that.userInfo = res.userInfo

    40. wx.cloud.callFunction({

    41. name: 'like',

    42. data: {

    43. id: id,

    44. type: type,

    45. like: arr,

    46. name: that.userInfo.nickName

    47. }

    48. }).then(res => {

    49. if (type === '1') {

    50. tools.showToast('取消点赞成功')

    51. } else {

    52. tools.showToast('点赞成功~')

    53. }

    54. // getOpenId()方法里会执行一遍获取日记列表

    55. that.getOpenId()

    56. })

    57. }

    58. })

    59. } else {

    60. that.showDialog = true

    61. }

    62. }

    63. })

    64. },

    65. // 授权获取用户信息

    66. login (e) {

    67. const that = this

    68. console.log(that.tempObj, e)

    69. if (e.target.errMsg === 'getUserInfo:ok') {

    70. wx.getUserInfo({

    71. success: function (res) {

    72. that.userInfo = res.userInfo

    73. wx.cloud.callFunction({

    74. name: 'like',

    75. data: {

    76. id: that.tempObj.id,

    77. type: that.tempObj.type,

    78. like: that.tempObj.like,

    79. name: that.userInfo.nickName

    80. }

    81. }).then(res => {

    82. if (that.tempObj.type === '1') {

    83. tools.showToast('取消点赞成功')

    84. } else {

    85. tools.showToast('点赞成功~')

    86. }

    87. // getOpenId()方法里会执行一遍获取日记列表

    88. that.getOpenId()

    89. })

    90. }

    91. })

    92. }

    93. that.showDialog = false

    94. }

    你的心事我全知晓——心情日记小程序丨实战

    2、首页获取日记列表,在存储日记到数据库集合的时候我会在每条日记对象中添加一个like属性,like默认是一个空数组;

    3、当用户点赞或取消点赞时,组件data中tempObj属性会临时存储三个参数:①、对应日记的_id;②、用户操作的类型是点赞(点赞是‘2’)或是取消点赞(取消点赞是‘1’);③、对应日记的like数组;

    4、通过小程序api的wx.getSetting({})来判断用户是否已经授权。如果授权了获取用户信息,未授权则弹框引导用户点击确认按钮去手动授权;

    5、授权成功后,拿到用户信息,我们开始调用点赞或取消点赞相关的云函数,如下:

    1. const cloud = require('wx-server-sdk')

    2. cloud.init()

    3. const db = cloud.database()

    4. exports.main = async (event, context) => {

    5. try {

    6. // wxContext内包含用户的openId

    7. const wxContext = cloud.getWXContext()

    8. // 定义空数组

    9. let arr = []

    10. if (event.like && event.like.length > 0) {

    11. // 让定义的数组等于用户操作的当前日记下的like数组

    12. arr = event.like

    13. // 定义一个计数变量

    14. let count = 0

    15. // 循环遍历,当openId相同时替换like数组中的相同项,并存储对应的type

    16. arr.forEach((item, index) => {

    17. if (item.openId === wxContext.OPENID) {

    18. count++

    19. arr.splice(index, 1, {

    20. openId: wxContext.OPENID,

    21. type: event.type,

    22. name: event.name

    23. })

    24. }

    25. })

    26. // 当计数变量为0时,说明在这条日记中,like数组中未存储过此用户,直接push此用户并存储type

    27. if (count === 0) {

    28. arr.push({

    29. openId: wxContext.OPENID,

    30. type: event.type,

    31. name: event.name

    32. })

    33. }

    34. } else {

    35. // 如果此条日记like数组本身就为空,直接push当前用户并存储type

    36. arr.push({

    37. openId: wxContext.OPENID,

    38. type: event.type,

    39. name: event.name

    40. })

    41. }

    42. // 通过云开发操作数据库的相关api,即update通过_id来更新集合中某条数据

    43. return await db.collection('diary').doc(event.id).update({

    44. data: {

    45. like: arr

    46. }

    47. })

    48. } catch (e) {

    49. console.error(e)

    50. }

    51. }

    6、相关云函数操作说明都写在上面的注释里,有不清楚的欢迎留言,由于点赞功能未更新到线上(原因是因为审核不通过),想体验的同学也可以加本人微信号,提供体验权限。

    发表心情效果图

    讲解

    1、通过首页右下角的发布加号,进入发布心情页;

    2、地址等相关信息是从首页通过路由带过来的;

    3、下面重点讲解下关于上传图片到云存储并写入数据库的操作过程,内容如下:

    1. upload () {

    2. const that = this

    3. wx.chooseImage({

    4. count: 1,

    5. sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有

    6. sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有

    7. success: function (res) {

    8. wx.showLoading({

    9. title: '上传中'

    10. })

    11. // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片

    12. let filePath = res.tempFilePaths[0]

    13. const name = Math.random() * 1000000

    14. const cloudPath = 'picture/' + name + filePath.match(/\.[^.]+?$/)[0]

    15. wx.cloud.uploadFile({

    16. cloudPath, // 云存储图片名字

    17. filePath // 临时路径

    18. }).then(res => {

    19. console.log(res)

    20. wx.hideLoading()

    21. that.imgUrl = res.fileID

    22. }).catch(e => {

    23. console.log('[上传图片] 失败:', e)

    24. })

    25. }

    26. })

    27. },

    28. save () {

    29. const that = this

    30. if (that.desc) {

    31. that.getSrcFlag = false

    32. const db = wx.cloud.database()

    33. const diary = db.collection('diary')

    34. if (that.imgUrl === '../../static/images/default.png') {

    35. that.imgUrl = '../../static/images/default.jpg'

    36. }

    37. diary.add({

    38. data: {

    39. desc: that.desc,

    40. time: tools.getNowFormatDate(),

    41. url: that.imgUrl,

    42. name: that.name,

    43. weather: that.weather,

    44. address: that.address,

    45. like: []

    46. }

    47. }).then(res => {

    48. wx.reLaunch({

    49. url: '/pages/index/main'

    50. })

    51. }).catch(e => {

    52. console.log(e)

    53. })

    54. } else {

    55. tools.showToast('写点什么吧~')

    56. }

    57. }

    4、这里的cloudPath可以自己定义,存储到云中是这样的:

    5、我们通过组件data中的imgUrl临时存储手动上传的图片路径,最终通过保存按钮一起存储到云数据库qq空间日志音乐要什么插件,存如到数据库是这样的:

    日记详情页详情页效果图

    讲解

    详情就不过多讲解,这里利用了一些小程序api,比方说动态改变头部标题,每次进入动态随机改变顶部标题背景,点赞数也是从首页带过来的。

    访客页效果图

    1、授权前

    2、授权后

    总结

    总体来说,云开发很好用,但在大型项目开发方面仍有提升空间。从图片和数据加载这块的效果来看,传统服务端拿到的数据明显要快很多,既然有这么一个免费的工具,我想感兴趣的同学可以利用起来,玩点小demo,新花样,用云开发实现所思所想。

    获取源码

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    标签: 小程序
    < 上一篇 下一篇 >
    发表评论
    14870文章数 1评论数
    热门文章
    随机文章
    最近发表
    标签列表