评论

mpvue+云开发,纯前端实现婚礼邀请函小程序

这是一个有爱的小程序

作者:黄彬

前言

感谢OnceLove提供的思路,借助他的小程序的界面UI风格,自己重新用mpvue实现了属于自己的婚礼邀请函,前前后后花了3天时间。

在这之前本人是没想过要自己实现这样一个项目,原因是后台那块是个麻烦事,所以当媳妇让我自己实现这个邀请函的时候,起初我是拒绝的。后面由于快要过年了,公司项目没有重大更新,趁着这段空闲时间,自己研究了下小程序自带的云开发,无需后台支持,前后端都可以自己来实现,下面我将一一介绍本项目的实现过程 !

本小程序为婚礼正式使用的小程序,婚期将至,感兴趣的可以扫码体验本项目,沾沾喜气,欢迎大家体验,有什么问题可以在本文给我留言。

源码地址:

https://gitee.com/roberthuang123/wedding

准备工作

  1. mpvue框架 mpvue官方文档 
    http://mpvue.com/mpvue/
  2. 小程序·云开发 小程序·云开发文档
    https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/getting-started.html

注意:使用mpvue前,首先你得先熟悉vue框架的基本使用

项目结构介绍

common目录: 放一些公共资源,如js,css,json

components目录:组件相关的.vue文件都放在这里

pages目录:所有页面都放在这个目录

utils目录:使用mpvue时自动生成,可忽略

app.json文件:

{  
	"pages": [    
		"pages/index/main",    
    		"pages/photo/main",    
        	"pages/map/main",    
        	"pages/greet/main",    
        	"pages/message/main"  ],  
	"window": {    
    		"backgroundTextStyle": "light",    
            	"navigationBarBackgroundColor": "#fff",    
                "navigationBarTitleText": "WeChat",    
                "navigationBarTextStyle": "black"  },  
	"tabBar": {    
    		"color": "#ccc",    
            	"selectedColor": "#ff4c91",    
                "borderStyle": "white",    
                "backgroundColor": "#ffffff",    
                "list": [      
                {          
                	"pagePath": "pages/index/main",          
                    	"iconPath": "static/images/1-1.png",          
                        "selectedIconPath": "static/images/1-2.png",          
                        "text": "邀请函"      
                 },      
                 {          
                 	"pagePath": "pages/photo/main",          
                    	"iconPath": "static/images/2-1.png",          
                        "selectedIconPath": "static/images/2-2.png",          
                        "text": "甜蜜相册"      
                  },      
                  {          
                  	"pagePath": "pages/map/main",          
                    	"iconPath": "static/images/3-1.png",          
                        "selectedIconPath": "static/images/3-2.png",          
                        "text": "酒店导航"      
                   },      
                   {          
                   	"pagePath": "pages/greet/main",          
                    	"iconPath": "static/images/4-1.png",          
                        "selectedIconPath": "static/images/4-2.png",          
                        "text": "好友祝福"      
                    },      
                    {          
                    	"pagePath": "pages/message/main",          
                        "iconPath": "static/images/5-1.png",          
                        "selectedIconPath": "static/images/5-2.png",          
                        "text": "留言评论"     
                    }    
               ]  
         },  
         "requiredBackgroundModes": ["audio"]
   }

App.vue文件:本人主要是为了增加项目更新后的提醒,所以在这个文件加了些相关内容,内容如下:

<script>export default {  
	onLaunch () {    
    		// 检测小程序是否有新版本更新    
        	if (wx.canIUse('getUpdateManager')) {      
            		const updateManager = wx.getUpdateManager()      
                    	updateManager.onCheckForUpdate(function (res){        				
                        // 请求完新版本信息的回调        
                        if (res.hasUpdate) {          
                        	updateManager.onUpdateReady(function () {            	
                            	wx.showModal({              
                                	title: '更新提示',              
                                    	content: '新版本已经准备好,是否重启应用?',              
                                        success: function (res) {                
                                        if (res.confirm) {                  
                                        // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启                  
                                        updateManager.applyUpdate()                
                                        }              
                                   }            
                              })          
                        })          
                        // 小程序有新版本,会主动触发下载操作(无需开发者触发)          
                        wx.getUpdateManager().onUpdateFailed(function () {            
                        // 当新版本下载失败,会进行回调            
                        wx.showModal({              
                        title: '提示',              
                        content: '检查到有新版本,下载失败,请检查网络设置',              
                        showCancel: false            
                        })          
                    })       
               }      
         })    
    } else { 
        // 版本过低则无法使用该方法      
	wx.showModal({        
    		title: '提示',        
            	confirmColor: '#5BB53C',        
                content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'      
                })    
    }  
}}
</script>
<style lang="stylus">
page    
	height 100%
