记2024-08原生微信小程序开发

继2024.08

最近需要开发一个微信小程序的一个功能模块,但是之前在学的时候都是好几年前的东东了,然后重新快速过了一遍b站大学的教程,这篇文章就是基于教程进行的一些总结,和自己开发过程当中使用到的一些点和一些技巧什么的吧。

快速编写样式

在vscode当中安装cssTree插件,之后在wxml当中全选当前写好的代码,ctrl+ship+p调出插件选择对应cssTree插件,就会生成一个less文件,这个文件里面就是根据class类名生成的样式结构树

再安装 Easy less插件,在vscode设置当中选择插件配置打开setting文件。添加less编译配置。之后当保存了index.less之后就会同步生成到index.wxss当中

js 复制代码
  "less.compile": {
    "compress": false, //是否压缩
    "sourceMap": false, //是否生成map文件,有了这个可以在调试台看到less行数
    "out": true, // 是否输出css文件,false为不输出,千万不要是false
    "outExt": ".wxss" // 输出文件的后缀,小程序可以写'.wxss'
    // "outExt": ".css", // 输出文件的后缀,小程序可以写'.wxss'
  }

路径别名

使用 resolveAlias 配置项用来自定义模块路径的映射规则。配置了之后,会对 require 里的模块路径进行规则匹配并映射成配置的路径。在app.json当中添加以下配置,表示使用@符号就是这个app.json的根路径(其实也就是我们的业务代码下的根路径了)resolveAlias对应的文档

json 复制代码
	"resolveAlias": {
		"@/*": "/*"
	}

构建npm

先给小程序项目初始化一个npm和安装一个UI库,而后在开发者工具当中选择工具->构建npm,构建完成之后就会有我们的老朋友node_modules了

shell 复制代码
npm init
npm i @vant/weapp

拆分

为了将小程序代码和npm相关的文件进行分开,在根目录下新增miniprogram文件夹,将小程序相关代码放到该文件夹当中,那么外面就只有以下几个文件了。

  • .eslintrc.js
  • package.json
  • package-lock.json
  • project.cofig.json
  • project.private.config.json

配置

将文件都分开之后在project.config.json当中对文件进行配置,新增和修改了这些:也就是将原本在根目录下允许的小程序换到了miniprogram目录下

  • compileType
  • miniprogramRoot
  • setting当中的packNpmManually和packNpmRelationList
json 复制代码
{
  "compileType": "miniprogram",
  "miniprogramRoot": "miniprogram/",
  "libVersion": "trial",
  "packOptions": {
    "ignore": [],
    "include": []
  },
  "setting": {
    "packNpmManually": true,
    "packNpmRelationList": [
      {
        "packageJsonPath": "./package.json",
        "miniprogramNpmDistDir": "./miniprogram"
      }
    ],
    "coverView": true,
    "es6": true,
    "postcss": true,
    "minified": true,
    "enhance": true,
    "showShadowRootInWxmlPanel": true,
    "babelSetting": {
      "ignore": [],
      "disablePlugins": [],
      "outputPath": ""
    }
  },
  "condition": {},
  "editorSetting": {
    "tabIndent": "auto",
    "tabSize": 2
  },
  "appid": "你的APPID",
  "srcMiniprogramRoot": "miniprogram/"
}

使用UI库

在微信小程序当中推荐了一个WeUI。但是组件还是少了些,这里使用一个Vant Weapp

cmd 复制代码
// 安装库、安装完成之后需要重新构建npm,见上一个构建npm章节
npm i @vant/weapp
  • 将 app.json 中的 "style": "v2" 去除,小程序的新版基础组件强行加上了许多样式,难以覆盖,不关闭将造成部分组件样式混乱。
  • 引入组件,在app.json当中引入就是全局注册、在对应pages下的json引入就是局部引入
json 复制代码
"usingComponents": {
  "van-button": "@vant/weapp/button/index"
}

分包

在小程序开发当中由于对项目包体积大小有规定,而项目越来越大的时候分包就必不可少了。在pages(也就是所有存放页面的目录)同级新增一个modules目录用来表示子包(其他业务页面)同时在app.json当中添加配置

