Day14-微信小程序-交友小程序-复盘
一、在iconfont上面注册然后创立自己得项目,先把想要使用得图片以SVG得形式下载下来,然后上传到自己得项目中
==注意要把图片得名字命名为英文得才行
然后就可以在代码中,style/iconfont/iconfont.wxss 把iconfont中自动生成得css代码复制过去
然后在app.wxss中引入这个 iconfont.wxss
/**app.wxss**/
@import "style/iconfont/iconfont.wxss"
如果想要使用iconfont项目中得图标得话,基本格式:
<text class="iconfont icondianzan"></text>
class第一个参数,就是我们新建得 iconfont.wxss文件的名字,后面就是我们要使用的图片的代码了
二、tabbar的创立
1、tabbar的图片不能直接使用 上面的iconfont的格式,要用url也就是图片的路径才行的
这里的方法是把iconfont上面的图标下载到本地,然后在代码文件中在image目录下新建一个tabbar的文件然后复制下载好的图标过去
(直接使用绝对路径即可,比如 "images/tabbar/附近.png")
2、因为tabbar的图标有两种状态,故在下载图标的时候。就要把两种都下载了,可以直接选择一个亮一点的颜色和一个暗一点的颜色下载下来即可)
3、这个tabbar下面的图标命名的话可以使用中文的了,如果是选中的图标的话就在原来的基础上面加 “ _active"来命名即可了
4、tabbar图标下面的文字也要和选中或者未被选中的颜色是要一样的,可以在iconfont中查看颜色的”#。。。。“表示,复制过去级课
也是有文字选中和没选中的属性的
"tabBar": {
"color":"#cdcdcd",
"selectedColor":"#1296db",
"list": [
{
"iconPath":"images/tabbar/首页.png",
"selectedIconPath":"images/tabbar/首页_active.png",
"pagePath": "pages/index/index",
"text": "首页"
},
{
"iconPath": "images/tabbar/附近.png",
"selectedIconPath": "images/tabbar/附近_active.png",
"pagePath": "pages/near/near",
"text": "附近"
},
{
"iconPath": "images/tabbar/消息.png",
"selectedIconPath": "images/tabbar/消息_active.png",
"pagePath": "pages/message/message",
"text": "消息"
},
{
"iconPath": "images/tabbar/个人.png",
"selectedIconPath": "images/tabbar/个人_active.png",
"pagePath": "pages/user/user",
"text": "我的"
}
]
}
三、首页UI设计
1、布局ul的时候如果用一般的标签的话,一般直接用class来标识,而不用id来标识的
2、在wx中text标签其实和html中的span很像
四、我的页面
1、注意了微信只能搞两个环境,如果要用第二个环境的话,就要在app.js下面的env设置为这个环境的id才行的
2、在对数据库进行操作的时候,一般在db方法的后面都会加上一个then。
这个就是为了查看用户上传的是不是成功的,符合了ES6的promise
比如:
bindGetUserInfo(ev){ // console.log(ev); let userInfo = ev.detail.userInfo; if(!this.data.logged && userInfo){ // 数据库云插入 用户信息操作 db.collection('users').add({ data:{ // 获取用户的微信头像 userPhoto:userInfo.avatarUrl, nickName:userInfo.nickName, // 个人签名 signature:'', // 电话号码 phoneNumber: '', // 微信号 weixinNumber:'', // 点赞数 links:0, // 当前注册的时间 time: new Date() // 上面空的字段都是授权的时候获取不了的,要用户自己填写的 } //这个就是为了查看用户上传的是不是成功的,符合了ES6的promise }).then((res)=>{ console.log(res); });//如果是失败的话一般也是在后面直接用catch } }
五、登录模块
1、因为用户的信息在很多页面都会被用到的,所以要吧这个信息变成一种全局的变量,就可以在app.js里面,通过设置:
this.userInfo = {}
通过这样的设置,就可以定义一个全局保存这个用户信息的对象了
(
这样通过this挂载,就可以在每个不同的页面中使用这个用户的信息了
之后在每一个页面的js文件中,通过 const app = getApp()
通过这个内置的getApp就可以拿到全局的app.js 里面的this对象了,就可以在每个页面中用 app.userInfo的形式访问这个全局的用户信息了
)
2、如果要在数据库里面差信息的话,一般都是用 doc来查,通过传入这个数据的id值,查找到这个id对应下的数据之后,就可以触发一个get方法来获得这个数据了
===然后同理的用了数据库的方法之后,在get的后面也会触发一个then来返回结果了
db.collection('users').doc(res._id).get().then((res)=>{
console.log(res.data);
});
一般这个找到的数据返回的结果通过一个 res.dara来获得的
app.userInfo = Object.assign(app.userInfo , res.data);
Object.assign(target, ...sources)==如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。
![]()
以上的方法就是得到了用户的信息,但是如果想要下次登录的时候不用再次这样授权的话,就要用云函数里面的登录界面来查找有没有用户这个openid了
2、注意了:如果要对云函数进行了修改之后,一定要右键点击重新部署
3、并且在对云函数操作之前,也要右键提前部署一下,然后在云开发云函数中查看一下这个函数有没有被部署进去
4、云函数的后面也是有一个可以用来返回结果的then的
5、在对数据库进行操作的时候,用where一般都是用来查询指定属性的值,也就是提前知道了这个属性的值,然后就吧这个数据中的这个属性的值和我们要找的书写纸这个字段找到
找到之后就可以通过get方法来进行返回了
6、我们通过在input加上一个函数 bindtext的话就可以在js文件中定义,吧我们输入的东西实时的赋值给signature了(我们输入的文本其实是保存在了ev.detail.value
7、如果是要对数据库的某一个字段进行更新的话,其实也可以使用update来更新的,就是直接在data域里面吧我们想要修改的写入即可了
8、给用户提示:showloading-》hideloading-》showtoast可以作为一套
9、一般从wxml中触发的函数,在js里面这个函数都会有一个ev变量的
10、一般不仅要改变前端的形式还要改变数据库中用户的字段才行的,以便下次进入的时候可以查询到上次的状态的
11、因为这个小程序中很多地方都可以修改用户的信息,这个时候可能导致,我这边修改了但是在user页面中是没有修改的,就可以在user.js里面的onshow中,
也就是每次只要是切换到这个页面的时候就对数据进行最新的更新即可了
onShow: function () { this.setData({ userPhoto : app.userInfo.userPhoto, nickName : app.userInfo.nickName }) },
六、头像设置
1、微信封装好的功能,可以直接在本地选择上传图片的 wx.chooseImage
2、进行云存储和云上传文件的话,使用wx.cloud.uploadFile
3、这里为了可以不让每次上传的图片可能导致因为上传的路径相同导致的覆盖,这里用了一个常规的操作就是通过在后面定义一个date的时间戳,使得我们的文件路径会通过时间的变化而改变也就不会上传两个文件出现上传路径相同的尴尬情况了
七、点赞功能实现
1、如果在获取数据库的信息的时候,但是不想要获取全部的信息的话,一般可以用field来定义你想要的字段信息了
2、如果需要在js逻辑层中用到wxml中传过来的数据的话,就可以在wxml中使用自定义属性 “data-...”的形式
3、如果要给别的用户点赞的话,因为对数据库操作的权限中没有,所以就要在服务端中进行,也就是要用到云函数了,
扩展:
https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/database/command/Command.inc.html
数据库的运算符一般都是通过db.command来获得的,
如果data是字符串,使用eval("("+data+")")可以将其转换为json对象,和JSON.parse的功能一样。

也就是通过了 eval('('+event.data+')');的方法 "{links : _.inc(1)}"把从前端传过来的变成了JSON的形式,然后为了保险起见,我们吧这个JSON对象进行展开
作为数据库update函数的data域
,
where也是同理的,就是前端传过来的 event.where 可能是一个多熟悉的JSON对象,所以不能直接作为数据库update的data域,所以就先用一个扩展运算符来处理一下的
八、点赞次数的优化
1、定义了wxs文件之后,一定要做这个文件中提供一个对外的借口
比如:
module.exports.unitFormat = unitFormat;
这个uunitFormat即使这个文件的名字也是里面函数的名字了
2、在使用定义好的wxs文件的时候,要在使用的wxml开头的时候引入:
<wxs src="../../utils/unitFormat.wxs" module="m2" />
在wxml使用的话直接传入参数:
<text>{{ m2.unitFormat(item.links) }}</text>
九、首页推荐与最新功能实现
1、在对数据库进行操作的时候,如果要对获取的数据的顺序有要求的话,可以用
.orderBy('progress', 'desc')
这个就是progress大的在前面,第二个参数可以是desc或者是asc的
ev.target.dataset
一般如果使用了自定义属性的话,比如data-www 那么我可以在这个用了自定义属性的标签中,如果有点击事件的话
可以在js逻辑函数中,通过
options: {
styleIsolation: 'apply-shared'
},
===通过这样额外的设置之后,就可以在这个组件里面使用全局的iconfont图片了
因为要给这个组件传入用户的电话号码才行,由于wxml中可以直接使用data域里面定义的数据,所以就可以直接在wxml中传入这个定电话号码即可了
在组件中的 properties 是用来接受传过来的参数的,然后还要指定数据的类型
比如我们传过去的电话号码式一个字符串形式的
properties: {
phoneNumber : String
},
再把调用的方法写到methods里面
在这个组件文件wxml中引入我们的打电话的图标,然后这个图标添加上一个点击事件,用来处理从前端传过来的电话号码
这个打电话功能微信通过:
wx.makePhoneCall({
phoneNumber: this.data.phoneNumber
})
直接给phoneNumber传入待拨打的电话号码即可了
====在组件的methonds方法里面如果要访问我们从前端传递过来的参数值的时候,直接通过this.data.名字 来进行反访问即可了
2、复制微信号组件的制作
和上面定义 打电话的组件式一模一样的
通过 wx.setClipboardData 来实现这个功能
wx.setClipboardData({ data: 'data', success (res) { wx.getClipboardData({ success (res) { console.log(res.data) // data } }) } })
1、可以通过判断在全局下面的userInfo有没有这个用户的id来判断这个用户是否已经登陆,也就是检测登陆状态
if( app.userInfo._id) 来判断即可
2、如果要跳转到 tabbar 的页面的时候,比如“我的页面”“首页”附近”这些,就不能使用navigator来跳转,这个navigator式跳转到普通页面中适合的
但是如果要跳转到tabbar页面的话就不能这样使用了
===小扩展: 小程序中页面栈最多十层。

3、小的优化点:因为我们通过showtooast来提示用户“跳转到登陆”界面的话,是有一个时间的,到那时这个是异步的操作,也就是说
如果我们不给跳转到“我的页面”这个操作设置一个执行的时间的话,可能就辉导致这个提示信息一出现,就直接跳转了,没有给用户反应的时间了,减低了用户体验====所以我们要设置跳转的时间和给用户提示的时间要是一个时间才行的
===所以就可以使用一个 setTimeout来控制 执行语句的进行
setTimeout(()=>{
wx.switchTab({
url: '/pages/user/user',
})
} , 2000);
这个message字段的胡其实就是 userId 表示的是 list数值中的用户想要加的人,也就是list数值中的用户都发了好友请求给这个人
如果,因为我直接进了这个用户的detail里面,所以我可以直接通过 this.data.detail._id来得到我看的是哪个用户的详情页的id
然后我就可以在数据库 message 字段里面通过这个id来查找,这个用户有没有这个massgae字段
如果有了的话,就把我的请求加上去进行更新。如果没有的话就在message字段里面添加上 我加他的合格信息
同时也在message里面添加上一个 userId 是他的id的这个字段了

2、更新 message 的话
因为是更新,所以要看看这个字段的list里面有没有我的信息,如果有的话,就不用添加了
如果没有的话就要进行添加即可了,又可以做一个判断了
===如果要在一个数组中查找有没有某一个数值的话,可以用数组本身带有的 includes 方法来进行查询
但是如果没有在list里面找到我的id的话。就要添加上我的id了,这种添加的功能其实可以直接用doc来找到这个字段之后,用update来进行更新,但是在客户端这种更新的功能还是有限,为了防止后面因为在客户端更新产生的影响,所以在这里是使用了用服务端也就是云函数来实现这个更新能力了

待解决:给云函数 update 传递参数的时候的格式为什么要这样的呢 data : `{list : _.unshift(' ${app.userInfo._id} ')}`
21
3、在message添加了这样的字段之后 应该要在消息中出现一个小红点,提示用户有消息,并且要在消息中添加一个显示消息列表的东西
并且还是要实时的更新,就是这个人在登陆状态的话,也可以直接收到了,也就是要实现实时的监听数据库中list的实时变化了,这个可以使用watch
我们可以在user页面中进行检测即可,也就是在登陆之后进行检测了
通过
====在tabbar里面的onreay并不会再次的触发(但是普通页面的onreay是会被再次触发的),但是他也是会触发onshow的
所以在tabbar页面的话是基于这个就可以在onshow中添加东西,来监听现在的消息变化情况了。
这里为了练习使用组件,我们这里把在消息页面中删除消息这个功能也做成了一个组件来使用了
(往左滑动的时候,可以看到 删除这个按钮,不然就看不到,这种滑动的功能的实现
详细的可以直接看 https://www.cnblogs.com/SCAU-gogocj/p/13179536.html 这篇博文
1、因为使用了 “删除消息”removelist这个组件,所以通过这个组件删除掉了之后,还要把这个删除的信息传递给前端让前端重新绘制这个已经删除的消息之后的消息列表才行的
2、在消息列表中,包括删除消息的功能还有显示消息的功能全部都是通过removeList这个文件来实现的了
3、给“删除”这两个字添加一个点击事件,点击了之后就会进行提示 类似于”是否删除消息“
可以使用微信提供的 wx.showModel 来实现这个功能
demo
wx.showModal({
title: '提示',
content: '这是一个模态弹窗',
success (res) {
if (res.confirm) {
console.log('用户点击确定')
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
然后做到,在组件中对数据进行了操作之后,再把这个数据传回到父中呢?
所以在message.wxml中队子组件remove-list设置
<remove-list wx:for="{{ userMessage }}" wx:key="{{index}}" messageId="{{ item }}"
bindmyevent="onMyEvent"/>
在父亲中 通过这个 bindmyevent,然后通过在父亲的js里面定义一个onMyEvent来接收从儿子传到父亲的这个数据了
然后在儿子中,把返回的结果,通过 this.triggerEvent('myevent',list)
第一个参数就是在父亲中定义的 bindmyevent 后面的myevent ,第二个参数就是我们得到的已经过滤后的数组了
然后在父亲的js中,定义接受的方法 onMyevent
onMyEvent(ev){ this.setData({ userMessage : [] },()=>{ this.setData({ userMessage: ev.detail }); }); }
开始的时候先吧这个变成空的数组(防止不是数组,或者其他情况,这个是一个以防万一的操作),之后通过this.setdata的回调来给这个数组赋值为从removelist中传过来的已经被过滤的数组即可了
3、在组件中之所以要用到 lifetime要包围的话,是因为在组件中没有默认的onload onready这种时间生命周期的区域的,所以就要人工的添加这样的东西,因为我们要进行下面一系列操作的话肯定是要先得到这个用户的信息才行的,所以最开始的时候就进行attached的函数即可了
(这个函数就是把这个用户的id传过来然后查找到这个id在message字段中对应数据的list数组),并赋值给userMessage
十五、建立friendList字段 实现 好友关系
1、注意:如果要在数据库users字段里面添加一个新的数据流的话,不仅要在数据库里面进行”添加操作,还要在user.js 在初始化用户代码中也要添加上对这个数据流的初始化才行的
2、因为如果别人添加了我,然后我同意了,所以我的friendlist中就有了这个人的id,这个时候也要在这个人的friendlist中添加上我的id才行的,如果单单是
db.collection('users').doc(app.userInfo._id).update({
data : {
friendList : _.unshift(this.data.messageId)
}
是对我个人的friendlist进行操作的话,可以直接用数据库本身带有的update进行更新 集合 _unshift 即可了,但是如果还要更新好友的friendlist的话因为权限的问题,无法直接在客户端来完成,这时候就要调用服务端的 update云函数才行了
十六、好友详情页+好友列表页面
(根据好友的关系来设置 用户界面,比如我是你的好友我就可以看到你的微信号和消息了,还有就是最上面的”添加好友“变成了”已是好友“
十七、附近的人 页面
1、注意如果要访问用户的隐私比如 他的地址这些的话,在调用微信提供的API之前要在app.json里面添加一个 permission的字段
"permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序位置接口的效果展示" } }
(记得在 json 文件里面是不能有注释出现的)
2、如果报错说什么 setdata出问题了,一般都是回调函数没有用箭头函数,比如 success :(res)->{} 即可l
3、在map标签中 直接添加上 show-location 这个属性的话,就可以通过微信提供的 点 来表示我的位置了
4、因为我们在进入 near 之后就立马对用户进行定位然后把附近的人也搞了,也就是把用户的信息和附近的人的信息都搞了(这个操作会在我点击 在地图中显示的图片来找到这个用户的详情页要快,所以就可以在wxml中
===还要注意的一点就是,tabbar页面的话,它只进行一次onready,但是onshow是只要切换到它了就会进行的


浙公网安备 33010602011771号