Taro3.x 快速开发微信小程序以及 minidebug 小程序调试工具使用

简介: Taro3.x 快速开发微信小程序以及 minidebug 小程序调试工具使用

前言

最近公司准备开发一款扫码开票类型的微信小程序,时间紧,任务急。第一反应就是打开小程序开放平台查看开发文档,哦豁,官方的组件也太少了吧,难道要自己手写吗 ?经过多方调研,了解目前市面上比较流行的小程序开发框架有 UniappTaro 。因为目前公司技术栈完全使用的 react hooks + ts 开发,所以在框架选择上自然就选择了 Taro 。

Taro 简介image.pngTaro 是一个开放式跨端跨框架解决方案,支持使用 React/Vue/Nerv 等框架来开发 微信 / 京东 / 百度 / 支付宝 / 字节跳动 / QQ 小程序 / H5 / RN 等应用。现如今市面上端的形态多种多样,Web、React Native、微信小程序等各种端大行其道。当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。

安装及使用

Taro 项目基于 node,请确保已具备较新的 node 环境(>=12.0.0),推荐使用 node 版本管理工具 nvm 来管理 node,这样不仅可以很方便地切换 node 版本,而且全局安装时候也不用加 sudo 了。

CLI 工具安装


首先,你需要使用 npm 或者 yarn 全局安装 @tarojs/cli,或者直接使用 npx:

# 使用 npm 安装 CLI
npm install -g @tarojs/cli
# OR 使用 yarn 安装 CLI
yarn global add @tarojs/cli
# OR 安装了 cnpm,使用 cnpm 安装 CLI
cnpm install -g @tarojs/cli

npm 5.2+ 也可在不全局安装的情况下使用 npx 创建模板项目:

npx @tarojs/cli init taro_init_template

这里为了方便快捷,建议直接使用 npx 创建模板项目哈

image.png

运行&启动项目

# yarn
 yarn dev:weapp
 yarn build:weapp
# npm script
 npm run dev:weapp
 npm run build:weapp
# 仅限全局安装
 taro build --type weapp --watch
 taro build --type weapp
# npx 用户也可以使用
 npx taro build --type weapp --watch
 npx taro build --type weapp
# watch 同时开启压缩
$ set NODE_ENV=production && taro build --type weapp --watch # Windows
$ NODE_ENV=production taro build --type weapp --watch # Mac

以上是微信小程序的编译命令,其它小程序编译可以查看项目文件夹下的 package.json 文件夹

image.png运行小程序,你会发现在项目目录下多出了一个 dist 文件夹,打开微信开发者工具,用自己微信号登录,点击小程序界面的 image.png+ ,导入项目,项目名称自己定义,目录选择刚刚创建模板项目下的 diimage.pngst 文件夹,AppIimage.pngd 可以暂时使用测试号哦,后期可以自己注册一个用于开发使用。image.pngimage.png[sitemap 索引情况提示] 根据 sitemap 的规则[0],当前页面 [pages/index/index] 将被索引

遇到上述警告,可以设置 project.config.json => setting => checkSiteMap


{
 "miniprogramRoot": "dist/",
 "projectname": "taro_template",
 "description": "taro_template",
 "appid": "touristappid",
 "setting": {
  "urlCheck": true,
  "es6": false,
  "postcss": false,
  "preloadBackgroundData": false,
  "minified": false,
  "newFeature": true,
  "autoAudits": false,
  "coverView": true,
  "showShadowRootInWxmlPanel": false,
  "scopeDataCheck": false,
  "useCompilerModule": false,
    // 这里添加哦
  "checkSiteMap":false
 },
 "compileType": "miniprogram",
 "simulatorType": "wechat",
 "simulatorPluginLibVersion": {},
 "condition": {}
}

快速创建新页面 & 增加 TabBar

Taro create --name [页面名称] 能够在当前项目的pages目录下快速生成新的页面文件,并填充基础代码,是一个提高开发效率的利器。新增页面并且配置 app.config.ts

app.config.ts 完整配置

export default {
  pages: [
    "pages/index/index",
    "pages/setting/setting",
    // "pages/login/login"
  ],
  subpackages: [
    {
      root: "pages/login/",
      pages: [
        "login"
      ]
    }
  ],
  window: {
    backgroundTextStyle: "light",
    navigationBarBackgroundColor: "#fff",
    navigationBarTitleText: "WeChat",
    navigationBarTextStyle: "black"
  },
  tabBar: {
    list: [
      {
        pagePath: "pages/index/index",
        text: "首页",
        iconPath: "assets/images/tab_index.png",
        selectedIconPath: "assets/images/tab_index_active.png"
      },
      {
        pagePath: "pages/setting/setting",
        text: "个人中心",
        iconPath: "assets/images/tab_setting.png",
        selectedIconPath: "assets/images/tab_setting_active.png"
      }
    ],
    color: "#BFBFBF",
    selectedColor: "#1296DB",
    backgroundColor: "#fff",
    borderStyle: "white"
  }
};