js 复制代码
  "subpackages": [
    {
      "root": "modules/data",
      "name": "数据",
      "pages": [
        "pages/list/index",
        "pages/my/index"
      ]
    }
  ]

这个时候打包之后在modeles当中data(数据子包)就会进行分开打包。选择详情->基本信息->本地代码->代码依赖分析查看结果

分包预下载

规则配置,表示在进入pages/index页面之前先将modules分包下载下来,不论是在WIFI还是流量的网络下。

js 复制代码
  "preloadRule": {
    "pages/index": {
      "network": "all",
      "packages": ["modules"]
    }
  }

交互封装

Loading

js 复制代码
const defaultOptions = {
  title: "加载中",
  mask: true,
};

/**
 * 统一封装原生loading效果
 * @param {Object} options 配置选项
 * @param {string} options.title 提示的标题
 * @param {string} options.mask 是否遮罩
 */
export const showLoading = (options = {}) => {
  options = Object.assign({}, defaultOptions, options);
  wx.showLoading(options);
};

export const hideLoading = () => {
  wx.hideLoading();
};

响应Promise,使用的地方得到响应通过boo判断是确认还是取消

js 复制代码
const defaultParams = {
  title: "提示",
  content: "这是一个模态弹窗",
  showCancel: true,
  cancelText: "取消",
  cancelColor: "#000",
  confirmText: "确定",
  confirmColor: "#576B95",
};

/**
 * 展示模态框
 * 点击了确定或者取消按钮通过回传回去,异步接收通过true or false 判断
 *
 * @param {Object} options 配置选项
 * @param {string} options.title 提示的标题
 * @param {string} options.content 提示的内容
 * @param {boolean} options.showCancel 是否显示取消按钮
 * @param {string} options.cancelText 取消按钮的文字,最多 4 个字符
 * @param {string} options.cancelColor 取消按钮的文字颜色,必须是 16 进制格式的颜色字符串
 * @param {string} options.confirmText 确认按钮的文字,最多 4 个字符
 * @param {string} options.confirmColor 确认按钮的文字颜色,必须是 16 进制格式的颜色字符串
 */
export const showModal = (params) => {
  params = Object.assign({}, defaultParams, params);
  return new Promise((resolve) => {
    wx.showModal({
      ...params,
      success(res) {
        // 点了确认res当中会有confirm,取消则是cancel
        resolve(res.confirm);
      },
    });
  });
};

Toast

js 复制代码
const defaultOptions = {
  title: "",
  icon: "success",
  image: "",
  duration: 2000,
  mask: false,
};

/**
 * 展示提示框
 *
 * 下面是入参对象的部分配置
 * @param title 提示的内容
 * @param icon 提示的图标
 * @param image 本地图标,优先级高于icon
 * @param duration 显示延迟时间
 * @param mask 是否显示透明蒙层,防止触摸穿透
 */
export const showToast = (options) => {
  options = Object.assign({}, defaultOptions, options);
  wx.showToast(options);
};

请求封装

这里对wx.request请求进行封装,主要逻辑在于

  • 合并参数
  • 设置token
  • 发送请求
  • 请求响应后通过Promise返回,使用的地方通过async await拿到响应体
js 复制代码
import { delLocalSync, getLocalSync } from "./localStorage";
import { showLoading, hideLoading } from "./loding";
import { showToast } from "./toast";

const baseUrl = "http://127.0.0.1";
const defaultOptions = {
  method: "GET",
  timeout: 90000,
};
/**
 * 整合一个公共发送请求接口
 * @param {Object} options
 * @param {string} method string 请求方式
 * @param {string} url string 请求地址
 * @param {number} timeout number 请求超时时间
 */

export const request = (options) => {
  options = Object.assign({}, defaultOptions, options);
  const { url, data, method, header } = options;

  showLoading();

  const token = getLocalSync("token");

  if (token) {
    header["Authorization"] = token;
  }

  return new Promise((resolve, reject) => {
    wx.request({
      url: baseUrl + url,
      method,
      data,
      header,
      success: (result) => {
        const { statusCode, data } = result;
        if (statusCode === 200) {
          resolve(result.data);
        } else if (statusCode === 400) {
          showToast({ title: data.message, icon: "none" });
        } else if (statusCode === 401) {
          delLocalSync("token");
          showToast({ title: "登录信息过期,请重新登录", icon: "none" });
        }
      },
      fail: (err) => {
        reject(err);
      },
      complete: () => {
        hideLoading();
        // 如果后端接口直接抛异常就走这个判断,再弹提示
      },
    });
  });
};

