以反馈页面为例
添加Vue页面
在views文件夹中添加文件夹,再添加文件(注意命名格式)
添加示例代码
<template>
<div>
<van-nav-bar
:title="this.title"
left-text="返回"
left-arrow
@click-left="goBack"
fixed
/>
<div>
<van-form @submit="submitFeedback">
<van-field
v-model="feedback.ftext"
label="反馈"
placeholder="请输入您的反馈"
type="textarea"
rows="3"
style="margin-top: 60px;"
required
/>
<van-uploader
:after-read="afterReadFile"
:max-count="1"
accept="image/gif, image/jpeg, image/png"
style="margin-top: 20px;"
>
<div class="avatar-container">
<img v-if="feedback.attachment"
:src="feedback.attachment" class="avatar" alt="Uploaded Avatar" />
<img v-else src="https://th.bing.com/th/id/OIP.X-5ho42VHJwTZg1ixPxo4wAAAA?pid=ImgDet&rs=1" class="avatar" alt="Default Plus Image" />
</div>
</van-uploader>
<div class="submit-button">
<van-button type="primary" native-type="submit" block>提交反馈</van-button>
</div>
</van-form>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
title: '反馈',
feedback: {
ftext: '',
attachment: '',
},
};
},
methods: {
goBack() {
this.$router.push({ path: '/profile' });
},
afterReadFile(file) {
// 这里你可以处理文件上传,然后将链接或其他信息存储到 feedback.attachment
const formData = new FormData();
formData.append('file', file.file); // 'file' 必须与后端接收的字段名相匹配
axios
.post(`${process.env.VUE_APP_BASE_URL}auth/uploadavatar`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
.then((response) => {
console.log('上传成功', response.data);
this.feedback.attachment = response.data.data.avatar_url;
})
.catch((error) => {
console.error('上传失败', error);
this.$bvToast.toast('上传失败', {
title: '系统提醒',
variant: 'danger',
solid: true,
});
});
},
submitFeedback() {
if (this.feedback.ftext.trim() === '') {
this.$toast('反馈内容不能为空');
return;
}
this.$axios
.post(`${process.env.VUE_APP_BASE_URL}auth/submitFeedback`, this.feedback)
.then((response) => {
if (response.data.code === 200) {
this.$toast('反馈提交成功');
// 你可以在这里做一些跳转或其他操作
this.$router.push('/profile');
} else {
this.$toast(`反馈提交失败: ${response.data.message}`);
}
})
.catch((error) => {
this.$toast(`提交出错: ${error.message}`);
});
},
},
};
</script>
<style>
.submit-button {
margin: 20px;
}
body {
background-color: #f0f0f0; /* 灰色背景 */
}
</style>
在router/index.js中添加
{
path: '/feedback',
name: 'feedback',
meta: {
auth: true,
},
component: () => import('@/views/feedback/FeedbackView.vue'),
},
-
path: '/feedback'
: 这一行定义了路由的路径,也就是URL的一部分。当用户访问网站的/feedback
部分时,该路由就会被触发。 -
name: 'feedback'
: 这是给路由一个具体的名字,有助于程序中其他地方引用。 -
meta: { auth: true }
:meta
字段通常用于存储路由的一些元信息。auth: true
表明访问这个路由需要用户认证。 -
component: () => import('@/views/feedback/FeedbackView.vue')
: 这一行是指定当路由被触发时应该加载哪个组件。这里使用了动态导入(import
),表示FeedbackView.vue
组件只有在路由被访问时才会被加载。这可以提高应用程序的初始加载速度,因为不需要一开始就加载所有组件。
然后运行就能看到了
常见的utils,service,store/module文件夹的结构讲解,以用axios发送请求为例
我们原本的axios是直接写在vue文件中,在代码量少的时候看着还行,但是一旦这个页面变得复杂,封装的重要性就体现出来了。
在utils中有request.js,可以当成一个发请求的黑盒。
以下节选需要添加的相关代码
postService.js
import request from '@/utils/request';
const submitFeedback = ({ ftext, attachment }) => {
return request.post('auth/submitFeedback', { ftext, attachment });
};
export default {
submitFeedback,
};
submitFeedback
函数的定义是一个 Service 的示例。它封装了提交反馈的逻辑(通过 HTTP POST 请求),并提供了一个统一的接口供其他部分(例如 UI 组件或 Vuex 动作)使用。这有助于保持这些其他部分的代码清晰和专注,同时使反馈提交的逻辑易于更改和测试。
store/module/post.js
import postService from '@/service/postService';
const postModule = {
namespaced: true,
actions: {
submitFeedback(context, { ftext, attachment }) {
return new Promise((resolve, reject) => {
postService.submitFeedback({ ftext, attachment }).then((res) => {
resolve(res);
}).catch((err) => {
reject(err);
});
});
},
},
};
export default postModule;
一个 Vuex 模块的定义,它用于管理 Vue 应用程序中的状态。下面是代码的具体作用:
-
定义 postModule:
const postModule
定义了一个名为 postModule 的 Vuex 模块。 -
命名空间(namespaced):
namespaced: true
表示这个模块是命名空间化的,这样就可以让这个模块的状态和其他模块隔离开。 -
actions:这个模块中定义了一个名为
submitFeedback
的 action。- submitFeedback:这个 action 接受一个包括
ftext
和attachment
的对象作为参数,并返回一个 Promise。 - 该 action 使用
postService.submitFeedback
方法向服务器发送反馈数据,并根据响应来决定是否解决(resolve
)或拒绝(reject
)这个 Promise。
- submitFeedback:这个 action 接受一个包括
Vuex 模块将不同的关注点分离开来,这种方式使得每个模块的代码都保持简洁和聚焦,提高了可维护性和可扩展性。
store/index.js
import postModule from './module/post';
modules: {
postModule,
},
这段代码是一个 Vue 应用的 Vuex 存储的主配置文件,主要作用是定义和配置 Vue 应用的中央状态管理系统。
FeedbackView.vue
mapActions
先导入
import { mapActions } from 'vuex';
methods中添加
...mapActions('postModule', { SubmitFeedback: 'submitFeedback' }),
mapActions
是一个辅助函数,用于将组件的方法映射为 store.dispatch
调用。它使得你可以更容易地在组件中调用 Vuex 的 actions。
-
引入
mapActions
:首先,从 'vuex' 导入了mapActions
辅助函数。 -
使用
mapActions
:调用mapActions
并传递两个参数。第一个参数是模块的命名空间,即 'postModule'。第二个参数是一个对象,用于定义组件中的方法名称与模块中的 action 名称之间的映射关系。 -
映射 Action:这个映射表明,当在组件中调用
SubmitFeedback
方法时,它实际上会调用 'postModule' 模块中的 'submitFeedback' action。这样,你就可以在组件中像调用普通方法一样调用这个 action。 -
扩展操作符:扩展操作符 (
...
) 用于将映射后的方法合并到组件的methods
对象中。这使得你可以直接在组件模板和逻辑中使用这些方法。
这样做可以使得组件与 Vuex 存储的耦合降低,以一种更直观的方式调用 Vuex actions。
调用submitFeedback
把
this.$axios
.post(`${process.env.VUE_APP_BASE_URL}auth/submitFeedback`, this.feedback)
改为
this.SubmitFeedback(this.feedback)
就大功告成了。
<template>
</template>
<script>
import { mapActions } from 'vuex';
export default {
data() {
return {
title: '反馈',
feedback: {
ftext: '',
attachment: '',
},
};
},
methods: {
...mapActions('postModule', { SubmitFeedback: 'submitFeedback' }),
submitFeedback() {
if (this.feedback.ftext.trim() === '') {
this.$toast('反馈内容不能为空');
return;
}
this.SubmitFeedback(this.feedback)
.then((response) => {
if (response.data.code === 200) {
this.$toast('反馈提交成功');
// 你可以在这里做一些跳转或其他操作
this.$router.push('/profile');
} else {
this.$toast(`反馈提交失败: ${response.data.message}`);
}
})
.catch((error) => {
this.$toast(`提交出错: ${error.message}`);
});
},
},
};
</script>
<style>
</style>
为什么花这么大力气封装请求,直接在文件中两行搞定不香吗?
这是我的亲身教训。
封装后,当多个文件都需要这一个函数的时候方便使用,最重要的是日后修改或者维护方便。
比如我后端Path有命名不规范的地方,此时要改的话,找前端相关代码会比较麻烦。
noauth.POST("/api/auth/uploadphotos", controller.UploadPhotos)
noauth.POST("/api/auth/uploadavatar", controller.UploadAvatar)
noauth.POST("/api/auth/updateavatar", controller.UpdateAvatar)
auth.POST("/api/auth/getavatar", controller.GetAvatar)
不过为了项目,麻烦也都必须改!!!
错就要认 打就企定