小程序 Taro - EricYangXD/LearnReact GitHub Wiki

小程序 Taro

小程序的官方开发文档日新月异,要想不踩坑则必须时刻关注官方文档!!!

小程序登录流程

  • 参考这篇文章

  • 简单来说就是:1.先wx.login()拿到code,2.把code传给后端,后端拿到code后跟微信服务器通信,获得用户的openid和sessionkey等信息,3.再进行自定义登录流程即可。

  • 每个用户的openid是固定。后端跟微信服务器通信时也需要这个小程序的appkey、appsecret等信息,这是固定的不会变化。

获取用户设置然后获取授权拿到用户信息

    Taro.getSetting({
      success(res) {
        if (!res.authSetting['scope.userInfo']) {
          Taro.authorize({
            scope: 'scope.userInfo',
            success() {
              console.log('getSetting', res);
            },
          });
        } else {
          // 必须是在用户已经授权的情况下调用
          Taro.getUserInfo({
            success(result) {
              console.log('getUserInfo', result);
              const userInfo = result.userInfo;
              setUserInfo({ ...userInfo });
              Taro.navigateTo({ url: '/pages/index/index' });
            },
          });
        }
      },
      fail(err) {
        Taro.showToast({
          title: `获取用户信息失败,请授权 ${err}`,
          icon: 'none',
          duration: 2000,
        });
      },
    });

获取写入图片权限

    Taro.getSetting({
      success(res) {
        if (!res.authSetting['scope.writePhotosAlbum']) {
          Taro.authorize({
            scope: 'scope.writePhotosAlbum',
            success() {
              console.log('writePhotosAlbum', res);
            },
          });
        } else {
          // 必须是在用户已经授权的情况下调用
          // TODO save picture
          save2album();
        }
      },
      fail(err) {
        Taro.showToast({
          title: `获取用户信息失败,请授权 ${err}`,
          icon: 'none',
          duration: 2000,
        });
      },
    });

绘制Canvas

  • 使用Painter
<Painter
  palette={palette}
  onImgOK={onImgOK}
  onImgErr={onImgErr}
  customStyle="position:fixed; left:-9999rpx;"
  />

  /**
   * 保存图片到本地相册
   */
  const save2album = () => {
    if (filePath !== '') {
      Taro.saveImageToPhotosAlbum({
        filePath,
        success(res) {
          Taro.showModal({
            title: '图片保存成功',
            content: '图片成功保存到相册了,快去发朋友圈吧~',
            showCancel: false,
            confirmText: '确认',
          });
        },
        fail(err) {
          Taro.showModal({
            title: '图片保存失败',
            content: '请重新尝试!',
            showCancel: false,
            confirmText: '确认',
          });
        },
      });
    } else {
      Taro.showToast({
        title: '获取图片地址失败',
        duration: 2000,
      });
    }
  };
  /**
   * Painter绘制canvas成功后的回调
   */
  const onImgOK = (e) => {
    setFilePath(e.path);
  };
  /**
   * Painter绘制canvas失败后的回调
   */
  const onImgErr = (e) => {
    Taro.showToast({
      title: '生成图片失败',
      duration: 2000,
    });
  };

Taro 保存图片

  const saveCard = async () => {
    // 将Canvas图片内容导出指定大小的图片
    const res = await Taro.canvasToTempFilePath({
      x: 0,
      y: 0,
      width: 750,
      height: 1980,
      destWidth: 750,
      destHeight: 1980,
      canvasId: 'cardCanvas',
      fileType: 'png',
    });

    const saveRes = await Taro.saveImageToPhotosAlbum({
      filePath: res.tempFilePath,
    });

    if (saveRes.errMsg === 'saveImageToPhotosAlbum:ok') {
      Taro.showModal({
        title: '图片保存成功',
        content: '图片成功保存到相册了,快去发朋友圈吧~',
        showCancel: false,
        confirmText: '确认',
      });
    } else {
      Taro.showModal({
        title: '图片保存失败',
        content: '请重新尝试!',
        showCancel: false,
        confirmText: '确认',
      });
    }
  };

SCSS/SASS/Less/Stylus/CSS互相转换

网站

  • eg.
bg-image($url)
  background-image: url($url + '@2x.png')
  @media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio: 3)
    background-image: url($url + '@3x.png')
@mixin bg-image($url) {
  background-image: url($url + '@2x.png');
  @media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio: 3) {
    background-image: url($url + '@3x.png');
  }
}

字体转换工具

  • 字体库转base64

Here

iPhone X+ 机型适配

  • 文章

  • 最简单的方案即使用Apple官方推出的css函数env()、constant()来适配,对于底部空白的部分可以自行加个view。

    /*兼容 IOS<11.2*/
    padding-bottom: calc(108px + constant(safe-area-inset-bottom));
    /*兼容 IOS>11.2*/
    padding-bottom: calc(108px + env(safe-area-inset-bottom));
  • 配合js判断机型
import Taro from '@tarojs/taro';

// iphone X
const IPHONE_X = /iphone x/i;
// >= iPhone11
const IPHONE_X_11 = /iphone 1\d/i;
// 未适配机型-新机型
const IPHONE_UNKNOWN = /unknown\(iphone\)/i;

// 方法一:使用model判断是否是IPhoneX及其他包含安全区域的机型手机
export const isIpx = () => {
  const model = Taro.getSystemInfoSync().model;
  return (
    model.search(IPHONE_X) > -1 ||
    model.search(IPHONE_X_11) > -1 ||
    model.search(IPHONE_UNKNOWN) > -1
  );
};

按需注入

  • 降低小程序的启动时间和运行时内存
{
  "lazyCodeLoading": "requiredComponents"
}

