当前位置: 首页 > news >正文

uniapp-uniapp + vue3 + pinia 搭建uniapp模板

使用技术

⚡️uni-app, Vue3, Vite, pnpm

📦 组件自动化引入

🍍 使用 Pinia 的状态管理

🎨 tailwindcss - 高性能且极具灵活性的即时原子化 CSS 引擎

😃 各种图标集为你所用

🔥 使用 新的 <script setup> 语法

📥 API 自动加载 - 直接使用 Composition API 无需引入

🌍 API 采用模块化自动导入方式 根据demo.js文件设置接口,以API_xxx_method的方式命名,在请求时无需导入 直接使用useRequest()函数返

要求

Vue3/Vite版要求 node 版本>=18.0.0

前期准备

安装pnpm

// 全局安装
npm install pnpm -g 
// 切换淘宝源
pnpm config set registry https://registry.npmmirror.com/
// 查看源
pnpm config get registry

pnpm 跟 npm 和 yarn 的差距就是把原来每个项目安装 modules 放到统一的文件夹中,通过符号链接(软连接)和硬链接,注意项目要和 pnpm 统一存依赖的 modules 同盘,不然就等于丢失了 pnpm 的优势。

安装uni-app脚手架

点击下载 默认模板,或者通过下面命令行拉取

# 创建以 typescript 开发的工程  
npx degit dcloudio/uni-preset-vue#vite-ts vue3-vite-uni# 创建以非 typescript 开发的工程  
npx degit dcloudio/uni-preset-vue#vite my-vue3-project

然后就会默认得到以下结构的项目👇:

依赖安装

进入到项目根目录后,启动集成终端(vscode),输入以下命令

pnpm install

如有报下面错误👇

