蓝桥杯18584-个人消息同步
文章目录
- **蓝桥杯18584-个人消息同步**
- **1. 题目介绍**
- **2. 项目结构**
- **3. 目标**
- **目标 1:完善 `store/messageStore.js`**
- **目标 2:完善 `component/NavBar.js`**
- **目标 3:完善 `views/Message.js`**
- **4. 代码实现**
- **`store/messageStore.js`**
- **`component/NavBar.js`**
- **`views/Message.js`**
- **5. 运行效果**
- **6. 知识扩展 axios和fetch**
- **1. `fetch`**
- **特点**
- **基本用法**
- **使用 `async/await`**
- **设置请求选项**
- **2. `axios`**
- **特点**
- **基本用法**
- **使用 `async/await`**
- **设置请求选项**
- **拦截器**
- **取消请求**
- **3. `fetch` 和 `axios` 的对比**
- **4. 选择使用场景**
- **总结**
- **4. 选择使用场景**
- **总结**
1. 题目介绍
在大部分面向 C 端的页面中,当用户登录后,通常会推送个人用户的消息。为了在多个组件中共享和同步这些消息数据,通常会使用状态管理工具来存储和管理这些数据。在 Vue2 中,常用的状态管理工具是 Vuex,而在 Vue3 中,推荐使用 Pinia。
本题的目标是使用 Vue3 + Pinia 来实现个人消息的同步功能。具体任务包括:
- 在
store/messageStore.js
中完成数据请求,并将请求到的消息数据存储到 Pinia 的状态管理中。 - 在
component/NavBar.js
中动态显示消息的数量。 - 在
views/Message.js
中动态渲染消息列表。
2. 项目结构
项目的目录结构如下:
复制
├── component
│ ├── Loading.js
│ └── NavBar.js
├── css
├── data.json
├── images
├── index.html
├── lib
├── main.js
├── store
│ └── messageStore.js
└── views└── Message.js
component
:组件文件夹,包含Loading.js
和NavBar.js
。css
:样式文件夹。data.json
:模拟的消息数据文件。images
:图片文件夹。index.html
:主页面。lib
:项目依赖的文件夹。main.js
:主程序入口。store/messageStore.js
:Pinia 状态管理文件。views
:页面文件夹,包含Message.js
。
3. 目标
目标 1:完善 store/messageStore.js
-
任务:
- 在
store/messageStore.js
中,完成数据请求(请求地址必须使用提供的常量MockUrl
)。 - 将请求回来的数据中的消息数组存放到
messageState
中。
- 在
-
数据格式:
{"code": 200,"data": [{"msg_id": "643fbb014fc3aacc730bfa8c","label": "系统消息","content": "❗️❗️❗️【会员升级通知】4月21日大动作!会员体系全新升级,新增14项权益!所有训练营,蓝桥杯备赛课、蓝桥IT人才培养计划、...","send_at": "2023-04-19 17:57:21"},// ... 其他消息] }
-
实现步骤:
- 使用
fetch
或axios
发起请求,获取data.json
中的数据。 - 将
data.data
中的消息数组存储到messageState
中。
- 使用
目标 2:完善 component/NavBar.js
-
任务:
- 在导航栏的铃铛图标上方动态显示消息的数量。
- 使用
messageState
的长度来显示消息数量。
-
实现步骤:
- 从
messageStore
中获取messageState
。 - 在模板中使用
{{ messageStore.messageState.length }}
动态显示消息数量。
- 从
目标 3:完善 views/Message.js
-
任务:
- 使用
messageState
中的数据动态渲染消息列表。 - 单条消息的模板已提供,直接使用
v-for
遍历messageState
并渲染。
- 使用
-
实现步骤:
- 在
onMounted
钩子中调用getUserMessage
方法获取消息数据。 - 使用
v-for
遍历messageState
,渲染每条消息。
- 在
4. 代码实现
store/messageStore.js
import { defineStore } from 'pinia';
import { ref } from 'vue';export const useMessageStore = defineStore('message', () => {const messageState = ref([]);// 定义请求地址 MockUrlconst MockUrl ='./data.json'; let getUserMessage =async () =>{// TODO:待补充代码const ref=await axios(MockUrl);messageState.value=ref.data.data;// TODO:END} return {messageState, getUserMessage}
})
component/NavBar.js
import { reactive, ref } from "vue";
import { useMessageStore } from "../store/messageStore.js";const NavBar = {setup() {const messageStore = useMessageStore();const headerData = reactive({headerArr: ["学习", "蓝桥杯", "考证", "讨论区", "校企版"],});const isShowPop = ref(true);return {headerData,messageStore,isShowPop,};},template: `<div class="header-container"><div class="main-header"><div class="menu-container"><a href="" class="header-brand"><img class="logo" src="./images/logo.png" /></a><div class="menu-content"><divclass="menu-item"v-for="(item, index) in headerData.headerArr":key="index"><a href="" class="menu-link"><span class="menu-text">{{ item }}</span></a></div></div></div><div class="auth-container"><a href="" class="vip-link"><div class="vip-link-content"><img alt="" src="./images/vip.png" /><span>会员</span></div></a><div :class="[{'show-message-box':isShowPop},'exit']"><div class="flex"><span href="" class="user-message">// TODO:待补充代码 目标 2 <div class="tip">{{ messageStore.messageState.length }}</div><img class="pointer" src="./images/message.png" alt="" /></span></div><div class="message-popover"><div class="msg-popover-header"><div class="msg-header-title pointer active">学习消息</div><div class="msg-header-title pointer">蓝桥杯消息</div><div class="msg-header-title pointer">订单系统消息</div></div><div class="msg-container"><div class="msg-content singe-line" v-for="msg in messageStore.messageState" :key="msg.msg_id">{{ msg.content }}</div></div></div></div></div></div></div>`,
};export default NavBar;
views/Message.js
javascript
复制
import { ref, onMounted } from "vue";
import { useMessageStore } from "../store/messageStore.js";
const Message = {template: `<div class="message-container" ><section class="system-message flex justify-start items-center"><span class="ml-10px">系统自动清理一年前的已读消息</span></section><section class="flex justify-start items-center mt-20px"><div class="message-type-button active-message">学习消息</div><div class="message-type-button">蓝桥杯消息</div><div class="message-type-button">订单系统消息</div></section><loading v-if="isLoading"/><template v-else><!-- TODO: 待修改代码 目标 3 --><!-- 单条消息模板 start--><div class="message-content-wrapper mt-20px" v-for="i in messageStore.messageState" :key="i.msg_id"><div class="message-list"><div class="message-item"><div class="message-content"><div class="message-cate"><span class="label label-success font-14">{{i.label}}</span></div><div class="message-main-content">{{i.content}}</div></div><div class="msg-create-time text-right"><small> {{i.send_at}} </small></div></div></div></div><!-- 单条消息模板 end--><template></div> `,setup() {const messageStore = useMessageStore();const isLoading = ref(false);onMounted(async () => {isLoading.value = true;await messageStore.getUserMessage();isLoading.value = false;});return { isLoading, messageStore };},
};
export default Message;
5. 运行效果
- 目标 1:消息数据成功请求并存储到
messageState
中。 - 目标 2:导航栏的铃铛图标上方动态显示消息数量。
- 目标 3:消息列表页面动态渲染消息内容。
6. 知识扩展 axios和fetch
1. fetch
fetch
是浏览器原生提供的用于发起网络请求的 API,基于 Promise 实现。它是现代 JavaScript 中推荐使用的网络请求工具。
特点
- 原生支持:
fetch
是浏览器原生 API,无需额外安装库。- 在现代浏览器中广泛支持(IE 不支持)。
- 基于 Promise:
- 使用 Promise 处理异步操作,支持
async/await
。
- 使用 Promise 处理异步操作,支持
- 简单易用:
- 语法简洁,易于上手。
- 默认不携带 Cookie:
- 默认情况下,
fetch
不会发送或接收 Cookie。如果需要,需要显式设置credentials: 'include'
。
- 默认情况下,
- 错误处理:
fetch
只有在网络错误时才会拒绝 Promise(如网络断开)。- 对于 HTTP 错误(如 404 或 500),
fetch
不会自动拒绝,需要手动检查response.ok
。
基本用法
fetch('https://api.example.com/data').then(response => {if (!response.ok) {throw new Error('网络请求失败');}return response.json(); // 解析 JSON 数据}).then(data => {console.log('请求成功:', data);}).catch(error => {console.error('请求失败:', error);});
使用 async/await
async function fetchData() {try {const response = await fetch('https://api.example.com/data');if (!response.ok) {throw new Error('网络请求失败');}const data = await response.json();console.log('请求成功:', data);} catch (error) {console.error('请求失败:', error);}
}
设置请求选项
fetch('https://api.example.com/data', {method: 'POST', // 请求方法headers: {'Content-Type': 'application/json', // 请求头},body: JSON.stringify({ key: 'value' }), // 请求体credentials: 'include', // 携带 Cookie
}).then(response => response.json()).then(data => console.log(data)).catch(error => console.error(error));
2. axios
axios
是一个基于 Promise 的 HTTP 客户端,可以在浏览器和 Node.js 中使用。它是一个第三方库,提供了更多高级功能和更好的错误处理。
特点
- 跨平台支持:
- 可以在浏览器和 Node.js 中使用。
- 自动转换数据:
- 自动将请求和响应的数据转换为 JSON。
- 更好的错误处理:
- 对于 HTTP 错误(如 404 或 500),
axios
会自动拒绝 Promise。
- 对于 HTTP 错误(如 404 或 500),
- 请求和响应拦截器:
- 支持拦截器,可以在请求发送前或响应到达前进行统一处理。
- 取消请求:
- 支持取消请求的功能。
- 默认携带 Cookie:
- 默认情况下,
axios
会发送和接收 Cookie。
- 默认情况下,
基本用法
axios.get('https://api.example.com/data').then(response => {console.log('请求成功:', response.data);}).catch(error => {console.error('请求失败:', error);});
使用 async/await
async function fetchData() {try {const response = await axios.get('https://api.example.com/data');console.log('请求成功:', response.data);} catch (error) {console.error('请求失败:', error);}
}
设置请求选项
axios.post('https://api.example.com/data', { key: 'value' }, {headers: {'Content-Type': 'application/json',},withCredentials: true, // 携带 Cookie
}).then(response => console.log(response.data)).catch(error => console.error(error));
拦截器
// 请求拦截器
axios.interceptors.request.use(config => {console.log('请求发送前:', config);return config;
}, error => {return Promise.reject(error);
});// 响应拦截器
axios.interceptors.response.use(response => {console.log('响应到达前:', response);return response;
}, error => {return Promise.reject(error);
});
取消请求
const source = axios.CancelToken.source();axios.get('https://api.example.com/data', {cancelToken: source.token,
}).then(response => console.log(response.data)).catch(error => {if (axios.isCancel(error)) {console.log('请求被取消:', error.message);} else {console.error('请求失败:', error);}});// 取消请求
source.cancel('请求被用户取消');
3. fetch
和 axios
的对比
特性 | fetch | axios |
---|---|---|
原生支持 | 是 | 否(需要安装) |
跨平台支持 | 仅浏览器 | 浏览器和 Node.js |
自动转换 JSON | 需要手动调用 response.json() | 自动转换 |
错误处理 | 需要手动检查 response.ok | 自动处理 HTTP 错误 |
拦截器 | 不支持 | 支持请求和响应拦截器 |
取消请求 | 不支持 | 支持 |
默认携带 Cookie | 需要设置 credentials: 'include' | 默认携带 |
语法简洁性 | 较简洁 | 更简洁(功能更丰富) |
4. 选择使用场景
fetch
:- 适合简单的请求场景,尤其是现代浏览器环境。
- 不需要额外安装库,减少项目依赖。
axios
:- 适合需要更强大功能的场景,如拦截器、取消请求、自动错误处理等。
- 在需要兼容旧版浏览器或 Node.js 环境中使用。
总结
fetch
是浏览器原生 API,简单易用,适合现代浏览器环境。
| 支持请求和响应拦截器 |
| 取消请求 | 不支持 | 支持 |
| 默认携带 Cookie | 需要设置credentials: 'include'
| 默认携带 |
| 语法简洁性 | 较简洁 | 更简洁(功能更丰富) |
4. 选择使用场景
fetch
:- 适合简单的请求场景,尤其是现代浏览器环境。
- 不需要额外安装库,减少项目依赖。
axios
:- 适合需要更强大功能的场景,如拦截器、取消请求、自动错误处理等。
- 在需要兼容旧版浏览器或 Node.js 环境中使用。
总结
fetch
是浏览器原生 API,简单易用,适合现代浏览器环境。axios
是一个功能更强大的第三方库,适合需要高级功能的场景