image    
     display block
</style>

main.js文件:

import Vue from 'vue'
import App from './App'
Vue.config.productionTip = falseApp.mpType = 'app'
wx.cloud.init({  
	env: '云开发环境ID'
})
const app = new Vue(App)
app.$mount()

functions目录:主要放一些云函数,这里不清楚云函数的文章后面会提及

images目录:主要放一些静态资源图片

页面介绍

  • 首页——邀请函

首页着重和大家讲解下背景音乐的实现方法

const audioCtx = wx.createInnerAudioContext()

首先,wx.createInnerAudioContext 接口获取实例

接着,通过实例的相关方法来实现音乐的播放与暂停功能

关于小程序音频相关文档

https://developers.weixin.qq.com/miniprogram/dev/api/InnerAudioContext.html

具体代码如下:

<script>
import IndexSwiper from 'components/indexSwiper'
import tools from 'common/js/h_tools'
const audioCtx = wx.createInnerAudioContext()
export default {  
	name: 'Index',  
    	components: {    
        	IndexSwiper  
        },  
        data () {    
        	return {      
            		isPlay: true,      
                    	list: []    
          }  
	},  
	onShow () {   
		const that = this    
    		that.isPlay = true    
        	that.getMusicUrl()  
	},
	methods: {    
		audioPlay () {      
    			const that = this      
            		if (that.isPlay) {        
                		audioCtx.pause()        
                  	 	that.isPlay = false        
                    		tools.showToast('您已暂停音乐播放~')      
                   	 } else {        
                    		audioCtx.play()        
                       		that.isPlay = true        
                        	tools.showToast('背景音乐已开启~')      
	 		}    
   	},
	getList () {      
		const that = this      
    		const db = wx.cloud.database()      
        	const banner = db.collection('banner')      
        	banner.get().then(res => {        
        		that.list = res.data[0].bannerList      
        	})    
	},
	getMusicUrl () {      
		const that = this      
    		const db = wx.cloud.database()     
       		const music = db.collection('music')      
        	music.get().then(res => {       
        		let musicUrl = res.data[0].musicUrl        
            		audioCtx.src = musicUrl        
                	audioCtx.loop = true        
                   	audioCtx.play()        
                	that.getList()      
                	})    
            	} 
	},
	onShareAppMessage: function (res) {   
		return {      
    			path: '/pages/index/main'    
            	}  
 	}	
}
</script>

以上代码中使用到了云开发相关功能,文章后面会介绍,请大家稍安勿躁

  • 相册页——就一个轮播图,这里就不过多介绍
  • 地图页——这里着重讲一下地图标签map

map标签 关于map组件的使用文档

这里讲一下标记点markers

data () {    
	return {      
    	// qqSdk: '',      
    	markers: [{        
    	iconPath: '../../static/images/nav.png',        
        id: 0,        
        latitude: 30.08059,        
        longitude: 115.93027,        
        width: 50,        
        height: 50      
        }]   
    }  
}
<template>    
	<div class="map">        
    	<image mode="aspectFit" class="head-img" src="../../static/images/t1.png"/>        
        <map class="content" id="map" longitude="115.93027" latitude="30.08059" :markers="markers" scale="18" @tap="toNav">        
        </map>        
        <div class="call">            
        	<div class="left" @tap="linkHe">                
            	<image src="../../static/images/he.png"/>                
                <span>呼叫新郎</span>            
        </div>            
        <div class="right" @tap="linkShe">                
        	<image src="../../static/images/she.png"/>                
            	<span>呼叫新娘</span>            
        </div>        
    </div>        
    <image class="footer" src="../../static/images/grren-flower-line.png"/>    
    </div>
</template>
  • 祝福页——也是云开发相关内容,后面会介绍
  • 留言页——也是云开发相关内容,后面会介绍

云开发介绍

  • project.config.json文件:
"cloudfunctionRoot": "static/functions/"

进行云开发首先我们需要找到上面这个文件,在上面这个json文件中加上上面这句

cloudfunctionRoot 用于指定存放云函数的目录

  • app.json文件:
