├── .browserslistrc
├── .editorconfig
├── .env
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .npmrc
├── .prettierignore
├── .prettierrc.js
├── README.md
├── babel.config.js
├── config
└── index.js
├── global.d.ts
├── mock
└── api.ts
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── project.config.json
├── project.private.config.json
├── public
├── favicon.ico
└── index.html
├── src
├── api
│ ├── http.interceptor.ts
│ ├── http.ts
│ └── tsg.config.ts
├── app.config.ts
├── app.ts
├── common
│ └── decorator
│ │ └── catch
│ │ └── index.ts
├── component
│ └── if
│ │ └── index.tsx
├── config
│ ├── config.default.ts
│ ├── config.develop.ts
│ ├── config.release.ts
│ ├── config.trial.ts
│ └── index.ts
├── index.html
├── main.ts
├── module
│ └── demo
│ │ ├── first
│ │ ├── index.config.ts
│ │ ├── index.module.scss
│ │ └── index.tsx
│ │ └── two
│ │ ├── index.config.ts
│ │ ├── index.module.scss
│ │ └── index.tsx
├── polyfill.ts
├── setup
│ └── index.ts
└── theme
│ └── app.scss
├── tailwind.config.js
└── tsconfig.json
/.browserslistrc:
--------------------------------------------------------------------------------
1 | chrome >= 51
2 | ios >= 10
3 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | insert_final_newline = false
13 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | VUE_APP_BASE_ROUTE=/
2 | VUE_APP_BASE_URL=$VUE_APP_BASE_ROUTE
3 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 | dist
4 | coverage
5 | public
6 | *.d.ts
7 | *.js
8 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | browser: true,
6 | },
7 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
8 | plugins: ['@typescript-eslint'],
9 | parser: '@typescript-eslint/parser',
10 | parserOptions: {
11 | ecmaVersion: 2020,
12 | sourceType: 'module',
13 | ecmaFeatures: {
14 | jsx: true,
15 | },
16 | },
17 | rules: {
18 | '@typescript-eslint/unbound-method': 'off',
19 | '@typescript-eslint/ban-ts-comment': 'off',
20 | '@typescript-eslint/explicit-module-boundary-types': 'off',
21 | '@typescript-eslint/no-empty-function': 'warn',
22 | '@typescript-eslint/ban-types': [
23 | 'error',
24 | {
25 | extendDefaults: true,
26 | types: {
27 | '{}': false,
28 | },
29 | },
30 | ],
31 | '@typescript-eslint/no-explicit-any': 'off',
32 | 'no-debugger': 'warn',
33 | 'no-case-declarations': 'off',
34 | '@typescript-eslint/no-unused-vars': 'off',
35 | },
36 | }
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | deploy_versions/
3 | .temp/
4 | .rn_temp/
5 | node_modules/
6 | .DS_Store
7 | .gitlab-ci.yml
8 | yarn-error.log
9 | .idea
10 | .swc
11 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmmirror.com/
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .editorconfig
2 | .gitignore
3 | .prettierignore
4 | .idea
5 | node_modules
6 | dist
7 | pnpm-lock.yaml
8 | *.d.ts
9 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: false,
3 | singleQuote: true,
4 | printWidth: 100,
5 | trailingComma: 'all',
6 | arrowParens: 'avoid',
7 | plugins: [require('prettier-plugin-tailwindcss')],
8 | }
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 使用vue3-oop开发小程序
2 |
3 | - vue3
4 | - tsx + vue3-oop
5 | - 依赖注入
6 |
7 | ## 开发
8 |
9 | ```shell
10 | pnpm i
11 | pnpm run dev
12 | ```
13 |
14 | 然后打开微信开发者工具查看
15 |
16 | ### 开发h5
17 |
18 | ```shell
19 | pnpm run dev:h5
20 | ```
21 |
22 | ## 打包
23 |
24 | 类似vue-cli一样根据mode来加载环境变量
25 |
26 | ```shell
27 | pnpm run dev --mode master
28 | ```
29 |
30 | 会加载 `.env.master` 环境变量
31 |
32 |
33 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | // babel-preset-taro 更多选项和默认值:
2 | // https://github.com/NervJS/taro/blob/next/packages/babel-preset-taro/README.md
3 | // 小程序端原生组件
4 |
5 | module.exports = {
6 | presets: [
7 | [
8 | 'taro',
9 | {
10 | framework: 'vue3',
11 | ts: false,
12 | },
13 | ],
14 | ],
15 | plugins: [
16 | [
17 | 'import',
18 | {
19 | libraryName: '@nutui/nutui-taro',
20 | customName: (name) => `@nutui/nutui-taro/dist/packages/${name.toLowerCase()}`,
21 | style: (name, file) => name + '/style',
22 | camel2DashComponentName: false,
23 | },
24 | 'nutui4-taro',
25 | ],
26 | ],
27 | }
28 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | import { loadEnv } from "@vue3-oop/taro-plugin";
2 | import { UnifiedWebpackPluginV5 } from "weapp-tailwindcss";
3 |
4 | const env = loadEnv()
5 | const isH5 = process.env.TARO_ENV === 'h5'
6 | const isWatch = process.env.VUE_APP_WATCH === 'true'
7 | /**
8 | *
9 | * @type {import('@tarojs/taro/types/compile').IProjectConfig}
10 | */
11 | const config = {
12 | projectName: 'vue3taro',
13 | framework: 'vue3',
14 | designWidth: 375,
15 | deviceRatio: {
16 | 375: 2,
17 | },
18 | sourceRoot: 'src',
19 | outputRoot: `dist`,
20 | compiler: {
21 | type: 'webpack5',
22 | prebundle: {
23 | enable: false,
24 | },
25 | },
26 | plugins: [
27 | '@tarojs/plugin-html',
28 | '@tarojs/plugin-http',
29 | '@vue3-oop/taro-plugin',
30 | isWatch ? '@tarojs/plugin-mock' : undefined,
31 | ].filter(Boolean),
32 | copy: {
33 | patterns: [
34 | isH5
35 | ? {
36 | from: 'public/',
37 | to: 'dist/',
38 | ignore: ['**/index.html'],
39 | }
40 | : undefined,
41 | ].filter(Boolean),
42 | },
43 | sass: {
44 | data: '@import "@nutui/nutui-taro/dist/styles/variables.scss";',
45 | },
46 | mini: {
47 | optimizeMainPackage: {
48 | enable: true,
49 | },
50 | postcss: {
51 | pxtransform: {
52 | enable: true,
53 | config: {},
54 | },
55 | url: {
56 | enable: true,
57 | config: {
58 | limit: 1024, // 设定转换尺寸上限
59 | },
60 | },
61 | cssModules: {
62 | enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
63 | config: {
64 | namingPattern: 'module', // 转换模式,取值为 global/module
65 | generateScopedName: '[local]--[hash:base64:5]',
66 | },
67 | },
68 | },
69 | webpackChain(chain, webpack) {
70 | chain.merge({
71 | plugin: {
72 | install: {
73 | plugin: UnifiedWebpackPluginV5,
74 | args: [
75 | {
76 | appType: 'taro',
77 | // 注意这一行(不传默认 react)
78 | framework: 'vue3', // 'vue2' / 'vue3'
79 | disabled: isH5,
80 | injectAdditionalCssVarScope: true,
81 | },
82 | ],
83 | },
84 | },
85 | })
86 | },
87 | },
88 | h5: {
89 | useDeprecatedAdapterComponent: true,
90 | publicPath: process.env.VUE_APP_BASE_URL,
91 | router: {
92 | basename: process.env.VUE_APP_BASE_ROUTE.replace(/\/$/, ''),
93 | mode: 'browser',
94 | },
95 | staticDirectory: 'static',
96 | esnextModules: ['nutui-taro', 'icons-vue-taro'],
97 | postcss: {
98 | pxtransform: {
99 | enable: true,
100 | config: {},
101 | },
102 | cssModules: {
103 | enable: true,
104 | config: {
105 | namingPattern: 'module',
106 | localsConvention: 'camelCaseOnly',
107 | generateScopedName: '[local]--[hash:base64:5]',
108 | },
109 | },
110 | },
111 | devServer: {
112 | open: false,
113 | },
114 | },
115 | }
116 | module.exports = () => config
117 |
--------------------------------------------------------------------------------
/global.d.ts:
--------------------------------------------------------------------------------
1 | // 热更新需要用
2 | declare var __VUE_HMR_RUNTIME__: any
3 | // 环境变量定义
4 | declare namespace __WebpackModuleApi {
5 | interface NodeProcess {
6 | env: {
7 | NODE_ENV: 'development' | 'production'
8 | TARO_ENV: 'weapp' | 'swan' | 'alipay' | 'h5' | 'rn' | 'tt' | 'quickapp' | 'qq' | 'jd'
9 | VUE_APP_MODE: string
10 | BASE_URL: string
11 | VUE_APP_BASE_ROUTE: string
12 | VUE_APP_BASE_URL: string
13 | }
14 | }
15 | }
16 |
17 | declare module '@tarojs/components' {
18 | export * from '@tarojs/components/types/index.vue3'
19 | }
20 |
--------------------------------------------------------------------------------
/mock/api.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | 'GET /api/abc': {
3 | status: 1,
4 | data: [11111],
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "taro3-vue3-template",
3 | "version": "1.0.0",
4 | "private": true,
5 | "description": "taro3-vue3-template",
6 | "templateInfo": {
7 | "name": "default",
8 | "typescript": true,
9 | "css": "sass"
10 | },
11 | "scripts": {
12 | "dev": "pnpm run build --watch",
13 | "dev:prod": "NODE_ENV=production pnpm run build --watch",
14 | "build": "taro build --type weapp",
15 | "build:master": "pnpm run build --mode master",
16 | "dev:h5": "pnpm run build:h5 --watch",
17 | "build:h5": "taro build --type h5",
18 | "preview:h5": "serve -s dist",
19 | "type:check": "tsc --noEmit",
20 | "lint": "eslint --fix .",
21 | "api": "tsg -c ./src/api/tsg.config.ts",
22 | "postinstall": "simple-git-hooks && weapp-tw patch"
23 | },
24 | "dependencies": {
25 | "@abraham/reflection": "^0.12.0",
26 | "@babel/runtime": "^7.23.5",
27 | "@nutui/nutui-taro": "^4.2.3",
28 | "@tarojs/components": "3.6.20",
29 | "@tarojs/helper": "3.6.20",
30 | "@tarojs/plugin-framework-vue3": "3.6.20",
31 | "@tarojs/plugin-html": "3.6.20",
32 | "@tarojs/plugin-platform-h5": "^3.6.20",
33 | "@tarojs/plugin-platform-weapp": "3.6.20",
34 | "@tarojs/runtime": "3.6.20",
35 | "@tarojs/shared": "3.6.20",
36 | "@tarojs/taro": "3.6.20",
37 | "@vue3-oop/taro-hooks": "^1.0.1",
38 | "axios": "^1.6.2",
39 | "injection-js": "^2.4.0",
40 | "path-to-regexp": "^6.2.1",
41 | "ts-essentials": "^9.4.1",
42 | "tslib": "^2.6.2",
43 | "vue": "^3.3.9",
44 | "vue3-oop": "^1.0.6"
45 | },
46 | "devDependencies": {
47 | "@babel/core": "^7.23.5",
48 | "@commitlint/cli": "^18.4.3",
49 | "@commitlint/config-conventional": "^18.4.3",
50 | "@tarojs/cli": "^3.6.20",
51 | "@tarojs/plugin-http": "^3.6.20",
52 | "@tarojs/plugin-mock": "^0.0.9",
53 | "@tarojs/webpack5-runner": "3.6.20",
54 | "@types/lodash": "^4.14.202",
55 | "@types/node": "^20.10.1",
56 | "@types/webpack-env": "^1.18.4",
57 | "@typescript-eslint/eslint-plugin": "^6.13.1",
58 | "@typescript-eslint/parser": "^6.13.1",
59 | "@vue/babel-plugin-jsx": "^1.1.5",
60 | "@vue/compiler-sfc": "^3.3.9",
61 | "@vue3-oop/taro-plugin": "^1.0.5",
62 | "babel-plugin-import": "^1.13.8",
63 | "babel-preset-taro": "3.6.20",
64 | "cross-env": "^7.0.3",
65 | "css-loader": "6.8.1",
66 | "eslint": "~8.54.0",
67 | "eslint-config-prettier": "^8.9.0",
68 | "eslint-config-taro": "3.6.20",
69 | "eslint-plugin-prettier": "^4.0.0",
70 | "eslint-plugin-vue": "^9.19.2",
71 | "lint-staged": "^15.1.0",
72 | "lodash": "^4.17.21",
73 | "postcss": "^8.4.31",
74 | "postcss-preset-env": "^9.3.0",
75 | "prettier": "^2.8.8",
76 | "prettier-plugin-tailwindcss": "^0.4.1",
77 | "serve": "^14.2.1",
78 | "simple-git-hooks": "^2.9.0",
79 | "style-loader": "3.3.3",
80 | "swagger-schema-official": "2.0.0-bab6bed",
81 | "tailwindcss": "~3.3.5",
82 | "tailwindcss-rem2px-preset": "^1.0.3",
83 | "ts-gear": "^4.11.7",
84 | "ts-node": "^10.9.1",
85 | "typescript": "^5.3.2",
86 | "vite": "^4.4.9",
87 | "vue-loader": "^17.3.1",
88 | "weapp-tailwindcss": "^3.0.3",
89 | "webpack": "^5.89.0"
90 | },
91 | "commitlint": {
92 | "extends": [
93 | "@commitlint/config-conventional"
94 | ]
95 | },
96 | "simple-git-hooks": {
97 | "pre-commit": "pnpm exec lint-staged",
98 | "commit-msg": "pnpm exec commitlint -e \"$@\""
99 | },
100 | "lint-staged": {
101 | "*.{ts,tsx}": [
102 | "eslint --fix"
103 | ],
104 | "*.{css,scss,html,json}": [
105 | "prettier --write"
106 | ]
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | 'postcss-preset-env': {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "miniprogramRoot": "dist/",
3 | "projectname": "WechatAppDemo",
4 | "description": "WechatAppDemo",
5 | "appid": "wx3f627368f76b01c7",
6 | "setting": {
7 | "urlCheck": false,
8 | "es6": false,
9 | "postcss": false,
10 | "minified": false,
11 | "checkSiteMap": false,
12 | "babelSetting": {
13 | "ignore": [],
14 | "disablePlugins": [],
15 | "outputPath": ""
16 | },
17 | "condition": false,
18 | "minifyWXSS": false,
19 | "ignoreUploadUnusedFiles": false,
20 | "ignoreDevUnusedFiles": false
21 | },
22 | "compileType": "miniprogram",
23 | "libVersion": "3.1.3",
24 | "srcMiniprogramRoot": "dist/",
25 | "packOptions": {
26 | "ignore": [],
27 | "include": []
28 | },
29 | "condition": {},
30 | "editorSetting": {
31 | "tabIndent": "auto",
32 | "tabSize": 4
33 | },
34 | "simulatorPluginLibVersion": {}
35 | }
--------------------------------------------------------------------------------
/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 | "projectname": "vue3-taro",
4 | "setting": {
5 | "compileHotReLoad": false,
6 | "bigPackageSizeSupport": true
7 | },
8 | "libVersion": "3.1.3"
9 | }
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agileago/vue3-taro/6f59b82f6204fc907730c8512d125466c0f0e9f1/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/api/http.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { abcRequest } from '@/api/http'
2 | import type { AxiosResponse } from 'axios'
3 | import config from '@/config'
4 |
5 | // 过滤返回数据
6 | function handleResponseSuccess(res: AxiosResponse) {
7 | return res.data
8 | }
9 | // 处理错误
10 | function handleResponseError(error: any) {
11 | // 后端返回401直接到登录
12 | if (error?.response?.status === 401) {
13 | location.href = config.BASE_ROUTE + 'login'
14 | return
15 | }
16 | if (error?.response) {
17 | const data = error.response.data
18 | const responseError = new Error(data?.message || data)
19 | // @ts-ignore
20 | responseError.code = data?.code
21 | // @ts-ignore
22 | responseError.detail = data
23 |
24 | throw responseError
25 | }
26 |
27 | throw error
28 | }
29 |
30 | abcRequest.interceptors.response.use(handleResponseSuccess)
31 | abcRequest.interceptors.response.use(undefined, handleResponseError)
32 |
--------------------------------------------------------------------------------
/src/api/http.ts:
--------------------------------------------------------------------------------
1 | import type { AxiosInstance, AxiosRequestConfig } from 'axios'
2 | import axios from 'axios'
3 | import * as pathToRegexp from 'path-to-regexp'
4 | import type { RequestParameter } from 'ts-gear'
5 | import config from '@/config'
6 |
7 | // region 基础方法 基本不需要动
8 |
9 | // 此类型主要用于简化响应类型
10 | type ReturnEntityType = T
11 | export type { AxiosRequestConfig }
12 | /**
13 | * 解析url中的参数 /abc/:id 替换id
14 | * @param url
15 | * @param option
16 | */
17 | export const parseUrl = (url: string, option?: RequestParameter): string => {
18 | if (option) {
19 | if (option.path) {
20 | Object.getOwnPropertyNames(option.path).forEach(k => {
21 | option.path[k] = encodeURIComponent(String(option.path[k]))
22 | })
23 | url = pathToRegexp.compile(url)(option.path)
24 | }
25 | }
26 | return url
27 | }
28 | /**
29 | * 转换成axios里面的配置
30 | * @param url
31 | * @param option
32 | */
33 | export function interceptRequest(
34 | url: string,
35 | option?: RequestParameter,
36 | ): [string, AxiosRequestConfig] {
37 | try {
38 | url = parseUrl(url, option)
39 | } catch (e: any) {
40 | throw new Error(e.message)
41 | }
42 | option = option || {}
43 | const requestOption: AxiosRequestConfig = {
44 | method: option.method || 'get',
45 | }
46 | if (option.header) {
47 | requestOption.headers = option.header
48 | }
49 | if (option.body) {
50 | requestOption.data = option.body
51 | }
52 | if (option.formData) {
53 | const formData = new FormData()
54 | Object.keys(option.formData).forEach(k => {
55 | formData.append(k, option?.formData[k])
56 | })
57 | requestOption.data = formData
58 | }
59 | if (option.query) {
60 | requestOption.params = option.query
61 | }
62 | return [url, requestOption]
63 | }
64 | /**
65 | * 创建请求方法
66 | * @param ax
67 | */
68 | export const createRequester = (ax: AxiosInstance) => {
69 | return function (apiUrl: string, param: RequestParameter, config: AxiosRequestConfig = {}) {
70 | // eslint-disable-next-line prefer-const
71 | let [url, option] = interceptRequest(apiUrl, param)
72 | option = { url, ...option, ...config }
73 | return ax.request(option) as unknown as Promise>
74 | }
75 | }
76 | // endregion
77 |
78 | // 创建request 对request进行拦截各种操作
79 | export const abcRequest = axios.create({
80 | baseURL: config.API,
81 | })
82 |
83 | export const abcRequester = createRequester(abcRequest)
84 |
--------------------------------------------------------------------------------
/src/api/tsg.config.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * each project will use the "requester" function when request remote api
3 | * so this file would be included into your source file when compile
4 | * */
5 | import type { Project } from 'ts-gear'
6 | import { generateRequestFunctionName } from 'ts-gear/lib/tool/generateRequestFunctionName'
7 | // @ts-ignore
8 | import prettier from '../../.prettierrc'
9 | import * as _ from 'lodash'
10 |
11 | // 调用的所有api
12 | const projects: Partial[] = [
13 | {
14 | name: 'abc',
15 | source: 'http://211.154.163.74:21191/we_uc/openapi_json',
16 | },
17 | ]
18 |
19 | /**
20 | * 生成请求代码样例:
21 | * (option?: RequestType, config?: AxiosRequestConfig) => requester('/url', {method: 'post', ...option}, config)
22 | */
23 | const requestTemplate: Project['generateRequestFunction'] = function (arg) {
24 | // 适配 fastApi 路径参数需要被path-to-regexp正确解析
25 | const path = arg.pathname.replace(/{(\w+?)}/g, (s, p1) => `:${p1}`)
26 | let parameter = arg.parameterTypeName
27 | ? `option${!arg.parameterRequired ? '?' : ''}: ${arg.parameterTypeName}, `
28 | : ''
29 | parameter += 'config?: AxiosRequestConfig'
30 | const body = `requester<${arg.responseSuccessTypeName}>('${path}', { method: '${
31 | arg.httpMethod
32 | }' ${arg.parameterTypeName ? ', ...option' : ''}}, config)`
33 | return `(${parameter}) => ${body}`
34 | }
35 | function createStandardProjects(projects: Partial[]) {
36 | return projects.map(p => {
37 | const { name } = p
38 | return {
39 | dest: '../api',
40 | keepGeneric: false,
41 | shouldExportResponseType: false,
42 | shouldExportRequestOptionType: false,
43 | shouldForceSkipRequestHeaderOption: true,
44 | importRequesterStatement: `import { ${
45 | _.camelCase(name) + 'Requester'
46 | }, type AxiosRequestConfig } from "../http"`,
47 | prettierConfig: prettier,
48 | // 生成请求函数名称
49 | generateRequestFunctionName(arg) {
50 | return (
51 | 'api' + _.upperFirst(_.camelCase(name)) + _.upperFirst(generateRequestFunctionName(arg))
52 | )
53 | },
54 | generateRequestFunction: requestTemplate,
55 | ...p,
56 | } as Project
57 | })
58 | }
59 |
60 | export default createStandardProjects(projects)
61 |
--------------------------------------------------------------------------------
/src/app.config.ts:
--------------------------------------------------------------------------------
1 | export default defineAppConfig({
2 | pages: ['module/demo/first/index', 'module/demo/two/index'],
3 | window: {
4 | navigationBarBackgroundColor: '#fff',
5 | navigationBarTitleText: '小程序Taro1',
6 | navigationBarTextStyle: 'black',
7 | },
8 | subpackages: [],
9 | })
10 |
--------------------------------------------------------------------------------
/src/app.ts:
--------------------------------------------------------------------------------
1 | import './polyfill'
2 | import '@abraham/reflection'
3 | import './theme/app.scss'
4 | import { createApp } from 'vue'
5 | import { setup } from '@/setup'
6 | import App from './main'
7 |
8 | const app = createApp(App)
9 | setup(app)
10 | export default app
11 |
--------------------------------------------------------------------------------
/src/common/decorator/catch/index.ts:
--------------------------------------------------------------------------------
1 | import Taro from '@tarojs/taro'
2 |
3 | /**
4 | * 自动处理异常装饰器,适合异常后无后续处理的请求
5 | * @param msg 自定义提示消息
6 | * @param loadingKey 自定义loading
7 | */
8 | export function Catch(loading = true, loadingKey?: string | ((obj: any) => void)): MethodDecorator {
9 | return function (target: any, key: string | symbol, desc: PropertyDescriptor) {
10 | const fn = desc.value
11 | desc.value = async function (this: any, ...args: any[]) {
12 | try {
13 | loading && Taro.showLoading()
14 | return await fn.apply(this, args)
15 | } catch (e: any) {
16 | console.error(e)
17 | if (e.message) {
18 | Taro.showToast({
19 | icon: 'error',
20 | title: e.message,
21 | duration: 4000,
22 | })
23 | }
24 | } finally {
25 | loading && Taro.hideLoading()
26 | if (loadingKey) {
27 | if (typeof loadingKey === 'string') this[loadingKey] = false
28 | else loadingKey(this)
29 | }
30 | }
31 | }
32 | return desc
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/component/if/index.tsx:
--------------------------------------------------------------------------------
1 | import type { SetupContext } from 'vue'
2 |
3 | export interface IfProps {
4 | /*判断条件*/
5 | condition: any
6 | }
7 | export function If(props: IfProps, ctx: SetupContext) {
8 | if (!props.condition) return null
9 | return ctx.slots.default?.()
10 | }
11 |
--------------------------------------------------------------------------------
/src/config/config.default.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 默认本地开发配置
3 | */
4 | export default class Config {
5 | env = process.env.VUE_APP_MODE
6 | // 基础路由 /app/
7 | BASE_ROUTE = process.env.VUE_APP_BASE_ROUTE
8 | // 静态资源路径
9 | BASE_URL = process.env.VUE_APP_BASE_URL
10 | HOST = 'http://localhost:9527'
11 | // 后端API
12 | get API() {
13 | return this.HOST + '/api'
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/config/config.develop.ts:
--------------------------------------------------------------------------------
1 | import Config from '@/config/config.default'
2 |
3 | export default class extends Config {}
4 |
--------------------------------------------------------------------------------
/src/config/config.release.ts:
--------------------------------------------------------------------------------
1 | import Config from '@/config/config.default'
2 |
3 | export default class extends Config {}
4 |
--------------------------------------------------------------------------------
/src/config/config.trial.ts:
--------------------------------------------------------------------------------
1 | import Config from '@/config/config.default'
2 |
3 | export default class extends Config {}
4 |
--------------------------------------------------------------------------------
/src/config/index.ts:
--------------------------------------------------------------------------------
1 | import Config from './config.default'
2 | import Develop from './config.develop'
3 | import Release from './config.release'
4 | import Taro from '@tarojs/taro'
5 |
6 | let TargetConf = Config
7 |
8 | const { miniProgram } = Taro.getAccountInfoSync()
9 |
10 | switch (miniProgram.envVersion) {
11 | case 'develop':
12 | TargetConf = Develop
13 | break
14 | case 'trial':
15 | TargetConf = Develop
16 | break
17 | case 'release':
18 | TargetConf = Release
19 | break
20 | }
21 |
22 | const config = new TargetConf()
23 |
24 | export default config
25 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { VueComponent } from 'vue3-oop'
2 | // 全局服务挂载
3 | export default class App extends VueComponent {}
4 |
--------------------------------------------------------------------------------
/src/module/demo/first/index.config.ts:
--------------------------------------------------------------------------------
1 | export default definePageConfig({
2 | navigationBarBackgroundColor: '#781d1d',
3 | navigationBarTitleText: 'demo第一页',
4 | })
5 |
--------------------------------------------------------------------------------
/src/module/demo/first/index.module.scss:
--------------------------------------------------------------------------------
1 | .title {
2 | color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/src/module/demo/first/index.tsx:
--------------------------------------------------------------------------------
1 | import { Hook, Link, VueComponent } from 'vue3-oop'
2 | import { MiniHook } from '@vue3-oop/taro-hooks'
3 | import { abcRequest } from '@/api/http'
4 | import { useRouter } from '@tarojs/taro'
5 | import { Button } from '@tarojs/components'
6 |
7 | export default class First extends VueComponent {
8 | router = useRouter()
9 | @MiniHook('Load')
10 | load() {
11 | abcRequest('/abc', { method: 'get', params: { a: 1 } }).then(res => console.log('res', res))
12 | }
13 |
14 | @Hook('Mounted')
15 | handlePhone() {
16 | console.log(111, this.abc)
17 | }
18 |
19 | @Link() abc?: HTMLButtonElement
20 |
21 | render() {
22 | return (
23 |
24 |
aaa
25 |
33 |
34 | )
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/module/demo/two/index.config.ts:
--------------------------------------------------------------------------------
1 | export default definePageConfig({
2 | navigationBarBackgroundColor: '#56cea0',
3 | navigationBarTitleText: 'webview',
4 | })
5 |
--------------------------------------------------------------------------------
/src/module/demo/two/index.module.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agileago/vue3-taro/6f59b82f6204fc907730c8512d125466c0f0e9f1/src/module/demo/two/index.module.scss
--------------------------------------------------------------------------------
/src/module/demo/two/index.tsx:
--------------------------------------------------------------------------------
1 | import { VueComponent } from 'vue3-oop'
2 | import { WebView } from '@tarojs/components'
3 |
4 | export default class Two extends VueComponent {
5 | render() {
6 | return
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/polyfill.ts:
--------------------------------------------------------------------------------
1 | const obj = {
2 | Array: Array,
3 | Date: Date,
4 | Error: Error,
5 | Function: Function,
6 | Math: Math,
7 | Object: Object,
8 | RegExp: RegExp,
9 | String: String,
10 | TypeError: TypeError,
11 | setTimeout: setTimeout,
12 | clearTimeout: clearTimeout,
13 | setInterval: setInterval,
14 | clearInterval: clearInterval,
15 | }
16 |
17 | // @ts-ignore
18 | Object.assign(global, obj)
19 |
20 | // @ts-ignore
21 | if (typeof window === 'object' && typeof window.global === 'object') {
22 | // @ts-ignore
23 | Object.assign(window.global, obj)
24 | }
25 | export {}
26 |
--------------------------------------------------------------------------------
/src/setup/index.ts:
--------------------------------------------------------------------------------
1 | import type { App } from 'vue'
2 | import '@/api/http.interceptor'
3 |
4 | export function setup(app: App) {}
5 |
--------------------------------------------------------------------------------
/src/theme/app.scss:
--------------------------------------------------------------------------------
1 | @import 'tailwindcss/base';
2 | @import 'tailwindcss/components';
3 | @import 'tailwindcss/utilities';
4 |
5 | * {
6 | margin: 0;
7 | padding: 0;
8 | box-sizing: border-box;
9 | }
10 |
11 | page,
12 | html,
13 | body {
14 | font-family: -apple-system, 'Noto Sans', 'Helvetica Neue', Helvetica, 'Nimbus Sans L', Arial,
15 | 'Liberation Sans', 'PingFang SC', 'Hiragino Sans GB', 'Noto Sans CJK SC', 'Source Han Sans SC',
16 | 'Source Han Sans CN', 'Microsoft YaHei', 'Wenquanyi Micro Hei', 'WenQuanYi Zen Hei', 'ST Heiti',
17 | SimHei, 'WenQuanYi Zen Hei Sharp', sans-serif;
18 | /* prettier-ignore */
19 | max-width: 750PX;
20 | margin: 0 auto;
21 | height: 100%;
22 | }
23 |
24 | view,
25 | scroll-view {
26 | box-sizing: border-box;
27 | }
28 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ['./src/**/*.{ts,tsx}'],
4 | theme: {
5 | extend: {
6 | },
7 | },
8 | corePlugins: {
9 | preflight: false
10 | },
11 | plugins: [],
12 | presets: [
13 | // rem space to px
14 | require('tailwindcss-rem2px-preset'),
15 | ],
16 | }
17 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2021",
4 | "module": "ESNext",
5 | "strict": true,
6 | "preserveConstEnums": true,
7 | "moduleResolution": "node",
8 | "experimentalDecorators": true,
9 | "emitDecoratorMetadata": true,
10 | "useDefineForClassFields": false,
11 | "verbatimModuleSyntax": true,
12 | "skipLibCheck": true,
13 | "skipDefaultLibCheck": true,
14 | "noImplicitAny": false,
15 | "allowSyntheticDefaultImports": true,
16 | "esModuleInterop": true,
17 | "resolveJsonModule": true,
18 | "allowJs": false,
19 | "importHelpers": true,
20 | "outDir": "lib",
21 | "sourceMap": true,
22 | "baseUrl": ".",
23 | "rootDir": ".",
24 | "jsx": "preserve",
25 | "types": ["@tarojs/taro", "webpack-env", "vite/client", "vue/jsx"],
26 | "paths": {
27 | "@/*": ["src/*"]
28 | }
29 | },
30 | "exclude": ["node_modules", "dist"]
31 | }
32 |
--------------------------------------------------------------------------------