细心的同学可能会发现,app.config.ts 文件中增加了 subpackages 配置,下面来详细讲下这个配置的作用

subpackages 分包

在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。

目前小程序分包大小有以下限制:

  • 整个小程序所有分包大小不超过 20M
  • 单个分包/主包大小不能超过 2M

注意:作为 tabbar 页面不能使用分包,可以使用分包的页面添加到 subpackages,且在 pages 中移除

路由

Taro.switchTab(option)

跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面

Taro.reLaunch(option)

关闭所有页面,打开到应用内的某个页面

Taro.redirectTo(option)

关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。

Taro.navigateTo(option)

保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 Taro.navigateBack 可以返回到原页面。小程序中页面栈最多十层。

Taro.navigateBack(option)

关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。

路由不做过多介绍,详细使用方法请参考官方文档。

请求封装 Taro.request

定义统一状态
export const HTTP_STATUS = {
    SUCCESS: 200,
    CREATED: 201,
    ACCEPTED: 202,
    CLIENT_ERROR: 400,
    AUTHENTICATE: 301,
    FORBIDDEN: 403,
    NOT_FOUND: 404,
    SERVER_ERROR: 500,
    BAD_GATEWAY: 502,
    SERVICE_UNAVAILABLE: 503,
    GATEWAY_TIMEOUT: 504
  }
  export const REFRESH_STATUS = {
    NORMAL: 0,
    REFRESHING: 1,
    NO_MORE_DATA: 2
  }
定义错误统一输出方法
import { formatTime } from "../utils/common"
/**
 *
 * @param {string} name 错误名字
 * @param {string} action 错误动作描述
 * @param {string} info 错误信息,通常是 fail 返回的
 */
// eslint-disable-next-line
export const logError = (name: string, action: string, info?: string | object ) => {
  if (!info) {
    info = 'empty'
  }
  let time = formatTime(new Date())
  console.error(time, name, action, info)
  if (typeof info === 'object') {
    info = JSON.stringify(info)
  }
}
定义 request.ts
import Taro from '@tarojs/taro'
import { HTTP_STATUS } from './status'
import { logError } from './error'
import { baseUrl } from './baseUrl'
import { checkLogin } from "./auth"
export default {
  baseOptions(params, method = 'GET') {
    let { url, data } = params
    let contentType = 'application/json'
    contentType = params.contentType || contentType
    type OptionType = {
      url: string,
      data?: object | string,
      method?: any,
      header: object,
      // mode: string,
      success: any,
      error: any,
      xhrFields: object,
    }
    const setCookie = (res: {
      cookies: Array<{
        name: string,
        value: string,
        expires: string,
        path: string
      }>,
      header: {
        'Set-Cookie': string
      }
    }) => {
      if (res.cookies && res.cookies.length > 0) {
        let cookies = Taro.getStorageSync('cookies') || '';
        res.cookies.forEach((cookie, index) => {
          // windows的微信开发者工具返回的是cookie格式是有name和value的,在mac上是只是字符串的
          if (cookie.name && cookie.value) {
            cookies += index === res.cookies.length - 1 ? `${cookie.name}=${cookie.value};expires=${cookie.expires};path=${cookie.path}` : `${cookie.name}=${cookie.value};`
          } else {
            cookies += `${cookie};`
          }
        });
        Taro.setStorageSync('cookies', cookies)
      }
      // if (res.header && res.header['Set-Cookie']) {
      //   Taro.setStorageSync('cookies', res.header['Set-Cookie'])
      // }
    }
    const option: OptionType = {
      url: url.indexOf('http') !== -1 ? url : baseUrl + url,
      data: data,
      method: method,
      header: {
        'content-type': contentType,
        // 增加请求头
        cookie: Taro.getStorageSync('cookies')
      },
      // mode: 'cors',
      xhrFields: { withCredentials: true },
      success(res) {
        console.log('res', res)
        setCookie(res)
        if (res.statusCode === HTTP_STATUS.NOT_FOUND) {
          return logError('api', '请求资源不存在')
        } else if (res.statusCode === HTTP_STATUS.BAD_GATEWAY) {
          return logError('api', '服务端出现了问题')
        } else if (res.statusCode === HTTP_STATUS.FORBIDDEN) {
          return logError('api', '没有权限访问')
        } else if (res.statusCode === HTTP_STATUS.AUTHENTICATE) {
          Taro.clearStorage()
          //跳转到登录页面
          checkLogin()
          return logError('api', '请先登录')
        } else if (res.statusCode === HTTP_STATUS.SUCCESS) {
          return res.data
        }
      },
      error(e) {
        logError('api', '请求接口出现问题', e)
      }
    }
    // eslint-disable-next-line
    return Taro.request(option)
  },
  get(url, data?: object) {
    let option = { url, data }
    return this.baseOptions(option)
  },
  post: function (url, data?: object, contentType?: string) {
    let params = { url, data, contentType }
    return this.baseOptions(params, 'POST')
  },
  put(url, data?: object) {
    let option = { url, data }
    return this.baseOptions(option, 'PUT')
  },
  delete(url, data?: object) {
    let option = { url, data }
    return this.baseOptions(option, 'DELETE')
  }
}
定义 baseUrl.ts
export const baseUrl = 'http://172.36.0.26:3000'
定义 api.ts
import request from "./request"
export const getDetail = (params):Promise<any>=>{
    return request.get('/url', params)
}
组件中使用
const getDetail = ()=>{
    api.getDetail({
      data: 1232
    }).then((res)=>{
      console.log(res)
    })
  }

Dva 集成使用

react 状态状态管理库:Redux,Dva,Mobx ... 本次搭建采用 Dva 来搭建,终于为什么选用 Dva ,完全就是为了尝鲜,因为以前项目中一直使用的 redux,redux 的繁琐想必大家也是知道的。大家也可以去尝试下使用 Mobx 。Mobx 可以称得上是这几个库中最简洁的库了。

当然了,hooks 中的 useContext() 也是组件之间共享状态的一种方案。

安装
npm install --save dva-core dva-loading
npm install --save redux react-redux redux-thunk redux-logger

新增 src/utils/dva.ts

// src/utils/dva.ts
import {create } from 'dva-core';
// import {createLogger } from 'redux-logger';
import createLoading from 'dva-loading';
let app: {use: (arg0: any) => void; model: (arg0: any) => any; start: () => void; _store: any; getStore: () => any; dispatch: any};
let store: {dispatch: any};
let dispatch: any;
let registered: boolean;
function createApp(opt: {models: any[]; initialState: any }) {
  // redux日志, 引用redux-logger
  // opt.onAction = [createLogger()];
  app = create(opt);
  app.use(createLoading({}));
  if (!registered) opt.models.forEach((model: any) => app.model(model));
  registered = true;
  app.start();
  store = app._store;
  app.getStore = () => store;
  dispatch = store.dispatch;
  app.dispatch = dispatch;
  return app;
}
export default {
  createApp,
  getDispatch() {
    return app.dispatch;
  },
  getStore() { // 这个是在非组件的文件中获取Store的方法, 不需要可以不暴露
    return app.getStore();
  },
};
新增 models 文件夹

models 下专门用来统一管理自己的数据

models/index.ts

import { GlobalModelState } from "./setting/types"
import setting from "./setting/index"
const models:Array<GlobalModelState> = [
    setting
]
export default models

models/setting/index.ts

import * as types from "./types";
const setting: types.GlobalModelState = {
  namespace: "setting",
  state: {
    userInfo: {}
  },
  // 修改 state 中的数据
  reducers: {
    setUserInfo(state, { data }) {
      console.log(data);
      return {
        ...state,
        userInfo: data.userInfo
      };
    }
  }
  // 异步操作后修改 state 中的数据
  // effects: {
  //   *changeName({ payload }, { put, call }) {
  //     // call 触发异步
  //     // let data = yield call("/api", payload);
  //     // put 触发 action
  //     yield put({
  //       type: "saveName",
  //       data: {
  //         name: "异步修改的",
  //       },
  //     });
  //     yield console.log("run");
  //   },
  // },
};
export default setting;
入口集成

将入口文件 app.ts 修改成 app.tsx,引入 Provider、dva、models。

import { Component, useEffect } from "react";
import { View, Text } from "@tarojs/components";
import "./app.scss";
// 此处必须使用 react-redux 否则报错
import { Provider } from "react-redux";
import dva from "./utils/dva";
import models from "./models";
// 集成 dva
const dvaApp = dva.createApp({
  initialState: {},
  models,
  enableLog: false
});
const store = dvaApp.getStore();
const App: React.FC = ({ children }): JSX.Element => {
  return <Provider store={store}>{children}</Provider>;
};
export default App;

获取 store 中的数据 (useSelector)