代码质量检查

在微信开发者工具当中选择 工具 -> 真机性能分析工具 运行完成之后会打开对应的代码质量tab,查看不通过的项进行修改

自定义表格

其实感觉小程序项目做表格是不太好的,可能是还是用PC端的逻辑来做的UI就会要做表格,下面是一个自定义表格和一些样式可以参考一下

html 复制代码
<view class="table">
    <view class="table__header">
        <view class="check__cell">
            <checkbox value="cb" color="#1979FF" checked="{{false}}" />
        </view>
        <view class="card__cell">姓名</view>
        <view class="imsi__cell">年龄</view>
    </view>

    <view class="table__body">
        <view class="table__item" wx:for="{{tableData}}" wx:for-index="index" wx:for-item="item" wx:key="id">
            <view class="check__cell">
                <checkbox value="{{item.isChecked}}" color="#1979FF" checked="{{item.isChecked}}" />
            </view>
            <view class="card__cell">{{item.name}}</view>
            <view class="imsi__cell">{{item.age}}</view>
        </view>
    </view>
</view>

对应的样式

less 复制代码
view.table {
  padding: 20rpx 20px 0 20px;

  view.table__header {
    display: flex;
    background-color: #F5F5F5;
    height: 72rpx;
    align-items: center;
    font-size: 28rpx;
    font-weight: bold;
    text-align: center;

    .check__cell {
      width: 100rpx;
    }

    .card__cell {
      width: 50%;
    }

    .imsi__cell {
      width: 50%;
    }
  }

  view.table__body {
    height: calc(100vh - 450rpx);
    overflow: scroll;
  }

  view.table__item {
    display: flex;
    height: 64rpx;
    align-items: center;
    font-size: 28rpx;
    text-align: center;

    .check__cell {
      width: 100rpx;
    }

    .card__cell {
      width: 50%;
    }

    .imsi__cell {
      width: 50%;
    }
  }
}

OCR文本识别

方案一:小程序插件

首先需要在微信公众平台上面 设置-> 第三方设置 -> 插件管理,添加OCR支撑这个插件。然后在详情当中有开发文档,需要先去购买限制,一天有一百次免费使用。

在app.json当中声明插件,同时图省事的话可以把包直接全局引入,也可以在要使用的页面当中注册这个组件

json 复制代码
 "plugins": {
    "ocr-plugin": {
      "version": "3.1.3",
      "provider": "wx4418e3e031e551be"
    }
  }

  "usingComponents": {
    "ocr-navigator": "plugin://ocr-plugin/ocr-navigator"
  }

使用的话就比较简单了,这里以扫描车牌为例:

html 复制代码
<ocr-navigator bind:onSuccess="platenumSuccess" certificateType="platenum">
    <button type="primary">车牌识别</button>
</ocr-navigator>
<view>OCR识别的车牌是:{{licensePlate}}</view>

// 在对应的js当中添加扫描成功的方法
platenumSuccess(event){
	this.setData({
		licensePlate: event.detail.number.text
	})
},

方案二:前端 tesseract.js

这个以Vue3的代码为例:首先需要安装npm i tesseract.js。其中第一次使用会去加载对应的资源会有一点点慢

js 复制代码
<template>
  <div>
    <div style="marginTop:100px">
      <input id="image-input" accept="image/*" type="file" @change="handleChage">
      <br/>
      <button @click="processImage">提取文字</button>
      <div id="show-picture"></div>
    </div>
    <div>
      <p style="color:red">提取到的内容:</p>
      <span id="result"></span>
    </div>
  </div>
</template>

<script setup>
import {createWorker} from 'tesseract.js';

