GitHub地址: https://github.com/MUOU-HANG/ant-design-vue-template.git 查看时请切换开发分支进行查看到代码
0)目录架构
1)通知tab的实现notifyList.vue
<template> <a-list item-layout="horizontal" :data-source="data.notifies"> <template v-if="!data.notifies.length == 0" v-slot:renderItem="{ item }"> <a-list-item> <a-list-item-meta description="三年前"> <template v-slot:title> <a href="#">{{ item.title }}</a> </template> <template v-slot:avatar> <a-avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" /> </template> </a-list-item-meta> </a-list-item> </template> <template v-if="data.notifies.length == 0"> <a-empty description="暂无通知" /> </template> <a-list-item> <a-button type="info" block @click="clearNotify">清空通知</a-button> <a-button type="info" block> <router-link to="">查看更多</router-link> </a-button> </a-list-item> </a-list> </template> <script lang="ts"> import { data, useGetNotify, useClearNotify } from "./index"; export default { name: "", /** 父组件传过来的值 */ props: {}, inject: ["user"], /** 组件 */ components: {}, setup(props, { emit }) { // 获取通知数据 useGetNotify(emit, data); // 清空数据 const { clearNotify } = useClearNotify(emit, data); /** 返回值 */ return { data, clearNotify }; } }; </script> <style lang="scss" scoped></style>通知标签页的实现,主要用来List组件,利用组件自带功能可以轻松的生成列表。为了数据和方法方便管理,单独抽离数据和方法在index.ts文件中,
import { Count } from "@/types/header/noticeBadge"; import { reactive } from "vue"; // 初始化数据 const data = reactive({ notifies: [], messages: [], todos: [] }); // 获取通知数据 const useGetNotify = (emit: any, data: Count) => { // 从数据库获取数据 const notifies = [ { title: "Ant Design Title 1" }, { title: "Ant Design Title 2" }, { title: "Ant Design Title 3" }, { title: "Ant Design Title 4" } ]; data.notifies = notifies; emit("getNumber", data); }; // 清空通知 const useClearNotify = (emit: any, data: Count) => { const clearNotify = () => { // 调用接口,删除数据库中的数据(这里用清空数组模拟) data.notifies = []; emit("getNumber", data); }; return { clearNotify }; }; // 获取消息数据 const useGetMessage = (emit: any, data: Count) => { const messages = [ { name: "曲丽丽", title: "评论了你", date: "三年前" }, { name: "曲丽丽", title: "回复了你", date: "三年前" }, { name: "曲丽丽", title: "标题", date: "三年前" } ]; data.messages = messages; emit("getNumber", data); }; // 清空消息数据 const useClearMessage = (emit: any, data: Count) => { const clearMessage = () => { // 调用接口,删除数据库中的数据(这里用清空数组模拟) data.messages = []; emit("getNumber", data); }; return { clearMessage }; }; // 获取待办数据 const useGetTodo = (emit: any, data: Count) => { const todos = [ { done: false, tag: "grey", tagDesc: "未开始", title: "任务名称", description: "任务需要在 2017-01-12 20:00 前启动" }, { done: true, tag: "red", tagDesc: "马上到期", title: "代码变更", description: "冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务" }, { done: false, tag: "orange", tagDesc: "已耗时8天", title: "信息安全考试", description: "指派竹尔于 2017-01-09 前完成更新并发布" }, { done: false, tag: "blue", tagDesc: "进行中", title: "ABDC版本发布", description: "冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务" }, { done: false, tag: "grey", tagDesc: "未开始", title: "任务名称", description: "任务需要在 2017-01-12 20:00 前启动" }, { done: true, tag: "red", tagDesc: "马上到期", title: "代码变更", description: "冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务" }, { done: false, tag: "orange", tagDesc: "已耗时8天", title: "信息安全考试", description: "指派竹尔于 2017-01-09 前完成更新并发布" }, { done: false, tag: "blue", tagDesc: "进行中", title: "ABDC版本发布", description: "冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务" } ]; data.todos = todos; emit("getNumber", data); }; // 清空待办数据 const useClearTodo = (emit: any, data: Count) => { const clearTodo = () => { // 调用接口,删除数据库中的数据(这里用清空数组模拟) data.todos = []; emit("getNumber", data); }; return { clearTodo }; }; // 完成待办事项 const useDoneTodo = (emit, data: Count) => { const todoDone = (index: number) => { // 修改数据库中该条记录的状态 data.todos[index].done = true; emit("getNumber", data); }; return { todoDone }; }; export { data, useGetMessage, useClearMessage, useGetNotify, useClearNotify, useGetTodo, useClearTodo, useDoneTodo };由于没有后端也没有使用mockjs,我就用数组代替进行相关操作,具体的实现方式,使用了函数式编程。在index.ts中进行业务操作(若业务繁多,可再次进行拆分),在notifyList.vue中导入后,即可正常使用。由于``notifyList.vue是一个组件,因此使用Vue的emit方法向父组件传值,具体使用方法可参考官方文档。当父组件(即index.vue`)获取到数据后,即可进行数据的处理,渲染或者计算通知的数量并进行赋值。
消息推送模块分为三个子组件,分别是:notifyList.vue,messageList.vue,todoList.vue,实现方式答题类似,都是通过emit传值,父组件进行数据处理。todoList还增加了一个功能,即点击后状态改成已完成,者主要是判断数据中done字段的值,控制其显示。
具体代码如下:
2)message.vue文件
<template> <a-list item-layout="horizontal" :data-source="data.messages"> <template v-if="!data.messages.length == 0" v-slot:renderItem="{ item }"> <a-list-item> <a-list-item-meta :description="item.date"> <template v-slot:title> <a href="#">{{ item.name }} {{ item.title }}</a> </template> <template v-slot:avatar> <a-avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" /> </template> </a-list-item-meta> </a-list-item> </template> <template v-if="data.messages.length == 0"> <a-empty description="暂无通知" /> </template> <a-list-item> <a-button type="info" block @click="clearMessage">清空通知</a-button> <a-button type="info" block> <router-link to="">查看更多</router-link> </a-button> </a-list-item> </a-list> </template> <script lang="ts"> import { data, useGetMessage, useClearMessage } from "./index"; export default { name: "", /** 父组件传过来的值 */ props: {}, /** 组件 */ components: {}, setup(props, { emit }) { // 获取消息数据 useGetMessage(emit, data); // 清空消息 const { clearMessage } = useClearMessage(emit, data); /** 返回值 */ return { data, clearMessage }; } }; </script> <style lang="scss" scoped></style>3)todoList.vue文件
<template> <a-list item-layout="horizontal" :data-source="data.todos"> <template v-if="!data.todos.length == 0" v-slot:renderItem="{ item, index }"> <a-list-item> <a-list-item-meta :description="item.description" @click="todoDone(index)"> <template v-slot:title> <a href="#">{{ item.title }}</a> <a-tag :color="item.tag" class="todo-tags" v-if="!item.done"> {{ item.tagDesc }} </a-tag> <a-tag color="#2db7f5" class="todo-tags" v-else> 已完成 </a-tag> </template> </a-list-item-meta> </a-list-item> </template> <template v-if="data.todos.length == 0"> <a-empty description="暂无通知" /> </template> </a-list> <a-list> <a-list-item> <a-button type="info" block @click="clearTodo">清空通知</a-button> <a-button type="info" block> <router-link to="">查看更多</router-link> </a-button> </a-list-item> </a-list> </template> <script lang="ts"> import { data, useGetTodo, useClearTodo, useDoneTodo } from "./index"; export default { name: "TodoList", /** 父组件传过来的值 */ props: {}, /** 组件 */ components: {}, setup(props, { emit }) { // 获取待办数据 useGetTodo(emit, data); // 清空待办 const { clearTodo } = useClearTodo(emit, data); // 完成待办事项 const { todoDone } = useDoneTodo(emit, data); /** 返回值 */ return { data, clearTodo, todoDone }; } }; </script> <style lang="scss" scoped> .todo-tags { float: right; } </style>4)index.vue文件
<template> <div class="notice-badge-wrap"> <a-dropdown :trigger="['click']"> <span @click="e => e.preventDefault()"> <BellOutlined class="icon" /> <a-badge :count="data.count" class="notice-badge"> <a href="#" class="head-example" /> </a-badge> </span> <template v-slot:overlay> <a-menu style="width:344px;height:450px;overflow: hidden;"> <a-tabs class="user-center-tabs"> <a-tab-pane key="1"> <template v-slot:tab> 通知 ({{ data.notifyItemCount }}) </template> <HeaderNotifyList @getNumber="getNumber" /> </a-tab-pane> <a-tab-pane key="2"> <template v-slot:tab> 消息 ({{ data.messageItemCount }}) </template> <HeaderMessageList @getNumber="getNumber" /> </a-tab-pane> <a-tab-pane key="3"> <template v-slot:tab> 待办 ({{ data.todoItemCount }}) </template> <HeaderTodoList @getNumber="getNumber" /> </a-tab-pane> </a-tabs> </a-menu> </template> </a-dropdown> </div> </template> <script lang="ts"> import HeaderNotifyList from "@c/layoutHeader/headerNotifyBadge/notifyList.vue"; import HeaderMessageList from "@c/layoutHeader/headerNotifyBadge/messageList.vue"; import HeaderTodoList from "@c/layoutHeader/headerNotifyBadge/todoList.vue"; import { BellOutlined } from "@ant-design/icons-vue"; import { Todo, Count } from "@/types/header/noticeBadge"; import { reactive } from "vue"; // 查看更多 export default { name: "", /** 父组件传过来的值 */ props: {}, /** 组件 */ components: { BellOutlined, HeaderNotifyList, HeaderMessageList, HeaderTodoList }, provide: { user: "John Doe" }, setup() { const data = reactive({ notifyItemCount: 0, messageItemCount: 0, todoItemCount: 0, count: 0 // 总的消息数,用徽标显示 }); const getNumber = (e: Count) => { data.notifyItemCount = e.notifies.length; data.messageItemCount = e.messages.length; // 筛选todo是否完成 const result: Todo[] = e.todos.filter(r => r.done == false); data.todoItemCount = result.length; data.count = e.notifies.length + e.messages.length + result.length; }; /** 返回值 */ return { data, getNumber }; } }; </script> <style lang="scss" scoped> .icon { @include icon(18px, "", 0 0 0 0); } .notice-badge-wrap { position: relative; .notice-badge { position: absolute; top: 15px; left: 40px; } } .user-center-tabs { padding: 0 20px; width: 361px; height: 100%; overflow-y: scroll; } </style>用户中心比较简单,只是完成了页面的跳转,不加赘述
headerUserCenter.vue文件
<template> <div class="user-center"> <a-dropdown :trigger="['click']"> <a class="user" @click="e => e.preventDefault()"> <a-avatar class="user-avatar" src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" /> <span> Serati Ma </span> </a> <template v-slot:overlay> <a-menu class="uer-center-items"> <a-menu-item> <router-link to="/userCenter">个人中心</router-link> </a-menu-item> <a-menu-item> <router-link to="/changePassword">修改密码</router-link> </a-menu-item> <a-divider></a-divider> <a-menu-item> <router-link to="/login">退出登录</router-link> </a-menu-item> </a-menu> </template> </a-dropdown> </div> </template> <script lang="ts"> export default { name: "", /** 父组件传过来的值 */ props: {}, /** 组件 */ components: {}, setup() { const callback = (key: any) => { console.log(key); }; /** 返回值 */ return { callback }; } }; </script> <style lang="scss" scoped> .user { font-size: 14px; color: black; line-height: $headerHeight; .user-avatar { margin-top: -8px; } } .uer-center-items { margin-top: 15px; > * { padding: 5 20px; } } </style>