从零搭建uniapp项目

目录

创建uni-app项目

基础架构

[安装 uni-ui 组件库](#安装 uni-ui 组件库)

安装sass依赖

easycom配置组件自动导入

配置view等标签高亮声明

配置uni-ui组件类型声明

[解决 标签 错误](#解决 标签 错误)

关于tsconfig.json中提示报错

关于非原生标签错误(看运气)

[安装 uview-plus 组件库](#安装 uview-plus 组件库)

​编辑

[Pinia 配置](#Pinia 配置)

[pinia 依赖安装](#pinia 依赖安装)

测试

[pinia 持久化配置](#pinia 持久化配置)


创建uni-app项目

复制代码
npx degit dcloudio/uni-preset-vue#vite-ts new-project-name

new-project-name:这里更改一下为自己的项目名称

基础架构

安装 uni-ui 组件库

官网:uni-app官网

通过官网说明文档相对应的搭建

复制代码
pnpm i @dcloudio/uni-ui

安装sass依赖

javascript 复制代码
pnpm i [email protected] -D
pnpm i [email protected] -D

easycom配置组件自动导入

javascript 复制代码
// pages.json
{
  // uniapp 配置文件
  "easycom": {
	    "autoscan": true,
        // 以正则方式自定义组件匹配规则
		"custom": {
			// uni-ui 规则如下配置
		    "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
            // 以serive开头的组件,在 components 文件夹中查找引入(需要重启服务器)
            //"^serive(.*)": "@/components/serive/serive$1.vue"
		}
	},
	
	// 其他内容
	pages:[
		// ...
	]
}

配置view等标签高亮声明

javascript 复制代码
pnpm i -D miniprogram-api-typings @uni-helper/uni-app-types

安装成功后复制对应的依赖包名放置在 tsconfig.json中的type字段

同时加上 vueCompilerOptions 配置

javascript 复制代码
  "vueCompilerOptions": {
    "experimentalRuntimeMode": "runtime-uni-app"
  },

配置uni-ui组件类型声明

组件声明类型依赖官网(注意:如果缓慢需要魔法):@uni-helper/uni-ui-types - npm

javascript 复制代码
pnpm i -D @uni-helper/uni-ui-types

安装成功后复制对应的依赖包名放置在 tsconfig.json中的type字段

解决 标签 错误

关于tsconfig.json中提示报错

选项"importsNotUsedAsValues"已删除。请从配置中删除它。请改用"verbatimModuleSyntax"

主要是我们使用的tsconfig版本太低了

步骤1:

更新@vue/tsconfig版本,在package.json文件中找到@vue/tsconfig,把版本号改为0.7.0

复制代码
 "@vue/tsconfig": "^0.7.0",

随后运行pnpm 更新依赖

复制代码
pnpm install

最后更改 tsconfig 地址

复制代码
  "extends": "@vue/tsconfig/tsconfig.dom.json",

这样就不报错了

关于非原生标签错误(看运气)

当我们发现正常标签报错

更改我们的 tsconfig.json,参考一下我下面的配置

javascript 复制代码
{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "compilerOptions": {
    "sourceMap": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    },
    "lib": ["esnext", "dom"],
     // 类型声明文件
    "types": [
      "@uni-helper/uni-ui-types",   // uni-ui 组件类型
      "@dcloudio/types", // uni-app API 类型
      "miniprogram-api-typings", // 原生微信小程序类型
      "@uni-helper/uni-app-types" // uni-app 组件类型
    ]
  },
    // vue 编译器类型,校验标签类型
  "vueCompilerOptions": {
    //新增加的配置 experimentalRuntimeMode 已废弃,现调整为 nativeTags,请升级 Volar 插件至最新版本
    "nativeTags": ["block", "component", "template", "slot"],
    // experimentalRuntimeMode 已废弃,请升级 Vue - Official 插件至最新版本
    "plugins": ["@uni-helper/uni-app-types/volar-plugin"]
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}

如果还是爆红,多次尝试重启 Vue - Official 插件,以及重启vscode,我就是这样不明不白的改好了。

安装 uview-plus 组件库

执行命令安装 uview 依赖

TypeScript 复制代码
pnpm install uview-plus

挂载使用

TypeScript 复制代码
import uviewPlus from 'uview-plus'
 app.use(uviewPlus);

由于uview-plus 不是原生组件,所以我们要自定义声明类型,这样就不会爆红波浪线了

uview-plus.d.ts

TypeScript 复制代码
// src/types/uview-plus.d.ts
declare module 'uview-plus' {
  import { Plugin } from 'vue';
  const install: Plugin;
  export default install;
}

全局样式配置

TypeScript 复制代码
 /* src\uni.scss */
@import  'uview-plus/theme.scss';
TypeScript 复制代码
// src\App.vue
<style lang="scss">
	/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
	@import "uview-plus/index.scss";
</style>

自动导入

TypeScript 复制代码
// pages.json
{
	"easycom": {
		"autoscan": true,
		// 注意一定要放在custom里,否则无效,https://ask.dcloud.net.cn/question/131175
		"custom": {
			"^u--(.*)": "@/uni_modules/uview-plus/components/u-$1/u-$1.vue",
			"^up-(.*)": "@/uni_modules/uview-plus/components/u-$1/u-$1.vue",
	        "^u-([^-].*)": "@/uni_modules/uview-plus/components/u-$1/u-$1.vue"
		}
	},
	// 此为本身已有的内容
	"pages": [
		// ......
	]
}

Pinia 配置

Pinia官网(注意:如果缓慢需要魔法):Pinia | The intuitive store for Vue.js

pinia 依赖安装

执行命令安装 Pinia 依赖

复制代码
pnpm install pinia

分包创建目录

index.ts配置pinia

TypeScript 复制代码
import { createPinia } from "pinia";
const pinia = createPinia();    // 创建 Pinia 实例
// 默认导出,给 main.ts 使用
export default pinia;
// 模块统一导出
export * from "./modules/counter";

main.ts 使用 pinia

TypeScript 复制代码
import { createSSRApp } from "vue";
import App from "./App.vue";
import pinia from "./stores";
export function createApp() {
  const app = createSSRApp(App);
  app.use(pinia); // 挂载pinia
  return {
    app,
  };
}
测试

counter.ts

TypeScript 复制代码
import { defineStore } from "pinia";
import { computed, ref } from "vue";
export const useCounterStore = defineStore("counter", () => {
    
    // 声明 数据类型
    const count = ref(0);
    // 定义 计数器方法
    const increment = () => {
        count.value++;
    }

    // 声明基于数据派生的计算属性
    const double = computed(() => {
        return count.value * 2;
    })

    // 返回 计数器数据、方法、计算属性
    return {
        count,
        double,
        increment,
    }
    },
);

Test.vue

html 复制代码
<script lang="ts" setup>
import { useCounterStore } from '@/stores';
import { storeToRefs } from 'pinia';
const counter = useCounterStore();

const { count } = storeToRefs(counter);
const {double} = storeToRefs(counter)
const {increment} =  counter

</script>

<template>
  <div class="Test">
    <uni-card>
      <text>计数:{{ count }}</text>
      <br>
      <text>双倍:{{ double }}</text>
    </uni-card>
    <up-button @tap="increment">+</up-button>

  </div>
</template>


<style lang="scss" scoped></style>

pinia 持久化配置

执行命令安装 pinia-plugin-persistedstate 依赖

html 复制代码
pnpm i pinia-plugin-persistedstate

index.ts配置持久化

html 复制代码
import { createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
const pinia = createPinia();    // 创建 Pinia 实例

pinia.use(piniaPluginPersistedstate);   // 使用 pinia-plugin-persistedstate 持久化配置

// 默认导出,给 main.ts 使用
export default pinia;

// 模块统一导出
export * from "./modules/counter";

配置持久化 counter.ts

TypeScript 复制代码
import { defineStore} from "pinia";
import { computed, ref } from "vue";

export const useCounterStore = defineStore("counter", () => {
    
    // 声明 数据类型
    const count = ref(100);
    // 定义 计数器方法
    const increment = () => {
        count.value++;
        console.log('增加了:',count.value);
    }

    // 声明基于数据派生的计算属性
    const double = computed(() => {
        return count.value * 2;
    })
    // 返回 计数器数据、方法、计算属性
    return {
        count,
        double,
        increment,
    }  
},
    // 配置项 
    {
        // 网页端的 持久化配置
        // persist: true
        // 移动端的 持久化配置
        // persist: {
        //     storage: localStorage,
        //     key: 'count',
        // }

        // 小程序的 持久化配置, 同时兼容大部分浏览器H5
        persist: {
            storage: {
                getItem(key) {
                    return uni.getStorageSync(key);
                },
                setItem(key, value) {
                    return uni.setStorageSync(key, value);
                },
            }
        }
    }
);

报错 X [ERROR] Could not resolve "destr"

解决方法:

降低 持久化依赖的版本

html 复制代码
  "pinia-plugin-persistedstate": "^3.2.3",

测试效果,成功持久化存储到本地

请求配置

添加拦截器

TypeScript 复制代码
// src/utils/http.ts

import { useUserStore } from "@/stores/modules/user"
// 基础的请求地址
const baseUrl = "http://localhost:3000"
// 拦截器配置
const httpInterceptor = {
    // 拦截前触发
    invoke(options: UniApp.RequestOptions) {
        // 1、非 http 开头需拼接地址
        if (!options.url.startsWith('http')) {
            options.url = baseUrl + options.url
        }
        // 2、请求超时,如果没有配置则默认 60s
        options.timeout = options.timeout || 10000
        // 3、添加小程序端请求头标识
        options.header = options.header || {
            ...options.header,  // 如果请求设置方法前配置了 header 则保留之前配置过的
            'source-client': 'uniapp'
        }
        // 4、添加 token 请求标识
        const userStore = useUserStore();
        // 这里 ?. 表示 可选链操作符,如果 userStore.userInfo 为空,则 token 为 undefined
        const token = userStore.userInfo?.token;

        if  (token) {
            options.header['Authorization'] = 'Bearer ' + token;
        }
    }
}
// 添加拦截器,这里共用一份拦截器
uni.addInterceptor('request', httpInterceptor)
uni.addInterceptor('uploadFile', httpInterceptor)

添加封装请求函数

TypeScript 复制代码
// src/utils/http.ts

// .....  接着添加

// 2.3 指定响应数据结构
interface Data<T>{
    code: number,
    msg: string,
    result: T
}
// 2.2 添加类型,支持泛型
const http = <T>(options: UniApp.RequestOptions) => {
    // 返回 Promise 对象
    return new Promise<Data<T>>((resolve, reject) => {
        uni.request({
            ...options,
            // 2、请求成功
            success: (res) => {
                // 2.1 提取核心数据 res.data

                // 类型断言指定数据类型
                resolve(res.data as Data<T>)
            },
            fail: (err: UniApp.GeneralCallbackResult) => {
                reject(err)
            }
        })
    })
}

添加响应拦截

TypeScript 复制代码
// src/utils/http.ts

// .....  接着添加

// 2.2 添加类型,支持泛型
const http = <T>(options: UniApp.RequestOptions) => {
    // 返回 Promise 对象
    return new Promise<Data<T>>((resolve, reject) => {
        uni.request({
            ...options,
            // 2、请求成功
            success: (res) => {
                // 2.1 提取核心数据 res.data

                // 状态码 2xx,axios 就是这样设计的
                if (res.statusCode >= 200 && res.statusCode < 300) {
                    // 类型断言指定数据类型
                    resolve(res.data as Data<T>)
                } else if (res.statusCode === 401) {
                    // 401 错误 -> 清理用户信息,跳转登录页
                    const userStore = useUserStore();
                    userStore.clearUserInfo();
                    uni.navigateTo({        // 跳转登录页
                        url: '/pages/login/login'
                    });
                    reject(res);
                } else {
                    // 其他错误 --> 根据后端错误信息轻提示
                    uni.showToast({
                        title: (res.data as Data<T>).msg || '请求错误',
                        icon: 'none'
                    });
                    reject(res);
                }
            },
            // 响应失败
            fail: (err: UniApp.GeneralCallbackResult) => {
                uni.showToast({
                    title:'网络请求错误,请尝试切换网络',
                    icon: 'none'
                });
                reject(err)
            }
        })
    })
}

--------------------------------- 持续更新中---------------------------------

相关推荐
coding随想2 小时前
JavaScript ES6 解构:优雅提取数据的艺术
前端·javascript·es6
小小小小宇2 小时前
一个小小的柯里化函数
前端
灵感__idea2 小时前
JavaScript高级程序设计(第5版):无处不在的集合
前端·javascript·程序员
小小小小宇3 小时前
前端双Token机制无感刷新
前端
小小小小宇3 小时前
重提React闭包陷阱
前端
小小小小宇3 小时前
前端XSS和CSRF以及CSP
前端
UFIT3 小时前
NoSQL之redis哨兵
java·前端·算法
超级土豆粉3 小时前
CSS3 的特性
前端·css·css3
星辰引路-Lefan3 小时前
深入理解React Hooks的原理与实践
前端·javascript·react.js
wyn200011283 小时前
JavaWeb的一些基础技术
前端