//将选择的图片显示在页面上
const handleChage = () => {

  document.getElementById('result').innerText = '';
  let getUserPhoto = document.getElementById('image-input');


  //创建一个FileReader对象,用于读取图像文件
  let reader = new FileReader();

  //读取第一个文件,并转为base64格式
  reader.readAsDataURL(getUserPhoto.files[0]);

  //只显示第一个图片
  reader.onload = function () {
    let image = document.createElement('img');
    image.width = '400';

    //设置图片
    image.src = reader.result;
    let showPicture = document.getElementById('show-picture');
    while (showPicture.firstChild) {
      showPicture.removeChild(showPicture.firstChild);
    }
    showPicture.appendChild(image);
  };
};


const processImage = () => {
  let worker;
  let input = document.getElementById('image-input');
  if (input.files && input.files[0]) {
    let reader = new FileReader();
    reader.onload = async function (e) {

      //创建一个Worker线程,参数为需要识别的语言, chi_sim代表简体中文
      worker = await createWorker('chi_sim');
      worker.recognize(e.target.result)
          .then(result => {

            // 提取出的文字,给元素赋值
            console.log(' =====', result);
            let extractedText = result.data.text;
            document.getElementById('result').innerText = extractedText;

          })
          .catch(error => {
            console.error('Error:', error);
          }).finally(() => {
        if (worker)

            // 清除当前Worker线程
          worker.terminate();

      });
    };
    reader.readAsDataURL(input.files[0]);
  }
};
</script>

方案三:java Spore.OCR

使用java实现的是使用这个Spire.OCR,代码是基于springboot来写的哈(非常感谢您使用我们的 Spire.OCR for Java 产品。试用版在功能上没有任何限制,只是在结果文档中有试用提示信息。)

先安装maven依赖,安装不下来的话就配置一下这个仓库地址

xml 复制代码
<repositories>
    <repository>
        <id>com.e-iceblue</id>
        <name>e-iceblue</name>
        <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
    </repository>
</repositories>

<dependency>
	<groupId>e-iceblue</groupId>
	<artifactId>spire.ocr</artifactId>
	<version>1.9.0</version>
</dependency>

其他依赖文件请根据您所使用的操作系统选择下载:这个下载下来的是dependencies压缩包解压放在项目的根目录下

利用java实现:这里直接贴代码了

java 复制代码
package com.ocr.ocrserver.controller;

import com.spire.ocr.OcrException;
import com.spire.ocr.OcrScanner;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OcrController {

    @RequestMapping("/")
    public String home() throws OcrException {
        //指定依赖文件的路径
        String dependencies = "dependencies\\";

        String imageFile = "8.png";

        //创建OcrScanner对象,并设置其依赖文件路径
        OcrScanner scanner = new OcrScanner();
        scanner.setDependencies(dependencies);

        //扫描指定的图像文件
        scanner.scan(imageFile);

        //获取扫描的文本内容
        String scannedText = scanner.getText().toString();

        return scannedText;
    }
}

报错:Exception in thread "main" java.lang.NoClassDefFoundError: sun/misc/BASE64De

表示 Java 虚拟机(JVM)在运行时尝试加载某个类,但没有找到指定的类。这里的错误信息显示找不到的类是 sun/misc/BASE64Decoder,这是 Java 内置的类,用于进行 Base64 编码和解码。将jdk版本降到1.8。你出任你出,我用java8

方案四:小程序原生

在微信小程序的文档当中有一个AI视觉算法 VKOCRAnchor

使用这个也是可以实现的,首先找到他的github代码地址,把代码拉一份下来。GitHub代码。把整个仓库拉一份下来,将这个OCR的目录拷一份到自己的项目当中。需要在app.json配置对应的路径

  • 安装依赖 npm i threejs-miniprogram 安装之后构建一下
  • 在behavior.js当中还引入了.../loaders/gltf-loader,将仓库当中的这个loaders拷贝过来
  • 之后就是重新编译查看效果了,这个时候发现UI好像不一样,发现是canvas的高度太高啦,在wxml文件当中找到canvas元素将其宽高改成0,这个也是没啥用的。要是想要这个canvas展示就自己重新设置一下宽高。
  • 最后一步,发现不管是在开发工具当中编译发现报错,识别不出来?这个时候懵逼了,后面发现在手机上进行预览是正常的,难道不能在模拟器运行?

到这也就完成了这一块的功能,其中获取识别后的数据在behavior.js当中的updateAnchors回调当中