"window": {    
	"backgroundTextStyle": "light",    
    	"navigationBarBackgroundColor": "#fff",    
        "navigationBarTitleText": "WeChat",    
        "navigationBarTextStyle": "black"
},
"cloud": true

增加字段 "cloud":true实现云开发能力的兼容性

  • 开通云开发

在开发者工具工具栏左侧,点击 “云开发” 按钮即可开通云开发

  • 云开发控制台

  • 数据库

云开发提供了一个 JSON 数据库

  • 存储

云开发提供了一块存储空间,提供了上传文件到云端、带权限管理的云端下载能力,开发者可以在小程序端和云函数端通过 API 使用云存储功能。

  • 云函数

云函数是一段运行在云端的代码,无需管理服务器,在开发工具内编写、一键上传部署即可运行后端代码。

下面开始讲解使用云开发的过程:

  1. 云能力初始化,在小程序端开始使用云能力前,需先调用 wx.cloud.init 方法完成云能力初始化
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
App.mpType = 'app'
wx.cloud.init({  
	env: '云开发环境ID'
})
const app = new Vue(App)
app.$mount()
  1. 数据库的使用:

在开始使用数据库 API 进行增删改查操作之前,需要先获取数据库的引用。

以下调用获取默认环境的数据库的引用:

const db = wx.cloud.database()

要操作一个集合,需先获取它的引用:

const todos = db.collection('todos')

接下来是操作数据库的相关示例:

例:首页获取背景音乐资源

getMusicUrl () { 
	const that = this      
    	const db = wx.cloud.database()      
        const music = db.collection('music')      
        music.get().then(res => {        
        	let musicUrl = res.data[0].musicUrl        
            	audioCtx.src = musicUrl        
                audioCtx.loop = true        
                audioCtx.play()        
                that.getList()      
        })
}

例:首页获取轮播图数组

getList () {      
	const that = this      
    	const db = wx.cloud.database()      
        const banner = db.collection('banner')      
        banner.get().then(res => {        
        	that.list = res.data[0].bannerList      
        })
}

例:祝福页,用户送上祝福存储用户

<script>import tools from 'common/js/h_tools'
export default {  
	name: 'Greet',  
    	data () {    
        	return {      
            		userList: [],      
                    	openId: '',      
                        userInfo: ''    
                     }  
         },  
         onShow () {    
         	const that = this    
            	that.getUserList()  
         },  
         methods: {    
         	scroll (e) {      
            	console.log(e)    
                },
	sendGreet (e) {      
    		const that = this      
            	if (e.target.errMsg === 'getUserInfo:ok') {        
                	wx.getUserInfo({          
                    		success: function (res) {            
                            		that.userInfo = res.userInfo            
                                    	that.getOpenId()          
                                        }        
                            })     
                 }   
	},
	addUser () {      
    		const that = this      
            	const db = wx.cloud.database()      
                const user = db.collection('user')      
                user.add({        
                	data: {          
                    		user: that.userInfo        
                            }      
                }).then(res => {        
                	that.getUserList()      
 		})    
	},
	getOpenId () {      
		const that = this      
        	wx.cloud.callFunction({        
            		name: 'user',        
                    	data: {}      
                }).then(res => {        
                	that.openId = res.result.openid        
                    	that.getIsExist()      
                	}
                )    
	},
	getIsExist () {      
		const that = this      
        	const db = wx.cloud.database()      
            	const user = db.collection('user')      
            	user.where({        
            		_openid: that.openId      
                }).get().then(res => {        
                	if (res.data.length === 0) {          
                    		that.addUser()        
                    	} else {          
                        	tools.showToast('您已经送过祝福了~')        
                        }      
                })    
	},
	getUserList () {      
		const that = this      
        	wx.cloud.callFunction({        
            		name: 'userList',        
                    	data: {}      
                        }).then(res => {        
                        	that.userList = res.result.data.reverse()      
                        })   
               }  
	}
}
</script>
  • 进入祝福页,首先我们需要获取送祝福的好友列表
getUserList () {      
	const that = this      
    	wx.cloud.callFunction({        
        name: 'userList',        
        data: {}      
        }).then(res => {        
        	that.userList = res.result.data.reverse()      
        })
}

这里用到了云函数,之所以用云函数是因为小程序端在获取集合数据时服务器一次默认并且最多返回 20 条记录,云函数端这个数字则是 100。

下面给大家看看云函数的使用方法:

上面我们讲过在project.config.json文件中配置云函数存放位置

下面是云函数messageList的index.js文件:

const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
const MAX_LIMIT = 100
exports.main = async (event, context) => { 
	// 先取出集合记录总数  
    	const countResult = await db.collection('message').count()  
        const total = countResult.total  
        // 计算需分几次取  
        const batchTimes = Math.ceil(total / 100)  
        // 承载所有读操作的 promise 的数组  
        const tasks = []  
        for (let i = 0; i < batchTimes; i++) {    
        	const promise = db.collection('message').skip(i * MAX_LIMIT).limit(MAX_LIMIT).get()    
            	tasks.push(promise)  
        }  
        // 等待所有  
        return (await Promise.all(tasks)).reduce((acc, cur) => ({    
        	data: acc.data.concat(cur.data),    
            	errMsg: acc.errMsg  
        }))
}

使用云函数前,在开发者工具上,找到messageList目录,右键如图:

点击上传并部署:云端安装依赖(不上传node_modules)

得到如图的提示:

安装完点击完成就能使用当前云函数了,使用方法即:

getUserList () {      
	const that = this      
    	wx.cloud.callFunction({        
        	name: 'userList',        
            	data: {}      
        }).then(res => {        
        that.userList = res.result.data.reverse()     
        })
}

数组之所以要倒序是因为希望新祝福的的用户在最前面显示

  • 接着是用户送上祝福的时候存储用户

这里我们用到了云函数获取用户信息,

当小程序端调用云函数时,云函数的传入参数中会被注入小程序端用户的 openid,开发者无需校验 openid 的正确性,因为微信已经完成了这部分鉴权,开发者可以直接使用该 openid

下面是云函数user的index.js文件:

// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {  
	const wxContext = cloud.getWXContext()
  	return {    
    		event,    
        	openid: wxContext.OPENID,    
            	appid: wxContext.APPID,    
                unionid: wxContext.UNIONID  
     }
}

主要是为了获取当前操作用户的openid,获取当前用户的openid方法:

getOpenId () {      
	const that = this      
    	wx.cloud.callFunction({        
        	name: 'user',        
            	data: {}      
        }).then(res => {        
        	that.openId = res.result.openid        
            	that.getIsExist()      
        })
}

接着判断当前用户是否已经存在于数据库中,即getIsExist()方法:

getIsExist () {      
	const that = this      
    	const db = wx.cloud.database()      
        const user = db.collection('user')      
        user.where({        
        	_openid: that.openId      
        }).get().then(res => {        
        	if (res.data.length === 0) {          
            		that.addUser()        
            	} else {          
                	tools.showToast('您已经送过祝福了~')        
                }      
        })
}

如果得到的数组长度为零则添加改用户到数据库,否则则提醒当前用户已经送过祝福

接下来介绍存储用户信息的方法,即addUser():

addUser () {      
	const that = this      
    	const db = wx.cloud.database()      
        const user = db.collection('user')      
        user.add({        
        	data: {          
            		user: that.userInfo        
                }      
  	}).then(res => {        
    		that.getUserList()      
    })
}

存入到数据库的信息是这样的:

有人要看数据库字段,其实很简单,这是首页轮播图的字段,见下图:

这是留言的评论,如图:

总结

在这里给大家讲解几点细节:

  1. 云开发是免费的;
  2. 数据库集合名首先必须要建立;
  3. 数据库集合为空时,这里本人没有处理细节,会报错,先通过使用自己的小程序写入一条数据,错误就可以解决了;
  4. 云函数新建后一定要创建并安装依赖;
  5. 如果担心有些评论不太友好希望有删除功能,可以给自己开放权限,在每条评论加一个删除按钮,仅自己使用的时候通过唯一的openid控制删除按钮为可见,其他人不可见,从而来管理留言列表;
  6. 数据库建立集合后记得将权限放开,如下图:

最后总结:

  1. 除了一些静态资源放在项目中,其他资源建议一律存储在云开发-存储管理中,这样的话,方便更换资源而不用再次提交等待小程序审核,更换后的资源可以立即生效;
  2. 我知道大家都喜欢拿来就能直接看到同样效果的东西,本项目因为涉及到后台数据,不可能完全把本人的环境放出来给大家使用,建议真的要实现相关功能或类似项目的小伙伴对照我的思路重新做一个属于自己的作品才最有意义。

最后一次编辑于  2019-02-27  
点赞 1
收藏
评论

1 个评论

  • Y.
    Y.
    2019-07-31


    右键function不出现新增云函数等问题

    2019-07-31
    赞同
    回复
登录 后发表内容