蓝桥杯18584-个人消息同步
蓝桥杯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([]);
// 定义请求地址 MockUrl
const 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">
<div
class="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
是一个功能更强大的第三方库,适合需要高级功能的场景