全局注册组件

{
  usingComponents:{
    'keyboard':'components/../index',
  }
}

分享对话、朋友圈

  useShareAppMessage(() => {
    return {
      title: '啦啦啦啦',
imageUrl:'https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eraEeftaBoduGGBHx3noVp5XQ8aYKwWAN74LqWR26mMhD8rTdXbGDxf3LpdYhO0BVtMZhHsg2VIBA/132',
      path: `/pages/index`,
    };
  });

  useShareTimeline(() => {
    return {
      title: '啦啦啦啦',
imageUrl:'https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eraEeftaBoduGGBHx3noVp5XQ8aYKwWAN74LqWR26mMhD8rTdXbGDxf3LpdYhO0BVtMZhHsg2VIBA/132',
    };
  });

Taro3.x 版本中接入Painter,实现图片导出功能

目前我在 Taro3.x+React+TypeScript 项目中通过如下方式可以使用,应该有更好的方法,该方法只是应急:

  1. 通过submodule把核心模块引入到项目中
git submodule add https://github.com/Kujiale-Mobile/PainterCore.git components/drawer
  1. 在app.config.ts中全局注册Painter
  usingComponents: {
    'my-painter': 'components/drawer/painter',
  }
  1. 之后在.tsx文件中直接可以使用
   <my-painter
      palette={palette}
      onImgOK={onImgOK}
      onImgErr={onImgErr}
      customStyle={painterStyle}
      use2D
   />
  1. 观察编译后的小程序原生代码长这样:
<my-painter is="components/drawer/painter" bind:img-err="eh"  bind:img-ok="eh" id="_n_256" >
...
</my-painter>

而components/drawer/painter里getImageInfo(filePath)函数触发的是imgOK,如下:

that.triggerEvent('imgOK', {
    path: filePath,
});

尝试把 "imgOK" 替换为 "img-ok",可以正常触发回调 "onImgOK",所以在回调 "onImgOK"里通过e.detail.path获取到生成的canvas图片地址filePath,然后按照正常步骤保存图片即可。

// .tsx中的回调
const onImgOK = (e) => {
    console.log('onImgOK', e);
    setFilePath(e.detail.path);
};
  1. 对于customStyle,一般不需要显示这个canvas,所以设置为:const painterStyle = 'position:fixed; left:-9999rpx;';

  2. 剩下的就是把palette写出来。

如何配置项目,避免开发环境appid和生产环境appid管理使用混乱

Taro官方貌似没有配置的教程,所以要么是手动改,要么也可以参考如下方案:

  1. 我们知道Taro对环境的配置文件放在config/目录下,因此我们在config下(其他地方也可以)新建一个updateConfig.js文件

  2. 利用nodejs的fs模块对文件进行读写。updateConfig.js代码如下:


/**
 * 根据环境更新../project.config.json中的appid字段
 * @env NODE_ENV=development 将config/dev.js中的appid配置设置到../project.config.json中
 * @env NODE_ENV=production 将config/prod.js中的appid配置设置到../project.config.json中
 */

const fs = require('fs');
const path = require('path');
const DEV_CONFIG = require('./dev');
const PROD_CONFIG = require('./prod');

const { readFileSync, writeFileSync } = fs;

function updateProjectConfig(filePath) {
  const fileOption = { encoding: 'utf-8' };
  const fileContent = readFileSync(filePath, fileOption);
  const config = JSON.parse(fileContent.toString());
  if (process.env.NODE_ENV === 'production') {
    config.appid = PROD_CONFIG.appid;
    console.log(`[PROD] appId = ${config.appid}`);
  } else {
    config.appid = DEV_CONFIG.appid;
    console.log(`[DEV] appId = ${config.appid}`);
  }
  const newConfig = JSON.stringify(config, null, 2);
  writeFileSync(filePath, newConfig, fileOption);
}

updateProjectConfig(path.join(__dirname, '../project.config.json'));

  1. 把开发和生产的appid分别配置到config/dev.js和config/prod.js中;

  2. 然后再package.json中配置一下启动命令即可。例:

"scripts": {
    "start": "npm run dev:weapp",
    "build": "npm run build:weapp",
    "build:weapp": "taro build --type weapp",
    "dev:weapp": "npm run precond-weapp:dev && npm run build -- --watch",
    "precond-weapp:dev": "cross-env NODE_ENV=development node ./config/updateProjectConfig.js",
    "precond-weapp:prod": "cross-env NODE_ENV=production node ./config/updateProjectConfig.js",
    "build:dev": "npm run precond-weapp:dev && npm run build",
    "build:prod": "npm run precond-weapp:prod && npm run build"
},
  • 这样运行npm start即可在开发模式下进行开发,如果要在真机预览,则新建一个有NODE_ENV=production的命令,打包的时候压缩一下体积即可。
  • 对于生产的包,运行npm run build:prod即可得到。
  • --watch开启热更新。

页面跳转之前进行「简单提示」的做法

// useEffect(() => { // Taro.eventCenter.once(getCurrentInstance()?.router?.onHide, () => { // console.log('onHide'); // }); // Taro.eventCenter.on('beforegoback', () => { // console.log('beforegoback'); // }); // Taro.disableAlertBeforeUnload() // Taro.enableAlertBeforeUnload({ // message: '询问对话框内容询问对话框内容询问对话框内容询问对话框内容', // success(res) { // console.log(res); // Taro.navigateBack({ delta: 1 }); // }, // fail(e) { // console.log(e); // }, // }); // }, []);

Hooks in Taro

  • 常用的除了React中的hooks,还有taro封装的:useRouter,useReady,useDidShow,useDidHide,useShareAppMessage等等

  • 文档链接