此项目运用运用 vue 全家桶技术(vue+vue-cli+vuex+vue-router+node...),前后台分离和组件化的方式开发,使用WeUl基础样式库进行前台页面的搭建,后台使用的是MongoDB数据库进行编写,使用阿里云短信服务进行验证码注册。实现了下拉刷新、消息发送、大图预览、朋友圈发表。。。。
MVVM 框架:Vue.js 2.0
状态管理:Vuex
页面路由:Vue-router
弹窗插件:WeUl
聊天插件:vue-socket.io
环境配置:node.js + cnpm
图片插件:vue-photo-preview
页面展示
代码
使用阿里云短信服务,输入手机号进行验证,输入合法的手机号才可以发送验证码,验证码后台验证,要输入正确的验证码才能登陆。一分钟之后要重新发送,重新获取。
async signup () {
// 验证手机号
if (!(/^1[3456789]\d{9}$/.test(this.mobile))) {
weui.topTips('请输入合法的手机号', 2000)
return false
}
// 验证码
if (!this.code) {
weui.topTips('请填入验证码', 2000)
return false
}
// 发送请求,注册或者登录
const res = await service.post('/users/signup', {
phonenum: this.mobile,
code: this.code
})
/* 注册成功后的处理
1.将登录或者注册的用户信息保存起来,以供其他页面使用
2.跳转到用户本来想要请求的页面
*/
if (res.data.code === 0) {
weui.toast('登录成功', 2000)
this.$store.dispatch('setUser', res.data.data)
this.$router.go(-1)
}
},
// 验证码
async getCode () {
// 验证手机号
if (!(/^1[3456789]\d{9}$/.test(this.mobile))) {
weui.topTips('请输入合法的手机号', 2000)
return false
}
// 向服务器接口发送请求
const res = await service.get('/users/phonecode', {
phonenum: this.mobile
})
console.log(res)
// 开启定时器,60s倒计时
this.countTimeCode()
},
// 倒计时
countTimeCode () {
// 为this对象(当前的vue实例)动态添加一个属性clearFlag
this.clearFlag = setInterval(() => {
if (this.timecode === 0) {
this.timecode = 60
// 清除定时器
clearInterval(this.clearFlag)
return
}
this.timecode--
}, 1000)
}
},
beforeDestroy () {
clearInterval(this.clearFlag)
}
朋友圈列表是分组件开发,分别有列表组件、头部组件、背景图页面、下拉刷新组件、上拉刷新组件、评论组件和点赞组件。
3.2.1头部组件
向下滚动一定距离才会展示,点击相机图标进行判断如果没有登录则返回登录页面若登录则跳转到发布朋友圈页面。
goPublish () {
/**
* 判断用户是否登录
* - 如果没有登录,跳转到登录页面
* - 如果登录,则跳转到publish页面
*/
if (!this.$store.state.currentUser._id) {
this.$router.push('login')
return
}
this.$router.push('publish')
}
3.2.2背景图页面
背景图展示和更换,若此用户没有更换过页面会展示系统默认背景图片和头像(从文件夹里自动分配),若此用户有自己的背景图和头像(数据库会有对应的数据可以拿出来进行展示),会展示自己的背景图和头像,点击背景更换。
computed: {
// 设置用户的背景图像
topBgImg () {
const url = this.$store.state.currentUser.bgurl || require('../../assets/images/topbg.jpg')
// console.log(url)
return {
backgroundImage: `url(${url})`
}
},
// 设置用户头像
usreAvatar () {
const url = this.$store.state.currentUser.avatar || require('../../assets/images/avatar.jpg')
return url
},
// 设置用户昵称
nickname () {
return this.$store.state.currentUser.nickname
}
}
changeBg () {
const sefl = this
// 弹出菜单
weui.actionSheet([
{
label: '从相册选择',
onClick: function () {
// 展示一个用于选择图片的对话框
sefl.$refs.uploaderBg.click()
}
}], [
{
label: '取消',
onClick: function () {
console.log('取消')
}
}
])
},
// 更换用户的背景 图像
async submit (obj) {
// 更换数据库中用户的背景图像
const res = await service.post('users/update', {
userId: this.$store.state.currentUser._id,
bgurl: obj.data.url
})
// 更新本地用户背景图像
if (res.data.code === 0) {
this.$store.dispatch('setUser', {
...this.$store.state.currentUser,
bgurl: obj.data.url
})
}
}
3.2.3列表组件
展示用户头像、帖子内容、帖子的发表时间和点赞和评论功能,实现了大图预览,可以查看朋友发表的图片的高清大图。(vue-photo-preview)
{
{data.user.nickname}}
{
{data.content}}
{
{formatTime(data.create)}}
赞
取消
评论
{
{item.nickname ||item.user.nickname}}
{
{item.user.nickname}}:
{
{item.content}}
3.2.4点赞组件
点赞喜欢的帖子,通知vuex的store更新朋友圈的列表的数据
// 点赞和取消点赞
operaLike () {
if (this.data.isLike) {
// 取消点赞
this.removeLike()
} else {
// 点赞
this.addLike()
}
},
// 取消点赞
async removeLike () {
const res = await service.post('likecomment/removelike', {
postId: this.data._id
})
if (res.data.code === 0) {
this.$store.dispatch('removeLike', {
pid: this.data._id,
user: this.$store.state.currentUser
})
}
},
// 点赞
async addLike () {
const res = await service.post('likecomment/addlike', {
postId: this.data._id
})
if (res.data.code === 0) {
this.$store.dispatch('addLike', {
pid: this.data._id,
user: this.$store.state.currentUser
})
}
}
3.2.5评论组件
点击评论获取用户点击的位置,展示文本框,输入内容成功评论。对安卓系统和iOS系统进行了判断,根据系统的不同展示位置也不同。使用了vuex公交车,进行数据传值,更新展示到页面。
addComment (e) {
// 获取当前点击的坐标
this.data.pageY = e.pageY
this.data.clientY = e.clientY
this.$bus.$emit('showInput', this.data)
}
// 发表评论
async publish (data) {
const res = await service.post('likecomment/addcomment', {
postId: data.data._id,
content: data.value
})
if (res.data.code === 0) {
this.showInput = false
this.$store.dispatch('addComment', {
pid: res.data.data.post, // 帖子的id
content: data.value,
user: this.$store.state.currentUser
})
}
}
点击列表页的相机图标,跳转到发布朋友圈页面。动态内容限制在200字以内,上传图片限制在五张,上传的图片可以预览,删除。
oninput () {
if (this.content.length > 200) {
this.content = this.content.substr(0, 200)
}
this.letterCount = this.content.length
},
// 查看大图
preImg (e) {
const self = this
const style = e.target.getAttribute('style')
const url = style.split('"')[1]
var gallery = weui.gallery(url, {
onDelete: function () {
self.deleteImg(e.target, gallery)
}
})
},
// 删除图片
deleteImg (target, gallery) {
const self = this
weui.confirm('确定删除该图片?', () => {
// 从数组picList中删除图片
const id = target.dataset.id
const index = self.picList.findIndex(item => {
return item.id === id
})
self.picList.splice(index, 1)
// 删除对应的dom元素
target.remove()
self.uploadCount--
})
gallery.hide(function () {
console.log('`gallery` has been hidden')
})
}
const self = this
weui.uploader('#uploader', {
url: service.baseURL + '/post/uploadimg',
auto: true,
type: 'file', // 将图片文件上传,而不是base64再上传
fileVal: 'image',
compress: {
width: 1600,
height: 1600,
quality: 0.8
},
onBeforeQueued: function (files) {
// `this` 是轮询到的文件, `files` 是所有文件
if (['image/jpg', 'image/jpeg', 'image/png', 'image/gif'].indexOf(this.type) < 0) {
weui.alert('请上传符合条件的图片')
return false // 阻止文件添加
}
if (this.size > 10 * 1024 * 1024) {
weui.alert('请上传不超过10M的图片')
return false
}
if (files.length > self.totalUploadCount) { // 防止一下子选择过多文件
weui.alert('最多只能上传' + self.totalUploadCount + '张图片,请重新选择')
return false
}
if (self.uploadCount + 1 > self.totalUploadCount) {
weui.alert('最多只能上传' + self.totalUploadCount + '张图片')
return false
}
++self.uploadCount
// return true; // 阻止默认行为,不插入预览图的框架
},
onBeforeSend: function (data, headers) {
const token = document.cookie.split('=')[1]
headers['wec-access-token'] = token
// return false; // 阻止文件上传
},
onProgress: function (procent) {
// console.log(this, procent)
// return true; // 阻止默认行为,不使用默认的进度显示
},
onSuccess: function (ret) {
ret.data.id = this.id
self.picList.push(ret.data)
// console.log(this, ret)
// return true; // 阻止默认行为,不使用默认的成功态
},
onError: function (err) {
console.log(this, err)
// return true; // 阻止默认行为,不使用默认的失败态
}
})
此页面展示了个人详细信息,可点击修改个人资料。
3.4.1 消息列表
点击私信进入消息列表页面,展示与好友们的聊天的最后一条消息,可以通过关键字进行消息搜索,点击与该好友的聊天内容,进入到与好友的聊天页面。
async fetchData () {
this.loading = true
const res = await service.get('message/getchatlist', {
keyword: this.keyword
})
if (res.data.code === 0) {
this.loading = false
this.dataList = res.data.data
}
},
searchChat () {
this.fetchData()
}
点击好友名片中的发消息可以与好友进行聊天进入到聊天页面。获取与好友的历史聊天记录展示到页面。默认情况下只显示文本框,点击加号显示更多内容,可以发送图片。运用vue-socket.io和socket.io-client插件,实现了聊天的实时通讯。
created () {
if (this.$store.state.currentUser && this.$store.state.currentUser._id) {
// 登录socket
this.$socket.emit('login', this.$store.state.currentUser)
}
// 获取历史聊天数据
this.fetchData()
},
sockets: {
// 接收消息
recieveMsg: function (obj) {
if (obj.fromUser._id === this.toUserId) {
this.addMessage({
content: obj.content,
fromUser: obj.fromUser,
main: false
})
}
},
/**
* 服务器掉之后,客户端会重新连接,连接成功后会触发下面的事件
* 我们就在这个事件中,重新登录
*/
reconnect (obj) {
if (this.$store.state.currentUser && this.$store.state.currentUser._id) {
// 登录socket
this.$socket.emit('login', this.$store.state.currentUser)
}
}
}
// 获取聊天记录
async fetchData () {
const res = await service.get('message/getchathistory', {
toUser: this.toUserId
})
if (res.data.code === 0) {
this.dataList = (res.data.data)
}
},
// 发表文字内容
async publish (data) {
// 将当前的消息储存到数据库
const res = await service.post('message/addmsg', {
content: { type: 'str', value: data.value },
toUser: this.toUserId
})
// 将当前的消息储存到dataList中
this.addMessage({
content: { type: 'str', value: data.value },
fromUser: this.$store.state.currentUser,
mine: true
})
if (res.data.code !== 0) {
weui.topTips('消息发送失败')
}
}
// 上传图片成功之后,将图片作为一条消息
async uploaded (data) {
// 将当前的消息储存到数据库
const res = await service.post('message/addmsg', {
content: { type: 'pic', value: data.data },
toUser: this.toUserId
})
// 将当前的消息储存到dataList中
this.addMessage({
content: { type: 'pic', value: data.data },
fromUser: this.$store.state.currentUser,
mine: true
})
if (res.data.code !== 0) {
weui.topTips('图片发送失败')
}
}