前言
(首先欢迎访问chenjinxu.top!!!)说起来为啥要叫一系统呢,因为我是同济的,然后同济的学生一般用的网站的地址是1.tongji.edu.cn,我们都叫他一系统或者一块钱,因此我在做自己网站的第一个子系统的时候想到的第一个名字是一系统,当然进去之后会有一个更详细的命名就是了,不过"官方"的命名依然是一系统!!同时本文的代码的github链接是:GitHub - RidenShogunei/personal-blog-vue-frontend: 一系统,功能包括音乐播放器,扫雷,动画,留言板等,已上线chenjinxu.top
正文
项目结构
这是项目的详细结构
```
personal-blog-vue-frontend
├─ .browserslistrc
├─ .eslintrc.js
├─ .git
│ ├─ config
│ ├─ description
│ ├─ FETCH_HEAD
│ ├─ HEAD
│ ├─ hooks
│ │ ├─ applypatch-msg.sample
│ │ ├─ commit-msg.sample
│ │ ├─ fsmonitor-watchman.sample
│ │ ├─ post-update.sample
│ │ ├─ pre-applypatch.sample
│ │ ├─ pre-commit.sample
│ │ ├─ pre-merge-commit.sample
│ │ ├─ pre-push.sample
│ │ ├─ pre-rebase.sample
│ │ ├─ pre-receive.sample
│ │ ├─ prepare-commit-msg.sample
│ │ ├─ push-to-checkout.sample
│ │ └─ update.sample
│ ├─ index
│ ├─ info
│ │ └─ exclude
│ ├─ logs
│ │ ├─ HEAD
│ │ └─ refs
│ │ ├─ heads
│ │ │ └─ main
│ │ └─ remotes
│ │ └─ origin
│ │ └─ HEAD
│ ├─ objects
│ │ ├─ info
│ │ └─ pack
│ │ ├─ pack-86997cd53ef12bd3f5cbb8274bd2cfeb80ae81ff.idx
│ │ └─ pack-86997cd53ef12bd3f5cbb8274bd2cfeb80ae81ff.pack
│ ├─ packed-refs
│ └─ refs
│ ├─ heads
│ │ └─ main
│ ├─ remotes
│ │ └─ origin
│ │ └─ HEAD
│ └─ tags
├─ .gitignore
├─ babel.config.js
├─ jsconfig.json
├─ package-lock.json
├─ package.json
├─ public
│ ├─ badend.wav
│ ├─ favicon.ico
│ ├─ index.html
│ └─ yuanshen.mp4
├─ README.md
├─ src
│ ├─ App.vue
│ ├─ assets
│ │ ├─ background.jpg
│ │ ├─ blacktiane.jpg
│ │ ├─ blog.jpg
│ │ ├─ diary.jpg
│ │ ├─ kafuka.png
│ │ ├─ learn.jpg
│ │ ├─ lrosrick.jpg
│ │ ├─ password.png
│ │ ├─ personal.jpg
│ │ ├─ refresh.svg
│ │ ├─ shibao.jpg
│ │ ├─ starhunter.png
│ │ ├─ trueback.jpg
│ │ └─ yaya.png
│ ├─ components
│ │ └─ backItem.vue
│ ├─ logs
│ │ ├─ 3.15
│ │ ├─ 3.17
│ │ ├─ 3.21
│ │ └─ 3.23
│ ├─ main.js
│ ├─ router
│ │ └─ index.js
│ ├─ store
│ │ └─ index.js
│ └─ views
│ ├─ animationPage.vue
│ ├─ Blog
│ │ └─ blogPage.vue
│ ├─ camera
│ │ └─ cameraPage.vue
│ ├─ crazy
│ │ └─ crazyPage.vue
│ ├─ diaryPage.vue
│ ├─ game
│ │ ├─ endPage.vue
│ │ ├─ enterPage.vue
│ │ ├─ gamePage.vue
│ │ └─ winPage.vue
│ ├─ HomePage.vue
│ ├─ learnPage.vue
│ ├─ mainPage.vue
│ ├─ musicPage.vue
│ ├─ navigatePage.vue
│ └─ personal
│ ├─ passwordPage.vue
│ └─ personalPage.vue
├─ video
│ ├─ 初步.mp4
│ └─ 启动.mp4
└─ vue.config.js
```
大体思路
其实做一系统的时候我也是怎么说呢,就是很多功能都是做着为了更加熟悉一下技术啥的,举个例子,就是learn部分,这个能存50个字的书啥的,其实本质是把文字存在了localstorage里,然后列表啥的也是读取localstorage,这个功能其实没啥意义,只是为了用一用这个技术,同理动画部分和crazy部分也是,一个是为了应用three.js,一个是想用用动画的那些keyframe啥的操作,本质上都是练手的操作,这之中其实没遇到太多问题.所以接下来我会详细讲的就只有音乐播放器,留言板,个人中心(其实本质是管理中心部分)还有扫雷,现在来看一系统的问题其实挺多的,很多的地方没能做到复用和集中化管理,当然这些都在二系统改进了很多.....
音乐播放器
这里其实本质上是一个调用api的播放器,每次点击按钮就会返回十首歌,本质上是一个for循环,调用10次api.虽然是一个简单的东西,但是在这里我一开始遇到了一个问题,就是有的时候数组更新了但是视图没有更新,在我和chatgpt的详细对话之后,我终于发现了问题所在,那就是在 Vue.js 中,`:key` 是一个特殊的属性,Vue 使用它来追踪每个节点的唯一性。这样当数据变更的时候,只有改变的那一部分再次被渲染,而不是全部重新渲染。按照我原先的代码,音乐文件的 URL 在 Axios 的异步请求完成之后才会被设定。但是,页面在此之前就已经完成了加载,也就是说,`<audio>` 标签在没有设定 `musicurl` 的情况下就已经被渲染了。由于 URL 在初次渲染时是未定义的,所以音乐播放器无法播放任何音频。当 `musicurl` 从 Axios 获取成功后,它会更新,但是 `<audio>` 标签并不会立即更新。这是因为 Vue 认为 `<audio>` 标签已经被渲染过,因此即便 `musicurl` 发生了改变,Vue 也不会触发重新渲染。当我为 `<audio>` 标签添加 `:key` 属性时,就是告诉 Vue 追踪这个标签的状态,并在检测到 `:key` 变化时重新渲染。所以,当你将 `musicurl` 设为 `:key` 的值,每次 `musicurl` 变化时 Vue 就会重新渲染 `<audio>` 标签。这确保播放器的源 URL 总是最新的,也使得音乐播放器可以正常工作。这是一个很有意义的发现.
留言板
留言板这一块其实还行,至少前端做的比较简单,主要的问题和收获大概都在后端.
个人中心
这里其实唯一值得详细说一下的就是我在进入这个个人中心(实际上可以成称为管理中心)的时候做了权限设置,也就是要输入相应的密码才能进入,这里我用的是路由守卫的技术,如下:
{
path: '/person',
name: 'person',
component: () => import('../views/personal/personalPage.vue'),
beforeEnter: (to, from, next) => {
// 检查用户是否是从密码输入页面过来的
if (from.path === '/password') {
next();
} else {
// 否则,重定向到密码输入页面
next('/password');
}
},
}
在进入这个个人中心之前会检测是否是从密码输入界面来的,而在密码界面只有输入密码才能跳转.因此保证了个人中心一定要输入密码才能进入,这里再详细说一下路由守卫的知识吧:
在Vue.js中,路由守卫被称为导航守卫(Navigation Guards)。Vue.js提供了三种类型的导航守卫:全局守卫、路由独享守卫和组件内守卫。下面将详细介绍每种守卫类型,并给出简单的示例。
1. 全局守卫:
全局守卫是应用程序范围内的守卫,它们影响所有的路由。在Vue.js中,全局守卫包括`beforeEach`、`beforeResolve`和`afterEach`。
- beforeEach:在每次路由切换之前调用,可以用于进行身份验证或权限检查。
router.beforeEach((to, from, next) => {
// 模拟身份验证
if (to.meta.requiresAuth && !isAuthenticated()) {
next('/login');
} else {
next();
}
});
- beforeResolve:在每次路由切换之前调用,与`beforeEach`类似,但在路由解析完成之后调用。
router.beforeResolve((to, from, next) => {
// 在路由解析完成后执行一些逻辑
next();
});
- afterEach:在每次路由切换之后调用,可以用于记录路由导航或执行其他后续操作。
router.afterEach((to, from) => {
// 记录路由导航
console.log(`Navigated from ${from.path} to ${to.path}`);
});
2. 路由独享守卫:
路由独享守卫仅在特定路由配置中定义,它们会影响单个路由。这也是我使用的(
const router = new VueRouter({
routes: [
{
path: '/dashboard',
component: Dashboard,
beforeEnter: (to, from, next) => {
// 在进入特定路由之前执行一些逻辑
if (isAdmin()) {
next();
} else {
next('/login');
}
}
}
]
});
3. 组件内守卫:
组件内守卫是在组件内部定义的钩子函数,用于控制组件的进入和离开。
- beforeRouteEnter:在进入路由之前调用,但无法访问组件实例。
export default {
beforeRouteEnter(to, from, next) {
// 在进入路由之前执行一些逻辑
if (isAuthenticated()) {
next();
} else {
next('/login');
}
},
// ...
}
- beforeRouteUpdate:在路由参数发生变化时调用,例如同一个组件不同参数的路由切换。
export default {
beforeRouteUpdate(to, from, next) {
// 在路由参数发生变化时执行一些逻辑
if (to.params.id !== from.params.id) {
// 执行一些操作
}
next();
},
// ...
}
- beforeRouteLeave:在离开当前路由时调用,可以用于执行一些清理操作或确认对话框的显示。
export default {
beforeRouteLeave(to, from, next) {
// 在离开当前路由之前执行一些逻辑
if (hasUnsavedChanges()) {
if (confirm('Are you sure you want to leave?')) {
next();
} else {
next(false);
}
} else {
next();
}
},
// ...
}
这些是Vue.js中的常见路由守卫类型和使用示例。通过使用这些守卫,您可以在路由导航过程中添加身份验证、权限检查、数据预加载等逻辑,以保护和控制您的应用程序的访问。
扫雷
这个其实就是先初始化数组放置炸弹,随机的当然,然后再次遍历数组,将整张的map的数字填写正确,之后就是一些简单的css操作,唯一值得一提的是扫雷盘的css样式我使用了table样式:
<table id="minesweeper">
<tbody>
<tr v-for="(row, rowIndex) in rows" :key="rowIndex">
<td class="gezi" v-for="(col, colIndex) in row" :key="colIndex" @click="clickCell(rowIndex, colIndex)">
<div v-if="!col.isRevealed">?</div> <!-- If not revealed, show a question mark. -->
<div v-else-if="col.mine"><img src="../../assets/shibao.jpg" class="img"
:class="{ animate: isMineExploded }" /></div>
<!-- If revealed and it's a mine, show a bomb. -->
<div v-else>{{ col.value }}</div> <!-- If revealed and it's not a mine, show a zero. -->
</td>
</tr>
</tbody>
</table>
结语
一系统的前端部分差不多能说的就这些,其实在这期间没有遇到太多的坑就是了.....