总结下我的处女小程序。
小程序类似mvvm框架,和vue好像,这里主要以项目为主整理总结以供日后参考,可为初级小程序学习指南,主要包括以下:
- 云开发,数据库与云函数的使用
- 小程序生命周期
- 其他涉及音频,存储,动画,相关技巧
项目需求:
主要分四部分:多语言翻译,保存翻译历史,收藏功能,留言功能
项目截图及代码地址
云开发:
- 留言功能演示nodejs云函数后端开发
- 收藏功能演示小程序前端开发
⑴. 使用云函数增删改查留言
首先需要初始化开发环境:
App({
onLaunch: function() {
wx.cloud.init({
env: 'test-263ef7',
traceUser: true,
})
},
...
})
功能A:用户添加留言:
onSend() {
// 需要存入数据库的信息
let data = {
name: app.globalData.userInfo.name,
avatar:app.globalData.userInfo.avatar,
content: this.data.content,
time: this.formateTime(new Date()),
};
// 判断
if (!data.name || !data.content || !data.avatar) {
wx.showToast({
title: '留言失败',
})
return;
}
// 添加留言
wx.cloud.callFunction({
// 云函数名称
name: "addMessages",
// 传入的数据
data,
// 调用成功
success: res => {
// res 包含该条留言的所有信息,包括随机生成_id
},
fail() {
console.log("云函数 addMessages 调用失败")
}
})
},
保存示意图:
新建nodejs云函数代码
// index.js
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init();
// 云函数里面也需要指定环境
const db = cloud.database({
env: "test-263ef7"
})
// 云函数入口函数
exports.main = async (event, context) => {
// 保存
let res = await db.collection("message-trans").add({
data: {
name: event.name,
content: event.content,
time: event.time,
avatar: event.avatar
},
})
let id = res._id;
// 返回该条留言的所有信息
return db.collection("message-trans").doc(id).get()
}
打印event,context
功能B: 用户获取所有留言
onLoad: function() {
wx.cloud.callFunction({
name: "getAllMessages",
success: res => {
let mes = res.result.data;
mes = mes.reverse();
this.setData({
messages: mes
});
...
},
fail: () => {
console.log("云函数 getAllMessages 调用失败")
}
});
},
新增getAllMessages 云函数
exports.main = async (event, context) => {
return await db.collection("message-trans").get();
}
功能C: 删除留言
// 每个 view 设置data的内容:
data-name="{{message.name}}"
data-time="{{message.time}}"
data-index="{{index}}"
data-content="{{message.content}}"
// js
onDeleteMes(e) {
let time = e.currentTarget.dataset.time;
let index = e.currentTarget.dataset.index;
wx.showModal({
title: '提示',
content: '是否删除该留言',
success: (res) => {
if (res.confirm) {
wx.cloud.callFunction({
name: "deleteMessage",
// 根据 时间和用户名来确认是 当前用户的留言,,只能删除自己的留言
data: {
time,
name:app.globalData.userInfo.name
},
success: res => {
...
},
fail() {
console.log("云函数 deletemessgae调用失败")
}
})
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
新建deleteMessage云函数
exports.main = async(event, context) => {
return db.collection("message-trans").where({
// 查询条件
time: event.time,
name: event.name
}).remove();
}
PS: 如果两名昵称相同的人在同一时间留言,会把两个人的都删除,所以可增加查询条件:比如name,time,content,avatar都相同,
注意:
每次修改云函数需要重新上传部署
⑵. 前端增删改查收藏功能
"/utils/favorite.js"
const db = wx.cloud.database();
const app = getApp();
let Favorite = {
name: "favorite-trans",
openid: app.globalData.userid,
// 收藏
like(data) {
return new Promise((resolve, reject) => {
db.collection(this.name).add({
data,
success: (res) => {
resolve(res)
},
fail() {
console.log("收藏失败")
}
})
})
},
// 取消收藏
unLike(data) {
return new Promise((resolve, reject) => {
if(data.id){
db.collection("favorite-trans").doc(data.id).remove();
}else{
db.collection(this.name).where({
_openid: this.openid,
query: data.query,
result: data.result
}).get({
success: (res) => {
let id = res.data[0]._id;
db.collection("favorite-trans").doc(id).remove();
resolve(res)
}
})
}
})
},
// 获取所有收藏
//云函数可以获取100条数据,普通方式只能获取20条, 所以这里依然使用云函数获取收藏列表
getAll() {
return new Promise((resolve, reject) => {
wx.cloud.callFunction({
name: "getAllFavorites",
success: res => {
let fa = res.result.data;
fa = fa.reverse();
resolve(fa)
},
fail: () => {
console.log("云函数 getAllFavorites 调用失败")
}
});
})
},
// 检查是否收藏
check(data) {
return new Promise((resolve, reject) => {
db.collection(this.name).where({
_openid: this.openid,
query: data.query,
result: data.result
}).get({
success: (res) => {
let flag = res.data.length ? true : false;
resolve(flag)
},
fail() {
console.log("检查是否收藏失败")
}
})
})
}
}
export default Favorite;
云函数 getAllFavorites
页面切换与小程序生命周期
(1). 页面切换的几种方式:
- 页面链接:<navigator>
- tabBar
- wx.navigateTo
- wx.switchTab
- wx.reLaunch
- wx.navigateBack
(2). 生命周期回调函数
onLoad >> 监听页面加载,只触发一次,参数中获取打开当前页面路径中的参数
示例:
// history 进入 index
// history
wx.reLaunch({
url: `../index/index?query=${data.query}&result=${data.result}`,
})
// index
onLoad(options) {
if (options.query && options.result) {...}
}
onShow >> 监听页面显示, 每次进入该页面都会触发,
如果每次进入页面都需要重新渲染
onShow(){
this.onLoad();
}
onReady >> 页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。
对界面内容进行设置的 API, 需要在onReady 之后
onHide >> 页面隐藏/切入后台时触发
示例:离开页面时保存最终状态并存入历史
onHide() {
...
},
onUnload() {
this.onHide();
},
onUnload >> 页面卸载时触发,如redirectTo
或navigateBack
到其他页面时。
本地存储
wx.setStorageSync(string key, any data)
wx.getStorageSync(string key)
可以存入任何数据类型
音频
示例:播放单词发音
onGetcurVoice() {
const audio = wx.createInnerAudioContext()
audio.src = this.data.allTranistion.tSpeakUrl;
audio.play();
audio.onPlay(() => {
console.log('开始播放')
this.setData({
isSayingCur: true
})
})
audio.onEnded(() => {
console.log('播放结束')
this.setData({
isSayingCur: false
})
})
audio.onError((res) => {
console.log(res)
})
}
剪切板
示例:复制翻译结果
onCopy() {
let flag = 1;
if (!this.data.query) {
wx.showToast({
title: '啥都没有',
})
flag = 0
}
if (flag) {
wx.setClipboardData({
data: String(this.data.result),
success: res => {
wx.showToast({
title: '复制成功',
})
}
})
}
},
动画
示例:
onChangeOrigin() {
[app.globalData.curLang, app.globalData.prevLang] = [app.globalData.prevLang, app.globalData.curLang];
wx.setStorageSync('trans_prevLang', app.globalData.prevLang);
wx.setStorageSync('trans_curLang', app.globalData.curLang);
const animation1 = wx.createAnimation({
duration: 1000,
timingFunction: 'ease',
});
const animation2 = wx.createAnimation({
duration: 1000,
timingFunction: 'ease',
})
animation1.translateX(65).step();
animation2.translateX(-65).step();
this.setData({
animationPrev: animation1.export(),
animationCur: animation2.export(),
});
setTimeout(() => {
animation1.translateX(0).step();
animation2.translateX(0).step();
this.setData({
animationPrev: animation1.export(),
animationCur: animation2.export(),
});
this.setData({
curLang: app.globalData.curLang,
prevLang: app.globalData.prevLang
});
}, 500);
}
其他
1.wx:if 与 hidden 的取舍
因为 wx:if
之中的模板也可能包含数据绑定,所以当 wx:if
的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。
同时 wx:if
也是惰性的,如果在初始渲染条件为 false
,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。
相比之下,hidden
就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。
一般来说,wx:if
有更高的切换消耗而 hidden
有更高的初始渲染消耗。,
- 如果需要频繁切换的情景下,用
hidden
更好 - 在运行时条件不大可能改变则
wx:if
较好。
2.动态class
<view class="aaa {{showFlag ? "bbb":""}}"></view>
3. catchtap 阻止冒泡
4.使用云函数保存时不会在数据库中存储 openid ,普通方法会。
小程序码:
Appendix:
小程序官方教程
相对于代码,最难的是有明确的业务需求,有可见的项目图纸,论产品经理与ui设计师的重要性[泪奔],用户体验至上。
护眼美图: