常见开发任务.md
14 KB
常见开发任务
最后更新: 2026-02-09 目的: 记录项目中的常见开发任务和解决方案
1. 添加新页面
步骤
# 1. 创建页面目录
mkdir src/views/mypage
# 2. 创建页面文件
touch src/views/mypage/index.vue
touch src/views/mypage/index.config.js
页面文件
<!-- src/views/mypage/index.vue -->
<template>
<div class="mypage">
<h1>{{ title }}</h1>
</div>
</template>
<script setup>
/**
* 我的页面
*
* @description 这是一个示例页面
*/
import { ref } from 'vue';
const title = ref('我的页面');
</script>
<style lang="less" scoped>
.mypage {
padding: 20px;
h1 {
font-size: 24px;
}
}
</style>
页面配置
// src/views/mypage/index.config.js
export default {
navigationBarTitleText: '我的页面',
};
添加路由
// src/router/routes/modules/mypage/index.js
export default {
path: '/mypage',
name: 'MyPage',
component: () => import('@/views/mypage/index.vue'),
meta: {
title: '我的页面',
},
};
2. 添加新组件
步骤
# 1. 创建组件目录
mkdir src/components/MyComponent
# 2. 创建组件文件
touch src/components/MyComponent/index.vue
组件文件
<!-- src/components/MyComponent/index.vue -->
<template>
<div class="my-component">
<h2>{{ title }}</h2>
<slot></slot>
</div>
</template>
<script setup>
/**
* 我的组件
*
* @description 这是一个示例组件
* @component MyComponent
*/
const props = defineProps({
/** 标题 */
title: {
type: String,
default: '',
},
});
const emit = defineEmits({
/** 点击事件 */
click: (event) => true,
});
</script>
<style lang="less" scoped>
.my-component {
h2 {
font-size: 20px;
}
}
</style>
使用组件
<template>
<div>
<MyComponent
title="组件标题"
@click="handleClick"
>
组件内容
</MyComponent>
</div>
</template>
<script setup>
import MyComponent from '@components/MyComponent/index.vue';
const handleClick = (event) => {
console.log('组件被点击:', event);
};
</script>
3. 添加 API 接口
步骤
# 1. 创建 API 文件
touch src/api/myfeature.js
API 文件
/**
* 我的特性 API
*
* @description 我的特性相关接口
*/
import { fn, fetch } from '@/api/fn';
const Api = {
FEATURE: '/srv/?a=myfeature',
};
/**
* 获取特性数据
*
* @description 获取特性数据
* @param {Object} params - 请求参数
* @param {number} params.id - ID
* @returns {Promise<Object>} 响应数据
*/
export const featureAPI = (params) => fn(fetch.get(Api.FEATURE, params));
/**
* 提交特性数据
*
* @description 提交特性数据
* @param {Object} params - 请求参数
* @param {string} params.name - 名称
* @returns {Promise<Object>} 响应数据
*/
export const submitFeatureAPI = (params) => fn(fetch.post(Api.FEATURE, params));
使用 API
<script setup>
import { featureAPI, submitFeatureAPI } from '@/api/myfeature';
import { onMounted } from 'vue';
const fetchData = async () => {
try {
const { data } = await featureAPI({ id: 123 });
if (data) {
console.log('获取数据成功:', data);
}
} catch (err) {
console.error('获取数据失败:', err);
}
};
const submitData = async () => {
try {
const { data } = await submitFeatureAPI({ name: '名称' });
if (data) {
console.log('提交成功:', data);
}
} catch (err) {
console.error('提交失败:', err);
}
};
onMounted(() => {
fetchData();
});
</script>
4. 添加 Store
步骤
# 1. 创建 Store 文件
touch src/store/myfeature.js
Store 文件
/**
* 我的特性 Store
*
* @description 管理特性相关状态
*/
import { defineStore } from 'pinia';
export const useMyFeatureStore = defineStore('myfeature', {
state: () => ({
data: null,
loading: false,
error: null,
}),
getters: {
/**
* 是否有数据
*/
hasData: (state) => state.data !== null,
/**
* 数据数量
*/
dataCount: (state) => state.data?.length || 0,
},
actions: {
/**
* 获取数据
*
* @param {number} id - ID
*/
async fetchData(id) {
this.loading = true;
this.error = null;
try {
const { data } = await featureAPI({ id });
this.data = data;
} catch (err) {
this.error = err.message;
} finally {
this.loading = false;
}
},
/**
* 清空数据
*/
clearData() {
this.data = null;
this.error = null;
},
},
});
使用 Store
<script setup>
import { useMyFeatureStore } from '@/store/myfeature';
import { onMounted } from 'vue';
const featureStore = useMyFeatureStore();
onMounted(() => {
featureStore.fetchData(123);
});
</script>
<template>
<div v-if="featureStore.loading">加载中...</div>
<div v-else-if="featureStore.error">{{ featureStore.error }}</div>
<div v-else>
<p>数据数量: {{ featureStore.dataCount }}</p>
<p>有数据: {{ featureStore.hasData }}</p>
</div>
</template>
5. 路由跳转
方式 1: 路径跳转
import { useRouter } from 'vue-router';
const router = useRouter();
// 跳转(Hash 模式需要包含前缀)
router.push('/index.html/mypage');
方式 2: 命名路由
import { useRouter } from 'vue-router';
const router = useRouter();
// 跳转(推荐)
router.push({ name: 'MyPage' });
方式 3: 带参数跳转
import { useRouter } from 'vue-router';
const router = useRouter();
// 带查询参数
router.push({
name: 'MyPage',
query: { id: 123, name: 'test' }
});
// 带路径参数
router.push({
name: 'MyPageDetail',
params: { id: 123 }
});
方式 4: 返回
import { useRouter } from 'vue-router';
const router = useRouter();
// 返回上一页
router.back();
// 或
router.go(-1);
6. 获取路由参数
查询参数
import { useRoute } from 'vue-router';
const route = useRoute();
// 获取查询参数
const id = route.query.id;
const name = route.query.name;
路径参数
import { useRoute } from 'vue-router';
const route = useRoute();
// 获取路径参数
const id = route.params.id;
7. 使用 Vant 组件
按钮
<template>
<van-button type="primary">主要按钮</van-button>
<van-button type="success">成功按钮</van-button>
<van-button type="warning">警告按钮</van-button>
<van-button type="danger">危险按钮</van-button>
<van-button plain>朴素按钮</van-button>
<van-button round>圆形按钮</van-button>
</template>
表单
<template>
<van-form @submit="onSubmit">
<van-cell-group inset>
<van-field
v-model="username"
name="username"
label="用户名"
placeholder="用户名"
:rules="[{ required: true, message: '请填写用户名' }]"
/>
<van-field
v-model="password"
type="password"
name="password"
label="密码"
placeholder="密码"
:rules="[{ required: true, message: '请填写密码' }]"
/>
</van-cell-group>
<div style="margin: 16px;">
<van-button round block type="primary" native-type="submit">
提交
</van-button>
</div>
</van-form>
</template>
<script setup>
import { ref } from 'vue';
const username = ref('');
const password = ref('');
const onSubmit = (values) => {
console.log('表单数据:', values);
};
</script>
弹窗
<template>
<van-button type="primary" @click="showDialog">显示弹窗</van-button>
</template>
<script setup>
import { showDialog } from 'vant';
const showDialog = () => {
showDialog({
title: '标题',
message: '这是弹窗内容',
}).then((action) => {
console.log('确认', action);
}).catch(() => {
console.log('取消');
});
};
</script>
8. 使用 Element Plus 组件
按钮
<template>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
<el-button round>圆形按钮</el-button>
</template>
表格
<template>
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="age" label="年龄" width="180" />
<el-table-column prop="address" label="地址" />
</el-table>
</template>
<script setup>
import { ref } from 'vue';
const tableData = ref([
{
name: '张三',
age: 30,
address: '北京市',
},
{
name: '李四',
age: 25,
address: '上海市',
},
]);
</script>
9. 添加 Keep-Alive 缓存
步骤
// 在 store 中添加页面
import { useMainStore } from '@/store';
const mainStore = useMainStore();
// 添加需要缓存的页面
const keepThisPage = () => {
const keepPages = [...mainStore.keepPages];
if (!keepPages.includes('PageName')) {
keepPages.push('PageName');
}
mainStore.keepPages = keepPages;
};
// 移除缓存
const removeKeepPage = () => {
const keepPages = mainStore.keepPages.filter(page => page !== 'PageName');
mainStore.keepPages = keepPages.length ? keepPages : ['default'];
};
使用
<script setup>
import { onMounted } from 'vue';
import { useMainStore } from '@/store';
const mainStore = useMainStore();
onMounted(() => {
// 添加到缓存
mainStore.keepThisPage();
});
</script>
10. 处理微信分享
步骤
// 引入微信分享工具
import { share } from '@/utils/share';
// 设置分享
const setShare = () => {
share({
title: '分享标题',
desc: '分享描述',
link: window.location.href,
imgUrl: 'https://example.com/share.png',
});
};
// 在页面加载时设置
onMounted(() => {
setShare();
});
11. 添加音频播放
单模式
<template>
<audioBackground
:audio-url="audioUrl"
:autoplay="false"
@play="handlePlay"
@pause="handlePause"
/>
</template>
<script setup>
import audioBackground from '@components/audioBackground.vue';
import { ref } from 'vue';
const audioUrl = ref('/audio/guide.mp3');
const handlePlay = () => {
console.log('开始播放');
};
const handlePause = () => {
console.log('暂停播放');
};
</script>
播放列表模式
<template>
<audioList
v-model:playlist="playlist"
:current-index="currentIndex"
/>
</template>
<script setup>
import audioList from '@components/audioList.vue';
import { ref } from 'vue';
const playlist = ref([
{
id: 1,
title: '音频 1',
url: '/audio/1.mp3',
},
{
id: 2,
title: '音频 2',
url: '/audio/2.mp3',
},
]);
const currentIndex = ref(0);
</script>
12. 使用高德地图
初始化地图
import AMapLoader from '@amap/amap-jsapi-loader';
const initMap = async () => {
try {
const AMap = await AMapLoader.load({
key: 'YOUR_AMAP_KEY',
version: '2.0',
plugins: ['AMap.Scale', 'AMap.ToolBar'],
});
const map = new AMap.Map('container', {
zoom: 11,
center: [116.397428, 39.90923],
});
return map;
} catch (err) {
console.error('地图加载失败:', err);
}
};
添加标记
const addMarker = (map, position) => {
const marker = new AMap.Marker({
position: position,
map: map,
});
return marker;
};
13. 错误处理
统一错误处理
const handleError = (err) => {
console.error('操作失败:', err);
// 显示错误提示
showToast(err.message || '操作失败,请重试');
// 上报错误
// reportError(err);
};
// 使用
try {
await someAPI();
} catch (err) {
handleError(err);
}
Toast 提示
import { showToast } from 'vant';
// 成功提示
showToast('操作成功');
// 错误提示
showToast({
type: 'fail',
message: '操作失败',
});
14. 加载状态
使用 Loading
<template>
<div v-if="loading" class="loading">加载中...</div>
<div v-else>
<!-- 内容 -->
</div>
</template>
<script setup>
import { ref } from 'vue';
const loading = ref(false);
const fetchData = async () => {
loading.value = true;
try {
const { data } = await someAPI();
// 处理数据
} catch (err) {
console.error(err);
} finally {
loading.value = false;
}
};
</script>
使用 Vant Loading
<template>
<van-button @click="showLoading">显示加载</van-button>
</template>
<script setup>
import { showLoadingToast, closeToast } from 'vant';
const showLoading = () => {
showLoadingToast({
message: '加载中...',
forbidClick: true,
duration: 0,
});
// 模拟异步操作
setTimeout(() => {
closeToast();
}, 2000);
};
</script>
15. 图片处理
图片懒加载
<template>
<van-image
:src="imageUrl"
lazy-load
:show-error="true"
:show-loading="true"
>
<template #error>
<div class="error">加载失败</div>
</template>
</van-image>
</template>
<script setup>
import { ref } from 'vue';
const imageUrl = ref('/images/example.jpg');
</script>
图片预览
<template>
<van-image
:src="imageUrl"
@click="previewImage"
/>
</template>
<script setup>
import { ref } from 'vue';
import { showImagePreview } from 'vant';
const imageUrl = ref('/images/example.jpg');
const images = ref([
'/images/1.jpg',
'/images/2.jpg',
'/images/3.jpg',
]);
const previewImage = () => {
showImagePreview({
images: images.value,
startPosition: 0,
});
};
</script>