方案五:第三方服务

在腾讯云、阿里云、百度云都有OCR文本识别进行出售,也可以直接进行购买进行使用。

表单规则校验

在这里推荐使用async-validator,下面整个案例看一下怎么使用,先npm安装就跳过了,安装完之后记得在开发工具当中npm构建

下面简单的说明了一下使用方法,以及简单校验、正则校验、自定义校验三个规则。在校验的时候我们需要异步等待,同时如果没有通过校验的我们可以拿到errors,这个是一个数组,每一项就对应校验规则某个字段,最后只要有没通过的就resolve(false)。在提交的时候拿到这个值去判断

  • 创建规则数组
  • 实例化Schema对象,将rule传进去
  • 调用validate方法进行校验,得到error(校验未通过的项)
js 复制代码
import Schema from "async-validator";
Page({
  /**
   * 页面的初始数据
   */
  data: {
    name: "",
    age: 18,
    email: "",
  },

  // 表单校验
  onValidate() {
    // 匹配年龄的正则(表示匹配1-150)
    const ageRegExp = /^(?:[1-9][0-9]?|1[0-4][0-9]|150)$/;

    // email 正则
    const emailRegExp =
      /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/;

    // 校验规则
    const rules = {
      name: [{ required: true, message: "姓名不能为空" }],
      // 还可以通过min max 指定最大最小值
      age: [
        { required: true, message: "年龄不能为空" },
        { pattern: ageRegExp, message: "请输入1到150之间的数" },
      ],
      email: [
        { required: true, message: "邮箱地址不能为空" },
        {
          pattern: emailRegExp,
          message: "邮箱不合法请检查",
        },
      ],
      // 自定义校验规则,和el-plus大差不大的
      emailV: [
        {
          asyncValidator: (rule, value) => {
            return new Promise((resolve, reject) => {
              console.log(value);
              if (!value) {
                reject("请输入啊,哥们");
              } else {
                resolve();
              }
            });
          },
        },
      ],
    };

    const validator = new Schema(rules);
    return new Promise((resolve) => {
      validator.validate(this.data, (errors) => {
        if (errors) {
          // 这个是封装的消息展示
          showToast({ title: errors[0].message, icon: "error" });
          resolve({ valid: false });
        } else {
          resolve({ valid: true });
        }
      });
    });
  },

  // 提交按钮触发事件
  async onSubmit() {
    const { valid } = await this.onValidate();
    if (!valid) return;
    // 验证通过,做后续业务逻辑
  },
});

自动化测试

自动化测试这里又涉及到了python使用测试的库是 minium 这里安装python和开发工具pycharm就调过来了哈,

首先初始化一个项目,先添加一个config.json配置文件

  • project_path 是小程序项目存放的位置
  • dev_tool_path 是微信开发者工具的位置
  • debug_mode 调试模式用debug就好了
json 复制代码
{
  "project_path": "D:\\xxx\\xxx\\ocrprogram",
  "dev_tool_path": "D:\\soft\\wechat_devtools\\install\\wx_tools\\cli.bat",
  "debug_mode": "debug"
}

简单来个demo测试一下。先需要通过pip install minium 安装一下这个库,代码是很通俗易懂的哈,要是不会py就把他理解成js或者java代码就好了,创建一个类继承过来,然后定义方法,通过对应的方法去找元素(Ele)再触发点击事件。

python 复制代码
import minium

class Test(minium.MiniTest):
    def test1(self):
        # 找到录入按钮模拟点击
        enter = self.page.get_element("view[class='model enter']")
        enter.click()

        # 找到下一步的按钮再模拟点击
        next = self.page.get_element("van-button[class='next']")
        next.click()

运行测试,运行之后会自动打开微信开发者工具并且预览项目指定对应的交互操作,完成之后会在py项目当中生成outputs文件夹,预览里面的index.html文件(也就是我们要的测试报告)

  • -c 指定config配置文件
  • -m 指定对应要执行的模块,也就是对应的py文件,这里可以不用跟上文件后缀
  • -g 表示生成测试报告
cmd 复制代码
minitest -c config.json -m test -g

最终来说,不同的小程序测试脚本不同,实际开发还是根据实际为准,获取按钮事件、获取input焦点、添加随机字符等等。

