uniapp开发微信小程序[色彩大师]:Email留言和标签栏
4744 views, 2023/10/17 updated Go to Comments
本章,我们将继续完善小程序 Demo,学习标签栏和云函数发送Email邮件功能。
标签栏
标签栏是吸附在小程序底部的栏位,通过点击它可以快速在核心页面之间切换。
要使用标签栏,首先得做点准备工作,比如合适的图标。隆重推荐字节跳动的开源图标库 iconpark ,量大管饱,还完全免费。
在iconpark选择2种你喜欢的图标,分别下载线性(未选中状态)和填充(选中状态)的 PNG 文件(所以共计2种4个图标),大小选择48像素。
将图标放到项目的 /static/tabbar/
目录,像下面这样:
下一步,新建中国色chineseColor页面:
记得勾选在pages.js中注册,使其自动注册:
uniapp 的路由切换,是通过 pages.json
全局配置文件实现的。同样的,标签栏也是在此文件中配置。
修改 pages.json
如下:
// pages.json
{
"pages": [{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "变色龙"
}
},
{
"path": "pages/chineseColor/chineseColor",
"style": {
"navigationBarTitleText": "中国色",
"enablePullDownRefresh": false
}
}
],
"tabBar": {
"color": "#000",
"selectedColor": "#4976c9",
"list": [{
"iconPath": "/static/tabbar/platte00.png",
"selectedIconPath": "/static/tabbar/platte01.png",
"pagePath": "pages/index/index",
"text": "调色盘"
},
{
"iconPath": "/static/tabbar/layers00.png",
"selectedIconPath": "/static/tabbar/layers01.png",
"pagePath": "pages/chineseColor/chineseColor",
"text": "中国色"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "变色龙",
"navigationBarBackgroundColor": "#000",
"backgroundColor": "#fff"
},
"uniIdRouter": {}
}
注意看标签栏的图标和路径是如何对应的。
刷新模拟器看看效果,底部就变成这样了:
既然要做中国色,那首先得要有足够的颜色数据。
将事先准备好的颜色数据导入为 common/chineseColors.js
文件:
// common/chineseColors.js
const chineseColors = [{
"name": "粉鳳仙",
"pinyin": "fěn fèng xiān",
"hsb": {
h: 0,
s: 18,
b: 92,
},
}, {
"name": "浅棕茶",
"pinyin": "qiǎn zōng chá",
"hsb": {
h: 38,
s: 24,
b: 69,
},
}, {
"name": "暗苔緑",
"pinyin": "àn tái lv̀",
"hsb": {
h: 151,
s: 33,
b: 44,
},
}, {
"name": "銀白色",
"pinyin": "yín bái sè",
"hsb": {
h: 44,
s: 9,
b: 92,
},
},
...
]
export {
chineseColors,
}
// 数据来源:
// Frank Lin. http://www.2kil.com/
// Dlog_Shuai https://ext.dcloud.net.cn/plugin?id=3558
// 数据有筛选和清洗。有需要的读者可从 https://github.com/stacklens/chameleon-tutorial 下载。
在前面章节中,我们已经开发完成了用来展示颜色的组件 ColorPanel
,可以继续拿来复用。不过在此之前,先要解决一个小问题:ColorPanel
作为子组件,它应该如何修改父组件的数据呢?可能你会想到修改 props
,毕竟父组件是通过它来动态改变子组件的状态的。但是很遗憾,Vue 里不推荐你这样做,因为这样互相修改数据很容易导致项目难以维护。
解决方法是子组件不直接修改父组件的数据,而是抛出一个事件,通知父组件:我这边现在发生了状况,你看看要不要更新下数据?
因此,在 ColorPanel.vue
增加一行代码,抛出事件:
// components/ColorPanel/ColorPanel.vue
...
methods: {
...
onClickCanvas() {
uni.setClipboardData({
data: "#" + this.hex,
});
// 新增代码
this.$emit("clickPanel", this.hex)
},
}
...
this.$emit()
就是抛出事件的函数了,父组件可以通过 clickPanel
方法“感应”到事件的发生。
然后就可以愉快的写新页面 chineseColor.vue
了:
<!-- pages/chineseColor/chineseColor.vue -->
<template>
<view>
<uni-transition ref="trans" mode-class="fade" :duration="0" :show="true">
<view class="content">
<view class="card-padding">
<uni-row>
<uni-col :xs="8" :sm="6" :md="4" :lg="3" :xl="2" v-for="(item, index) in colors" :key="index">
<ColorPanel :hsb="item.hsb" @clickPanel="onClickPanel"></ColorPanel>
<view style="padding-bottom: 10px;"></view>
</uni-col>
</uni-row>
</view>
</view>
</uni-transition>
</view>
</template>
<script>
import {
chineseColors
} from "../../common/chineseColors.js"
export default {
data() {
return {
colors: chineseColors,
}
},
// 生命周期函数
onReady() {
this.$refs.trans.init({
duration: 2000,
timingFunction: 'ease-in-out',
delay: 500
})
},
methods: {
onClickPanel(hex) {
this.$refs.trans.step({
backgroundColor: "#" + hex
})
// 开始执行动画
this.$refs.trans.run(() => {})
},
},
}
</script>
<style scoped>
.content {
width: 100vw;
height: 100vh;
}
.card-padding {
padding-left: 20px;
padding-top: 15px;
}
</style>
代码量不大,需要注意的地方有两个:
- 注意看父组件是如何通过
@clickPanel="onClickPanel"
接住子组件抛出的事件的。 - 为了模仿中国色数据来源 Frank Lin. 炫酷的背景色过渡特效,这里用
uni-ui
插件的过渡元素<uni-transition>
将所有内容包裹起来,并根据文档,调用它的init()
、step()
、run()
等接口,当你点击画布时,让页面背景也过渡到对应的颜色。
差不多了,来看看效果:
任意点击画布,背景色也顺滑地过渡到对应颜色。
云函数与Email
发送Email是很实用的功能,比如用于开发者和用户的沟通。出于安全等方面的考虑,通常会在云函数中来实现。
云函数的详细介绍请看uniCloud文档,这里简明扼要说特点:
- 代码运行在云端,因此每次更新代码需要部署。
- 可以承担简单的传统后端的功能,相对以往租用云服务器的模式,会更加的实惠甚至免费。
在我之前的文章微信小程序开发:云端发送Email邮件中,已经实践过了。让我们在 uniapp 中再回味一下吧。
和前面一样,新建标签栏需要一些准备工作:
- 在 iconpark 下载喜欢的图标,并在
pages.json
注册feedback
页面和链接它的tabbar
。 - 在
pages
目录创建feedback
页面。
然后就可以写 feedback.vue
了。
老规矩,首先是模板:
<!-- pages/feedback/feedback.vue -->
<template>
<view>
<view class="container">
<view class="text content-center">
<text>想要新功能?</text>
</view>
<view class="text content-center">
<text>任何意见或建议都非常感谢。</text>
</view>
<view class="text content-center">
<text>你可以提交下面的表格来告诉我。</text>
</view>
<view class="padding-t-12">
<uni-easyinput type="textarea" autoHeight v-model="feedbackText" placeholder="对开发者的话..."></uni-easyinput>
</view>
<view class="content-center padding-t-12">
<button @click="submit" type="primary" size="mini">
提交留言
</button>
</view>
</view>
<!-- 提示消息 -->
<uni-popup ref="popup" type="message">
<uni-popup-message :type="msgType" :message="msgContent"></uni-popup-message>
</uni-popup>
</view>
</template>
...
代码里没有出现任何新知识,硬要说的话就是通知栏弹出层 <uni-popup>
了,绑定了 :type
和 :message
是为了根据邮件发送成功与否,动态修改弹出层的颜色和文本。
然后是脚本:
// pages/feedback/feedback.vue
...
<script>
export default {
data() {
return {
feedbackText: "",
msgType: "",
msgContent: "",
}
},
computed: {
// 防止留言文本过长
mailContent: function() {
return this.feedbackText.trim().slice(0, 2000)
},
},
methods: {
// 提交email留言
submit() {
if (this.mailContent === "") {
return uni.showToast({
title: "请输入想说的话哟",
icon: "none",
})
}
this.sendMail()
},
sendMail() {
// 调用云函数sendMail()
uniCloud.callFunction({
name: 'sendMail',
data: {
content: this.feedbackText,
}
})
.then(res => {
if (res.success === true) {
this.msgType = "success"
this.msgContent = "邮件发送成功"
this.feedbackText = ""
} else {
this.msgType = "error"
this.msgContent = "邮件发送失败,晚点再尝试下吧~"
}
return this.$refs.popup.open()
});
},
}
}
</script>
...
脚本里的新玩具,就是这个 uniCloud.callFunction()
方法了,它的作用就是发送 web 请求,调用在云端的云函数。 name
是云函数的名字, data
是需要传递过去的数据。
最后是样式:
/* pages/feedback/feedback.vue */
...
<style scoped>
.container {
padding: 20px;
}
.content-center {
display: flex;
justify-content: center;
align-items: center;
}
.text {
font-size: 14px;
color: #434343;
font-weight: 500;
}
.padding-t-12 {
padding-top: 12px;
}
</style>
页面里的代码就这么多了,接下来搞花里胡哨的云函数。
既然云函数是在云端的,所以需要进行一点设置,告诉云服务商你想搞一块地盘玩玩。
在项目路径上右键,选择创建uniCloud云开发环境,再选择阿里云:(阿里云流程简单些)
这时候项目里多出来 uniCloud
路径,右键点击云服务空间初始化向导:
接着就进入 uniCloud
的账号申请、阿里云服务申请等环节,很简单跟着向导走就行,这里就不展开了:
创建好账号后,新建服务空间chameleon,点击下一步,空间就关联上了:
别急,快完成了。
右键点击 uniCloud/cloudfunctions/
路径,选择新建云函数/对象:
然后创建名叫 sendMail
的云函数。
为了简化开发,发送Email需要借助库的帮助。
右击 sendMail
,选择使用命令行窗口打开所在目录,像下面这样:
这时候会弹窗问你要用内置窗口还是外置。
你可以选择内置命令行窗口,等待安装完成并打开。
在打开的命令行窗口中输入:
npm install nodemailer
安装发送Email的库。
注意,一定要看清楚安装的路径!确保库被安装到
../sendMail/node_modules/
路径中了。
安装成功后,准备工作就搞完了。
接着编写 ../sendMail/index.js
文件,这就是云函数的入口:
// uniCloud/cloudfunctions/sendMail/index.js
'use strict';
const nodemailer = require('nodemailer')
// 创建一个SMTP客户端配置
var config = {
host: 'smtp.qq.com', // 网易163邮箱是 smtp.163.com
port: 465, // 网易邮箱端口是 25
auth: {
user: '填写你自己的邮箱账号', // 邮箱账号
pass: '填写你自己的邮箱授权码' // 邮箱的授权码
}
};
exports.main = async (event, context) => {
let transporter = nodemailer.createTransport(config);
const content = event.content
// 创建一个邮件对象
var mail = {
// 发件人
from: '用户反馈 <xxx@yyy.com>',
// 主题
subject: 'Weapp [Chameleon] 用户反馈',
// 收件人
to: 'xxx@yyy.com',
// 邮件内容,text或者html格式
text: content
};
const info = await transporter.sendMail(mail)
return info
}
由于有 nodemailer
库的帮助,代码很简单,调用接口就完事了。这里难倒一众好汉的,通常是邮箱的 host、port、auth填不对这种低级的问题。
这里只简单提一下 QQ 邮箱的授权码。准备一个QQ邮箱。进入邮箱后,点击:设置 - 账户 - 开启 POP3/SMTP
服务。然后跟着QQ邮箱的引导步骤,最终你获得的授权码应该像下图这样:
写好云函数文件后,记得还要上传云函数!
它运行在云端,更新代码后需要部署:
大功告成了!
重启服务(建议选择连接云端函数):
效果如下:
提交留言后,你的Email邮箱中也会立即收到留言的内容。
结语
本系列文章到这里就结束了,相信你已经能感受到 uniapp 开发的优势了:
- 多端开发,一套代码处处运行,适配小团队。
- 以 Vue 为底层框架,学了怎么都不亏。
- 国内使用人群还算庞大,生态正在茂盛发展。
接下来的学习,你可能需要系统性的阅读Vue文档、uniapp文档,逐步扩展到学习uniCloud、前端网页托管以及三方库等衍生工具和生态中了。
路漫漫其修远兮,吾辈一同求索。
作者杜赛,新人写手,写有Django搭建博客、微信小程序开发todo-list等系列文章。
欢迎来Github仓库和变色龙小程序中给我点赞!
线上小程序经过版本更新(根据用户反馈的建议),功能相比教程中有所扩展。