官方文档:uni-app官网
uni-app
是一个使用 Vue.js 开发所有前端应用的框架,开发一套代码,可以在h5端、app端、小程序端同时使用。
开发一套代码,在微信小程序运行、h5端口、app端(手机模拟器 夜神模拟器)。
uniapp全局配置
index.html
App.vue
main.js
pages.json
globalStyle Object 否 设置默认页面的窗口表现
pages Object Array 是 设置页面路径及窗口表现
easycom Object 否 组件自动引入规则 2.5.5+
tabBar Object 否 设置底部 tab 的表现
组件
1、内置组件
视图容器组件:view scroll-view swiper swiper-item
基础内容组件: icon text rich-text
表单组件:form input radio buttom checkbox switch textarea
媒体组件:image radio audio
路由跳转组件:navigator openType="navigate|redirect|switchTab|navigateBack"
map地图
2、扩展 组件 uni-ui
3、第三方组件库 uview-ui 秋云-ucharts (插件市场 )
uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架
scss语法(了解)
<template>
<view class="outer">
<view class="c1">
<view class="c11">c1-->c11</view>
</view>
<view class="c2">
<view class="c11">c2-->c11</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
}
}
</script>
<style lang="scss">
/* css选择器
id #
标签 标签名
类选择 .
属性选择器 [name='admin']
子元素 >
子孙元素 空格
通配 *
*/
// .c2{
// background-color: gray;
// height: 150px;
// }
// .c2>.c11{
// background-color: gold;
// height: 100px;
// }
.c1{
.c11{
background-color: red;
height: 100px;
}
}
.c2{
background-color: gray;
height: 150px;
.c11{
background-color: gold;
height: 100px;
}
}
</style>
vue2语法(熟悉)
<template>
<view class="container">
{{id}}
<button @click="m1()">++</button>
<button @tap="m1()">++</button>
</view>
</template>
<script>
export default {
data() {
return {
id:1,
href: 'https://uniapp.dcloud.io/component/README?id=uniui'
}
},
methods: {
m1(){
console.log("-----m1-----");
this.id = ++this.id;
},
m2(){
console.log("=====m2====");
}
},
mounted() {
this.m1();
}
}
</script>
<style>
.container {
padding: 20px;
font-size: 14px;
line-height: 24px;
}
</style>
一、常见的事件类型
@click
用于处理用户点击操作。 可以绑定在按钮、列表项等元素上,当用户点击时触发相应的逻辑处理。 是标准的HTML DOM事件,在浏览器中通用。
@tap
也是用于处理用户点击事件。 是小程序和移动端框架(如微信、uni-app)封装的事件,专为触摸交互优化。 在移动端,由于浏览器的click延迟可能会导致用户体验卡顿,而@tap通过原生触摸事件(touchstart/touchend)实现即时响应。 在H5端,@tap会被编译为click(但通过触摸事件模拟,无延迟);在小程序/App端,@tap直接调用原生触摸事件;在PC端可能无效,需用@click。
@longpress 和 @longtap
用于处理长按操作。 可以绑定在需要长按触发逻辑的元素上,例如长按显示气泡框、长按删除等操作。 这两个事件在功能上相似,但具体实现和触发条件可能略有不同,具体使用哪个事件取决于你的应用需求和uniapp的版本。
其他手势事件: @touchstart:手指触摸动作开始。 @touchmove:手指触摸后移动。 @touchcancel:手指触摸被打断,如来电提醒、弹窗。 @touchend:手指触摸动作结束,如松开按钮。 这些事件为开发者提供了丰富的用户交互手段,可以根据实际需求选择合适的事件来处理用户交互和页面逻辑。
二、api
1、发起网络请求
uni.request
2、页面跳转的
uni.redirectTo
uni.naviateTo
uni.switchTab
uni.navigateBack
uni.relaunch
3、界面交互api
弹出框
uni.showToast uni.HideToast
uni.showLoading uni.HideLoading
4、定时任务
setTimeout
三、完整模块的api
列表查询
<template>
<view>
<view class="u-page">
<u-list>
<u-list-item v-for="(item, index) in indexList" :key="index">
<u-cell :title="item.channelName">
<u-avatar
slot="icon"
shape="square"
size="35"
:src="item.userImg"
customStyle="margin: -3px 5px -3px 0"
></u-avatar>
</u-cell>
</u-list-item>
</u-list>
</view>
</view>
</template>
<script>
export default {
data() {
return {
indexList:[]
}
},
methods: {
loadChannel(){
//发起网络请求,查询数据
uni.request({
url:"http://localhost:8080/system/channels/list",
method:"GET",
header: {
'authorization': 'Bearer '+uni.getStorageSync('token')
},
data:{
pageNum:1,
pageSize:10,
},
success: (res) => {
console.log(res.data);
this.indexList = res.data.rows;
}
})
}
},
onLoad() {
this.loadChannel();
}
}
</script>
<style>
</style>
封装request.js
1. 创建环境配置文件
在项目根目录创建 config/env.js
,管理不同环境的 URL:
// config/env.js
const ENV = process.env.NODE_ENV || 'development'; // 获取当前环境
const envConfig = {
development: { // 开发环境
BASE_API: 'http://dev.api.example.com',
STATIC_URL: 'http://dev.static.example.com'
},
production: { // 生产环境
BASE_API: 'https://api.example.com',
STATIC_URL: 'https://static.example.com'
},
// 其他环境(如测试环境)
test: {
BASE_API: 'http://test.api.example.com',
STATIC_URL: 'http://test.static.example.com'
}
};
// 导出当前环境配置
export default envConfig[ENV];
2. 封装全局请求工具
创建 utils/request.js
,实现以下功能:
自动拼接基础 URL
拦截请求/响应
统一错误处理
自动携带 Token
// utils/request.js
import env from '@/config/env'; // 引入环境配置
/**
* 封装 uni.request
* @param {Object} options 请求配置
*/
const request = (options) => {
// 1. 处理请求 URL(拼接环境变量中的 BASE_API)
if (!options.url.startsWith('http')) {
options.url = env.BASE_API + options.url;
}
// 2. 默认请求配置
const defaultOptions = {
method: 'POST',
header: {
'Content-Type': 'application/json',
'Authorization': uni.getStorageSync('token') || '' // 自动携带 Token
}
};
// 3. 合并配置
options = { ...defaultOptions, ...options };
// 4. 返回 Promise
return new Promise((resolve, reject) => {
uni.request({
...options,
success: (res) => {
// 5. 统一处理 HTTP 状态码
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data); // 请求成功
} else if (res.statusCode === 401) {
// Token 过期处理
uni.navigateTo({ url: '/pages/login/login' });
reject(new Error('未登录或登录已过期'));
} else {
reject(res.data); // 其他错误
}
},
fail: (err) => {
// 6. 网络错误处理
uni.showToast({ title: '网络错误', icon: 'none' });
reject(err);
}
});
});
};
// 7. 快捷方法封装(GET/POST/PUT/DELETE)
export const get = (url, data, options = {}) => {
return request({ url, data, method: 'GET', ...options });
};
export const post = (url, data, options = {}) => {
return request({ url, data, method: 'POST', ...options });
};
export default request;
3. 实际使用示例
import { get, post } from '@/utils/request';
export default {
methods: {
// GET 请求
async fetchData() {
try {
const res = await get('/user/info', { id: 123 });
console.log(res);
} catch (err) {
console.error(err);
}
},
// POST 请求
async submitForm() {
try {
const res = await post('/user/login', {
username: 'admin',
password: '123456'
});
console.log(res);
} catch (err) {
console.error(err);
}
}
}
};
4、普通表单新增
<template>
<view>
<uni-forms ref="form" :modelValue="formData" :rules="rules">
<uni-forms-item label="渠道名称" name="channelName">
<uni-easyinput type="text" v-model="formData.channelName" placeholder="请输入渠道名称" />
</uni-forms-item>
<uni-forms-item label="渠道编码" name="channelCode">
<uni-easyinput type="text" v-model="formData.channelCode" placeholder="请输入渠道名称" />
</uni-forms-item>
</uni-forms>
<button @click="submit">Submit</button>
</view>
</template>
<script>
import {
get,
post
} from '@/utils/request';
export default {
data() {
return {
// 表单数据
formData: {
channelName: '平安好卫士',
channelCode: 'pyhws'
},
rules: {
// 对name字段进行必填验证
channelName: {
rules: [{
required: true,
errorMessage: '请输入渠道名',
},
{
minLength: 3,
maxLength: 5,
errorMessage: '长度在 {minLength} 到 {maxLength} 个字符',
}
]
},
// 对code字段进行必填验证
channelCode: {
rules: [{
required: true,
errorMessage: '请输入渠道编码',
}]
}
}
}
},
methods: {
async loadChannel() {
const resp = await get('/system/channels/list', {});
console.log(resp);
},
async submit() {
const validate = await this.$refs.form.validate();
console.log('表单数据信息:', validate);
//接收数据
console.log(this.formData);
//发起网路请求
const resp = await post('/system/channels', this.formData);
console.log(resp, "新增结果");
if (resp.code == 200) { //成功
//跳转到列表查询
uni.navigateTo({
url: "/pages/channel/channel"
})
} else {
console.log("新增失败");
}
}
},
onLoad() {
this.loadChannel();
}
}
</script>
<style>
</style>
5、文件上传+form表单
<template>
<view>
<uni-forms ref="form" :modelValue="formData" :rules="rules">
<uni-forms-item label="渠道名称" name="channelName">
<uni-easyinput type="text" v-model="formData.channelName" placeholder="请输入渠道名称" />
</uni-forms-item>
<uni-forms-item label="渠道编码" name="channelCode">
<uni-easyinput type="text" v-model="formData.channelCode" placeholder="请输入渠道名称" />
</uni-forms-item>
<uni-forms-item label="选择图片" name="userImg">
<u-upload :fileList="fileList1" @afterRead="afterRead" @delete="deletePic" name="1" multiple
:maxCount="10"></u-upload>
</uni-forms-item>
</uni-forms>
<button @click="submit">Submit</button>
</view>
</template>
<script>
import {
get,
post
} from '@/utils/request';
export default {
data() {
return {
fileList1: [],
// 表单数据
formData: {
channelName: '平安好卫士',
channelCode: 'pyhws'
},
rules: {
// 对name字段进行必填验证
channelName: {
rules: [{
required: true,
errorMessage: '请输入渠道名',
},
{
minLength: 3,
maxLength: 5,
errorMessage: '长度在 {minLength} 到 {maxLength} 个字符',
}
]
},
// 对code字段进行必填验证
channelCode: {
rules: [{
required: true,
errorMessage: '请输入渠道编码',
}]
}
}
}
},
methods: {
async loadChannel() {
//const resp = await get('/system/channels/list', {});
//console.log(resp);
},
async submit() {
const validate = await this.$refs.form.validate();
console.log('表单数据信息:', validate);
//接收数据
console.log(this.formData);
//发起网路请求
const resp = await post('/system/channels', this.formData);
console.log(resp, "新增结果");
if (resp.code == 200) { //成功
//跳转到列表查询
uni.navigateTo({
url: "/pages/channel/channel"
})
} else {
console.log("新增失败");
}
},
// 删除图片
deletePic(event) {
this[`fileList${event.name}`].splice(event.index, 1);
},
// 新增图片
async afterRead(event) {
// 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
let lists = [].concat(event.file);
let fileListLen = this[`fileList${event.name}`].length;
lists.map((item) => {
this[`fileList${event.name}`].push({
...item,
status: "uploading",
message: "上传中",
});
});
for (let i = 0; i < lists.length; i++) {
const result = await this.uploadFilePromise(lists[i].url);
// console.log(JSON.parse(result).url,"--------");
// this.formData.userImg = JSON.parse(result).url;
let item = this[`fileList${event.name}`][fileListLen];
this[`fileList${event.name}`].splice(
fileListLen,
1,
Object.assign(item, {
status: "success",
message: "",
url: JSON.parse(result).url,
})
);
fileListLen++;
}
//打印输出所有的文件列表
console.log(this.fileList1);
//选择第一张照片,存储到数据库表
this.formData.userImg = this.fileList1[0].url;
},
uploadFilePromise(url) {
return new Promise((resolve, reject) => {
let a = uni.uploadFile({
url: "http://localhost:8080/common/upload", // 仅为示例,非真实的接口地址
filePath: url,
name: "file",
formData: {
user: "test",
},
header: {
'authorization': 'Bearer ' + uni.getStorageSync('token')
},
success: (res) => {
setTimeout(() => {
console.log(res.data, "文件上传后返回响应对象");
resolve(res.data);
}, 1000);
},
});
});
}
},
onLoad() {
this.loadChannel();
}
}
</script>
<style>
</style>
6、删除
request.js
export const put = (url, data, options = {}) => {
return request({ url, data, method: 'PUT', ...options });
};
export const del = (url, data, options = {}) => {
return request({ url, data, method: 'DELETE', ...options });
};
<u-list-item v-for="(item, index) in indexList" :key="index">
<u-cell :title="item.channelName">
<u-avatar slot="icon" shape="square" size="35" :src="item.userImg"
customStyle="margin: -3px 5px -3px 0"></u-avatar>
<text slot="value">修改|</text>
<text slot="value" @click="deleteChannel(item, index)">删除</text>
</u-cell>
</u-list-item>
</u-list>
async deleteChannel(item, index){
//获取主键
console.log(item.channelId);
const res = await del("/system/channels/"+item.channelId);
console.log(res);
//判断失败,提醒
//成功,刷新
this.loadChannel();
},
7、修改
1、点击修改按钮,传递id到修改页面
2、修改页面 onload函数中获取主键id
3、判断id是否存在,存在根据id查询详情,回显数据
4、更新数据到数据库表
5、联调新增和修改。
toEdit(item){
//跳转到新增|修改页面 传递主键
uni.navigateTo({
url:"/pages/channel/channelAdd?id="+item.channelId
})
},
onLoad(options) {
//判断是否是修改
if(options != null && options.id!=null && options.id!=''){
uni.setNavigationBarTitle({
title: '修改渠道'
});
//调用方法,查询详情
this.getChannelDtail(options.id);
}
}
async submit() {
const validate = await this.$refs.form.validate();
//接收数据
console.log(this.formData);
var resp = null ;
//发起网路请求
if(this.formData.channelId==null || this.formData.channelId==''){//新增
resp = await post('/system/channels', this.formData);
}else{//修改
resp = await put('/system/channels', this.formData);
}
if (resp.code == 200) { //成功
//跳转到列表查询
uni.navigateTo({
url: "/pages/channel/channel"
})
} else {
console.log("操作失败");
}
},
8、下拉刷新
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#dfd7ce",
"backgroundColor": "#F8F8F8",
"app-plus": {
"background": "#efeff4"
},
"enablePullDownRefresh": true
}
onPullDownRefresh() {
let pageSize = Math.ceil(this.total/3);
if(this.currentPage >= pageSize){
console.log("已经最后一页");
}else{
this.loadChannel(++this.currentPage);
}
setTimeout(()=>{
uni.stopPullDownRefresh();
},1000);
}
9、搜索+分页
<uni-forms ref="form" :modelValue="formData" >
<uni-forms-item label="渠道名称" name="channelName">
<uni-easyinput type="text" v-model="formData.channelName" placeholder="请输入渠道名称" />
</uni-forms-item>
<uni-forms-item label="渠道编码" name="channelCode">
<uni-easyinput type="text" v-model="formData.channelCode" placeholder="请输入渠道编码" />
</uni-forms-item>
</uni-forms>
<button @click="search">搜索</button>
async search(){
this.indexList = [];
this.loadChannel(1) ;
},