一.项目初始化
1.创建uniapp,vue3.0项目
- 创建以 javascript 开发的工程(如命令行创建失败,请直接访问 gitee 下载模板)
npx degit dcloudio/uni-preset-vue#vite my-vue3-project
npx degit dcloudio/uni-preset-vue#vite-alpha my-vue3-project
- 创建以 typescript 开发的工程(如命令行创建失败,请直接访问 gitee 下载模板)
npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project
命令行创建项目vue3.0+typescript+vite如图所示:
- 我用的是创建以 typescript 开发的工程
npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project
- 也可以直接访问gitee去下载模板:
- 用命令行创建好了项目,里面的目录有,如图所示:
2.安装依赖
npm i/cnpm i/pnpm i都可以 我喜欢用pnpm
启动到内置浏览器运行:
启动到微信开发者工具:
启动到抖音开发者工具:
引用scss样式
pnpm install sass node-sass sass-loader@10 -D
3.语法糖插件
解决 import {ref,reactive ...} from 'vue'大量引入的问题
配置后可以不用引入,直接使用
pnpm i -D unplugin-auto-import
- 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','vue-router']
})
],
});
4.解决@路径问题
vite.config.js (增加path,alias配置)
import { defineConfig } from "vite";
import uni from "@dcloudio/vite-plugin-uni";
import AutoImport from 'unplugin-auto-import/vite';
const path = require('path');
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
uni(),
AutoImport({
imports:['vue','vue-router']
})
],
resolve:{
//配置路径别名
alias:{
'@':path.resolve(__dirname,'./src')
}
}
});
5.代码格式化
5.1、导入插件
ext.dcloud.net.cn/plugin?id=7…
点击右侧使用HbuilderX导入插件按钮,插件会导入到HbuilderX中
HbuilderX ->工具->设置->插件配置 中可以按到相关插件
tips:在这里可以配置每次默认生成的.prettierrc.js内容
点开:打开文件.prettierrc.js进行配置
5.2、设置以后只选一个为prettier格式化代码
HbuilderX ->工具->设置->编译器设置中取消勾选 保存时自动化格式化,避免和官方格式化冲突
在文件中按下ctrl+S会触发,并且会在项目目录下自动生成配置文件。
1.prettierrc.js
2.prettierignore
.prettierignore文件中增加一个node_modules,node_modules也不需要格式化
5.3、vue文件双分栏 快捷键配置
配置后在vue文件中ctrl+shift+k即可生效
5.4、嵌套注释 在任意文件中按下ctrl+/会出现选择菜单,设置以后中选一个为嵌套注释。
6.启动,运行到h5,小程序。
也可以在内置中输入 pnpm run :mp-weixin
7.引入ui组价
可选的一些组件
- uView
- First UI
- uview-plus
- uv-ui
- Vant
- ThorUI
- tmui.desin
- uni-ui
7.1、安装uni-ui
官方提供的ui,可通过uni_modules导入全部组件。 ext.dcloud.net.cn/plugin?id=5…
7.2、安装uview-plus
Hbuilder X 方式:uiadmin.net/uview-plus/…
pnpm install sass sass-loader@10 -D
pnpm install dayjs clipboard
配置见官方文档 uiadmin.net/uview-plus/…
- main.js
- uni.scss
- App.vue
- pages.json
安装uview-plus,如下:
根据官方文档去配置相关依赖: uview-plus
pnpm i sass@1.63.2 -D
pnpm i sass-loader@10 -D
pnpm install uview-plus
pnpm install dayjs
pnpm install clipboard
配置easycom组件模式
引入成功,如下:
8.tabbar
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#313131",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/tabbar/index/index",
"text": "首页",
"iconPath": "static/2.png",
"selectedIconPath": "static/1.png"
},
{
"pagePath": "pages/tabbar/like/like",
"text": "推荐",
"iconPath": "static/3.png",
"selectedIconPath": "static/4.png"
},
{
"pagePath": "pages/tabbar/my/my",
"text": "我的",
"iconPath": "static/6.png",
"selectedIconPath": "static/5.png"
}
]
}
9.封装请求
一、uniapp提供的网络请求
uniapp.dcloud.net.cn/api/request…
uni.request({
url:"",
data:{},
success:res=>{
console.log(res)
}
})
二、将uni.request进行二次封装
1.新建一个utils/request.js文件
const BASE_URL = "";
const request = ({
url, // 请求url
method, // 请求方式:get/post/put/delete
params, // get请求提交参数
data, // post/put请求提交参数
headers, // 请求头
}) => {
return new Promise((resolve, reject) => {
if (!headers) {
const token = uni.getStorageSync("token");
headers = {
"Content-Type": "application/json;charset=utf-8",
Authorization: token,
TENANT_ID: 1,
};
}
uni.request({
url: BASE_URL + url,
data: method === "get" ? params : data,
method: method,
header: headers,
// 收到开发者服务器成功返回的回调函数
success: (res) => {
const { code, msg } = res.data;
if (code == 200) {
return resolve(res.data.data);
}
uni.showToast({
icon: "none",
duration: 3000,
title: msg,
});
return reject(msg);
},
// 接口调用失败的回调函数
fail(error) {
console.log("请求错误:", error);
uni.showToast({
icon: "none",
duration: 3000,
title: "网络异常,请稍后重试!",
});
return reject(error);
},
// 接口调用结束的回调函数(调用成功、失败都会执行)
complete() {},
});
});
};
export default request;
2.在src/api目录下新建一个index.js文件
// 拿到所有api
const modulesFiles = import.meta.glob('./*/*.{js,ts}', { eager: true })
const modules = {}
Object.keys(modulesFiles).forEach((key) => {
const mod = modulesFiles[key]
const fileNameMatch = key.match(/([^/]+)\.(js|ts)$/)
const moduleName = fileNameMatch ? fileNameMatch[1] : 'unknown'
modules[moduleName] = mod.default || mod
})
console.log('[API Modules]', modules)
export default modules
3.配置全局变量api
main.js
import { createSSRApp } from "vue";
import api from "@/api/index.js";
export function createApp() {
const app = createSSRApp(App);
//配置全局api
app.config.globalProperties.$api = api
return {
app,
};
}
4.测试 api/test/test.js
import request from '@/utils/request';
const BASE_API = '/api/test';
export default {
time() {
return request({
url: BASE_API + '/time',
method: 'get',
});
},
};
5.页面中来进行一个测试 pages/tabbar/index.vue
<template>
<text>hello</text>
</template>
<script setup>
const { proxy } = getCurrentInstance();
async function test() {
let res = await proxy.$api.test.time();
console.log(res);
}
test();
</script>
<style lang="scss" scoped></style>
10.pinia状态管理库(作用就是存储的持续化和模块化)
1.安装依赖
# 这里不要使用最新版,uniapp可能还不兼容还是怎么的,用低版本的
cnpm i pinia@2.0.36
2.安装pinia-plugin-persistedstate适用于Pinia的持久化存储插件
cnpm i pinia-plugin-persistedstate
3.配置
main.js
import { createSSRApp } from "vue";
import App from "./App.vue";
import uviewPlus from "uview-plus";
import api from "@/api/index.js";
import store from "@/store";
import { createPinia } from "pinia";
import { createPersistedState } from "pinia-plugin-persistedstate";
import { useTestStore } from "@/store/modules/test.js";
export function createApp() {
const app = createSSRApp(App);
const pinia = createPinia();
pinia.use(
createPersistedState({
storage: {
getItem(key) {
const data = uni.getStorageSync(key);
return data ? JSON.parse(data) : null;
},
setItem(key, value) {
uni.setStorageSync(key, JSON.stringify(value));
},
removeItem(key) {
uni.removeStorageSync(key);
},
},
auto: true,
})
);
app.use(pinia);
//useTestStore挂载一下
app.config.globalProperties.$store = {
test: {
useTestStore: useTestStore,
},
};
app.use(uviewPlus);
app.config.globalProperties.$api = api;
return {
app,
};
}
模块化:
新建一个store文件,然后再store下建一个index.js
const modulesFiles = import.meta.glob("./modules/*.js");
const modules = {};
async function loadModules() {
const moduleEntries = await Promise.all(
Object.keys(modulesFiles).map(async (key) => {
const moduleName = key.match(/\.\/modules\/([^.]+)\./)?.[1];
const module = await modulesFiles[key]();
return [moduleName, module.default || module];
})
);
return Object.fromEntries(moduleEntries);
}
// 导出一个异步函数或用于异步初始化
export { loadModules };
再新建一个store/modules/test.js测试页面
import { defineStore } from 'pinia' //pinia的使用
import { ref } from 'vue'
export const useTestStore = defineStore('test', () => {
const count = ref(0)
function add() {
count.value++
}
return { count, add }
})
在页面里pages页面里用,两种响应式的写法:
响应式可以使用toRefs或者storeToRefs
第一种写法
<template>
<view>
<view>11111111111111111111111111</view>
<text>{{ $store.test.useTestStore().count }}</text> // 这种是响应式的
<button @click="$store.test.useTestStore().add">click</button>
</view>
</template>
<script setup>
const { proxy } = getCurrentInstance();
const title = ref("hello");
proxy.$store.test.useTestStore().add();
const count = proxy.$store.test.useTestStore().count;
</script>
<style lang="scss" scoped></style>
第二种写法:
<template>
<view>
<text>{{ count }}</text>
<button @click="$store.test.useTestStore().add">click</button>
</view>
</template>
<script setup>
import { toRef } from "vue";
const { proxy } = getCurrentInstance();
let { count } = toRefs(proxy.$store.test.useTestStore());
</script>
<style lang="scss" scoped></style>
持久化的本地存储
11.全局组件
一.easycom
uniapp.dcloud.net.cn/component/#…
传统vue组件,需要安装、引用、注册,三个步骤后才能使用组件。easycom将其精简为一步。
只要组件安装在项目的components目录下或uni_modules目录下,并符合components/组件名称/组件名称.vue目录结构。就可以不用引用、注册,直接在页面中使用。
<template>
<view>
<uni-rate></uni-rate><!-- 这里会显示一个五角星,并且点击后会自动亮星 -->
</view>
</template>
<script>
// 这里不用import引入,也不需要在components内注册uni-list组件。template里就可以直接用
export default {
data() {
return {
}
}
}
</script>
12.mixin
创建一个mixin.js 公共的实例,然后把mixin引入一下在全局main.js里面,然后页面就能直接用了,也可以局部引用。
// 抽取公用的实例 - 操作成功与失败消息提醒内容等
export default {
data() {
return {
sexList: [
{ name: '不想说', value: 0 },
{ name: '男', value: 1 },
{ name: '女', value: 2 },
],
};
},
methods: {
// 操作成功消息提醒内容
submitOk(msg) {
uni.showToast({
title: msg || '操作成功!',
});
},
// 操作失败消息提醒内容
submitFail(msg) {
uni.showToast({
icon: 'none',
duration: 3000,
title: msg || '网络异常,请稍后重试!',
});
},
// 加载框
submitLoading(msg) {
uni.showLoading({
title: msg || '加载中',
});
setTimeout(function () {
uni.hideLoading();
}, 1000);
},
},
};
全局引用
import { createSSRApp } from 'vue';
import App from './App.vue';
// 抽取公用的实例 - 操作成功与失败消息提醒内容等
import mixin from '@/utils/mixin.js';
export function createApp() {
const app = createSSRApp(App);
app.mixin(mixin);
return { app };
}
局部引用
<script>
import mixin from '@/utils/mixin.js';
export default {
mixins: [mixin],
};
</script>
<script setup>
const { proxy } = getCurrentInstance();
async function submit() {
proxy.submitOk('保存成功');
}
</script>
在页面中使用
<template>
<view>{{ sexList }}</view>
</template>
<script setup>
const { proxy } = getCurrentInstance();
async function submit() {
proxy.submitOk('保存成功');
}
</script>
13.全局过滤器filters
当后端返回的数据格式不是前端想要的时候,我们前端可以将后端返回的数据处理成自己需要的格式。 常见的有:
-
- 时间过滤器
在utils文件中新建filters.js
import { getCurrentInstance } from "@vue/runtime-core"
export const filters ={
//获取性别值
sexName:(sex)=>{
//拿到mixin混入的属性值
const {proxy} = getCurrentInstance();
return proxy.sexList.find((obj)=>obj.value==sex).name;
},
};
在main.js中引入
import filters from "@/utils/filters.js";
//省略...
app.config.globalProperties.$filters=filters;
页面中 使用
{{ $filters.sexName(userObj.sex) }}