简易记事本前端开发(初步)
目录
简介
1. 创建Vue3项目和导入依赖
创建Vue3项目
安装依赖
2. 登录注册页面的编写
登录页面
注册页面
3. 首页仪表盘的编写
4. 事件分类的编写
5. 事件管理的编写
结语
简介
在本篇博客中,我们将一起探索如何使用Vue3框架,结合ECharts图表库和Element-Plus UI组件库,来构建一个简易记事本应用的前端部分。我们将涵盖从项目创建到各个功能模块的前端代码编写过程。
1. 创建Vue3项目和导入依赖
首先,我们需要创建一个Vue3项目,并导入必要的依赖。
创建Vue3项目
打开终端,运行以下命令来创建一个新的Vue3项目:
bash
npm install -g @vue/cli
vue create simple-notebook
cd simple-notebook
选择Vue 3作为项目的基础,并安装所需的配置。
安装依赖
接下来,我们需要安装ECharts和Element-Plus。
bash
npm install echarts element-plus
2. 登录注册页面的编写
我们将使用Element-Plus组件库来快速构建登录和注册页面。
登录页面
在src/views
目录下创建Login.vue
和Register.vue
文件,并使用Element-Plus的表单组件。
vue
<template>
<div class="login-container">
<div class="login-box">
<div class="login-header">
<div class="logo-container">
<svg class="logo" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
<path fill="#1890ff" d="M64 0C28.7 0 0 28.7 0 64s28.7 64 64 64 64-28.7 64-64S99.3 0 64 0zm32 98.7c0 3.5-2.8 6.3-6.3 6.3H38.3c-3.5 0-6.3-2.8-6.3-6.3V29.3c0-3.5 2.8-6.3 6.3-6.3h51.4c3.5 0 6.3 2.8 6.3 6.3v69.4z"/>
<path fill="#fff" d="M45 41h38v6H45zm0 20h38v6H45zm0 20h38v6H45z"/>
</svg>
</div>
<h2>简易记事本</h2>
<p class="subtitle">记录生活,规划未来</p>
</div>
<el-form :model="loginFormData" :rules="rules" ref="loginForm">
<el-form-item prop="username">
<el-input v-model="loginFormData.username" placeholder="请输入账户名" size="large" />
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginFormData.password" type="password" placeholder="请输入密码" size="large" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleLogin" style="width: 100%" size="large">
登录
</el-button>
</el-form-item>
</el-form>
<div class="register-link">
<router-link to="/register">没有账户?点击注册</router-link>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
const router = useRouter()
const loginForm = ref(null)
const loginFormData = reactive({
username: '',
password: ''
})
const rules = {
username: [
{ required: true, message: '请输入账户名', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, message: '密码长度不能小于6位', trigger: 'blur' }
]
}
const handleLogin = () => {
if (!loginForm.value) return
loginForm.value.validate((valid) => {
if (valid) {
// 这里可以添加登录逻辑,比如调用 API
ElMessage.success('登录成功!')
router.push('/dashboard') // 确保这里的路径是正确的
}
})
}
</script>
<style scoped>
.login-container {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(135deg, #1890ff 0%, #36cfc9 100%);
}
.login-box {
width: 420px;
padding: 40px;
background: rgba(255, 255, 255, 0.9);
border-radius: 12px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
}
.login-header {
text-align: center;
margin-bottom: 40px;
}
h2 {
margin: 0;
font-size: 28px;
color: #1890ff;
margin-bottom: 8px;
}
.subtitle {
margin: 0;
color: #666;
font-size: 16px;
}
:deep(.el-input__wrapper) {
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
:deep(.el-button) {
border-radius: 8px;
font-size: 16px;
height: 44px;
}
:deep(.el-form-item) {
margin-bottom: 24px;
}
.register-link {
text-align: center;
margin-top: 20px;
}
.register-link a {
color: #1890ff;
text-decoration: none;
}
.logo-container {
display: flex;
justify-content: center;
margin-bottom: 16px;
}
.logo {
width: 80px;
height: 80px;
animation: float 6s ease-in-out infinite;
}
@keyframes float {
0% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
100% {
transform: translateY(0px);
}
}
</style>
注册页面
Register.vue
的编写与登录页面类似,只是表单字段不同。
3. 首页仪表盘的编写
首页仪表盘主要展示用户的基本信息和事件统计。
vue
<template>
<div class="home-container">
<!-- 数据概览卡片 -->
<el-row :gutter="20">
<el-col :span="6" v-for="card in dataCards" :key="card.title">
<el-card class="data-card" shadow="hover">
<div class="data-header">
<div class="data-title">
<el-icon class="icon"><component :is="card.icon" /></el-icon>
<span>{{ card.title }}</span>
</div>
<div class="data-value">{{ card.value }}</div>
</div>
<div class="data-footer">
<span>{{ card.footerLabel }}</span>
<span :class="card.trend">{{ card.footerValue }}</span>
</div>
</el-card>
</el-col>
</el-row>
<!-- 图表区域 -->
<el-row :gutter="20" class="charts-container">
<el-col :span="12">
<el-card class="chart-card" shadow="hover">
<template #header>
<div class="chart-header">
<span>事件分类统计</span>
</div>
</template>
<div ref="pieChart" class="chart"></div>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card" shadow="hover">
<template #header>
<div class="chart-header">
<span>近7天事件趋势</span>
</div>
</template>
<div ref="lineChart" class="chart"></div>
</el-card>
</el-col>
</el-row>
<!-- 最近事件列表 -->
<el-card class="recent-events" shadow="hover">
<template #header>
<div class="recent-header">
<span>最近事件</span>
<el-button type="primary" link @click="$router.push('/dashboard/event-management')">
查看更多<el-icon><ArrowRight /></el-icon>
</el-button>
</div>
</template>
<el-table
:data="recentEvents"
style="width: 100%"
:row-class-name="tableRowClassName">
<el-table-column prop="title" label="事件标题">
<template #default="scope">
<div class="event-title">{{ scope.row.title }}</div>
</template>
</el-table-column>
<el-table-column prop="category" label="分类" width="120">
<template #default="scope">
<el-tag size="small" effect="plain">{{ scope.row.category }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="120">
<template #default="scope">
<el-tag :type="getStatusType(scope.row.status)" size="small">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180" />
</el-table>
</el-card>
</div>
</template>
<script setup>
import { ref, onMounted, reactive } from 'vue'
import * as echarts from 'echarts'
import { Calendar, Check, Warning, Folder, ArrowRight } from '@element-plus/icons-vue'
// 数据卡片
const dataCards = reactive([
{
title: '总事件数',
value: 156,
icon: 'Calendar',
footerLabel: '较上周',
footerValue: '+12%',
trend: 'up'
},
{
title: '已完成事件',
value: 89,
icon: 'Check',
footerLabel: '完成率',
footerValue: '57%',
trend: 'up'
},
{
title: '待处理事件',
value: 67,
icon: 'Warning',
footerLabel: '紧急事件',
footerValue: '5',
trend: 'warning'
},
{
title: '事件分类',
value: 8,
icon: 'Folder',
footerLabel: '本月新增',
footerValue: '+2',
trend: 'up'
}
])
// 最近事件
const recentEvents = ref([
{
title: '完成项目文档',
category: '工作',
status: '进行中',
createTime: '2024-03-01 10:00:00'
},
{
title: '团队会议',
category: '会议',
status: '已完成',
createTime: '2024-03-01 09:30:00'
},
{
title: '健身计划',
category: '生活',
status: '待开始',
createTime: '2024-03-01 09:00:00'
}
])
const getStatusType = (status) => {
const types = {
'已完成': 'success',
'进行中': 'primary',
'待开始': 'info'
}
return types[status] || 'info'
}
// 图表相关
const pieChart = ref(null)
const lineChart = ref(null)
onMounted(() => {
// 初始化饼图
const pieChartInstance = echarts.init(pieChart.value)
pieChartInstance.setOption({
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [{
type: 'pie',
radius: '50%',
data: [
{ value: 35, name: '工作' },
{ value: 30, name: '生活' },
{ value: 25, name: '学习' },
{ value: 20, name: '会议' },
{ value: 15, name: '娱乐' }
]
}]
})
// 初始化折线图
const lineChartInstance = echarts.init(lineChart.value)
lineChartInstance.setOption({
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: {
type: 'value'
},
series: [{
data: [8, 12, 15, 9, 11, 13, 10],
type: 'line',
smooth: true,
areaStyle: {
opacity: 0.3
}
}]
})
// 监听窗口大小变化
window.addEventListener('resize', () => {
pieChartInstance.resize()
lineChartInstance.resize()
})
})
const tableRowClassName = ({ rowIndex }) => {
return 'table-row-' + rowIndex
}
</script>
<style scoped>
.home-container {
padding: 20px;
}
.data-card {
height: 120px;
margin-bottom: 20px;
}
.data-header {
display: flex;
flex-direction: column;
gap: 10px;
}
.data-title {
display: flex;
align-items: center;
gap: 8px;
color: #666;
}
.icon {
font-size: 20px;
}
.data-value {
font-size: 24px;
font-weight: bold;
color: #303133;
}
.data-footer {
margin-top: 10px;
display: flex;
justify-content: space-between;
color: #909399;
font-size: 14px;
}
.up {
color: #67c23a;
}
.down {
color: #f56c6c;
}
.warning {
color: #e6a23c;
}
.charts-container {
margin-top: 20px;
}
.chart-card {
margin-bottom: 20px;
}
.chart {
height: 300px;
}
.chart-header {
font-size: 16px;
font-weight: 500;
}
.recent-header {
display: flex;
justify-content: space-between;
align-items: center;
}
:deep(.el-card__header) {
padding: 15px 20px;
border-bottom: 1px solid #ebeef5;
}
.el-row {
margin-bottom: 20px;
}
.recent-events {
transition: all 0.3s;
}
.recent-events:hover {
transform: translateY(-5px);
}
:deep(.el-table) {
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
:deep(.el-table__header) {
background-color: #f5f7fa;
}
:deep(.el-table__row) {
transition: all 0.3s;
}
:deep(.el-table__row:hover) {
transform: translateZ(20px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
.event-title {
font-weight: 500;
color: #303133;
}
:deep(.table-row-0) {
background-color: rgba(24, 144, 255, 0.05);
}
:deep(.table-row-1) {
background-color: rgba(54, 207, 201, 0.05);
}
:deep(.el-card) {
border-radius: 12px;
overflow: hidden;
}
.recent-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 0;
}
:deep(.el-card__header) {
border-bottom: 1px solid #f0f0f0;
padding: 0 20px;
}
</style>
4. 事件分类的编写
在src/views
目录下创建EventCategory.vue
文件。
vue
<template>
<div class="category-container">
<div class="category-header">
<h3>事件分类管理</h3>
<el-button type="primary" @click="handleAdd">
<el-icon><Plus /></el-icon>新增分类
</el-button>
</div>
<el-table :data="categories" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="name" label="分类名称" />
<el-table-column prop="count" label="事件数量" width="100" align="center" />
<el-table-column prop="createTime" label="创建时间" width="180" align="center" />
<el-table-column label="操作" width="200" align="center">
<template #default="scope">
<div class="operation-buttons">
<el-button type="primary" size="small" @click="handleEdit(scope.row)">
<el-icon><Edit /></el-icon>
<span>编辑</span>
</el-button>
<el-button type="danger" size="small" @click="handleDelete(scope.row)">
<el-icon><Delete /></el-icon>
<span>删除</span>
</el-button>
</div>
</template>
</el-table-column>
</el-table>
<!-- 新增/编辑对话框 -->
<el-dialog
:title="dialogType === 'add' ? '新增分类' : '编辑分类'"
v-model="dialogVisible"
width="30%">
<el-form :model="form" :rules="rules" ref="formRef" label-width="80px">
<el-form-item label="分类名称" prop="name">
<el-input v-model="form.name" placeholder="请输入分类名称"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Edit, Delete } from '@element-plus/icons-vue'
// 模拟数据
const categories = ref([
{ id: 1, name: '工作', count: 35, createTime: '2024-03-01 10:00:00' },
{ id: 2, name: '生活', count: 30, createTime: '2024-03-01 10:30:00' },
{ id: 3, name: '学习', count: 25, createTime: '2024-03-01 11:00:00' },
{ id: 4, name: '会议', count: 20, createTime: '2024-03-01 11:30:00' },
{ id: 5, name: '娱乐', count: 15, createTime: '2024-03-01 12:00:00' }
])
const dialogVisible = ref(false)
const dialogType = ref('add')
const formRef = ref(null)
const currentId = ref(null)
const form = reactive({
name: ''
})
const rules = {
name: [
{ required: true, message: '请输入分类名称', trigger: 'blur' },
{ min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }
]
}
const handleAdd = () => {
dialogType.value = 'add'
form.name = ''
dialogVisible.value = true
}
const handleEdit = (row) => {
dialogType.value = 'edit'
currentId.value = row.id
form.name = row.name
dialogVisible.value = true
}
const handleDelete = (row) => {
ElMessageBox.confirm(
'此操作将永久删除该分类,是否继续?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
const index = categories.value.findIndex(item => item.id === row.id)
categories.value.splice(index, 1)
ElMessage.success('删除成功')
})
}
const handleSubmit = () => {
formRef.value?.validate((valid) => {
if (valid) {
if (dialogType.value === 'add') {
const newCategory = {
id: categories.value.length + 1,
name: form.name,
count: 0,
createTime: new Date().toLocaleString()
}
categories.value.push(newCategory)
ElMessage.success('新增成功')
} else {
const index = categories.value.findIndex(item => item.id === currentId.value)
categories.value[index].name = form.name
ElMessage.success('编辑成功')
}
dialogVisible.value = false
}
})
}
</script>
<style scoped>
.category-container {
padding: 20px;
background-color: #fff;
border-radius: 4px;
}
.category-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.category-header h3 {
margin: 0;
font-size: 20px;
font-weight: 500;
}
.el-button {
display: flex;
align-items: center;
gap: 5px;
}
.operation-buttons {
display: flex;
justify-content: center;
gap: 8px;
}
.el-button {
display: inline-flex;
align-items: center;
gap: 4px;
}
:deep(.el-button .el-icon) {
margin: 0;
}
</style>
5. 事件管理的编写
在src/views
目录下创建EventManagement.vue
文件。
vue
<template>
<div class="event-container">
<div class="event-header">
<h3>事件管理</h3>
<el-button type="primary" @click="handleAdd">
<el-icon><Plus /></el-icon>新增事件
</el-button>
</div>
<!-- 搜索栏 -->
<div class="search-bar">
<el-form :inline="true" :model="searchForm">
<el-form-item>
<el-input
v-model="searchForm.keyword"
placeholder="搜索事件标题"
clearable
/>
</el-form-item>
<el-form-item>
<el-select v-model="searchForm.category" placeholder="选择分类" clearable>
<el-option
v-for="item in categories"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-select v-model="searchForm.status" placeholder="选择状态" clearable>
<el-option
v-for="item in statusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="resetSearch">重置</el-button>
</el-form-item>
</el-form>
</div>
<!-- 事件列表 -->
<el-table :data="events" style="width: 100%" border stripe>
<el-table-column prop="title" label="事件标题" />
<el-table-column prop="category" label="分类" width="120" />
<el-table-column prop="priority" label="优先级" width="100" align="center">
<template #default="scope">
<el-tag :type="getPriorityType(scope.row.priority)">
{{ scope.row.priority }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100" align="center">
<template #default="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180" align="center" />
<el-table-column label="操作" width="250" align="center">
<template #default="scope">
<div class="operation-buttons">
<el-button type="primary" size="small" @click="handleEdit(scope.row)">
<el-icon><Edit /></el-icon>
<span>编辑</span>
</el-button>
<el-button
type="success"
size="small"
@click="handleComplete(scope.row)"
v-if="scope.row.status !== '已完成'">
<el-icon><Check /></el-icon>
<span>完成</span>
</el-button>
<el-button type="danger" size="small" @click="handleDelete(scope.row)">
<el-icon><Delete /></el-icon>
<span>删除</span>
</el-button>
</div>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 30, 50]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
<!-- 新增/编辑对话框 -->
<el-dialog
:title="dialogType === 'add' ? '新增事件' : '编辑事件'"
v-model="dialogVisible"
width="40%">
<el-form :model="form" :rules="rules" ref="formRef" label-width="80px">
<el-form-item label="事件标题" prop="title">
<el-input v-model="form.title" placeholder="请输入事件标题"></el-input>
</el-form-item>
<el-form-item label="所属分类" prop="category">
<el-select v-model="form.category" placeholder="请选择分类">
<el-option
v-for="item in categories"
:key="item.id"
:label="item.name"
:value="item.name"
/>
</el-select>
</el-form-item>
<el-form-item label="优先级" prop="priority">
<el-select v-model="form.priority" placeholder="请选择优先级">
<el-option label="高" value="高" />
<el-option label="中" value="中" />
<el-option label="低" value="低" />
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="form.remark"
type="textarea"
rows="3"
placeholder="请输入备注信息"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Edit, Delete, Check } from '@element-plus/icons-vue'
// 分类数据
const categories = ref([
{ id: 1, name: '工作' },
{ id: 2, name: '生活' },
{ id: 3, name: '学习' },
{ id: 4, name: '会议' },
{ id: 5, name: '娱乐' }
])
// 状态选项
const statusOptions = [
{ value: '待开始', label: '待开始' },
{ value: '进行中', label: '进行中' },
{ value: '已完成', label: '已完成' }
]
// 搜索表单
const searchForm = reactive({
keyword: '',
category: '',
status: ''
})
// 模拟事件数据
const events = ref([
{
id: 1,
title: '完成项目文档',
category: '工作',
priority: '高',
status: '进行中',
createTime: '2024-03-01 10:00:00',
remark: '需要完成项目相关文档的编写工作'
},
{
id: 2,
title: '团队会议',
category: '会议',
priority: '中',
status: '已完成',
createTime: '2024-03-01 09:30:00',
remark: '讨论本周工作进展'
},
{
id: 3,
title: '健身计划',
category: '生活',
priority: '低',
status: '待开始',
createTime: '2024-03-01 09:00:00',
remark: '每周三次健身计划'
}
])
// 分页相关
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(100)
// 对话框相关
const dialogVisible = ref(false)
const dialogType = ref('add')
const formRef = ref(null)
const currentId = ref(null)
const form = reactive({
title: '',
category: '',
priority: '',
remark: ''
})
const rules = {
title: [
{ required: true, message: '请输入事件标题', trigger: 'blur' },
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
],
category: [
{ required: true, message: '请选择所属分类', trigger: 'change' }
],
priority: [
{ required: true, message: '请选择优先级', trigger: 'change' }
]
}
// 处理函数
const handleSearch = () => {
// 实现搜索逻辑
console.log('搜索条件:', searchForm)
}
const resetSearch = () => {
Object.keys(searchForm).forEach(key => {
searchForm[key] = ''
})
}
const handleSizeChange = (val) => {
pageSize.value = val
// 重新加载数据
}
const handleCurrentChange = (val) => {
currentPage.value = val
// 重新加载数据
}
const handleAdd = () => {
dialogType.value = 'add'
Object.keys(form).forEach(key => {
form[key] = ''
})
dialogVisible.value = true
}
const handleEdit = (row) => {
dialogType.value = 'edit'
currentId.value = row.id
Object.keys(form).forEach(key => {
form[key] = row[key]
})
dialogVisible.value = true
}
const handleDelete = (row) => {
ElMessageBox.confirm(
'此操作将永久删除该事件,是否继续?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
const index = events.value.findIndex(item => item.id === row.id)
events.value.splice(index, 1)
ElMessage.success('删除成功')
})
}
const handleComplete = (row) => {
const index = events.value.findIndex(item => item.id === row.id)
events.value[index].status = '已完成'
ElMessage.success('事件已完成')
}
const handleSubmit = () => {
formRef.value?.validate((valid) => {
if (valid) {
if (dialogType.value === 'add') {
const newEvent = {
id: events.value.length + 1,
...form,
status: '待开始',
createTime: new Date().toLocaleString()
}
events.value.push(newEvent)
ElMessage.success('新增成功')
} else {
const index = events.value.findIndex(item => item.id === currentId.value)
events.value[index] = {
...events.value[index],
...form
}
ElMessage.success('编辑成功')
}
dialogVisible.value = false
}
})
}
// 工具函数
const getPriorityType = (priority) => {
const types = {
'高': 'danger',
'中': 'warning',
'低': 'info'
}
return types[priority]
}
const getStatusType = (status) => {
const types = {
'已完成': 'success',
'进行中': 'primary',
'待开始': 'info'
}
return types[status]
}
</script>
<style scoped>
.event-container {
padding: 20px;
background-color: #fff;
border-radius: 4px;
}
.event-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.event-header h3 {
margin: 0;
font-size: 20px;
font-weight: 500;
}
.search-bar {
margin-bottom: 20px;
padding: 15px;
background-color: #f5f7fa;
border-radius: 4px;
}
.pagination {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
.operation-buttons {
display: flex;
justify-content: center;
gap: 8px;
}
.el-button {
display: inline-flex;
align-items: center;
gap: 4px;
}
:deep(.el-button .el-icon) {
margin: 0;
}
</style>
结语
一天把记事本项目前端样式简单写一下,目前只是初版,后面可能会迭代,需要的小伙伴不要老老实实复制代码,联系作者,自然会有全套代码