后端工程师如何快速入门小程序开发

375 阅读6分钟

背景

你好。欢迎阅读我的文章。

我是一名后端工程师,自己会一点前端

通过本文我将带你快速上手小程序开发,并且通过一个实际的场景带你入门前端开发思维。

趁着公司的一次研发需求快速入门小程序开发。并且由于所选择的技术框架Taro并没有提供对应的二维码生成插件,我就自己动手撸了一个组件:taroqrcode.vue3

现在我又启动了我第二个开源组件之路:taro-echarts-vue3(项目刚启动,欢迎各位同学和我一起贡献这个项目,等这个项目完成以后我们将启动第三个开源项目——适配小程序的高性能表格组件)

接下来进入正题……

手册不离手,是一种好习惯。

小程序基础

developers.weixin.qq.com/miniprogram…

小程序诞生自vue 2.x框架之后大量的借鉴了MVVM框架的设计风格,其底层用的还是WebView内核,简单粗暴的理解就还是网页技术。只不过做了部分优化(如对dom对象操作改为异步)但是还是换汤不换药。

你接下来需要做的是能看懂原生小程序源码,这就要求你大致读一下官方文档,了解工程结构、交互方式、架构设计即可。遇到问题可以快速找文档、github解决问题即可。

实际上线路看板小程序我就是这么做出来的,完成这个工作以后你会逐渐上手小程序开发,了解小程序的能力边界。这时候你需要读一些更加深入的文档和源码,下面是我的个人推荐:

如何使用框架快速产出

假设你已经有了不错的vue基础,那么我们首先要做的就是用vue开发小程序而不是直接学原生小程序开发(这个成本太高了)。

Taro框架是JD研发的开源多端开发框架,支持一套代码写各种小程序(对安卓和iOS支持不太友好),顺手还附赠了多套UI框架。Taro框架支持vue和React,简直让人欲罢不能。

  1. 用脚手架搭建基础框架(我选择的是Taro+NutUI+vue3+Sass)

  2. 了解webpack,知道基本概念,能上手配置

  3. 试着用Taro调用小程序原生接口(线路看板用到了获取手机号)

  4. 在H5模式下完成你绝大多数的UI工作

  5. 对于冲突的样式查找它的css选择器覆盖掉

  6. 在小程序开发工具中调试原生接口和css

  7. 发布上线

本次开发遇到的问题,以及我是用什么思路解决的

Taro框架中到底应该使用html标签还是小程序标签?

查官方文档,github搜代码看看别人是怎么写的,对比编译前后的差异反推taro做了什么

taro-docs.jd.com/docs/use-h5

Taro中怎么调用微信小程序原生api?比如怎么获取手机号

先看小程序官方文档,知道原生怎么写。然后查Taro文档,再百度(ChatGPT更好)找样例代码,改吧改吧调试。

developers.weixin.qq.com/miniprogram…

taro-docs.jd.com/docs/hybrid

编译失败了,怎么解决?

  • 问圈儿内的朋友(没什么用)

  • 把关键词放到ChatGPT分析根因

  • 把关键词放到github issue

UI框架样式冲突?

用调试工具找css选择器,覆盖掉

Sass样式文件不生效?

  • 问圈儿内的朋友

  • 故意写个错误语法看看文件是否生效(缩小问题范围)

  • 分析出一个初步结果以后把关键词放到百度

SASS快速入门

先把文档刷一遍,走马观花的看就行:www.sass.hk/guide/

你不需要完全按照官网的步骤去配置Sass-loader(sass-loader是一个编译器,将sass编译成css),脚手架自带了,直接上手写代码即可

taroqrcode.vue3是如何诞生的?

会抄代码,是一种技巧。

首先来说我需要qrcode的能力,我在Taro市场找了只有React的插件,甚至github也没有合适的组件供我开箱即用。

我就去npm上找h5和vue3可以用的包。

我注意到了它:www.npmjs.com/package/qrc…

好的,先把它引入工程

yarn add  qrcode.vue 

import { createApp } from 'vue'
import QrcodeVue from 'qrcode.vue'
createApp({
    data: {value: 'https://example.com',},
    template: '<qrcode-vue :value="value"></qrcode-vue>',
    components: {
        QrcodeVue,},
     }
).mount('#root')

当我把它引入到小程序工程时,在h5模式下很顺利的运行了起来。在小程序模式下很不幸的报错了:

const ctx = canvas.getContext('2d') //这行报错,空指针

我意识到是小程序dom api和bom api和浏览器不一致的问题: blog.csdn.net/ziyue13/art…

我们首先要做的是可以调试这个包,要在这行代码之上添加一个debugger指令:

  1. 移除npm 包管理的形式的依赖

    yarn remove qrcode.vue

  2. 通过源码形式引入整个包(其实就两个文件)

P.S. 好家伙,qrcode.vue源码写的真漂亮,想学习vue的渲染机制一定要看这个源码

  1. 插入debugger指令,并在控制台查看canvas对象。(果然不出所料,是null)

到目前为止,是什么、为什么都解决了。那么,怎么做?抄!抄谁?

我想到了NutUI的sinnature组件: nutui.jd.com/taro/vue/4x…

它一定是通过canvas实现的,一查源码果然:github.com/jdf2e/nutui…

好家伙,代码写的真垃圾(没办法微信小程序给的api只能这么操作)。

总结:

  1. canvas的dom对象通过vue的ref机制获取到的是对象,在h5模式下是dom对象,在小程序模式下是TaroElement。如果想获取dom对象,必须通过异步的方式,且必须延迟1s获取,否则获取到的对象是空对象。demo:

    onMounted(() => {
    setTimeout(() => {
    Taro.createSelectorQuery()
    .select('#' + state.id)
    .fields({
    node: true,
    size: true
    })
    .exec((res) => {
    let canvas = res[0].node;
    });
    },1000); });

  2. Path2D对象在小程序下只能通过canvas.createPath2D 创建,而不是new Path2D()

第二次问题爆发:真机测试不出二维码

等到我们开发完毕,真机回测的时候发现无论如何真机二维码不显示。而且真机模拟在控制台也没有任何报错。

这一定是微信小程序内核和标准webkit内核API不一致导致的。经过大量翻阅小程序开发文档、taro开发文档最终定位问题在于:标准webkit内核支持在new Path2D时通过SVG Path作为构造函数入参完成,而微信小程序在创建new Path2D对象时只能通过canvas.createPath2D来造作。具体API差异请查阅文档:

二维码本质上是一个二维矩阵,里面都是0和1。当为0是在canvas上打下一个白点(就是什么也不做)当为1时在当前位置打下一个黑点。

通过查API文档,我注意到path2d对象有这样一个方法可以满足我的需要:developers.weixin.qq.com/miniprogram…

那么接下来我只需要写个双层foreach,逐个打下我的矩阵即可。

改造前的代码如下:

function createPath2D(canvas: HTMLCanvasElement, cells: any): Path2D {
    if (isH5) {
        return new Path2D(generatePath(cells, props.margin));
    } else {
        return canvas.createPath2D(generatePath(cells, props.margin));
    }
}

改造后的代码如下:

function createPath2D(canvas: HTMLCanvasElement | any, cells: any): Path2D {
    if (isH5) {
        return new Path2D(generatePath(cells, props.margin));
    } else {
        const path2d = canvas.createPath2D();
        cells.forEach((row, y) => {
            row.forEach((cell, x) => {
                if (cell) {
                    path2d.rect(x, y, 1, 1)
                }
            });
        });
        return path2d;
    }
}