uni-app+vue3+ts项目搭建完整流程
項目代碼同步更新至碼云 uni-vue3-ts-template
開發(fā)前準備
利用 uni-app 開發(fā),有兩種方法:
- 通過
HBuilderX創(chuàng)建(需安裝HBuilderX編輯器) - 通過命令行創(chuàng)建(需安裝
NodeJS環(huán)境),推薦使用vscode編輯器
這里我們使用第2種方法,這兩種方法官方都有詳細介紹 點擊查看官方文檔
vscode 安裝插件
- 安裝 Vue3 插件,點擊查看官方文檔
- 安裝
Vue Language Features (Volar):Vue3 語法提示插件 - 安裝
TypeScript Vue Plugin (Volar):Vue3+TS 插件 - 工作區(qū)禁用 Vue2 的 Vetur 插件(Vue3 插件和 Vue2 沖突)
- 工作區(qū)禁用 @builtin typescript 插件(禁用后開啟 Vue3 的 TS 托管模式)
- 安裝 uni-app 開發(fā)插件
-
uni-create-view:快速創(chuàng)建 uni-app 頁面 -
uni-helper(插件套裝,安裝一個后會有多個插件) :代碼提示 -
uniapp小程序擴展:鼠標懸停查文檔
uni-create-view 插件使用
uni-create-view 安裝后,需要修改配置,進入 文件 -> 首選項 -> 設(shè)置,按以下選項修改即可
uni-create-view 使用方法:
在 src/pages 下右鍵,選擇 新建uni-app頁面,彈出輸入框,輸入 文件夾名稱 頁面名稱,然后回車
生成如下目錄文件
并且在 src/pages.json 目錄下,已將新界面配置進去
vscode 項目配置
項目生成后,在項目的根目錄進行
新建 .vscode 文件夾,并創(chuàng)建 settings.json 文件:
{
// 在保存時格式化文件
"editor.formatOnSave": true,
// 文件格式化配置
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// 配置語言的文件關(guān)聯(lián)
"files.associations": {
"pages.json": "jsonc", // pages.json 可以寫注釋
"manifest.json": "jsonc" // manifest.json 可以寫注釋
}
}
同樣,在 .vscode 文件夾內(nèi),創(chuàng)建 vue3 模板文件,命名為 vue3-uniapp.code-snippets:
{
"vue3+uniapp快速生成模板": {
"scope": "vue",
"prefix": "Vue3",
"body": [
"<script setup lang=\"ts\">",
"$2",
"</script>\n",
"<template>",
"\t<view class=\"\">test</view>",
"</template>\n",
"<style lang=\"scss\"></style>",
"$2"
],
"description": "vue3+uniapp快速生成模板"
}
}
然后,在空白vue文件中,輸入vue3,選擇此模板,即可快速生成代碼
項目初始化
項目創(chuàng)建
拉取 uni-app 官方項目基礎(chǔ)架構(gòu)代碼 https://uniapp.dcloud.net.cn/quickstart-cli.html
npx degit dcloudio/uni-preset-vue#vite-ts uni-vue3-ts-shop
cd uni-vue3-ts-shop
或者直接直接克隆國內(nèi) gitee 地址,然后修改項目名稱,并進入項目根目標
git clone -b vite-ts https://gitee.com/dcloud/uni-preset-vue.git
安裝ts擴展
主要是為了增加 uni-app 、微信小程序、nodejs 對ts的支持
npm i -D @uni-helper/uni-app-types miniprogram-api-typings @types/node
修改 tsconfig.json
{
"compilerOptions": {
"ignoreDeprecations": "5.0",
"allowJs": true,
},
"types": ["@dcloudio/types", "miniprogram-api-typings", "@uni-helper/uni-app-types"]
},
"vueCompilerOptions": {
// experimentalRuntimeMode 已廢棄,現(xiàn)調(diào)整為 nativeTags,請升級 Volar 插件至最新版本
"nativeTags": ["block", "component", "template", "slot"]
}
}
配置環(huán)境變量
點我查看官方文檔
新增env文件
根目錄下新建 .env 文件
VITE_HTTP = https://mock.mengxuegu.com/mock/6598258423a3c638568501db/uniapp_template
使用
獲取環(huán)境變量
process.env.NODE_ENV // 應(yīng)用運行的模式,比如vite.config.ts里
import.meta.env.VITE_HTTP // src下的vue文件或其他ts文件里
開啟 sourcemap
點我查看官方文檔
修改 vite.config.ts 文件:
export default defineConfig({
build: {
// 開發(fā)階段啟用源碼映射:https://uniapp.dcloud.net.cn/tutorial/migration-to-vue3.html#需主動開啟-sourcemap
sourcemap: process.env.NODE_ENV === 'development',
},
plugins: [uni()],
})
統(tǒng)一代碼規(guī)范
安裝 prettier
npm i -D prettier
根目錄下新建 .prettierrc.json
{
"singleQuote": true,
"semi": false,
"printWidth": 120,
"trailingComma": "all",
"endOfLine": "auto"
}
安裝 eslint
npm i -D eslint eslint-plugin-vue @rushstack/eslint-patch @vue/eslint-config-typescript @vue/eslint-config-prettier
根目錄下新建 .eslintrc.js
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
extends: [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier',
],
// 小程序全局變量
globals: {
uni: true,
wx: true,
WechatMiniprogram: true,
getCurrentPages: true,
getApp: true,
UniApp: true,
UniHelper: true,
App: true,
Page: true,
Component: true,
AnyObject: true,
},
parserOptions: {
ecmaVersion: 'latest',
},
rules: {
'prettier/prettier': [
'warn',
{
singleQuote: true,
semi: false,
printWidth: 120,
trailingComma: 'all',
endOfLine: 'auto',
},
],
'vue/multi-word-component-names': ['off'],
'vue/no-setup-props-destructure': ['off'],
'vue/no-deprecated-html-element-is': ['off'],
'@typescript-eslint/no-unused-vars': ['off'],
},
}
package.json 中新增命令 lint
{
"scripts": {
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
}
}
然后運行 npm run lint,將項目內(nèi)的文件格式化為 eslint 規(guī)定的格式(這個命令可隨時運行,以便有新頁面/插件加入時,解決代碼風格的問題)
規(guī)范git提交
非必需,適合多人開發(fā)
安裝 husky
安裝并初始化 husky
npx husky-init
如果是首次安裝,會有以下提示,輸入 y 回車即可
Need to install the following packages:
husky-init@8.0.0
Ok to proceed? (y)
安裝完成后,會多出 .husky 文件夾和 pre-commit 文件
安裝 lint-staged
npm i -D lint-staged
安裝完成后配置 package.json
{
"script": {
// ... 省略 ...
"lint-staged": "lint-staged"
},
"lint-staged": {
"*.{vue,ts,js}": ["eslint --fix"]
}
}
修改 pre-commit 文件
- npm test
+ npm run lint-staged
提交規(guī)范
至此,已完成 husky + lint-staged 的配置。之后,每次提交代碼,在提交信息前都要加入以下提交類型之一,譬如:feat: 首頁新增輪播圖
| 提交字段 | 說明 |
|---|---|
| feat: | 增加新功能 |
| fix: | 修復(fù)問題/BUG |
| style: | 代碼風格相關(guān)無影響運行結(jié)果的 |
| perf: | 優(yōu)化/性能提升 |
| refactor: | 重構(gòu) |
| revert: | 撤銷修改 |
| test: | 測試相關(guān) |
| docs: | 文檔/注釋 |
| chore: | 依賴更新/腳手架配置修改等 |
| workflow: | 工作流改進 |
| ci: | 持續(xù)集成 |
| types: | 類型定義文件更改 |
| wip: | 開發(fā)中 |
安裝 uni-ui 組件庫
非必需,也可使用其他組件庫
uni-ui 是DCloud提供的一個跨端ui庫,它是基于vue組件的、flex布局的、無dom的跨全端ui框架。查看官方文檔
安裝 uni-ui 及相關(guān)插件
sass sass-loader 是 uni-ui 的依賴庫,@uni-helper/uni-ui-types 是類型聲明文件
npm i -D sass sass-loader
npm i @dcloudio/uni-ui
npm i -D @uni-helper/uni-ui-types
修改配置
修改 tsconfig.json,配置類型聲明文件
{
"compilerOptions": {
"types": ["@dcloudio/types", "miniprogram-api-typings", "@uni-helper/uni-app-types", "@uni-helper/uni-ui-types"]
}
}
修改 src/pages.json,配置自動導入組件
{
"easycom": {
"autoscan": true,
"custom": {
// uni-ui 規(guī)則如下配置
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
"pages": [
// ……
]
}
安裝配置 pina
安裝
pinia-plugin-persistedstate 是持久化 pina 插件
npm i pinia pinia-plugin-persistedstate
使用
在 src 下新增以下目錄和文件
src
├─stores
│ ├─modules
│ │ └─user.ts
| └─index.ts
user.ts
import { defineStore } from 'pinia'
import { ref } from 'vue'
// 定義 Store
export const useMemberStore = defineStore(
'user',
() => {
// 用戶信息
const userInfo = ref<any>()
// 保存用戶信息,登錄時使用
const setUserInfo = (val: any) => {
userInfo.value = val
}
// 清理用戶信息,退出時使用
const clearUserInfo = () => {
userInfo.value = undefined
}
return {
userInfo,
setUserInfo,
clearUserInfo,
}
},
// TODO: 持久化
{
persist: true,
},
)
index.ts
import { createPinia } from 'pinia'
import persist from 'pinia-plugin-persistedstate'
// 創(chuàng)建 pinia 實例
const pinia = createPinia()
// 使用持久化存儲插件
pinia.use(persist)
// 默認導出,給 main.ts 使用
export default pinia
// 模塊統(tǒng)一導出
export * from './modules/user'
main.ts
import { createSSRApp } from 'vue'
import pinia from './stores'
import App from './App.vue'
export function createApp() {
const app = createSSRApp(App)
app.use(pinia)
return {
app,
}
}
持久化
插件默認使用 localStorage 實現(xiàn)持久化,小程序端不兼容,需要替換持久化 API。
修改 stores/modules/user.ts
export const useUserStore = defineStore(
'member',
() => {
//…省略
},
{
// 配置持久化
persist: {
// 調(diào)整為兼容多端的API
storage: {
setItem(key, value) {
uni.setStorageSync(key, value)
},
getItem(key) {
return uni.getStorageSync(key)
},
},
},
},
)
封裝請求
uniapp 攔截器
uni.addInterceptor 的使用參考 官方文檔
src 目錄下新建 utils 文件夾,并新建 http.ts 文件
import { useUserStore } from '@/stores'
const baseURL = import.meta.env.VITE_HTTP
// 攔截器配置
const httpInterceptor = {
// 攔截前觸發(fā)
invoke(options: UniApp.RequestOptions) {
// 非 http 開頭需拼接地址
if (!options.url.startsWith('http')) {
options.url = baseURL + options.url
}
options.timeout = 10000
// 添加請求頭標識
options.header = {
'request-client': 'wechart-app',
...options.header,
}
// 添加 token 請求頭標識
const memberStore = useUserStore()
const token = memberStore.userInfo?.token
if (token) {
options.header.Authorization = token
}
},
}
// 攔截 request 請求
uni.addInterceptor('request', httpInterceptor)
// 攔截 uploadFile 文件上傳
uni.addInterceptor('uploadFile', httpInterceptor)
由于 uni-app 的響應(yīng)攔截器對類型支持并不友好,所以我們自行封裝響應(yīng)攔截器,同一個文件,繼續(xù)
/**
* 請求函數(shù)
* @param UniApp.RequestOptions
* @returns Promise
*/
// Data類型根據(jù)后臺返回數(shù)據(jù)去定義
type Data<T> = {
code: string
msg: string
result: T
}
export const http = <T>(options: UniApp.RequestOptions) => {
return new Promise<Data<T>>((resolve, reject) => {
uni.request({
...options,
// 響應(yīng)成功
success(res) {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data as Data<T>)
} else if (res.statusCode === 401) {
// 401錯誤 -> 清理用戶信息,跳轉(zhuǎn)到登錄頁
const userStore = useUserStore()
userStore.clearUserInfo()
uni.navigateTo({ url: '/pages/login' })
reject(res)
} else {
// 其他錯誤 -> 根據(jù)后端錯誤信息輕提示
uni.showToast({
icon: 'none',
title: (res.data as Data<T>).msg || '請求錯誤',
})
reject(res)
}
},
// 響應(yīng)失敗
fail(err) {
uni.showToast({
icon: 'none',
title: '網(wǎng)絡(luò)錯誤,換個網(wǎng)絡(luò)試試',
})
reject(err)
},
})
})
}
使用
為了統(tǒng)一API文件,我們在 src 目錄下新建 api 文件夾,并新建 user.ts
import { http } from '@/utils/http'
export const getUserInfoAPI = (data: any) => {
return http({
url: '/user/info',
method: 'POST',
data,
})
}
然后在需要的地方調(diào)用,比如在 page/my/index.vue 里調(diào)用:
<script setup lang="ts">
import { useUserStore } from '@/stores'
import { getUserInfoAPI } from '@/api/user'
const userStore = useUserStore()
const getUserInfo = async () => {
const res = await getUserInfoAPI({ id: 'weizwz' })
console.log(res)
const { result } = res
userStore.setUserInfo(result)
}
</script>
<template>
<view class="">
<view>用戶信息: {{ userStore.userInfo }}</view>
<button
@tap="
userStore.setUserInfo({
userName: 'weizwz',
})
"
size="mini"
plain
type="primary"
>
保存用戶信息
</button>
<button @tap="userStore.clearUserInfo()" size="mini" plain type="primary">清理用戶信息</button>
<button @tap="getUserInfo()" size="mini" plain type="primary">發(fā)送請求</button>
</view>
</template>
<style lang="scss"></style>
效果如下,可以看到已經(jīng)調(diào)用成功:
如果調(diào)用被攔截的話,請檢查微信小程序里的項目設(shè)置,然后選中 不檢驗合法域名、web-view(業(yè)務(wù)域名)、TLS版本以及HTTPS證書 選項
注意事項
開發(fā)區(qū)別
uni-app 項目每個頁面是一個 .vue 文件,數(shù)據(jù)綁定及事件處理同 Vue.js 規(guī)范:
- vue文件中的
div標簽需替換為view標簽 - 屬性綁定
src="{ { url }}"升級成:src="url" - 事件綁定
bindtap="eventName"升級成@tap="eventName",支持()傳參 - 支持 Vue 常用指令
v-for、v-if、v-show、v-model等
其他補充
- 調(diào)用接口能力,建議前綴
wx替換為uni,養(yǎng)成好習慣,支持多端開發(fā)。 -
<style>頁面樣式不需要寫scoped,小程序是多頁面應(yīng)用,頁面樣式自動隔離。 - 生命周期分三部分:應(yīng)用生命周期(小程序),頁面生命周期(小程序),組件生命周期(Vue)
- 其他參考 uniapp-vue語法 官方文檔
文章部分內(nèi)容來自 小兔鮮兒項目 ,本文主要是在此基礎(chǔ)上補全了完整創(chuàng)建此項目的流程和所需的依賴
總結(jié)
以上是生活随笔為你收集整理的uni-app+vue3+ts项目搭建完整流程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分享历经软考高项二次上岸经验
- 下一篇: 5分钟搞定vue3函数式弹窗