const userInfo = useSelector(state => state.setting.userInfo).nickName

修改 store 中的数据 (useDispatch)

dispatch({
    type:"setting/setUserInfo",
    data:{
      userInfo
    }
  })

页面适配问题

Taro 默认按照designWidth:750的尺寸来进行自动转换,如果 UI 给的设计稿是 375 的宽度,可以修改 config => **index.js **

designWidth: 750,
  deviceRatio: {
    640: 2.34 / 2,
    750: 1,
    828: 1.81 / 2,
    375: 2
  },

当然了,只是修改上面部分还远远不够,这个时候运行项目,你会发现 taro-ui 组件样式变得好大,what ?组件被放大了两倍 ?不要慌,按照如下配置即可

yarn add postcss-px-scale
const config = {
  projectName: "taro_template",
  date: "2021-6-23",
  designWidth: 750,
  deviceRatio: {
    640: 2.34 / 2,
    750: 1,
    828: 1.81 / 2,
    375: 2
  },
  sourceRoot: "src",
  outputRoot: "dist",
  plugins: [],
  defineConstants: {},
  copy: {
    patterns: [],
    options: {}
  },
  framework: "react",
  mini: {
    postcss: {
      pxtransform: {
        enable: true,
        config: {}
      },
      url: {
        enable: true,
        config: {
          limit: 1024 // 设定转换尺寸上限
        }
      },
      cssModules: {
        enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
        config: {
          namingPattern: "module", // 转换模式,取值为 global/module
          generateScopedName: "[name]__[local]___[hash:base64:5]"
        }
      },
      // 这里增加配置
      "postcss-px-scale": {
        enable: true,
        config: { scale: 0.5, units: "rpx", includes: ["taro-ui"] }
      },
    },
  },
  h5: {
    publicPath: "/",
    staticDirectory: "static",
    esnextModules:['taro-ui'],
    postcss: {
      autoprefixer: {
        enable: true,
        config: {}
      },
      cssModules: {
        enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
        config: {
          namingPattern: "module", // 转换模式,取值为 global/module
          generateScopedName: "[name]__[local]___[hash:base64:5]"
        }
      },
      // 这里增加配置
      "postcss-px-scale": {
        enable: true,
        config: { scale: 0.5, units: "rem", includes: ["taro-ui"] }
      },
    },
  }
};
module.exports = function(merge) {
  if (process.env.NODE_ENV === "development") {
    return merge({}, config, require("./dev"));
  }
  return merge({}, config, require("./prod"));
};

扫二维码功能

扫码功能就很简单了,可以直接调用官方提供的方法

Taro.scanCode({
    success: result => {
      console.log("扫码成功的回调", result);
    }
  });

更多用法自己查看官方文档吧,这里就不做一一介绍了。

调试技巧 - minidebugimage.png

功能介绍

主要功能包括环境切换、身份Mock、应用信息获取、位置模拟、缓存管理、扫一扫、H5跳转、更新版本等。

安装
yarn add @jdlfe/minidebug-next
新建空页面 debug

活学活用,使用 cli 快速创建页面

Taro create -- debug

引入组件 Debug

import { View } from '@tarojs/components'
import { Debug } from '@jdlfe/minidebug-next'
import './debug.scss'
const Bug: React.FC = () => {
  return (
    <View>
      <Debug />
    </View>
  );
};
export default Bug;

增加页面配置入口,用于打开页面,页面最好配置到 subpackages 中,不然会造成主包比较大。image.pngimage.png更多用法参考 https://github.com/jdlfe/minidebug

源码地址

https://github.com/xushanpei/taro_init_template



