初始化项目
npx degit dcloudio/uni-preset-vue#vite my-vue3-project
限制包管理工具
{
"scripts": {
"preinstall": "npx only-allow npm"
}
}
vite.config.js
配置环境变量与公共基础路径
在根路径创建新文件.env.development
NODE_ENV=development
VITE_APP_BASE=/
在根路径创建新文件.env.production
NODE_ENV=production
VITE_APP_BASE=/
配置vite.config.js
import { defineConfig, loadEnv } from 'vite'
import path from 'path'
export default ({mode}) => {
const env = loadEnv(mode, process.cwd())
return defineConfig({
base: env.VITE_APP_BASE
})
}
配置开发服务器选项
{
server: {
host: '0.0.0.0',
port: 6400,
proxy: {
'/mock': {
target: 'https://mock.apifox.cn/m1/1156743-0-default',
changeOrigin: true,
rewrite: path => path.replace(/^/mock/, '')
}
}
}
}
生产环境去除打印与debugger
{
esbuild: {
drop: ['console', 'debugger']
}
}
配置别名
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
添加项目规范
设置工作空间及其配置
在根目录下创建.vscode
文件夹, 并创建settings.json
, 如下:
{
"npm.packageManager": "npm",
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"files.eol": "\n",
"editor.minimap.enabled": false,
"search.exclude": {
"**/node_modules": true,
"**/*.log": true,
"**/*.log*": true,
"**/bower_components": true,
"**/dist": true,
"**/elehukouben": true,
"**/.git": true,
"**/.gitignore": true,
"**/.svn": true,
"**/.DS_Store": true,
"**/.idea": true,
"**/.vscode": false,
"**/yarn.lock": true,
"**/tmp": true,
"out": true,
"dist": true,
"node_modules": true,
"CHANGELOG.md": true,
"examples": true,
"res": true,
"screenshots": true,
"yarn-error.log": true,
"**/.yarn": true
},
"files.exclude": {
"**/.cache": true,
"**/.editorconfig": true,
"**/.eslintcache": true,
"**/bower_components": true,
"**/.idea": true,
"**/tmp": true,
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true
},
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/.vscode/**": true,
"**/node_modules/**": true,
"**/tmp/**": true,
"**/bower_components/**": true,
"**/dist/**": true,
"**/yarn.lock": true
},
"eslint.validate": ["javascript", "javascriptreact", "vue"],
"path-intellisense.mappings": {
"@": "${workspaceRoot}/src"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[less]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"prettier.configPath": ".prettierrc",
"editor.formatOnSave": true,
"files.associations": {
"*.cjson": "jsonc",
"*.wxss": "css",
"*.wxs": "javascript",
"manifest.json": "jsonc",
"pages.json": "jsonc"
}
}
prettier
根目录下创建.prettierrc
,内容如下:
{
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"arrowParens": "avoid",
"jsxBracketSameLine": false,
"printWidth": 80,
"tabWidth": 2,
"tabSize": 2
}
安装依赖:
npm i prettier -D
eslint
相关
- 安装相关依赖
@vue/eslint-config-standard``babel-eslint``eslint-plugin-import``eslint-plugin-node``eslint-plugin-promise
eslint-plugin-standard``eslint-plugin-vue``eslint
@babel/eslint-parser
npm i @vue/eslint-config-standard babel-eslint eslint-plugin-import eslint-plugin-node eslint-plugin-promise eslint-plugin-standard eslint-plugin-vue eslint @babel/eslint-parser -D
- 添加eslint规则配置文件
在根目录下添加.eslintrc.js
module.exports = {
root: true,
env: {
node: true
},
extends: ['plugin:vue/vue3-essential'],
parserOptions: {
parser: '@babel/eslint-parser',
requireConfigFile: false
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'space-before-function-paren': 'off',
'no-unused-vars': 'warn',
'handle-callback-err': 'warn',
'vue/multi-word-component-names': 'off',
'vue/no-deprecated-v-bind-sync': 'off'
}
}
- 在根目录下添加忽略文件
.eslintignore
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.husky
.local
/bin
Dockerfile
规范化提交
安装Sass
npm i sass -D
配置使用:
- 新建
src/styles
文件夹, 添加global.scss, mixin.scss, animations.scss
- 填充文件内容
src/styles/mixin.scss
:
@mixin commonSizeColor {
color: pink;
font-size: 32px;
font-weight: 600;
}
src/styles/global.scss
:
@import './animations.scss';
@import './mixin.scss';
$header-bgColor: #007aff;
$color-success: #4cd964;
- 配置全局scss
vite.config.js
{
css: {
preprocessorOptions: {
scss: {
additionalData: '@import "@/styles/global.scss";'
}
}
}
}
配置unocss
安装
npm i -D unocss
// vite.config.ts
import Unocss from 'unocss/vite'
export default {
plugins: [
Unocss({ /* options */ }),
],
}
// main.ts
import 'uno.css'
简单使用
<div class="color-green color-pink">{{ title }}</div>
<div class="color-green font-bold ml-3">{{ title }}</div>
使用Pinia进行状态管理
安装
npm i pinia
注册
// main.js
import { createSSRApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
export function createApp() {
const app = createSSRApp(App)
app.use(pinia)
return {
app
}
}
封装Store
在src
下新建store
目录, 在store
下新建user.js
// user.js
import { defineStore } from 'pinia'
// 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useUserStore = defineStore('user', {
state: () => ({ count: 0, token: 'rtfyuyio' }),
getters: {
double: state => state.count * 2
},
actions: {
increment() {
this.count++
}
}
})
使用Store
// App.vue
<script setup>
import { useUserStore } from '@/store/user.js'
const store = useUserStore()
console.log('store.token', store.token)
</script>
请求封装
安装Axios
npm i axios
封装Axios
在src
下新建api
文件夹, 在api
下新建http.js
// http.js
import axios from 'axios'
import { getFullURL } from '@/utils'
import { useUserStore } from '@/store/user.js'
const instance = axios.create({
// Web 侧可以通过 vite.config.js 中的 proxy 配置,指定代理
// 小程序APP里需写完整路径,如 https://service-rbji0bev-1256505457.cd.apigw.tencentcs.com/release
// 可使用条件编译,详见 https://uniapp.dcloud.io/tutorial/platform.html#preprocessor
// #ifdef H5
baseURL: import.meta.env.VITE_APP_AXIOS_BASE_URL,
// #endif
// #ifndef H5
baseURL: 'https://mock.apifox.cn/m1/1156743-0-default',
// #endif
adapter(config) {
// console.log('request adapter ↓↓')
// console.log(config)
const { url, method, data, params, headers, baseURL, paramsSerializer } =
config
return new Promise((resolve, reject) => {
uni.request({
method: method.toUpperCase(),
url: getFullURL(baseURL, url, params, paramsSerializer),
header: headers,
data,
dataType: 'json',
responseType: config.responseType,
success: res => {
// console.log('request success ↓↓')
// console.log(res)
resolve(res)
},
fail: err => {
reject(err)
}
})
})
},
timeout: 8000
})
// 请求拦截
instance.interceptors.request.use(config => {
const store = useUserStore()
const { method } = config
const headers = {
// token: uni.getStorageSync('token')
token: store.token
}
// 不缓存get请求
if (method === 'get') {
headers['Cache-Control'] = 'no-cache'
}
// delete请求参数放入body中
// if(method === 'delete') {
// headers['Content-type'] = 'application/json;'
// Object.assign(config, {
// data: params,
// params: {}
// })
// }
return {
...config,
headers
}
})
// 响应拦截
instance.interceptors.response.use(response => {
// console.log('response ↓↓')
// console.log(response)
if ((response.status || response.statusCode) === 200) {
return response.data
}
return Promise.reject(response)
})
export default instance
上面代码中有用到一个getFullURL
方法, 如下:
import buildURL from 'axios/lib/helpers/buildURL'
export const getFullURL = (baseURL, url, params, paramsSerializer) => {
if (url.startsWith('http')) {
return buildURL(url, params, paramsSerializer)
}
baseURL = baseURL.endsWith('/') ? baseURL : `${baseURL}/`
url = url.startsWith('/') ? url.slice(1) : url
return buildURL(`${baseURL}${url}`, params, paramsSerializer)
}
开始使用
在api
下新建modules
文件夹, 其下新建user.js
// user.js
import request from '../http'
export const apiLogin = data => {
return request({
url: '/login',
method: 'POST',
data
})
}
路由使用
使用的路由插件为: uni-crazy-router
安装
npm i uni-crazy-router
注册与配置
在src
下新建文件夹router
, 在其下新建index.js
import uniCrazyRouter from 'uni-crazy-router'
export function setupRouter(app) {
// 接收vue3的实例,并注册uni-crazy-router
app.use(uniCrazyRouter)
}
uniCrazyRouter.beforeEach(async (to, from, next) => {
// 逻辑代码
// console.log('to', to)
next()
})
uniCrazyRouter.afterEach((to, from) => {
// 逻辑代码
})
uniCrazyRouter.onError((to, from) => {
// 逻辑代码
})
在main.js
中注册使用
// main.js
import { setupRouter } from './router'
// ...
setupRouter(app)
uniapp vue3版本H5 production环境下的特殊配置
因为uni vue3 vite在h5的production环境打包时会将uni.navigateTo等原生方法的字面量直接替换成底层函数,导致uni-crazy-router失效, 插件会恢复uni的5个全局跳转方法名
安装: npm i uni-vite-plugin-h5-prod-effect
在vite.config.js
中进行配置加载
// vite.config.js
import { defineConfig } from 'vite'
import h5ProdEffectPlugin from 'uni-vite-plugin-h5-prod-effect'
export default defineConfig({
plugins: [
// 对h5 production环境打包时的特殊处理,否则uni-crazy-router在这个环境会异常
h5ProdEffectPlugin()
],
})
使用
Demo
: 进行页面跳转
uni.navigateTo({
url: '/pages/test/test?a=1&b=1', // 不影响原生的参数传递
// 提供了基于页面级别的路由参数对象
routeParams: {
c:1,
d:1
},
// 提供了基于跳转过程的过程参数对象
passedParams: {
e:1,
f:1
}
})
Demo
: 获取跳转参数
export default {
data() {
return {
title: 'Hello'
}
},
onLoad() {
// 获取页面路由
// uni-app官方推荐方式,适用所有端
console.log(getCurrentPages()[getCurrentPages().length-1].route)
},
onShow() {
// 获取路由页面参数
console.log(this.$routeParams)
console.log(getCurrentPages()[getCurrentPages().length-1].$routeParams)
// 获取路由动作过程参数
console.log(this.$passedParams)
console.log(getCurrentPages()[getCurrentPages().length-1].$passedParams)
},
onUnload() {
},
methods: {
//....
}
}