博客后台管理系统
博客后台管理系统背景介绍
在学校的课程开设的影响下,对前端WEB开发
有着浓厚的兴趣,于是在经过了对大学前两年专业知识的学习,并下定决心能运用所学知识进行自主网页开发。为此我在学习学校基础课程的同时,利用课外的空闲时间去探索前端开发领域,对前端开发技术一点点积累学习,最后将知识点进行整合运用,产生了开发个人博客项目的想法。该博客后台项目是本人在大二暑假实现。
用到的技术栈:
前端:Element-UI
+ Vue2.0
+ Axois
+ Vue-Router
+ 第三方中间件
+ ECharts
后端:Node.js
+ Express框架
数据库:MySQL
项目版本控制工具: Git分布式版本控制系统
项目GitHub链接:个人博客后台管理系统
,starred支持小白一下,以示鼓励。
一、项目介绍
1.1 登录
用户登录使用了基于JWT中间件的token认证机制,进行用户信息的加密和解密。
// 导入配置文件
const secretKey = require('./config.js')
const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
// 使用jsonwebtoken进行用户名的token字符串生成
const token = jwt.sign({ username: bodys.username }, secretKey, { expiresIn: '30s' });
// 导入express-jwt,用于后续的token解析
const expressJWT = require('express-jwt');
// 导入解析密钥
const secretKey = require('./config.js')
// 出了以/api开头的接口不用token认证,其余都需要
app.use(expressJWT({ secret: secretKey }).unless({ path: [/^\/api\//] }))
// 使用错误中间件进行token过期的验证
app.use((err, req, res, next) => {
// 捕获身份认证失败的错误
if (err.name === 'UnauthorizedError') return res.send({
status: 401,
message: 'toke过期,身份验证失败'
})
// 其他未知错误
res.send({
status: 500,
message: '服务错误'
})
})
同时新增了在token认证机制下的用户持久化登录,每次用户请求数据时,请求头headers中的Authorization属性就自动携带用户的token值,服务器获取到token后进行有效时间的判断并解析,token在该有效时间能即可成功请求对应的接口数据。
// axios请求拦截器的使用
request.interceptors.request.use(config => {
// 请求头携带token值
config.headers.Authorization = window.localStorage.getItem('token');
// 将配置完成的config对象返回出去 如果不返回 请求则不会进行
return config;
}, err => {
// 返回使用Promise封装的错误信息
return Promise.reject(err);
});
// axios响应拦截器的使用
request.interceptors.response.use(response => {
// 用户登录持久化
const status = response.data.status;
// 接口数据状态码返回的是401时代表用户需要进行权限认证
if (status === 401) {
// 用户重新登陆信息提示
MessageBox.alert(
'登录状态已过期, 您可以继续留在该页面, 或者重新登陆',
'系统提示', {
confirmButtonText: '重新登录',
type: 'warning',
callback: action => {
// 将页面重定向为登录页面
location.href = '/';
}
}
)
// 清除用户过期的token
window.localStorage.removeItem('token');
}
// 将响应信息返回
return response;
}, err => {
// 返回使用Promise封装的错误信息
return new Promise(err);
})
当我们的token过期时,页面显示用户信息如下(我们手动修改一下有效的token)。可以看到,jwt认证机制已成功实现。
1.2 文章管理页
1.3 撰写文章页
1.4 文章分类页
1.5 用户管理页
1.6 管理员添加页
1.7 博主个人信息页
二、部分代码
2.1 登录
代码如下:
<template>
<div id="login-container">
<!-- 使用原生的Div+Css进行登录页面的样式设计 -->
<div class="login">
<form action="" style="height: 100%" method="post">
<!-- 整个的登录框内容 -->
<div class="login-box">
<!-- 登录框标题内容 -->
<div class="login-text">
<h3>个人博客后台管理</h3>
</div>
<!-- 登录框用户名内容 -->
<div class="login-username">
<input type="text" v-model="username" name="username" @blur="login" placeholder="请输入用户名">
<span class="info1" v-if="context === 'usn'"><strong>{{ info1 }}</strong></span>
<span class="info1" v-if="context === 'isnull'"><strong>{{ info3 }}</strong></span>
</div>
<!-- 登录框密码内容 -->
<div class="login-password">
<input type="password" v-model="password" name="passowrd" placeholder="请输入用户密码">
<span class="info2" v-if="context === 'psw'"><strong>{{ info2 }}</strong></span>
</div>
<!-- 登录框提交内容 -->
<div class="login-submit">
<router-link :to="url">
<button type="submit" id="submit" @click="login">登录</button>
</router-link>
</div>
</div>
</form>
</div>
</div>
</template>
2.2 文章管理
代码如下:
<template>
<div id="classify-container">
<div id="search">
<input type="text" placeholder="输入副分类进行搜索" v-model="searchMsg" @keyup.enter="search" />
<el-button type="primary" size="mini" @click="search">搜索文章</el-button>
</div>
<el-table :data="currentList" style="width: 100%">
<!-- 文章ID数据列 -->
<el-table-column label="ID" width="180">
<template slot-scope="scope">
<span style="margin-left: 10px">{{ scope.row.id }}</span>
</template>
</el-table-column>
<!-- 文章所属分类数据列 -->
<el-table-column label="分类" width="180">
<template slot-scope="scope">
<i class="el-icon-collection-tag"></i>
<span style="margin-left: 10px">{{ scope.row.title }}</span>
</template>
</el-table-column>
<!-- 文章所属副分类数据列 -->
<el-table-column label="副分类" width="180">
<template slot-scope="scope">
<i class="el-icon-time"></i>
<span style="margin-left: 10px">{{ scope.row.subtitle }}</span>
</template>
</el-table-column>
<!-- 文章标题内容数据列 -->
<el-table-column label="标题内容" width="180">
<template slot-scope="scope">
<i class="el-icon-document-copy"></i>
<span style="margin-left: 10px">{{ scope.row.md_content }}</span>
</template>
</el-table-column>
<!-- 文章创建日期数据列 -->
<el-table-column label="日期" width="180">
<template slot-scope="scope">
<i class="el-icon-date"></i>
<span style="margin-left: 10px">{{ scope.row.creatdate }}</span>
</template>
</el-table-column>
<!-- 文章操作列 -->
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 文章信息编辑模态框 -->
<el-dialog title="文章信息修改" :visible.sync="dialogFormVisible">
<el-form :model="form">
<!-- 文章的所属分类 -->
<el-form-item label="分类" :label-width="formLabelWidth">
<el-input v-model="form.title" autocomplete="off"></el-input>
</el-form-item>
<!-- 文章的所属副分类 -->
<el-form-item label="副分类" :label-width="formLabelWidth">
<el-input v-model="form.subtitle" autocomplete="off"></el-input>
</el-form-item>
<!-- 文章的标题内容 -->
<el-form-item label="标题内容" :label-width="formLabelWidth">
<el-input v-model="form.md_content" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<!-- 模态框的取消和确定按钮 -->
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="close">确 定</el-button>
</div>
</el-dialog>
<!-- 页面上下页操作按钮列 -->
<div class="operations">
<!-- 上一页操作按钮 -->
<el-button type="primary" icon="el-icon-arrow-left" size="mini" @click="pre"></el-button>
<el-button type="primary" size="mini" plain>
{{ page }} / {{ pages }}
</el-button>
<el-button type="primary" size="mini" plain>
总{{ allPage}}条
</el-button>
<!-- 下一页操作按钮 -->
<el-button type="primary" size="mini" @click="next" icon="el-icon-arrow-right"></el-button>
</div>
</div>
</template>
2.3 文章撰写
代码如下:
<template>
<div class="container">
<el-form ref="form" :model="sizeForm" label-width="80px" size="mini" style="padding: 5%">
<el-form-item label="主标题">
<el-input v-model="sizeForm.title"></el-input>
</el-form-item>
<el-form-item label="副标题">
<el-select v-model="sizeForm.subtitle" placeholder="请选择副标题类型">
<el-option label="JavaWeb笔记" value="JavaWeb笔记">JavaWeb笔记</el-option>
<el-option label="Java笔记" value="Java笔记"></el-option>
<el-option label="Vue笔记" value="Vue笔记"></el-option>
<el-option label="人生哲学" value="人生哲学"></el-option>
<el-option label="体育" value="体育"></el-option>
<el-option label="散文欣赏" value="散文欣赏"></el-option>
<el-option label="数据结构" value="数据结构"></el-option>
<el-option label="生活点滴" value="生活点滴"></el-option>
<el-option label="竞赛" value="竞赛"></el-option>
<el-option label="算法笔记" value="算法笔记"></el-option>
</el-select>
</el-form-item>
<el-form-item label="标题内容">
<el-input v-model="sizeForm.md_content" size="small"></el-input>
</el-form-item>
<el-form-item label="是否置顶">
<el-radio-group v-model="sizeForm.resource" size="medium">
<el-radio border label="是"></el-radio>
<el-radio border label="否"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="文章内容">
<el-input type="textarea" :rows="6" placeholder="请输入内容" v-model="sizeForm.content">
</el-input>
</el-form-item>
<el-form-item label="创建时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="sizeForm.date1" style="width: 100%;">
</el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="sizeForm.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item size="large">
<el-button type="primary" @click="onSubmit">立即撰写</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
2.4 文章分类
<template>
<div id="classify-container" style="height: 100%; background: white">
<div class="add-classify">
<h3>添加</h3>
<div>
<div style="font-size: 16px; font-weight:600">类别:</div>
<input type="text" v-model="classification1" placeholder="二级类别" />
</div>
<div>
<div style="font-size: 16px; font-weight:600">所属类别:</div>
<input type="text" v-model="classification2" placeholder="一级类别" />
</div>
<div style="float: right">
<el-button type="primary" size="mini" v-on:click="add">点击添加</el-button>
</div>
</div>
<div style="float: right; width: 70%">
<h3>管理</h3>
<el-table :data="tableData" style="width: 100%" border>
<el-table-column label="分类名称" width="230">
<template slot-scope="scope">
<i class="el-icon-time"></i>
<span style="margin-left: 10px">{{ scope.row.tname }}</span>
</template>
</el-table-column>
<el-table-column label="文章数" width="180">
<template slot-scope="scope">
<el-popover trigger="hover" placement="top">
<p>分类名称: {{ scope.row.tname }}</p>
<p>数量: {{ scope.row.number }}</p>
<div slot="reference" class="name-wrapper">
<el-tag size="medium">{{ scope.row.number }}</el-tag>
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="danger" size="mini" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
<!-- 页面上下页操作按钮列 -->
<div class="operations">
<el-button type="primary" size="mini" @click="pre">
<i class="el-icon-arrow-left"></i>
</el-button>
<el-button type="primary" size="mini" plain>
{{ current }} / {{ pages }}
</el-button>
<el-button type="primary" size="mini" plain>
总{{ allPage }}条
</el-button>
<el-button type="primary" size="mini" @click="next">
<i class="el-icon-arrow-right"></i>
</el-button>
</div>
</div>
</div>
</template>
代码如下:
2.5 管理员添加
代码如下:
<template>
<div id="register-container">
<div id="app">
<!-- Element-UI表单标签 -->
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px"
class="demo-ruleForm">
<!-- 用户名输入框 -->
<el-form-item label="用户名:" prop="username">
<el-input type="text" v-model="ruleForm.username" autocomplete="off" id="username" @blur="Check">
</el-input>
<span class="information">用户已经存在!!</span>
</el-form-item>
<!-- 密码输入框 -->
<el-form-item label="密码:" prop="pass">
<el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input>
</el-form-item>
<!-- 确认密码输入框 -->
<el-form-item label="确认密码:" prop="checkPass">
<el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input>
</el-form-item>
<!-- 年龄输入框 -->
<el-form-item label="身份:" prop="position">
<el-input v-model="ruleForm.position"></el-input>
</el-form-item>
<!-- 地址输入框 -->
<el-form-item label="住址:" prop="address">
<el-input v-model="ruleForm.address"></el-input>
</el-form-item>
<!-- 操作按钮 -->
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
<el-button type="danger" @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
2.6 管理员信息
代码如下:
<template>
<!-- 设置对应的唯一的最外层标签,进行包裹 -->
<div>
<el-table :data="userList" style="width: 100%">
<!-- ID数据列 -->
<el-table-column label="ID" width="180">
<template slot-scope="scope">
<span style="margin-left: 10px">{{ scope.row.id }}</span>
</template>
</el-table-column>
<!-- 管理员数据列 -->
<el-table-column label="用户名" width="180">
<template slot-scope="scope">
<i class="el-icon-user"></i>
<span style="margin-left: 10px">{{ scope.row.username }}</span>
</template>
</el-table-column>
<!-- 管理员登录密码数据列 -->
<el-table-column label="密码" width="180">
<template slot-scope="scope">
<i class="el-icon-lock"></i>
<span style="margin-left: 10px">{{ scope.row.password }}</span>
</template>
</el-table-column>
<!-- 管理员职业数据列 -->
<el-table-column label="职位" width="180">
<template slot-scope="scope">
<i class="el-icon-school"></i>
<span style="margin-left: 10px">{{ scope.row.position }}</span>
</template>
</el-table-column>
<!-- 管理员部分信息数据列 -->
<el-table-column label="用户名" width="180">
<template slot-scope="scope">
<el-popover trigger="hover" placement="top">
<p>职位: {{ scope.row.position }}</p>
<p>住址: {{ scope.row.address }}</p>
<div slot="reference" class="name-wrapper">
<el-tag size="medium">{{ scope.row.username }}</el-tag>
</div>
</el-popover>
</template>
</el-table-column>
<!-- 管理员操作列 -->
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 模态框 -->
<el-dialog title="管理信息修改" :visible.sync="dialogFormVisible">
<el-form :model="form">
<el-form-item label="用户名:" :label-width="formLabelWidth">
<el-input v-model="form.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="用户密码:" :label-width="formLabelWidth">
<el-input v-model="form.password" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="职位:" :label-width="formLabelWidth">
<el-input v-model="form.position" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="地址:" :label-width="formLabelWidth">
<el-input v-model="form.address" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="close">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
2.7 博主个人信息
代码如下:
<template>
<div class="manager-container">
<!-- 个人信息展示布局,这里使用的是原生的DIV+CSS布局 -->
<div class="manager-context">
<div class="content">
<h4>个人主页</h4>
<el-button type="primary" style="height:35px; margin-top:1%; line-height:9px"
@click="dialogFormVisible = true">
修改信息
</el-button>
</div>
<div class="content1">
<span>头像:</span>
<img src="../assets/image6.webp" alt="blank">
</div>
<div class="content2" style="min-height: 60px; line-height: 60px">
<div>工号: <span>{{ blogerList.id }} </span></div>
</div>
<div class="content2" style="min-height: 60px; line-height: 60px; clear:both">
<div>姓名:<span>{{ blogerList.name }}</span></div>
</div>
<div class="content2" style="min-height: 60px; line-height: 60px">
<div>年龄:<span>{{ blogerList.age }}</span></div>
</div>
<div class="content2" style="min-height: 60px; line-height: 60px">
<div>电话:<span>{{ blogerList.tel }}</span></div>
</div>
<div class="content2" style="min-height: 60px; line-height: 60px">
<div>学校:<span>{{ blogerList.school }}</span></div>
</div>
<div class="content2" style="min-height: 60px; line-height: 60px">
<div>地址:<span>{{ blogerList.address }}</span></div>
</div>
<div class="content2" style="min-height: 60px; line-height: 60px">
<div>上次修改时间:<span>{{ blogerList.edit }}</span></div>
</div>
<!-- 修改信息模态框,使用Element-Ui实现 -->
<el-dialog title="个人信息修改" :visible.sync="dialogFormVisible" width="65%">
<el-form :model="form">
<el-form-item label="年龄:" :label-width="formLabelWidth">
<el-input v-model="form.age" autocomplete="on"></el-input>
</el-form-item>
<el-form-item label="电话:" :label-width="formLabelWidth">
<el-input v-model="form.tel" autocomplete="on"></el-input>
</el-form-item>
<el-form-item label="学校:" :label-width="formLabelWidth">
<el-input v-model="form.school" autocomplete="on"></el-input>
</el-form-item>
<el-form-item label="地址:" :label-width="formLabelWidth">
<el-input v-model="form.address" autocomplete="on"></el-input>
</el-form-item>
</el-form>
<!-- 页脚处的按钮,进行信息的取消或者确定 -->
<div slot="footer" class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="confirm">确 定</el-button>
</div>
</el-dialog>
</div>
</div>
</template>
三 项目核心介绍
3.1 Vue2.0
Vue
作为当前最主流的前端框架,给开发者提供了一套简洁方便的代码规范,在本项目中就是以Vue为核心框架进行网页与数据的双向绑定从而实现MVVM
模式,大大减少了使用原生代码开发的时间,提高了开发人员的工作效率。
3.2 Axois
Axios
时目前最流行的ajax封装库之一,用于很方便地实现ajax
请求的发送。在项目中View
与View-Model
之间的数据交互均由使用Axois
发起的ajax
请求实现,具体的实现过程原理如下:在Express框架中挂载对应的路由
,网页标签进行事件绑定,当用户触发了事件执行的条件进行ajax异步请求
再由路由进行数据库MySQL的数据请求通过Response向网页提供得到的数据,并渲染到页面。
同时,作者将axios进行了简单的二次封装,以此提高代码的可维护性。
/ 创建axios实例
const request = axios.create({
// 请求地址的公共部分
baseURL: 'http://localhost:8000',
// 请求超时时间
timeout: 3000,
// 请求头中的Content-Type
headers: {
ContentType: 'application/json'
}
});
// axios请求拦截器的使用
request.interceptors.request.use(config => {
// 请求头携带token值
config.headers.Authorization = window.localStorage.getItem('token');
// 将配置完成的config对象返回出去 如果不返回 请求则不会进行
return config;
}, err => {
// 返回使用Promise封装的错误信息
return Promise.reject(err);
});
// axios响应拦截器的使用
request.interceptors.response.use(response => {
// 用户登录持久化
const status = response.data.status;
// 接口数据状态码返回的是401时代表用户需要进行权限认证
if (status === 401) {
// 用户重新登陆信息提示
MessageBox.alert(
'登录状态已过期, 您可以继续留在该页面, 或者重新登陆',
'系统提示', {
confirmButtonText: '重新登录',
type: 'warning',
callback: action => {
// 将页面重定向为登录页面
location.href = '/';
}
}
)
// 清除用户过期的token
window.localStorage.removeItem('token');
}
// 将响应信息返回
return response;
}, err => {
// 返回使用Promise封装的错误信息
return new Promise(err);
})
3.2.1 部分代码展示
// 使用axois发送ajax请求,并将行es6进行解构接收数据
const { data: res } = await this.$http.get("/article/add", {
params: {
'title': this.sizeForm.title,
'subtitle': this.sizeForm.subtitle,
'md_content': this.sizeForm.md_content,
'creatdate': date
}
})
// 后端返回的结果字符串判断
if (res === 'success') {
this.$message({
message: '添加成功!!',
type: 'success'
})
// 路由进行编程式跳转
this.$router.replace('/layout/article1/' + window.localStorage.getItem('username'))
} else {
this.$message.error('添加失败!!')
}
// (二十二) 创建添加文章的路由,进行article表的数据更新
app.get('/article/add', (req, res) => {
// 22.1 获取url中的查询参数
const params = req.query
// 22.2 设置对应的sql语句
const sql = "insert into article values(null, ?, ?, ?, ?, 1, 1, 1)"
// 22.3 执行对应的sql语句
conn.query(sql, [params.title, params.subtitle, params.md_content, params.creatdate], (err, results) => {
// 22.3.1 倘若执行过程中出现错误,将错误信息打印并直接停止后续代码的执行
if (err) {
console.log(err.message);
return
}
// 22.3.2 执行成功使用res.send()方法向客户端响应对应的字符串
if (results.affectedRows > 0) {
res.send('success')
}
})
})
3.3 Vue-Router
本项目使用Vue-cli
单页面开发模式,App.vue
作为根组件,其他vue组件之间的跳转由Vue-Router
插件提供技术实现,即相当于Html中的a标签
进行页面间的跳转。
3.3.1 部分代码展示
// (三) 创建对应的Router插件的实例对象
const router = new Router({
// 3.1 路由规则
routes: [
// 3.1.1 当用户输入的是'/'时,页面重定向到管理员登录页面
{ path: '/administrator/login', component: Login },
{ path: '/', redirect: '/administrator/login' },
// 3.1.2 注意下面的props属性,用来使用路由中的动态id的传输(倘若子规则开启,父规则也需要开启)
{
path: '/layout', component: Layout, children: [
{ path: 'article1/:username', component: Article1 },
{ path: 'userInfo', component: UserInfo },
{ path: 'addAdmin', component: AddAdmin },
{ path: 'article2', component: Article2 },
{ path: 'classify', component: Classify },
{ path: 'manager', component: Manager },
{ path: 'userInfoBack', component: UserInfoBack}
]
},
]
})
3.4 Element-UI
第一次使用现有的框架进行网页的开发,网页的美化展示效果让用户舒适的用时,不缺乏实用的功能。由于是第一次使用开发过程基本是以查阅文档进行开发为主,希望后续自己可以对Element-UI
的使用运用更佳运用于心。
3.4.1 Element-UI在Vue中的引入方式
import router from './router'
import axios from 'axios'
import jquery from "jquery";
Vue.prototype.$ = jquery;
Vue.config.productionTip = false
axios.defaults.baseURL = "http://localhost:8000"
Vue.prototype.$http = axios
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI)
3.5 数据可视化-ECharts
为了让用户对数据查看有更直观的感受,因此使用ECharts
对部分数据进行饼状图
的形式进行展示。
3.5.1 部分代码展示
etEchartData() {
const chart = this.$refs.datas
if (chart) {
const myChart = this.$echarts.init(document.getElementById('datas'))
const option = {
title: {
text: '统计',
subtext: '文章数',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: 'Access From',
type: 'pie',
radius: '50%',
data: [
{ value: 10, name: 'JavaWeb笔记' },
{ value: 2, name: 'Java笔记' },
{ value: 1, name: 'Vue笔记' },
{ value: 1, name: '人生哲学' },
{ value: 1, name: '体育' },
{ value: 1, name: '散文欣赏' },
{ value: 1, name: '数据结构' },
{ value: 13, name: '生活点滴' },
{ value: 1, name: '竞赛' },
{ value: 2, name: '算法笔记' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
myChart.setOption(option)
window.addEventListener("resize", function () {
myChart.resize()
})
}
this.$on('hook:destroyed', () => {
window.removeEventListener("resize", function () {
myChart.resize();
});
})
}
个人总结
在学校课程开设中,慢慢对前端产生兴趣,这次的个人博客系统自己做前端和后端,由于学校课程没有需要用的技术栈,所以自学了需要的技术栈,Node.js也是自己先过了一遍再进行Vue2.0的学习,两大技术支持学习完成后就进行项目的部署,在开发中达到使用巩固。这次的项目让我提升了独立自主学习,解决困难的能力。需要的同学可以私聊我拿源码,一起交流学习,一起进步。
自知自身技术的局限性,在后续的学习中将不断学习更多前端知识,并在本项目基础上不断改进完善。