相关文章
|
4月前
|
小程序 前端开发 Android开发
小程序微信分享功能如何开发?开放平台已绑定仍不能使用的问题?-优雅草卓伊凡
小程序微信分享功能如何开发?开放平台已绑定仍不能使用的问题?-优雅草卓伊凡
881 29
小程序微信分享功能如何开发?开放平台已绑定仍不能使用的问题?-优雅草卓伊凡
|
4月前
|
JSON 监控 小程序
微信百度字节小程序包过大解决方案(实战经验总结)-优雅草卓伊凡|果果|小无
微信百度字节小程序包过大解决方案(实战经验总结)-优雅草卓伊凡|果果|小无
221 14
微信百度字节小程序包过大解决方案(实战经验总结)-优雅草卓伊凡|果果|小无
|
6月前
|
存储 移动开发 小程序
校园圈子系统小程序(圈子论坛、私信聊天、资料共享、二手交易、兼职,跑腿)开源码开发/微信公众号、小程序、H5多端账号同步/搭建多城市的综合社交生活平台
基于开源技术栈构建的校园圈子系统小程序,整合社交与生活服务功能,涵盖兴趣圈子、私信聊天、资料共享、二手交易、兼职跑腿等六大核心模块。通过多端账号同步(微信公众号/小程序/H5),实现数据实时交互,满足学生群体的多元化需求。项目精准锚定校园市场,以“社交+服务”双轮驱动,提供一站式解决方案,支持快速部署与多校区运营,同时具备广告、佣金、会员等多元变现能力,是打造校园生态的理想工具。
503 4
校园圈子系统小程序(圈子论坛、私信聊天、资料共享、二手交易、兼职,跑腿)开源码开发/微信公众号、小程序、H5多端账号同步/搭建多城市的综合社交生活平台
|
5月前
|
监控 前端开发 小程序
陪练,代练,护航,代打小程序源码/前端UNIAPP-VUE2.0开发 后端Thinkphp6管理/具备家政服务的综合型平台
这款APP通过技术创新,将代练、家政、娱乐社交等场景融合,打造“全能型生活服务生态圈”。以代练为切入点,提供模块化代码支持快速搭建平台,结合智能匹配与技能审核机制,拓展家政服务和商业管理功能。技术架构具备高安全性和扩展性,支持多业务复用,如押金冻结、录屏监控等功能跨领域应用。商业模式多元,包括交易抽成、增值服务及广告联名,同时设计跨领域积分体系提升用户粘性,实现生态共生与B端赋能。
378 12
|
5月前
|
小程序 Java 关系型数据库
weixin163基于微信小程序的校园二手交易平台系统设计与开发ssm(文档+源码)_kaic
本文介绍了一款基于微信小程序的校园二手物品交易平台的开发与实现。该平台采用Java语言开发服务端,使用MySQL数据库进行数据存储,前端以微信小程序为载体,支持管理员和学生两种角色操作。管理员可管理用户、商品分类及信息、交易记录等,而学生则能注册登录、发布购买商品、参与交流论坛等。系统设计注重交互性和安全性,通过SSM框架优化开发流程,确保高效稳定运行,满足用户便捷交易的需求,推动校园资源共享与循环利用。
|
5月前
|
人工智能 开发框架 小程序
工会成立100周年纪念,开发职工健身AI运动小程序、APP方案推荐
为庆祝中华全国总工会成立100周年,特推出基于AI技术的智能健身系统,以小程序和APP形式呈现,助力职工健康生活。方案包括:1) 小程序插件,支持多种运动识别,开箱即用;2) APP插件,提供更高精度的运动检测;3) 成熟的「AI乐运动」系统,支持赛事活动管理。这些方案满足不同需求,推动全民健身体验升级,彰显工会对职工健康的关怀。
|
5月前
|
人工智能 小程序 NoSQL
【一步步开发AI运动小程序】二十一、如何将AI运动项目配置持久化到后端?
本文介绍基于云智「Ai运动识别引擎」的运动配置持久化方案,旨在优化小程序或Uni APP中AI运动识别能力。通过将运动检测参数(如`Key`、`Name`、`TickMode`、`rules`或`samples`)持久化到后端,可避免因频繁调整运动参数而重新发布应用,提升用户体验。持久化数据结构支持规则和姿态样本存储,适用于关系数据库、文件或文档数据库(如MongoDB)。此外,云智还提供运动自动适配工具及「AI乐运动」产品,助力快速实现AI体育、全民健身等场景。
|
5月前
|
小程序 关系型数据库 Java
weixin168“返家乡”高校暑期社会实践微信小程序设计与开发ssm(文档+源码)_kaic
本文探讨高校暑期社会实践微信小程序的开发与应用,旨在通过信息化手段提升活动管理效率。借助微信小程序技术、SSM框架及MySQL数据库,实现信息共享、流程规范和操作便捷。系统涵盖需求分析、可行性研究、设计实现等环节,确保技术可行、操作简便且经济合理。最终,该小程序可优化活动发布、学生信息管理和心得交流等功能,降低管理成本并提高工作效率。
|
8月前
|
移动开发 小程序
thinkphp+uniapp开发的多端商城系统源码/H5/小程序/APP支持DIY模板直播分销
thinkphp+uniapp开发的多端商城系统源码/H5/小程序/APP支持DIY模板直播分销
261 0
|
10月前
|
小程序 前端开发 JavaScript
在线课堂+工具组件小程序uniapp移动端源码
在线课堂+工具组件小程序uniapp移动端源码
193 0
在线课堂+工具组件小程序uniapp移动端源码

热门文章

最新文章