触发wxAPI

在minium当中可以通过call_wx_method方法去触发原生wxAPI,下面以获取系统配置为例。通过call_wx_method调用,入参直接传wxAPI的名称,然后后面的get方法和minium没有关系,是call_wx_method响应的是一个对象,这里通过get方法把外面包的几层不要的去掉。

python 复制代码
sys_info = self.app.call_wx_method("getSystemInfo").get("result", {}).get("result")
self.assertIsInstance(sys_info, dict, "is dict")
print('--------------系统信息------------')
print(sys_info)

# 得到结果
{'errMsg': 'getSystemInfo:ok', 'batteryLevel': 100, 'benchmarkLevel': -1, 'brand': 'devtools', 'memorySize': 2048, 'model': 'iPhone 15 Pro Max', 'system': 'iOS 10.0.1', 'platform': 'devtools', 'pixelRatio': 3, 'safeA
rea': {'top': 54, 'left': 0, 'right': 430, 'bottom': 898, 'width': 430, 'height': 844}, 'screenWidth': 430, 'screenHeight': 932, 'screenTop': 98, 'windowWidth': 430, 'windowHeight': 834, 'statusBarHeight': 54, 'versi
on': '8.0.5', 'language': 'zh_CN', 'SDKVersion': '3.5.1', 'enableDebug': False, 'fontSizeScaleFactor': 1, 'fontSizeSetting': 15, 'mode': 'default', 'host': {'env': 'WeChat'}, 'bluetoothEnabled': True, 'locationEnable
d': True, 'wifiEnabled': True, 'locationReducedAccuracy': True, 'albumAuthorized': True, 'bluetoothAuthorized': True, 'cameraAuthorized': True, 'locationAuthorized': True, 'microphoneAuthorized': True, 'notificationA
uthorized': True, 'notificationAlertAuthorized': True, 'notificationBadgeAuthorized': True, 'notificationSoundAuthorized': True, 'phoneCalendarAuthorized': True, 'deviceOrientation': 'portrait', 'devicePixelRatio': 3}

同理,我们也可以通过这个去调用加载图片

python 复制代码
        options = {
            'count': 1,  # 最多可以选择的图片张数
            'sizeType': ['original', 'compressed'],  # 所选的图片的尺寸
            'sourceType': ['album', 'camera']  # 选择图片来源
        }

        # 调用chooseMedia方法并传入选项
        result = self.app.call_wx_method('chooseMedia', options).get("result", {}).get("result")

        # 这个时候result的值
		# {'errMsg': 'chooseMedia:ok', 'failedCount': 0, 'type': 'image', 'tempFiles': [{'tempFilePath': 'http://tmp/KfQ128Lwv8Sv19ba87032dc5c89b40f6e34ad7d9a639.jpg', 'size': 1266964, 'fileType': 'image'}]}
        
        # 处理回调结果
        if result['errMsg'] == 'chooseImage:ok':
            chosen_images = result['tempFiles']
            # 在这里添加断言或其他测试逻辑
        else:
            print("Error choosing media:", result['errMsg'])

发送邮件

方案一:node环境

在前端发送邮件可以使用nodemailer,这是在node环境当中,下面以QQ邮箱发送为例,首先登录QQ邮箱,之后在设置-账号-开启POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务,并且拿到对应的授权码

js 复制代码
const nodemailer = require("nodemailer");

// 创建一个SMTP客户端配置对象
const transporter = nodemailer.createTransport({
  host: "smtp.qq.com", // QQ邮箱的SMTP服务器地址
  port: 465, // 端口号
  secure: true, // 使用SSL加密
  auth: {
    user: "12345678@qq.com", // 你的QQ邮箱账号
    pass: "授权码", // 你的QQ邮箱授权码
  },
});

// 设置邮件内容
const mailOptions = {
  from: "12345678@qq.com", // 发件人地址
  // to: '110@163.com', // 收件人地址
  to: "87654321@qq.com",
  subject: "你好,附件", // 邮件主题
  text: "对应的信息放在附件了", // 邮件正文(纯文本)
  html: "<div>时间:2024-10-10 10:00:00</div><div>编号:PC12138</div><div>名称:测试</div>", // html格式
  // 附件信息(名称和对应的路径)
  attachments: [
    {
      filename: "package.json",
      path: "./package.json",
    },
  ],
};

// 发送邮件
transporter.sendMail(mailOptions, (error, info) => {
  if (error) {
    console.log("Error sending email:", error);
  } else {
    console.log("Email sent:", info.response);
  }
});

在这里简单测试了一下发送的效果,其中接收邮箱是qq和阿里的就来挺快的和正常收发是一样的,但是用了网易163邮箱试了一下在163那边要很久才能收到通知,不知道这个是不是通知机制出问题了,还是卡了什么的,这个注意一下,后续使用的时候也记得测一测

自定义组件

在实际开发过程当中,组件的拆分是必不可少的,下面就简单的介绍一下wx组件的使用,整体结构和页面是一样的,在pages同级目录新增components用来放组件,组件需要在app.json当中进行引入,这个可以看前面使用UI库,和vantweapp一样引入即可。

组件数据传递

父组件往子组件传数据,子组件是通过Component构建的,通过properties用来接收,这个和vue就基本上是一样的,子组件本身使用数据直接用descItem即可。更多的自定义组件可以看官方API

js 复制代码
Component({
  options: {
    multipleSlots: true // 在组件定义时的选项中启用多slot支持
  },
  properties: {
    /**
     * 数据格式说明 数组对象[{},{},{}]
     * @param {string} batchNo 批号
     * @param {string} createTime 创建时间
     * @param {string} startLastTime 有效期开始
     * @param {string} endLastTime   有效期结束
     * @param {string} num 数量
     * @param {string} name 名称
     */
    descItem: {
      type: Object,
      default: () => {
        return {};
      },
    },
  },
  
  // 子组件本身的数据
  data: {
    
  },
  
  // 子组件往外暴露事件
  methods: {
    send(){
        this.triggerEvent("send", 1)
    },
  },
});

# 父组件传值
<Card descItem="{{item}}" bind:send="getSend" />

获取组件实例

通过this.selectComponent()方法获取实例,其中需要传子组件的选择器(id或class选择器)

js 复制代码
this.selectComponent('.crad')

Behavior

用于组件间代码共享的特性,可以把他当成vue2当中的mixins混入,behavior文档

js 复制代码
export default function getBehavior() {
  return Behavior({
    // 组件的对外属性,是属性名到属性设置的映射表
    properties: {
      myBehaviorProperty: {
        type: String,
      },
    },

    // 内部定义的数据
    data: {
      num: {},
    },

    // 数据字段监听器
    observers: {
      num: function (newNum) {
        console.log("num change --- ", newNum);
      },
    },

    // 组件生命周期函数
    attached: function () {},

    // 组件的方法
    methods: {
      myBehaviorMethod: function () {},
    },
  });
}

使用behavior

js 复制代码
import getBehavior from "./behavior";
Component({
  behaviors: [getBehavior()],
});

页面数据通信

  • eventChannel
  • 事件总线

在小项目当中可以使用,在庞大的项目当中还是避免使用这个,不然数据传来传去找的头皮发麻,应该用数据变化去驱动事件

全局数据

getApp()

在小程序app.js当中会初始化一个App全局对象,就好像Vue一样,这个里面是整个的初始化生命周期、全局数据等。

js 复制代码
// app.js
App({
  onLaunch() {},
  globalData: {
    userInfo: null
  },

  setUserInfo() {
    this.globalData.userInfo = {
      name: "admin",
    };
  },
});

如何使用全局数据

js 复制代码
const app = getApp()

// 获取全景数据
app.globalData.userInfo

// 调用方法
app.setOcrCard({name:'zhangsan'})

Store

在vue3或者vue2开发当中我们会使用pinia或者vuex,他的基本概念就是创建一个全局的Store管理数据。那么在小程序开发当中有没有这种框架捏。这个时候就要看 mobx-miniprogrammobx-miniprogram-bindings

js 复制代码
import { observable, action } from 'mobx-miniprogram'
// 使用 observable 创建一个被监测的对象
export const numStore = observable({
  // 创建应用状态
  numA: 1,
  numB: 2,
    
  // 使用 action 更新 numA 以及 numB
  update: action(function () {
    this.numA+=1
    this.numB+=1
  }),
 
  // 计算属性,使用 get 修饰符,
  get sum() {
    return this.numA + this.numB;
  }
})

使用定义好的numStore的数据

js 复制代码
// components/custom01/custom01.js
import { ComponentWithStore } from 'mobx-miniprogram-bindings'
import { numStore } from '../../stores/numstore'
 
ComponentWithStore({
  data: {
    
  },
  storeBindings: {
    store: numStore,
    fields: ['numA', 'numB', 'sum'],
    actions: ['update']
  }
})

数据监听&计算属性

小程序当中没有计算属性和监听的功能,如果想用的话可以使用miniprogram-computed

js 复制代码
import { ComponentWithComputed } from "miniprogram-computed";

ComponentWithComputed({
  data: {
    a: 1,
    b: 1,
  },

  computed: {
    total(data) {
      return data.a + data.b;
    },
  },

  watch: {
    a: function (a) {
      console.log(a);
    },
    // 同时对 a 和 b 进行监听
    "a, b": function (a, b) {
      this.setData({
        total: a + b,
      });
    },
  },
});

vue mini

在2024 vue conf上有对这个vue mini进行了介绍,文档地址在这。正好最近在做微信小程序就做了一些了解

  • 基于vue3,可以使用vue3当中的响应式
  • 组合式API

个人观点:后续还是要看对SFC的支持怎么样吧,现在只是把js层可以用这一层,wxml这一层还是要写原生的。不过也不妨是一个方案吧。

js 复制代码
import { ComponentWithStore } from 'mobx-miniprogram-bindings'
import { numStore } from '../../stores/numstore'
 
ComponentWithStore({
  data: {
    
  },
  storeBindings: {
    store: numStore,
    fields: ['numA', 'numB', 'sum'],
    actions: ['update']
  }
})

数据监听&计算属性

小程序当中没有计算属性和监听的功能,如果想用的话可以使用miniprogram-computed

js 复制代码
import { ComponentWithComputed } from "miniprogram-computed";

ComponentWithComputed({
  data: {
    a: 1,
    b: 1,
  },

  computed: {
    total(data) {
      return data.a + data.b;
    },
  },

  watch: {
    a: function (a) {
      console.log(a);
    },
    // 同时对 a 和 b 进行监听
    "a, b": function (a, b) {
      this.setData({
        total: a + b,
      });
    },
  },
});

vue mini

在2024 vue conf上有对这个vue mini进行了介绍,文档地址在这。正好最近在做微信小程序就做了一些了解

  • 基于vue3,可以使用vue3当中的响应式
  • 组合式API

个人观点:后续还是要看对SFC的支持怎么样吧,现在只是把js层可以用这一层,wxml这一层还是要写原生的。不过也不妨是一个方案吧。

相关推荐
丁总学Java6 分钟前
微信小程序,点击bindtap事件后,没有跳转到详情页,有可能是app.json中没有正确配置页面路径
微信小程序·小程序·json
OCR_wintone42111 分钟前
易泊车牌识别相机,助力智慧工地建设
人工智能·数码相机·ocr
说私域1 小时前
基于开源 AI 智能名片、S2B2C 商城小程序的用户获取成本优化分析
人工智能·小程序
mosen8681 小时前
Uniapp去除顶部导航栏-小程序、H5、APP适用
vue.js·微信小程序·小程序·uni-app·uniapp
qq22951165022 小时前
微信小程序的汽车维修预约管理系统
微信小程序·小程序·汽车
尚梦9 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
小飞哥liac12 小时前
微信小程序的组件
微信小程序
stormjun13 小时前
Java基于微信小程序的私家车位共享系统(附源码,文档)
java·微信小程序·共享停车位·私家车共享停车位小程序·停车位共享
paopaokaka_luck14 小时前
基于Spring Boot+Vue的助农销售平台(协同过滤算法、限流算法、支付宝沙盒支付、实时聊天、图形化分析)
java·spring boot·小程序·毕业设计·mybatis·1024程序员节
Bessie23416 小时前
微信小程序eval无法使用的替代方案
微信小程序·小程序·uni-app