├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .yarnrc ├── babel.config.js ├── changelog.md ├── config ├── dev.js ├── index.js └── prod.js ├── global.d.ts ├── package.json ├── project.config.json ├── readme.md ├── src ├── app.config.ts ├── app.less ├── app.tsx ├── components │ └── DemoTxt │ │ ├── index.module.scss │ │ └── index.tsx ├── constants │ └── env.ts ├── index.html ├── pages │ ├── home2 │ │ ├── index.config.ts │ │ ├── index.module.scss │ │ └── index.tsx │ └── index │ │ ├── index.config.ts │ │ ├── index.module.scss │ │ └── index.tsx ├── services │ └── demo.ts ├── store │ ├── index.ts │ ├── loader.js │ ├── loader_manual.ts │ └── models │ │ └── common.ts ├── typing │ └── demo.ts └── utils │ ├── index.ts │ └── request.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/dist/** 2 | **/node_modules/** 3 | **/server.js 4 | **/webpack.config*.js 5 | **/flow-typed/** 6 | src/types/** 7 | src/serviceWorker.js 8 | *.md 9 | *.log 10 | *.lock 11 | scripts/** 12 | public/**/* 13 | config/**/* 14 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['taro/react'], 3 | }; 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | .temp/ 3 | .rn_temp/ 4 | node_modules/ 5 | img/ 6 | package-lock.json 7 | yarn-error.log 8 | yarn.lock 9 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.svg 2 | package.json 3 | .umi 4 | .umi-production 5 | AUTHORS.txt 6 | lib/ 7 | es/ 8 | dist/ 9 | coverage/ 10 | CNAME 11 | LICENSE 12 | yarn.lock 13 | netlify.toml 14 | yarn-error.log 15 | *.sh 16 | *.snap 17 | .gitignore 18 | .npmignore 19 | .prettierignore 20 | .DS_Store 21 | .editorconfig 22 | .eslintignore 23 | **/*.yml 24 | 25 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "proseWrap": "never", 5 | "overrides": [{ 6 | "files": ".prettierrc", 7 | "options": { 8 | "parser": "json" 9 | } 10 | }], 11 | "tabWidth": 2, 12 | "useTabs": false, 13 | "semi": true, 14 | "jsxSingleQuote": true, 15 | "bracketSpacing": true, 16 | "jsxBracketSameLine": true, 17 | "arrowParens": "avoid", 18 | "endOfLine": "crlf" 19 | } 20 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | omit.js "https://registry.npmjs.org/omit.js" 2 | "@kkb:registry" "https://registry-npm.kaikeba.com" 3 | "@ant-design:registry" "https://registry.npm.taobao.org" 4 | registry "http://vd.kaikeba.com" 5 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | // babel-preset-taro 更多选项和默认值: 2 | // https://github.com/NervJS/taro/blob/next/packages/babel-preset-taro/README.md 3 | module.exports = { 4 | presets: [ 5 | ['taro', { 6 | framework: 'react', 7 | ts: true 8 | }] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ## 更新到Taro v1.3.9 2 | > Taro v1.3.9 3 | 4 | ## 2018年11月26日 5 | 优化action 代码 6 | -------------------------------------------------------------------------------- /config/dev.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | NODE_ENV: '"development"', 4 | FIG_ENV: '"dev"', 5 | }, 6 | defineConstants: {}, 7 | mini: {}, 8 | h5: { 9 | esnextModules: ['taro-ui'], 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | projectName: 'taro-kit', 3 | date: '2020-10-16', 4 | designWidth: 750, 5 | deviceRatio: { 6 | 640: 2.34 / 2, 7 | 750: 1, 8 | 828: 1.81 / 2, 9 | }, 10 | sourceRoot: 'src', 11 | outputRoot: 'dist', 12 | plugins: [], 13 | defineConstants: {}, 14 | copy: { 15 | patterns: [], 16 | options: {}, 17 | }, 18 | framework: 'react', 19 | mini: { 20 | postcss: { 21 | pxtransform: { 22 | enable: true, 23 | config: {}, 24 | }, 25 | url: { 26 | enable: true, 27 | config: { 28 | limit: 1024, // 设定转换尺寸上限 29 | }, 30 | }, 31 | cssModules: { 32 | enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true 33 | config: { 34 | namingPattern: 'module', // 转换模式,取值为 global/module 35 | generateScopedName: '[name]__[local]___[hash:base64:5]', 36 | }, 37 | }, 38 | }, 39 | }, 40 | h5: { 41 | publicPath: '/', 42 | staticDirectory: 'static', 43 | postcss: { 44 | autoprefixer: { 45 | enable: true, 46 | config: {}, 47 | }, 48 | cssModules: { 49 | enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true 50 | config: { 51 | namingPattern: 'module', // 转换模式,取值为 global/module 52 | generateScopedName: '[name]__[local]___[hash:base64:5]', 53 | }, 54 | }, 55 | }, 56 | // 小程序端 57 | weapp: { 58 | module: { 59 | postcss: { 60 | cssModules: { 61 | enable: true, 62 | config: { 63 | namingPattern: 'module', 64 | generateScopedName: '[name]__[local]___[hash:base64:5]', 65 | }, 66 | }, 67 | }, 68 | }, 69 | }, 70 | }, 71 | }; 72 | 73 | module.exports = function (merge) { 74 | if (process.env.NODE_ENV === 'development') { 75 | return merge({}, config, require('./dev')); 76 | } 77 | return merge({}, config, require('./prod')); 78 | }; 79 | -------------------------------------------------------------------------------- /config/prod.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | NODE_ENV: '"production"', 4 | FIG_ENV: '"prod"', 5 | }, 6 | defineConstants: {}, 7 | mini: {}, 8 | h5: { 9 | /** 10 | * 如果h5端编译后体积过大,可以使用webpack-bundle-analyzer插件对打包体积进行分析。 11 | * 参考代码如下: 12 | * webpackChain (chain) { 13 | * chain.plugin('analyzer') 14 | * .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, []) 15 | * } 16 | */ 17 | esnextModules: ['taro-ui'], 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /global.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.png"; 2 | declare module "*.gif"; 3 | declare module "*.jpg"; 4 | declare module "*.jpeg"; 5 | declare module "*.svg"; 6 | declare module "*.css"; 7 | declare module "*.less"; 8 | declare module "*.scss"; 9 | declare module "*.sass"; 10 | declare module "*.styl"; 11 | 12 | // @ts-ignore 13 | declare const process: { 14 | env: { 15 | TARO_ENV: 'weapp' | 'swan' | 'alipay' | 'h5' | 'rn' | 'tt' | 'quickapp' | 'qq' | 'jd'; 16 | [key: string]: any; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "taro-kit", 3 | "version": "1.0.1", 4 | "private": true, 5 | "description": "taro-kit", 6 | "templateInfo": { 7 | "name": "redux", 8 | "typescript": true, 9 | "css": "less" 10 | }, 11 | "scripts": { 12 | "build:weapp": "taro build --type weapp", 13 | "build:swan": "taro build --type swan", 14 | "build:alipay": "taro build --type alipay", 15 | "build:tt": "taro build --type tt", 16 | "build:h5": "taro build --type h5", 17 | "build:rn": "taro build --type rn", 18 | "build:qq": "taro build --type qq", 19 | "build:jd": "taro build --type jd", 20 | "build:quickapp": "taro build --type quickapp", 21 | "dev:weapp": "npm run build:weapp -- --watch", 22 | "dev:swan": "npm run build:swan -- --watch", 23 | "dev:alipay": "npm run build:alipay -- --watch", 24 | "dev:tt": "npm run build:tt -- --watch", 25 | "dev:h5": "npm run build:h5 -- --watch", 26 | "dev:rn": "npm run build:rn -- --watch", 27 | "dev:qq": "npm run build:qq -- --watch", 28 | "dev:jd": "npm run build:jd -- --watch", 29 | "dev:quickapp": "npm run build:quickapp -- --watch" 30 | }, 31 | "browserslist": [ 32 | "last 3 versions", 33 | "Android >= 4.1", 34 | "ios >= 8" 35 | ], 36 | "author": "", 37 | "license": "MIT", 38 | "dependencies": { 39 | "@babel/runtime": "^7.7.7", 40 | "@rematch/core": "^1.4.0", 41 | "@rematch/loading": "^1.2.1", 42 | "@tarojs/components": "3.3.15", 43 | "@tarojs/react": "3.3.15", 44 | "@tarojs/runtime": "3.3.15", 45 | "@tarojs/taro": "3.3.15", 46 | "react": "^16.10.0", 47 | "react-dom": "^16.10.0", 48 | "react-redux": "^7.2.0", 49 | "redux": "^4.0.0", 50 | "redux-logger": "^3.0.6", 51 | "redux-thunk": "^2.3.0", 52 | "taro-ui": "^3.0.0-alpha.3", 53 | "taro-weapp-poster": "^1.3.0" 54 | }, 55 | "devDependencies": { 56 | "@babel/core": "^7.8.0", 57 | "@tarojs/mini-runner": "3.3.15", 58 | "@tarojs/webpack-runner": "3.3.15", 59 | "@types/react": "^16.0.0", 60 | "@types/react-redux": "^7.1.9", 61 | "@types/webpack-env": "^1.13.6", 62 | "@typescript-eslint/eslint-plugin": "^2.x", 63 | "@typescript-eslint/parser": "^2.x", 64 | "babel-preset-taro": "3.3.15", 65 | "eslint": "^6.8.0", 66 | "eslint-config-taro": "3.3.15", 67 | "eslint-plugin-import": "^2.12.0", 68 | "eslint-plugin-react": "^7.8.2", 69 | "eslint-plugin-react-hooks": "^1.6.1", 70 | "stylelint": "9.3.0", 71 | "typescript": "^3.7.0" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "miniprogramRoot": "dist/", 3 | "projectname": "taro-kit", 4 | "description": "taro-kit", 5 | "appid": "touristappid", 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": false, 9 | "enhance": false, 10 | "postcss": false, 11 | "preloadBackgroundData": false, 12 | "minified": false, 13 | "newFeature": false, 14 | "coverView": true, 15 | "nodeModules": false, 16 | "autoAudits": false, 17 | "showShadowRootInWxmlPanel": true, 18 | "scopeDataCheck": false, 19 | "uglifyFileName": false, 20 | "checkInvalidKey": true, 21 | "checkSiteMap": true, 22 | "uploadWithSourceMap": true, 23 | "compileHotReLoad": false, 24 | "useMultiFrameRuntime": true, 25 | "useApiHook": true, 26 | "useApiHostProcess": true, 27 | "babelSetting": { 28 | "ignore": [], 29 | "disablePlugins": [], 30 | "outputPath": "" 31 | }, 32 | "bundle": false, 33 | "useIsolateContext": true, 34 | "useCompilerModule": true, 35 | "userConfirmedUseCompilerModuleSwitch": false, 36 | "userConfirmedBundleSwitch": false, 37 | "packNpmManually": false, 38 | "packNpmRelationList": [], 39 | "minifyWXSS": true 40 | }, 41 | "compileType": "miniprogram", 42 | "condition": {} 43 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | ## 可以 watch 这个项目,有更新,及时知道 11 | 12 | > 项目会不断迭代,有需求欢迎 issue 如果能帮到你,那就给个 star 呗! 13 | 14 | > 1 年前输出了一套 taro-kit 脚手架,有不少人加我微信,咨询一些问题,这段时间把这个脚手架升级后,总结并录制了课程,希望能帮助到大家,提高效率,节约时间。 15 | 16 | CLI 工具安装首先,你需要使用 npm 或者 yarn 全局安装@tarojs/cli,或者直接使用 npx: 17 | 18 | ```js 19 | # 使用 npm 安装 CLI 20 | $ npm install -g @tarojs/cli 21 | # OR 使用 yarn 安装 CLI 22 | $ yarn global add @tarojs/cli 23 | # OR 安装了 cnpm,使用 cnpm 安装 CLI 24 | $ cnpm install -g @tarojs/cli 25 | ``` 26 | 27 | ## 项目更新: 28 | 29 | > 2021年11月30日 30 | 31 | - 更新@tarojs/taro到:3.3.15 32 | 33 | - 添加海报生成插件:[taro-weapp-poster](https://github.com/Clycheng/taro-weapp-poster) 34 | 35 | 36 | > 2021 年 02 月 03 日 星期三 37 | 38 | - 更新依赖到:3.0.26 39 | - 更新.eslintrc 40 | - 添加 babel 配置 41 | - 添加 global.d.ts 42 | - 添加 tsconfig 43 | - 添加 yarn.lock 文件 44 | - 更新 config 文件 45 | 46 | 47 | ``` 48 | taro update project v版本号 49 | ``` 50 | 51 | > ![20210122111946](http://s.shudong.wang/note/20210122111946.png) 52 | 53 | ## 文章 54 | 55 | - [【小程序 taro 最佳实践】http 请求封装(方便使用,增加 token,统一错误日志记录和上报)](https://segmentfault.com/a/1190000016533592) 56 | - [【小程序 taro 最佳实践】异步 action 优雅实践(简化流程)](https://segmentfault.com/a/1190000016534001) 57 | - [【taro 最佳实践】设置好基础开发字体尺寸](https://segmentfault.com/a/1190000016514478) 58 | 59 | - [Taro 小程序,从 0 到 1 架构项目,打造自己的完美脚手架。 ](https://segmentfault.com/a/1190000019020009) 60 | 61 | ## 功能列表 62 | 63 | - [x] 封装 api 请求方式 64 | - [x] 更方便的创建 action:增加 createApiAction 65 | - [x] 基础像素试着为 1 倍即:1px 会编译成 2rpx(小程序默认是 2 倍)符合习惯 66 | - [x] 基础 demo 案列 67 | - [x] 增加生成海报类 68 | 69 | ## 升级功能列表 70 | 71 | - [x] 01.taro 从 0 到 1 项目架构课程介绍 72 | - [x] 02.初始化项目流程介绍、目录设计 73 | - [x] 03.让 alias 别名解决路径引用的烦恼 74 | - [x] 04.请求 api 返回 redux 的状态流程 75 | - [x] 05.封装 request get 请求,给 url 添加时间戳防止浏览器缓存 76 | - [x] 06.封装 request post Content-Type 分类请求 77 | - [x] 07.把 taro-advance 脚手架推送到私有仓库 78 | - [x] 08.弱网请求失败时自动发起 api 重试 79 | - [x] 09.异常日志上报封装设计思路 80 | - [x] 10.异常日志上报封装,五种级别输出。 81 | - [x] 11.上报收集日志平台系统介绍 82 | - [x] 12.实战接入日志平台 83 | - [x] 13.深度序列化错误 error 控制台上报 84 | - [x] 14.登录流程讲解(前端和后端实现流程) 85 | - [x] 15.登录实现详细讲解(token 附加到请求 header 头) 86 | - [x] 16.用户授权后更新用户信息流程 87 | - [x] 17.设计 createApiAction 自动 dispatch 优化开发体验 88 | - [x] 18.改造 actionType 支持庞大业务 89 | - [x] 19.Action 三种 ActionType 的集合 90 | - [x] 20.简化 reducers 的 swich 繁琐操作 91 | - [x] 21.增加 request 的状态 92 | - [x] 22.课程总结 93 | - [x] 23.添加 Prettier 格式化配置 94 | 95 | > 这个可以让你的 Taro 小程序跑的更优雅一些 96 | 97 | #### 升级后的项目仓库地址: 观看视频的同学加微信,发送你的 gitlab 账号,添加权限,你就看源代码了。 98 | 99 | https://gitlab.com/itxishu/taro-advance.git 100 | 101 | ## 观看地址:segmentfault 102 | 103 | #### 购买路径 104 | 在 https://shudong.wang 加我微信 105 | 106 | https://segmentfault.com/ls/1650000018991514 107 | 108 | ## 适宜人群 109 | 110 | - taro 小程序开发者 111 | - 需要 taro 基础架构开发人员 112 | 113 | ## 课程说明 114 | 115 | 本次课程主要针对于,正在使用 taro 小程序框架的同学,通过课程,你可以学到,框架的 request 请求优雅封装,异常自动重试,日志异常上报, redux 的三剑客优雅的配合使用, reducer 的 swich 简化繁琐操作,增加 state 的请求前,请求成功和失败的状态等。从开始架构足以支撑庞大业务小程序项目 116 | 117 | 课程有问题可以在 https://shudong.wang 我的博客扎到我,添加微信咨询 118 | 119 | ![2019-04-28-22-09-17](http://s.shudong.wang/2019-04-28-22-09-17.png) 120 | 121 | #### 有问题加微信问吧 122 | 123 | https://www.shudong.wang/about 124 | -------------------------------------------------------------------------------- /src/app.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | pages: ['pages/index/index', 'pages/home2/index'], 3 | window: { 4 | backgroundTextStyle: 'light', 5 | navigationBarBackgroundColor: '#fff', 6 | navigationBarTitleText: 'WeChat', 7 | navigationBarTextStyle: 'black', 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /src/app.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsdo/taro-kit/e894de3cb066a80ceaba63f049562789776d8fa2/src/app.less -------------------------------------------------------------------------------- /src/app.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Provider } from 'react-redux'; 3 | import configStore from './store'; 4 | 5 | import './app.less'; 6 | 7 | const store = configStore(); 8 | 9 | class App extends Component { 10 | componentDidMount() {} 11 | 12 | componentDidShow() {} 13 | 14 | componentDidHide() {} 15 | 16 | componentDidCatchError() {} 17 | 18 | // 在 App 类中的 render() 函数没有实际作用 19 | // 请勿修改此函数 20 | render() { 21 | return {this.props.children}; 22 | } 23 | } 24 | 25 | export default App; 26 | -------------------------------------------------------------------------------- /src/components/DemoTxt/index.module.scss: -------------------------------------------------------------------------------- 1 | .textBody { 2 | text-align: center; 3 | width: 100%; 4 | font-size: 60px; 5 | } 6 | -------------------------------------------------------------------------------- /src/components/DemoTxt/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { View, Text } from '@tarojs/components'; 4 | import styles from './index.module.scss'; 5 | 6 | const DemoTxt = props => { 7 | return ( 8 | 9 | 子组件内容{props.common?.num} 10 | 11 | ); 12 | }; 13 | 14 | export default connect( 15 | ({ common }: any) => ({ 16 | common, 17 | }), 18 | null, 19 | )(DemoTxt); 20 | -------------------------------------------------------------------------------- /src/constants/env.ts: -------------------------------------------------------------------------------- 1 | // 当前环境变量,dev test prod 2 | export const currentEnv = process.env.FIG_ENV; 3 | const ctext = currentEnv !== 'prod' ? `前端指北${currentEnv}` : '前端指北'; 4 | 5 | // 不要删除,用来识别当前项目环境 6 | console.log( 7 | `\n %c ${ctext} %c https://www.feup.cn \n`, 8 | 'color: #fff; background: #008bf8; padding:5px 0; font-size:12px;font-weight: bold;', 9 | 'background: #008bf8; padding:5px 0; font-size:12px;', 10 | ); 11 | 12 | export const isDevEnv = currentEnv === 'dev'; 13 | export const isPreEnv = currentEnv === 'pre'; 14 | export const isTestEnv = currentEnv === 'test'; 15 | export const isProdEnv = currentEnv === 'prod'; 16 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /src/pages/home2/index.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | navigationBarTitleText: '详情', 3 | }; 4 | -------------------------------------------------------------------------------- /src/pages/home2/index.module.scss: -------------------------------------------------------------------------------- 1 | .indexBody { 2 | flex-direction: column; 3 | width: 100%; 4 | .qrcode { 5 | width: 100%; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/pages/home2/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import Taro from '@tarojs/taro'; 4 | import { View, Image } from '@tarojs/components'; 5 | 6 | import styles from './index.module.scss'; 7 | 8 | const home2 = () => { 9 | const preImage = () => { 10 | Taro.previewImage({ 11 | urls: ['http://s.devland.cn/2fb4ddc0232eb758639be2890824da7c.jpeg'], 12 | }); 13 | }; 14 | 15 | return ( 16 | 17 | preImage()} 19 | mode='widthFix' 20 | className={styles.qrcode} 21 | src='http://s.devland.cn/2fb4ddc0232eb758639be2890824da7c.jpeg'> 22 | 23 | ); 24 | }; 25 | 26 | export default connect( 27 | ({ common }: any) => ({ 28 | common, 29 | }), 30 | (dispatch: any) => { 31 | return { 32 | add: dispatch.common?.increment, 33 | dec: dispatch.common?.dec, 34 | }; 35 | }, 36 | )(home2); 37 | -------------------------------------------------------------------------------- /src/pages/index/index.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | navigationBarTitleText: '前端指北', 3 | navigationBarTextStyle: 'white', 4 | navigationBarBackgroundColor: '#008bf8', 5 | }; 6 | -------------------------------------------------------------------------------- /src/pages/index/index.module.scss: -------------------------------------------------------------------------------- 1 | .indexBody { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | flex-direction: column; 6 | width: 100%; 7 | min-height: 100vh; 8 | .icon { 9 | width: 100px; 10 | height: 100px; 11 | } 12 | .desc { 13 | margin-top: 25px; 14 | } 15 | .routerLink { 16 | width: 300px; 17 | margin-top: 35px; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/pages/index/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { AtButton } from 'taro-ui'; 4 | import { View, Image, Text, Button } from '@tarojs/components'; 5 | import { navigateTo, useDidHide, useDidShow } from '@tarojs/taro'; 6 | import 'taro-ui/dist/style/components/button.scss'; // 按需引入组件样式 7 | import styles from './index.module.scss'; 8 | 9 | const Index = () => { 10 | const init = async () => { 11 | console.log('请求 数据'); 12 | }; 13 | useEffect(() => { 14 | init(); 15 | // eslint-disable-next-line 16 | }, []); 17 | 18 | useDidShow(() => { 19 | console.log('componentDidShow'); 20 | }); 21 | 22 | useDidHide(() => { 23 | console.log('componentDidHide'); 24 | }); 25 | 26 | const goPage = () => { 27 | navigateTo({ 28 | url: '/pages/home2/index', 29 | }); 30 | }; 31 | return ( 32 | 33 | 36 | 前端指北 37 | goPage()}> 41 | 关注我 42 | 43 | 44 | {/* I need Taro UI 45 | 46 | 49 | 52 | 55 | */} 56 | 57 | ); 58 | }; 59 | 60 | export default connect( 61 | ({ common }: any) => ({ 62 | common, 63 | }), 64 | (dispatch: any) => { 65 | return { 66 | add: dispatch.common?.increment, 67 | dec: dispatch.common?.dec, 68 | login: dispatch.common.login, 69 | }; 70 | }, 71 | )(Index); 72 | -------------------------------------------------------------------------------- /src/services/demo.ts: -------------------------------------------------------------------------------- 1 | import request from '../utils/request'; 2 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { init, RematchRootState } from '@rematch/core'; 2 | import createLoadingPlugin from '@rematch/loading'; 3 | // import * as models from './loader_manual'; 4 | import models from './loader'; 5 | 6 | const loadingPlugin = createLoadingPlugin({ asNumber: true }); 7 | const store = init({ 8 | plugins: [loadingPlugin], 9 | models, 10 | }); 11 | export type Store = typeof store; 12 | export type Dispatch = typeof store.dispatch; 13 | interface ILoadingPlugin { 14 | loading: { 15 | models: RematchRootState; 16 | effects: Dispatch; 17 | }; 18 | } 19 | export type iRootState = RematchRootState & ILoadingPlugin; 20 | 21 | const configureStore = () => { 22 | return store; 23 | }; 24 | 25 | export default configureStore; 26 | -------------------------------------------------------------------------------- /src/store/loader.js: -------------------------------------------------------------------------------- 1 | const files = require.context('./models', false, /\.(js|ts)$/); 2 | const models = {}; 3 | files.keys().forEach(key => { 4 | const filename = key.replace(/(\.\/|\.(js|ts))/g, ''); 5 | models[filename] = files(key).default; 6 | }); 7 | 8 | export default models; 9 | -------------------------------------------------------------------------------- /src/store/loader_manual.ts: -------------------------------------------------------------------------------- 1 | // 手动挂载models中的值,关联TS类型 2 | export { default as common } from './models/common'; 3 | -------------------------------------------------------------------------------- /src/store/models/common.ts: -------------------------------------------------------------------------------- 1 | import { createModel } from '@rematch/core'; 2 | import { getLogin } from '../../services/demo'; 3 | 4 | export default createModel({ 5 | state: { 6 | num: 0, 7 | }, 8 | reducers: { 9 | updateState(state, payload) { 10 | return { 11 | ...state, 12 | ...payload, 13 | }; 14 | }, 15 | }, 16 | effects: dispatch => ({ 17 | async login(payload) { 18 | const res = await getLogin(payload); 19 | return res; 20 | }, 21 | async increment(payload, rootState) { 22 | this.updateState({ 23 | num: rootState.common.num + 1, 24 | }); 25 | }, 26 | async dec(payload, rootState) { 27 | this.updateState({ 28 | num: rootState.common.num - 1, 29 | }); 30 | }, 31 | }), 32 | }); 33 | -------------------------------------------------------------------------------- /src/typing/demo.ts: -------------------------------------------------------------------------------- 1 | interface ILoginParams { 2 | contentType: number; 3 | platType: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // 设置url挂载参数 3 | export const setUrlQuery = options => { 4 | let { url, query } = options; 5 | if (!url) return ''; 6 | if (query) { 7 | let queryArr: string[] = []; 8 | for (const key in query) { 9 | if (query.hasOwnProperty(key)) { 10 | queryArr.push(`${key}=${query[key]}`); 11 | } 12 | } 13 | if (url.indexOf('?') !== -1) { 14 | url = `${url}&${queryArr.join('&')}`; 15 | } else { 16 | url = `${url}?${queryArr.join('&')}`; 17 | } 18 | } 19 | return url; 20 | }; 21 | 22 | /** 23 | * 获取url参数数据,返回obj对象 24 | */ 25 | export const getUrlToJson = url => { 26 | try { 27 | const strUrl = url || window?.location?.href || ''; 28 | let temp1 = strUrl.split('?'); 29 | let [_, pram] = temp1; 30 | if (pram === 'undefined' || !pram) { 31 | return {}; 32 | } 33 | let keyValue = pram.split('&'); 34 | let obj = {}; 35 | for (let i = 0; i < keyValue.length; i++) { 36 | let item = keyValue[i].split('='); 37 | let [key, value] = item; 38 | obj[key] = value; 39 | } 40 | return obj; 41 | } catch (error) { 42 | return {}; 43 | } 44 | }; 45 | 46 | // pc端七牛缩略图,指定宽 47 | export const getPcThumbImg = ({ url, width, height }) => { 48 | let newUrl = `${url}?imageView2/2/w/${width || 200}`; 49 | if (height) { 50 | newUrl += `/h/${height}`; 51 | } 52 | return newUrl; 53 | }; 54 | 55 | // 移动端七牛缩略图,指定宽 56 | export const getMobileThumbImg = ({ url, width, height }) => { 57 | let newUrl = `${url}?imageView2/0/w/${width || 200}`; 58 | if (height) { 59 | newUrl += `/h/${height}`; 60 | } 61 | return newUrl; 62 | }; 63 | 64 | /** 65 | * 判断用户浏览器终端信息 66 | * 67 | * browser.versions.ios 判断是否是IOS设备 68 | */ 69 | export const browser = () => { 70 | if (navigator) { 71 | const u = navigator ? navigator.userAgent : ''; 72 | return { 73 | trident: u.indexOf('Trident') > -1, // IE内核 74 | presto: u.indexOf('Presto') > -1, // opera内核 75 | webKit: u.indexOf('AppleWebKit') > -1, // 苹果、谷歌内核 76 | gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') === -1, // 火狐内核 77 | mobile: !!u.match(/AppleWebKit.*Mobile.*/), // 是否为移动终端 78 | ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端 79 | android: u.indexOf('Android') > -1 || u.indexOf('Adr') > -1, // android终端 80 | iPhone: u.indexOf('iPhone') > -1, // 是否为iPhone或者QQHD浏览器 81 | iPad: u.indexOf('iPad') > -1, // 是否iPad 82 | webApp: u.indexOf('Safari') === -1, // 是否web应该程序,没有头部与底部 83 | weixin: u.indexOf('MicroMessenger') > -1, // 是否微信 84 | }; 85 | } 86 | return {}; 87 | }; 88 | 89 | /** 90 | * 通用时间格式转换,将时间戳转换自己需要的格式 91 | * 92 | * [fmt] 第二参数类型字符串,注意指定 93 | * 年(y)、月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) ,毫秒(S)只能用 1 个占位符(是 1-3 位的数字) 94 | * 95 | * customFormatDate(时间戳, "yyyy-MM-dd hh:mm:ss.S") 转换后 2016-07-02 08:09:04.423 96 | */ 97 | export const customFormatDate = (UnixTime, fmt) => { 98 | if (!UnixTime) return ''; 99 | const dateTime = new Date(parseInt(`${UnixTime * 1000}`)); 100 | const o = { 101 | 'M+': dateTime.getMonth() + 1, //月份 102 | 'd+': dateTime.getDate(), //日 103 | 'h+': dateTime.getHours(), //小时 104 | 'm+': dateTime.getMinutes(), //分 105 | 's+': dateTime.getSeconds(), //秒 106 | 'q+': Math.floor((dateTime.getMonth() + 3) / 3), //季度 107 | S: dateTime.getMilliseconds(), //毫秒 108 | }; 109 | let newDataStrin = fmt || 'yyyy-MM-dd hh:mm:ss.S'; 110 | if (/(y+)/.test(newDataStrin)) { 111 | newDataStrin = newDataStrin.replace( 112 | RegExp.$1, 113 | (dateTime.getFullYear() + '').substr(4 - RegExp.$1.length), 114 | ); 115 | } 116 | for (let k in o) { 117 | if (new RegExp('(' + k + ')').test(newDataStrin)) { 118 | newDataStrin = newDataStrin.replace( 119 | RegExp.$1, 120 | RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length), 121 | ); 122 | } 123 | } 124 | return newDataStrin; 125 | }; 126 | -------------------------------------------------------------------------------- /src/utils/request.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@tarojs/taro'; 2 | 3 | type RequestOpts = Omit; 4 | 5 | const safeRequest = (url: string, options: RequestOpts) => { 6 | return new Promise((resolve, reject) => { 7 | request({ 8 | method: 'GET', 9 | ...options, 10 | header: { 11 | 'Content-Type': 'application/json', 12 | ...options?.header, 13 | }, 14 | url, 15 | }).then( 16 | response => { 17 | resolve(response?.data ?? response); 18 | }, 19 | err => { 20 | reject(err); 21 | }, 22 | ); 23 | }); 24 | }; 25 | 26 | /** 27 | * get 28 | * @param url 29 | * @param opts 30 | * @returns {Promise} 31 | */ 32 | const get = async (url: string, opts: RequestOpts): Promise => { 33 | return safeRequest(url, opts); 34 | }; 35 | 36 | /** 37 | * post 38 | * @param url 39 | * @param opts 40 | * @returns {Promise} 41 | */ 42 | const post = async (url: string, opts: RequestOpts): Promise => { 43 | return safeRequest(url, { 44 | ...opts, 45 | method: 'POST', 46 | }); 47 | }; 48 | 49 | /** 50 | * put 51 | * @param url 52 | * @param opts 53 | * @returns {Promise} 54 | */ 55 | const put = async (url: string, opts: RequestOpts): Promise => { 56 | return safeRequest(url, { 57 | ...opts, 58 | method: 'PUT', 59 | }); 60 | }; 61 | 62 | export default { 63 | get, 64 | post, 65 | put, 66 | }; 67 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "commonjs", 5 | "removeComments": false, 6 | "preserveConstEnums": true, 7 | "moduleResolution": "node", 8 | "experimentalDecorators": true, 9 | "noImplicitAny": false, 10 | "allowSyntheticDefaultImports": true, 11 | "outDir": "lib", 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "strictNullChecks": true, 15 | "sourceMap": true, 16 | "baseUrl": ".", 17 | "rootDir": ".", 18 | "jsx": "react", 19 | "jsxFactory": "React.createElement", 20 | "allowJs": true, 21 | "resolveJsonModule": true, 22 | "typeRoots": [ 23 | "node_modules/@types", 24 | "global.d.ts" 25 | ] 26 | }, 27 | "exclude": [ 28 | "node_modules", 29 | "dist" 30 | ], 31 | "compileOnSave": false 32 | } 33 | --------------------------------------------------------------------------------