This modules directory was created using the following registries configuration:{“default”:“https://registry.npmjs.org/”}. The current configuration is {“default”:“https://registry.npm.taobao.org/”}. To recreate the modules directory using the new settings, run “pnpm install -g”.

解决方案 下载源切换

pnpm config set registry https://registry.npmjs.org

启动项目,测试是否可以成功启动

执行该命令 会将此项目编译成微信小程序项目,该命令会持续监听修改并进行热更新

pnpm dev:mp-weixin

执行后会出现 dist\dev\mp-weixin文件夹结构

将此目录下的mp-weixin微信开发者工具进行打开

如未安装点击下面链接下载安装即可👇
微信开发者工具下载地址与更新日志 | 微信开放文档

启动运行成功后出现以下界面:

就说明项目已经成功运行了

配置自动化导入

依赖安装

pnpm i unplugin-auto-import -D

在vite.config.js中配置

vite.config.js

import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import autoImport from 'unplugin-auto-import/vite'// https://vitejs.dev/config/
export default defineConfig({plugins: [uni(),autoImport({imports: ['vue', 'uni-app', 'pinia'],dts: false})],
})

配置完后 重新执行pnpm dev:mp-weixin此时会生成auto-imports.d.ts文件

此时在pages/index/index.vue中不用引入直接可以使用vue的api

<script setup>
const title = ref('Hello World!')
</script>

然后只需返回微信开发者工具查看效果即可

因为这是实时更新的,如果

出现如下效果说明配置成功

引入 prerttier + eslint + stylelint

感兴趣的可以根据以下进行配置

我这里暂时没有做这个的配置和安装

插件安装

安装相关依赖包👇

pnpm add -D eslint @babel/eslint-parser eslint-config-airbnb-base eslint-config-prettier eslint-plugin-import eslint-plugin-prettier eslint-plugin-vue vue-global-api stylelint stylelint-scss stylelint-config-standard-scss stylelint-config-prettier

.editorconfig 配置

新建 .editorconfig 文件在项目根目录下

配置如下

# .editorconfig 文件
root = true[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
indent_style = space # 缩进风格(tab | space)
indent_size = 2 # 缩进大小
end_of_line = lf # 控制换行类型(lf | cr | crlf)
trim_trailing_whitespace = true # 去除行首的任意空白字符
insert_final_newline = true # 始终在文件末尾插入一个新行[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off # 关闭最大行长度限制
trim_trailing_whitespace = false # 关闭末尾空格修剪

.prettierrc.cjs 配置

新建 .prettierrc.cjs 文件在项目根目录下

module.exports = {// 一行的字符数,如果超过会进行换行,默认为80,官方建议设100-120其中一个数printWidth: 100,// 一个tab代表几个空格数,默认就是2tabWidth: 2,// 启用tab取代空格符缩进,默认为falseuseTabs: false,// 行尾是否使用分号,默认为true(添加理由:更加容易复制添加数据,不用去管理尾行)semi: false,vueIndentScriptAndStyle: true,// 字符串是否使用单引号,默认为false,即使用双引号,建议设true,即单引号singleQuote: true,// 给对象里的属性名是否要加上引号,默认为as-needed,即根据需要决定,如果不加引号会报错则加,否则不加quoteProps: 'as-needed',// 是否使用尾逗号,有三个可选值"<none|es5|all>"trailingComma: 'none',// 在jsx里是否使用单引号,你看着办jsxSingleQuote: true,// 对象大括号直接是否有空格,默认为true,效果:{ foo: bar }bracketSpacing: true,proseWrap: 'never',htmlWhitespaceSensitivity: 'strict',endOfLine: 'auto',
}

.eslintrc.cjs配置

新建 .eslintrc.cjs 文件在项目根目录下

// .eslintrc.cjs 文件
module.exports = {env: {browser: true,es2021: true,node: true,},extends: ['eslint:recommended','plugin:vue/vue3-essential',// eslint-plugin-import 插件, @see https://www.npmjs.com/package/eslint-plugin-import'plugin:import/recommended',// eslint-config-airbnb-base 插件, tips: 本插件也可以替换成 eslint-config-standard'airbnb-base',// 1. 接入 prettier 的规则'prettier','plugin:prettier/recommended','vue-global-api',],overrides: [{env: {node: true,},files: ['.eslintrc.{js}'],parserOptions: {sourceType: 'script',},},],parserOptions: {ecmaVersion: 'latest',parser: '@babel/eslint-parser',sourceType: 'module',},plugins: ['@babel/eslint-parser','vue',// 2. 加入 prettier 的 eslint 插件'prettier',// eslint-import-resolver-typescript 插件,@see https://www.npmjs.com/package/eslint-import-resolver-typescript'import',],rules: {// 3. 注意要加上这一句,开启 prettier 自动修复的功能'prettier/prettier': 'error',// turn on errors for missing imports'import/no-unresolved': 'off',// 对后缀的检测,否则 import 一个ts文件也会报错,需要手动添加'.ts', 增加了下面的配置后就不用了'import/extensions': ['error','ignorePackages',{ js: 'never', jsx: 'never', ts: 'never', tsx: 'never' },],// 只允许1个默认导出,关闭,否则不能随意export xxx'import/prefer-default-export': ['off'],'no-console': ['off'],// 'no-unused-vars': ['off'],// '@typescript-eslint/no-unused-vars': ['off'],// 解决vite.config.ts报错问题'import/no-extraneous-dependencies': 'off','no-plusplus': 'off','no-shadow': 'off','vue/multi-word-component-names': 'off','@typescript-eslint/no-explicit-any': 'off',},// eslint-import-resolver-typescript 插件,@see https://www.npmjs.com/package/eslint-import-resolver-typescriptsettings: {'import/parsers': {'@typescript-eslint/parser': ['.ts', '.tsx'],},'import/resolver': {typescript: {},},},globals: {uni: true,UniApp: true,wx: true,WechatMiniprogram: true,getCurrentPages: true,UniHelper: true,Page: true,App: true,},
}

.stylelintrc.cjs 配置

新建 .stylelintrc.cjs 文件在项目根目录下

// .stylelintrc.cjs 文件
module.exports = {root: true,extends: ['stylelint-config-standard','stylelint-config-standard-scss', // tips: 本插件也可以替换成 stylelint-config-recommended-scss'stylelint-config-recommended-vue/scss','stylelint-config-html/vue','stylelint-config-recess-order',],overrides: [// 扫描 .vue/html 文件中的<style>标签内的样式{files: ['**/*.{vue,html}'],customSyntax: 'postcss-html',},{files: ['**/*.{css,scss}'],customSyntax: 'postcss-scss',},],// 自定义规则rules: {// 允许 global 、export 、v-deep等伪类'selector-pseudo-class-no-unknown': [true,{ignorePseudoClasses: ['global', 'export', 'v-deep', 'deep'],},],'unit-no-unknown': [true,{ignoreUnits: ['rpx'],},],// 处理小程序page标签不认识的问题'selector-type-no-unknown': [true,{ignoreTypes: ['page'],},],'comment-empty-line-before': 'never',},
}

.eslintrc-auto-import.json 配置

{"globals": {"Component": true,"ComponentPublicInstance": true,"ComputedRef": true,"EffectScope": true,"ExtractDefaultPropTypes": true,"ExtractPropTypes": true,"ExtractPublicPropTypes": true,"InjectionKey": true,"PropType": true,"Ref": true,"VNode": true,"WritableComputedRef": true,"acceptHMRUpdate": true,"computed": true,"createApp": true,"createPinia": true,"customRef": true,"defineAsyncComponent": true,"defineComponent": true,"defineStore": true,"effectScope": true,"getActivePinia": true,"getCurrentInstance": true,"getCurrentScope": true,"h": true,"inject": true,"isProxy": true,"isReactive": true,"isReadonly": true,"isRef": true,"mapActions": true,"mapGetters": true,"mapState": true,"mapStores": true,"mapWritableState": true,"markRaw": true,"nextTick": true,"onActivated": true,"onAddToFavorites": true,"onBackPress": true,"onBeforeMount": true,"onBeforeUnmount": true,"onBeforeUpdate": true,"onDeactivated": true,"onError": true,"onErrorCaptured": true,"onHide": true,"onLaunch": true,"onLoad": true,"onMounted": true,"onNavigationBarButtonTap": true,"onNavigationBarSearchInputChanged": true,"onNavigationBarSearchInputClicked": true,"onNavigationBarSearchInputConfirmed": true,"onNavigationBarSearchInputFocusChanged": true,"onPageNotFound": true,"onPageScroll": true,"onPullDownRefresh": true,"onReachBottom": true,"onReady": true,"onRenderTracked": true,"onRenderTriggered": true,"onResize": true,"onScopeDispose": true,"onServerPrefetch": true,"onShareAppMessage": true,"onShareTimeline": true,"onShow": true,"onTabItemTap": true,"onThemeChange": true,"onUnhandledRejection": true,"onUnload": true,"onUnmounted": true,"onUpdated": true,"provide": true,"reactive": true,"readonly": true,"ref": true,"resolveComponent": true,"setActivePinia": true,"setMapStoreSuffix": true,"shallowReactive": true,"shallowReadonly": true,"shallowRef": true,"storeToRefs": true,"toRaw": true,"toRef": true,"toRefs": true,"toValue": true,"triggerRef": true,"unref": true,"useAttrs": true,"useCssModule": true,"useCssVars": true,"useRequest": true,"useSlots": true,"watch": true,"watchEffect": true,"watchPostEffect": true,"watchSyncEffect": true}
}

引入 husky + lint-staged + commitlint

感兴趣的可以根据以下进行配置

我这里暂时没有做这个的配置和安装

基本配置

说明

husky 用于git提交的钩子

lint-staged 一个在 git 暂存文件上(也就是被git add后的文件)运行已配置的格式工具;比如eslint、stylelintrc、…

commitlint 检查您的提交消息是否符合 常规提交格式 (Conventional commit format)

正确的提交格式:(): ,type 和 subject 默认必填

安装相关依赖包👇

pnpm i -D husky@6 lint-staged commitlint @commitlint/cli @commitlint/config-conventional

执行 npx husky install
并且在 package.json的scripts里面增加 "prepare": "husky install",(其他人安装后会自动执行) 根目录会生成 .hushy 文件夹。

.gitignore

_

commit-msg

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"npx --no-install commitlint --edit 

pre-commit

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"npx --no-install -- lint-staged

package.josn 增加如下属性👇:

...
"scripts": {..."prepare": "husky install",
},
"lint-staged": {"**/*.{html,vue,ts,cjs,json,md}": ["prettier --write"],"**/*.{vue,js,ts,jsx,tsx}": ["eslint --fix"],"**/*.{vue,css,scss,html}": ["stylelint --fix"]
}

根目录新增 .commitlintrc.cjs,内容如下👇

module.exports = {extends: ['@commitlint/config-conventional'],rules: {'type-enum': [2,'always',['feat','fix','perf','style','docs','test','refactor','build','ci','init','chore','revert','wip','workflow','types','release',],],'subject-case': [0],},
}

通过下面命令在钩子文件中添加内容👇

npx husky add .husky/pre-commit "npx --no-install -- lint-staged"
npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"

Commitizen & cz-git

说明
commitizen 基于Node.js的 git commit 命令行工具,辅助生成标准化规范化的 commit message
cz-customizable 标准输出格式的 commitizen 适配器

安装依赖包👇

pnpm add -D commitizen cz-customizable

修改 package.json指定使用的适配器

...
"scripts": {..."cz": "git-cz"
},"config": {"commitizen": {"path": "node_modules/cz-customizable"}}

更改提示消息模板 .cz-config.js

.cz-config.js

module.exports = {types: [{ value: 'feat', name: '✨ feat:     新功能' },{ value: 'fix', name: '🐛 fix:      修复' },{ value: 'init', name: '🎉 Init:     初始化' },{ value: 'docs', name: '📝 docs:     文档变更' },{ value: 'style', name: '💄 style:    代码格式(不影响代码运行的变动)' },{value: 'refactor',name: '♻️  refactor: 重构(既不是增加feature,也不是修复bug)',},{ value: 'perf', name: '⚡️ perf:     性能优化' },{ value: 'test', name: '✅ test:     增加测试' },{ value: 'revert', name: '⏪️ Revert:   回退' },{ value: 'build', name: '🚀‍ build:    构建过程或辅助工具的变动' },{ value: 'ci', name: '👷 ci:       CI 配置' },],// 消息步骤messages: {type: '请选择提交类型:',subject: '请简要描述提交(必填):',customScope: '请输入修改范围(可选):',body: '请输入详细描述(可选):',breaking: '列出任何BREAKING CHANGES(可选)',footer: '请输入要关闭的issue(可选):',confirmCommit: '确认使用以上信息提交吗?',},allowBreakingChanges: ['feat', 'fix'],skipQuestions: ['customScope'],subjectLimit: 72,
}

检测

在命令行中输入👇

git add .
pnpm cz

然后会出现本次提交选项

选择本次提交的类型,按要求写入然后回车即可

配置tailwindcss

中文官网地址:安装 - TailwindCSS中文文档 | TailwindCSS中文网

方式一

安装插件

pnpm install -D tailwindcss :安装 tailwindcss 插件

npx tailwindcss init :初始化生成 tailwind.config.js 文件

pnpm install postcss :用于将 CSS 转换为 JavaScript 插件的工具,允许使用插件来处理 CSS 文件。tailwindcss 本身是一个基于 PostCSS 的工具,因此需要 PostCSS 来解析和处理 Tailwind 的 CSS 指令。

pnpm install autoprefixer

  • 自动添加浏览器前缀: Autoprefixer 是一个 PostCSS 插件,它根据浏览器的兼容性信息,自动为 CSS 规则添加所需的浏览器前缀(例如 -webkit--moz- 等)。这确保了生成的 CSS 能够在尽可能多的浏览器中正常工作。
  • 与 Tailwind 的集成: 虽然 Tailwind 提供了许多实用的 CSS 类,但为了确保这些类在所有浏览器中都能正确渲染,Autoprefixer 是必不可少的。
配置 tailwind.config.js 文件
/** @type {import('tailwindcss').Config} */
export default {content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],darkMode: "media", // or 'media' or 'class'theme: {extend: {},},variants: {extend: {},},plugins: [],
};

配置 postcss.config.js 文件
export default {plugins: {tailwindcss: {},autoprefixer: {},},
};

在 main.js 里引入

这里首先需要在 static 目录下新建,style子目录,并在该子目录下新建 tailwind.css 文件

tailwind.css 文件配置如下:

@tailwind base;
@tailwind components;
@tailwind utilities;

最后需要在 main.js 里引入该文件

import "./static/style/tailwind.css";

在页面中检验 tailwindcss 是否安装成功

<view class="bg-gray-100 py-6 px-4 rounded-lg"><h2 class="text-xl font-bold mb-2">Title</h2><view class="text-gray-700">Description text...</view>
</view>

通过以上方式可能不行,会报错

那么下面我提供了另一种方式,亲测有效

方式二(推荐)

插件安装
pnpm install -D tailwindcss postcss autoprefixe

首先,执行 npx tailwindcss init -p 命令会给我们自动生成 tailwind.config.js 文件在项目根目录下

然后,在tailwind.config.js里做如下配置:

/** @type {import('tailwindcss').Config} */
module.exports = {content: ['./index.html', './src/**/*.{js,ts,jsx,tsx,vue}'],theme: {extend: {},},plugins: [],
} 

其次,在App.vue中引入

<style>
/*每个页面公共css */
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
</style>

再者在vite.config.js中进行配置

vite.config.js

import { defineConfig } from "vite";
import tailwindcss from 'tailwindcss';
import uni from "@dcloudio/vite-plugin-uni";export default defineConfig({css: {postcss: {plugins: [tailwindcss(),],},},plugins: [uni()],
});

接着,为了适配小程序,需要安装 pnpm i @uni-helper/vite-plugin-uni-tailwind

在vite.config.js中进行配置

// vite.config.js
import { defineConfig } from "vite";
import tailwindcss from 'tailwindcss';
import uni from "@dcloudio/vite-plugin-uni";
import uniTailwind from '@uni-helper/vite-plugin-uni-tailwind';export default defineConfig({css: {postcss: {plugins: [tailwindcss(),],},},plugins: [uni(), uniTailwind()],
});

最后, rem to rpx,由于tailwind默认是rem单位,需要转到rpx

在vite.config.js中进行配置

//tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {content: ['./index.html', './src/**/*.{js,ts,jsx,tsx,vue}'],theme: {extend: {},},plugins: [],presets: [require('tailwindcss-rem2px-preset').createPreset({// 32 意味着 1rem = 32rpxfontSize: 32,// 转化的单位,可以变成 px / rpxunit: 'rpx'})],
}

目前的 vite.config.js

import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import autoImport from 'unplugin-auto-import/vite'import tailwindcss from 'tailwindcss';
import uniTailwind from '@uni-helper/vite-plugin-uni-tailwind';// https://vitejs.dev/config/
export default defineConfig({css: {postcss: {plugins: [tailwindcss(),],},},plugins: [uni(),autoImport({imports: ['vue', 'uni-app', 'pinia'],dts: true}),uniTailwind()],
})

测试是否成功

pages/index/index.vue

view class="bg-gray-100 py-6 px-4 rounded-lg"><h2 class="text-xl font-bold mb-2">Title</h2><view class="text-gray-700">Description text...</view>
</view>

在微信开发者工具中查看结果

出现以上效果就说明配置成功!!!

配置pinia

基本配置

首先安装依赖包:

pnpm add pinia -S

然后写入文件:

store/modules/app.js

const useAppStore = defineStore("app", {state: () => ({device: "desktop",}),actions: {},
});export default useAppStore;

store/index.js

const store = createPinia()export default store

在main.js中引入

import { createSSRApp } from "vue";
import App from "./App.vue";import store from "./store";export function createApp() {const app = createSSRApp(App);app.use(store)return {app,};
}

页面中测试

pages/index/index.vue

<template><view class="content">...<view>{{appStore.device}}</view></view>
</template><script setup>
import useAppStore from "../../store/modules/app.js";const appStore = useAppStore();...
</script><style>
...
</style>

出现以上效果就说明pinia配置成功。

添加持久化

这一块不知道为什么会报错,目前还没解决我

首先安装依赖包:

pnpm add pinia pinia-plugin-persistedstate -S

然后写入文件:

// src/store/count.js
import { piniaStore } from '@/store'
export const useCountStore = defineStore('count', {state: () => {return {count: 0}},actions: {increment() {this.count++}},persist: true // 配置持久化
})export function useOutsideCountStore(){return useCountStore(piniaStore)
}

注意下面👇这个文件对持久化的处理,否则非h5环境不能正确持久化

// src/store/index.js
import { createPinia } from 'pinia'
import { createPersistedState } from 'pinia-plugin-persistedstate' // 数据持久化const store = createPinia()
store.use(createPersistedState({storage: {getItem: uni.getStorageSync,setItem: uni.setStorageSync,},}),
)
export default store

main.js 中配置

// src/main.js
import { createSSRApp } from 'vue'
import App from './App.vue'
import { setupStore } from './store'
import 'virtual:uno.css'
export function createApp() {const app = createSSRApp(App)setupStore(app)return {app}
}

检测

<view><button type="primary" @click="useCountStore.count++">点击 {{ count }}</button>
</view><script setup>import { useOutsideCountStore } from '@/store/count'const useCountStore = useOutsideCountStore()const count = computed(() => useCountStore.count)
</script>

Axios接入配置

基本配置

安装相关依赖包👇

pnpm add @uni-helper/axios-adapter axios

以下步骤创建对应文件粘贴代码即可

src/api/index.js

/*** 模块化方式处理 默认处理 modules文件夹下的所有js文件 内容以export default导出的文件* @param { 模块内容集合 } moduleContext* @returns modules集合*/
const modulesHandle = (moduleContext = {}) => {if (!Object.keys(moduleContext).length) returnconst modules = {}Object.keys(moduleContext).forEach((v) => {for (let key in moduleContext[v].default) {modules[key] = moduleContext[v].default[key]}})return modules
}const apis = modulesHandle(import.meta.glob('./modules/**/*.js', { eager: true }))
export const useRequest = () => apis

src/api/utils.js

// 请求状态错误
export const httpLogError = (error, msg) => {error.message = msguni.showToast({title: msg,icon: 'error',duration: 2000})
}// api请求错误
export const requestError = (response) => {return new Promise((_, reject) => {const { data } = responseconst msg = `api请求出错 ${response.config.url}:${data.message}`uni.showToast({title: msg,icon: 'error',duration: 2000})reject(data)})
}// 登录失效
export const throttleToLogin = () => {// uni.navigateTo({ url: '/pages/login/login' })
}

src/api/service.js

import axios from 'axios'
import { createUniAppAxiosAdapter } from '@uni-helper/axios-adapter'
import { httpLogError, requestError, throttleToLogin } from './utils'
export function createService() {const request = axios.create({ adapter: createUniAppAxiosAdapter() })request.interceptors.request.use((request) => {return request},(err) => {return Promise.reject(err)})request.interceptors.response.use((response) => {const dataAxios = response.data// 这个状态码是和后端约定的const { code, data } = dataAxiosconsole.log(dataAxios);// 根据 code 进行判断if (code === undefined) {return dataAxios} else {// 目前和公司后端口头约定是字符串,以防万一强制转字符串switch (`${code}`) {// code === 200 | 2 代表没有错误case '200':return data// code === 400001004 代表token 过期打回登录页case '400001004':throttleToLogin()breakcase '400':// 不是正确的 codereturn requestError(response)case '401':// 错误登录return throttleToLogin()default:// 不是正确的 codereturn requestError(response)}}}, (error) => {console.log(error);const status = error.response?.statusswitch (status) {// TODO 再考虑下怎么判断是跨域问题case undefined:case null:httpLogError(error, '网路错误或跨域')breakcase 400:httpLogError(error, '请求错误')breakcase 401:httpLogError(error, '未授权,请登录')breakcase 403:httpLogError(error, '拒绝访问')breakcase 404:httpLogError(error, `请求地址出错: ${error.response.config.url}`)breakcase 408:httpLogError(error, '请求超时')breakcase 500:httpLogError(error, '服务器内部错误')breakcase 501:httpLogError(error, '服务未实现')breakcase 502:httpLogError(error, '网关错误')breakcase 503:httpLogError(error, '服务不可用')breakcase 504:httpLogError(error, '网关超时')breakcase 505:httpLogError(error, 'HTTP版本不受支持')breakdefault:httpLogError(error, '请求错误')break}return Promise.reject(error)})return request
}export const service = createService()

src/api/request.js

import { service } from './service'
function createRequest(service) {function request(config) {// config 自定义配置// axios默认配置const configDefault = {baseURL: import.meta.env.VITE_APP_API_BASEURL, // 所有通过此配置的基础地址 在.env文件配置timeout: 15000, // 请求超时时间responseType: 'json', // 响应类型headers: {// 请求头配置...}}const requestConfig = Object.assign(configDefault, config)return service(requestConfig)}return request
}export const request = createRequest(service)

src/modules/demo.js

/*** 命名=》API_xxx_methodName*/import { request } from '@/api/request.js'
export default {API_DEMO_POST(data = {}) {return request({url: 'demo/mock',method: 'post',data})},API_DEMO_GET(params = {}) {return request({url: '/demo/get',method: 'get',params})}
}

环境变量配置

在项目根目录下分别新建以下配置文件

.env

# APP 名称
VITE_APP_TITLE = 'uniAppTemplate'# APP ID
VITE_UNI_APPID = ''
# 微信小程序 APP ID
VITE_WX_APPID = 'wx8ba795154c9fb51d'# h5部署网站的base,配置到 manifest.config.ts 里的 h5.router.base
VITE_APP_PUBLIC_BASE = './'# h5是否需要配置代理
VITE_APP_PROXY = false
VITE_APP_PROXY_PREFIX = '/api'

.env.development

# 开发环境# 请求地址
# https://jsonplaceholder.typicode.com 免费模拟数据
VITE_APP_API_BASEURL = 'https://jsonplaceholder.typicode.com'# storage前缀
VITE_APP_PREFIX = 'storage'

.env.production

# 生产环境# 请求地址
# https://jsonplaceholder.typicode.com 免费模拟数据
VITE_APP_API_BASEURL = 'https://jsonplaceholder.typicode.com'# storage前缀
VITE_APP_PREFIX = 'storage'

改造vite.config.js

import { defineConfig, loadEnv } from "vite";
import path from "node:path";
import UniManifest from "@uni-helper/vite-plugin-uni-manifest";import uni from "@dcloudio/vite-plugin-uni";
import autoImport from "unplugin-auto-import/vite";import tailwindcss from "tailwindcss";
import uniTailwind from "@uni-helper/vite-plugin-uni-tailwind";// https://vitejs.dev/config/
export default ({ command, mode }) => {const env = loadEnv(mode, path.resolve(process.cwd()));const { VITE_APP_API_BASEURL, VITE_APP_PROXY, VITE_APP_PROXY_PREFIX } = env;return defineConfig({css: {postcss: {plugins: [tailwindcss()],},},plugins: [UniManifest(),uni(),autoImport({imports: ["vue","uni-app","pinia",{"@/api": ["useRequest"],},],dts: true,}),uniTailwind(),],});
};

代理/别名配置

vite.config.js

import { defineConfig, loadEnv } from "vite";
import path from "node:path";
import UniManifest from "@uni-helper/vite-plugin-uni-manifest";import uni from "@dcloudio/vite-plugin-uni";
import autoImport from "unplugin-auto-import/vite";import tailwindcss from "tailwindcss";
import uniTailwind from "@uni-helper/vite-plugin-uni-tailwind";// https://vitejs.dev/config/
export default ({ command, mode }) => {const env = loadEnv(mode, path.resolve(process.cwd()));const { VITE_APP_API_BASEURL, VITE_APP_PROXY, VITE_APP_PROXY_PREFIX } = env;return defineConfig({resolve: {alias: {"@": path.join(process.cwd(), "./src"),"@img": path.join(process.cwd(), "./src/static/images"),},},css: {postcss: {plugins: [...],},},plugins: [...],server: {host: "0.0.0.0",hmr: true,// 仅 H5 端生效,其他端不生效(其他端走build,不走devServer)proxy: JSON.parse(VITE_APP_PROXY)? {[VITE_APP_PROXY_PREFIX]: {target: VITE_APP_API_BASEURL,changeOrigin: true,rewrite: (path) =>path.replace(new RegExp(`^${VITE_APP_PROXY_PREFIX}`), ""),},}: undefined,},});
};

测试axios

H5:

Wchat:

注意:

在小程序中记得要勾选

不然请求会报错

pages/index/index.vue

<template><view class="content">...<view class="content"><view><button type="primary" @click="getList">点击请求数据</button></view></view><view class="p-2" v-if="info"><view>姓名:{{info.title}}</view><view>ID:{{info.userId}}</view></view></view>
</template><script setup>
import useAppStore from "../../store/modules/app.js";
import { API_DEMO_GET } from "@/modules/demo.js";const appStore = useAppStore();const title = ref("Hello World!");
const subtitle = ref("uniapp-vue3-vite-tempalte");// 测试axios
const info = ref({});const getList = () => {uni.showLoading({title: "加载中...",});API_DEMO_GET().then((res) => {info.value = res;uni.hideLoading();}).catch(() => {uni.hideLoading();});
};
</script><style>
...
</style>

pages.json 配置

这里的配置可以参考uniapp官网的有关pages.json的配置即可

pages.json 页面路由 | uni-app官网

在页面新建 我的 界面

准备tabbar图标素材:📎tab.zip

配置 pages.json

{"pages": [{"path": "pages/index/index","style": {"navigationBarTitleText": "首页"}},{"path": "pages/mine/index","style": {"navigationBarTitleText": "我的"}}],"globalStyle": {"navigationBarTextStyle": "black","navigationBarTitleText": "uni-app","navigationBarBackgroundColor": "#F8F8F8","backgroundColor": "#F8F8F8"},"tabBar": {"color": "#909399","selectedColor": "#59a0e7","backgroundColor": "#FFFFFF","borderStyle": "black","list": [{"pagePath": "pages/index/index","iconPath": "static/tab/home1.png","selectedIconPath": "static/tab/home2.png","text": "首页"},{"pagePath": "pages/mine/index","iconPath": "static/tab/self1.png","selectedIconPath": "static/tab/self2.png","text": "个人中心"}]}
}

效果:

h5

wchat

图标库配置

对于这一块我目前没有成功。暂时不管先。

官网:https://icon-sets.iconify.design/

安装:

# 格式:pnpm add @iconify-json/[the-collection-you-want] -D# 例如
pnpm add @iconify-json/ep @iconify/tailwind -D

安装完后可以使用当前库下的所有图标
https://icon-sets.iconify.design/

测试

<text style="width: 40rpx; height: 40rpx" class="icon-[ep--bottom-right]"></text>

源码

📎uni-preset-vue-vite-template.zip

相关文章:

uniapp-uniapp + vue3 + pinia 搭建uniapp模板

使用技术 ⚡️uni-app, Vue3, Vite, pnpm &#x1f4e6; 组件自动化引入 &#x1f34d; 使用 Pinia 的状态管理 &#x1f3a8; tailwindcss - 高性能且极具灵活性的即时原子化 CSS 引擎 &#x1f603; 各种图标集为你所用 &#x1f525; 使用 新的 <script setup> …...

深度学习的一些数学基础

数学基础 万丈高楼平地起 怎么说呢&#xff0c;学的数二对于这些东西还是太陌生了&#xff0c;而且当时学的只会做题&#xff0c;不知道怎么使用/(ㄒoㄒ)/~~ 所以记下来一些不太清楚的前置知识点&#xff0c;主要来自《艾伯特深度学习》&#xff0c;书中内容很多&#xff0c…...

自由学习记录(13)

服务端常见的“资源” 在服务端&#xff0c;常见的“资源”指的是服务端提供给客户端访问、使用、处理或操作的各种数据和功能。根据不同类型的服务和应用场景&#xff0c;服务端的资源种类可以非常广泛。以下是一些常见的服务端资源类型&#xff1a; 1. 文件和静态资源 网页…...

低代码可视化-uniapp海报可视化设计-代码生成

在uni-app中&#xff0c;海报生成器通常是通过集成特定的插件或组件来实现的&#xff0c;这些插件或组件提供了生成海报所需的功能和灵活性。我们采用了lime-painter海报组件。lime-painter是一款canvas海报组件&#xff0c;可以更轻松地生成海报。它支持通过JSON及Template的方…...

一次使用LD_DEBUG定位问题的经历

在实际工作中&#xff0c;当遇到段错误&#xff0c;我们会很容易的想到这是非法访问内存导致的&#xff0c;比如访问了已经释放的内存&#xff0c;访问数据越界&#xff0c;尝试写没有写权限的内存等。使用gdb进行调试&#xff0c;查看出异常的调用栈&#xff0c;往往可以定位到…...

数据库安全:如何进行数据库安全审计?

数据库安全:如何进行数据库安全审计? 数据库安全审计是保障数据库安全的重要手段之一,可以帮助企业及时发现潜在的安全风险并采取相应的措施。以下是进行数据库安全审计的步骤和方法: 一、确定审计目标 在进行数据库安全审计之前,首先需要确定审计的目标。这可能包括以…...

【Python】基础语法错误和异常

在Python中&#xff0c;语法错误和异常是两个常见的问题。下面对它们进行简要介绍。 1.语法错误 (Syntax Error) 语法错误是指代码的语法不符合Python的语言规则。当Python解释器读取程序代码时&#xff0c;如果发现语法不正确&#xff0c;就会抛出语法错误。这种错误通常在代…...

获取每个页面的元素,并写入json

获取每个页面的元素&#xff0c;并写入json 想法&#xff1a;如何去记住每个页面的元素&#xff0c;如何实现不同页面的导航&#xff0c;如何从主页面遍历每一个页面的每一个元素 1.创建数据结构存储 2.树状图正好是我们想要的结构体&#xff1a;创建树状图结构体 3.记录每个页…...

【ShuQiHere】深入解析数字电路中的锁存器与触发器

深入解析数字电路中的锁存器与触发器 &#x1f916;&#x1f50c; 在数字电路设计中&#xff0c;**锁存器&#xff08;Latch&#xff09;和触发器&#xff08;Flip-Flop&#xff09;**是实现时序逻辑的基本元件。它们能够存储状态&#xff0c;是构建复杂数字系统的关键。本文将…...

【学习AI-相关路程-mnist手写数字分类-python-硬件:jetson orin NX-自我学习AI-基础知识铺垫-遇到问题(1) 】

【学习AI-相关路程-mnist手写数字分类-python-硬件&#xff1a;jetson orin NX-自我学习AI-基础知识铺垫-遇到问题&#xff08;1&#xff09; 】 1、前言2、先行了解&#xff08;1&#xff09;学习基础知识-了解jetson orin nx 设备&#xff08;2&#xff09;学习python&AI…...

数据轻松上云——Mbox边缘计算网关

随着工业4.0时代的到来&#xff0c;工厂数字化转型已成为提升生产效率、优化资源配置、增强企业竞争力的关键。我们凭借其先进的边缘计算网关与云平台技术&#xff0c;为工厂提供了高效、稳定的数据采集与上云解决方案。本文将为您介绍Mbox边缘计算网关如何配合明达云平台&…...

ifftshift函数

ifftshift 原理 将频域数据移回时域的函数。它通常与 fftshift 配合使用&#xff0c;后者用于将时域数据移动到频域中心。 而ifftshift所作的事正好相反&#xff0c;将频谱恢复到能量集中在两端&#xff08;或四个角&#xff09;上&#xff0c;接着就可以做逆傅里叶变换了 具…...

vue3 + ts + element-plus 二次封装 el-dialog

实现效果&#xff1a; 组件代码&#xff1a;注意 style 不能为 scoped <template><el-dialog class"my-dialog" v-model"isVisible" :show-close"false" :close-on-click-modal"false" :modal"false"modal-class&…...

MySQL9.0安装教程zip手动安装(Windows)

本章教程&#xff0c;主要介绍如何在Windows上安装MySQL9.0&#xff0c;通过zip方式进行手动安装。 一、下载MySQL压缩包 下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 二、解压MySQL压缩包 将下载好的压缩包&#xff0c;进行解压缩&#xff0c;并且将…...

如何在浏览器中查看格式化的 HTML?

问题描述 我需要这个 HTML 页面在我的浏览器中显示格式化后的信息。我只是将文件存储在本地驱动器上。我需要将文件上传到服务器才能将其作为 HTML 查看&#xff0c;还是可以在本地查看&#xff1f;如在屏幕截图中看到的&#xff0c;它当前显示相同的 HTML 代码。我尝试搜索&am…...

浅谈计算机存储体系和CPU缓存命中

一、计算机存储 一般关于计算机存储体系分为三层 ①三级缓存/寄存器 大多数寄存器只有四字节到八字节&#xff0c;只用于读取很小的数据&#xff1b;三级缓存是为了方便CPU读取内存中数据而存在的 ②内存————数据结构就是在内存中管理数据 ③硬盘————数据库/文件就…...

ES操作:linux命令

查询数据库所有索引 没有密码 curl -X GET "http://localhost:9200/_cat/indices?v" 有密码 curl -u elastic:my_password -X GET "http://localhost:9200/_cat/indices?v" 删除索引 curl-X DELETE "http://localhost:9200/index_XXX" 不…...

Java使用原生HttpURLConnection实现发送HTTP请求

Java 实现发送 HTTP 请求&#xff0c;系列文章&#xff1a; 《Java使用原生HttpURLConnection实现发送HTTP请求》 《Java使用HttpClient5实现发送HTTP请求》 《SpringBoot使用RestTemplate实现发送HTTP请求》 1、HttpURLConnection 类的介绍 HttpURLConnection 是 Java 提供的…...

TinyC编译器5—词法分析

1.词法分析的概念 词法分析也称为 分词 &#xff0c;此阶段编译器从左向右扫描源文件&#xff0c;将其字符流分割成一个个的 词 &#xff08; token 、 记号 &#xff0c;后文中将称为 token &#xff09;。所谓 token &#xff0c;就是源文件中不可再进一步分割的一串字符&am…...

电子电气架构---智能计算架构和SOA应用

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的人和事&#xff0c;多看一眼都是你的不…...

Python Numpy 实现神经网络自动训练:反向传播与激活函数的应用详解

Python Numpy 实现神经网络自动训练&#xff1a;反向传播与激活函数的应用详解 这篇文章介绍了如何使用 Python 的 Numpy 库来实现神经网络的自动训练&#xff0c;重点展示了反向传播算法和激活函数的应用。反向传播是神经网络训练的核心&#xff0c;能够通过计算梯度来优化模…...

Apache Calcite - 基于规则的查询优化

基于规则的查询优化 基于规则的查询优化&#xff08;Rule-based Query Optimization&#xff09;是一种通过应用一系列预定义的规则来优化查询计划的技术。这些规则描述了如何转换关系表达式&#xff0c;以提高查询执行的效率。基于规则的优化器并不依赖于统计信息&#xff0c…...

react学习笔记,ReactDOM,react-router-dom

react 学习 1. 下载与安装 下载 npm install -g create-react-app 安装 npx create-react-app xxx 推荐 npm init react-app xxx yarn create react-app xxx 2. 创建 react 元素 indexjs 文件 import React from "react"; import ReactDOM from "react…...

优化UVM环境(八)-整理project_common_pkg文件

书接上回&#xff1a; 优化UVM环境&#xff08;七&#xff09;-整理环境&#xff0c;把scoreboard拿出来放在project_common环境里 Prj_cmn_pkg.sv考虑到是后续所有文件的基础&#xff0c;需要引入uvm_pkg并把自身这个pkg import给后续的文件&#xff1a; 这里有3个注意事项&…...

【实战案例】Django框架连接并操作数据库MySQL相关API

本文相关操作基于上次操作基本请求及响应基础之上【实战案例】Django框架基础之上编写第一个Django应用之基本请求和响应 Django框架中默认会连接SQLite数据库&#xff0c;好处是方便无需远程连接&#xff0c;打包项目挪到其他环境安装一下依赖一会就跑起来&#xff0c;但是缺点…...

【其他】无法启动phptudy服务,提示错误2:系统找不到指定的文件

在服务中启动phpstudy服务时&#xff0c;提示“windows 无法启动phpstudy服务 服务(位于本地计算机上) 错误2:系统找不到指定的文件”的错误。导致错误的原因是可执行文件的路径不对&#xff0c;修改成正确的路径就可以了。 下面是错误的路径&#xff0c;会弹出错误窗口&#…...

AI驱动的支持截图或线框图快速生成网页应用的开源项目

Napkins.dev是什么 Napkins.dev是一个创新的开源项目&#xff0c;基于AI技术将用户的截图或线框图快速转换成可运行的网页应用程序。项目背后依托于Meta的Llama 3.1 405B大型语言模型和Llama 3.2 Vision视觉模型&#xff0c;结合Together.ai的推理服务&#xff0c;实现从视觉设…...

es集群索引是黄色

排查 GET /_cat/shards?hindex,shard,prirep,state,unassigned.reason 查询原因 发现node正常 执行重新分配 retry_failedtrue 参数告诉Elasticsearch重试那些因某种原因&#xff08;如节点故障、资源不足等&#xff09;而失败的分片分配。这个选项通常用来尝试再次分配那些…...

获取淘宝商品评论的方法分享-调用API接口item_review

在电商领域&#xff0c;商品评论是消费者了解产品、做出购买决策的重要依据。淘宝作为中国最大的电商平台之一&#xff0c;其商品评论系统涵盖了海量的用户反馈数据。为了帮助企业、电商数据分析师、市场研究人员以及普通消费者更高效地获取这些评论数据&#xff0c;淘宝开放平…...

MATLAB人脸考勤系统

MATLAB人脸考勤系统课题介绍 该课题为基于MATLAB平台的人脸识别系统。传统的人脸识别都是直接人头的比对&#xff0c;现实意义不大&#xff0c;没有一定的新意。该课题识别原理为&#xff1a;先采集待识别人员的人脸&#xff0c;进行训练&#xff0c;得到人脸特征值。测试的时…...