uniapp开发微信小程序[色彩大师]:Email留言和标签栏

1027 views, 2022/08/30 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仓库变色龙小程序中给我点赞!

线上小程序经过版本更新(根据用户反馈的建议),功能相比教程中有所扩展。




本文作者: 杜赛
发布时间: 2022年08月30日 - 15:07
最后更新: 2022年08月30日 - 15:07
转载请保留原文链接及作者