博客前端
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel ="shortcut icon" type="image/x-icon" href="./src/assets/">
|
||||
<title>Activiti</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
15
package.json
|
@ -8,8 +8,17 @@
|
|||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"arale-qrcode": "^3.0.5",
|
||||
"axios": "^1.6.0",
|
||||
"core-js": "^3.8.3",
|
||||
"github-markdown-css": "^5.4.0",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"markdown-it": "^13.0.2",
|
||||
"mavon-editor": "^2.10.4",
|
||||
"sass-loader": "^13.3.2",
|
||||
"vue": "^2.6.14",
|
||||
"vue-live2d": "^1.3.1",
|
||||
"vue-qr": "^4.0.9",
|
||||
"vue-router": "^3.5.1",
|
||||
"vuex": "^3.6.2"
|
||||
},
|
||||
|
@ -23,6 +32,10 @@
|
|||
"@vue/cli-service": "~5.0.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-vue": "^8.0.3",
|
||||
"vue-template-compiler": "^2.6.14"
|
||||
"less-loader": "^11.1.3",
|
||||
"stylus": "^0.61.0",
|
||||
"stylus-loader": "^7.1.3",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vuepress-plugin-sakura": "^1.2.1"
|
||||
}
|
||||
}
|
||||
|
|
7036
pnpm-lock.yaml
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 99 KiB |
|
@ -1,17 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
26
src/App.vue
|
@ -1,32 +1,8 @@
|
|||
<template>
|
||||
<div id="app">
|
||||
<nav>
|
||||
<router-link to="/">Home</router-link> |
|
||||
<router-link to="/about">About</router-link>
|
||||
</nav>
|
||||
<router-view/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
nav {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
nav a {
|
||||
font-weight: bold;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
nav a.router-link-exact-active {
|
||||
color: #42b983;
|
||||
}
|
||||
<style lang="scss">
|
||||
</style>
|
||||
|
|
After Width: | Height: | Size: 459 KiB |
After Width: | Height: | Size: 275 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 2.7 MiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 498 KiB |
After Width: | Height: | Size: 403 KiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 137 KiB |
After Width: | Height: | Size: 324 KiB |
After Width: | Height: | Size: 4.2 MiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 538 KiB |
After Width: | Height: | Size: 436 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 99 KiB |
|
@ -0,0 +1,189 @@
|
|||
<template>
|
||||
<div class="background-container">
|
||||
<Menu></Menu>
|
||||
<div class="centered-text">
|
||||
<h3>发布博客</h3>
|
||||
<h13 class="span loader">
|
||||
<span class="m">W</span><span class="m">E</span><span class="m">L</span><span class="m">C</span><span
|
||||
class="m">O</span><span class="m">M</span><span class="m">E</span> <span class="m">T</span><span
|
||||
class="m"></span><span class="m">O</span> <span class="m">X</span><span class="m"></span><span
|
||||
class="m">u</span><span class="m">b</span><span class="m">x</span><span class="m">'s</span> <span
|
||||
class="m">B</span><span class="m">L</span><span class="m">O</span><span class="m">G</span>
|
||||
|
||||
</h13>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Menu from './Menu.vue'
|
||||
export default {
|
||||
components:{
|
||||
Menu,
|
||||
},
|
||||
name: "HeaderView",
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.background-container {
|
||||
position: relative;
|
||||
height: 420px;
|
||||
width: 100%;
|
||||
background-image: url("../assets/about-archive.jpeg");
|
||||
background-size: cover;
|
||||
opacity: 0;
|
||||
/* 初始时设置透明度为0 */
|
||||
animation: fade-in 1s forwards;
|
||||
/* 使用动画效果渐变显示背景图 */
|
||||
/* z-index: 9999; */
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0.5;
|
||||
/* 动画开始时透明度为0 */
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
/* 动画结束时透明度为1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* 首页文字 */
|
||||
.centered-text {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
}
|
||||
|
||||
.centered-text h3 {
|
||||
margin: 0px;
|
||||
font-family: "Montserrat", sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 50px;
|
||||
color: #03dac6;
|
||||
transition: all 0.3s ease;
|
||||
text-shadow: 5px 5px 10px black;
|
||||
/* transform: translateX(19%); */
|
||||
}
|
||||
|
||||
.centered-text h3:hover {
|
||||
/* transform: translate3d(182px, -5px, 0px); */
|
||||
transform: translateY(-5px);
|
||||
color: #ff0266;
|
||||
}
|
||||
|
||||
.centered-text h13.span {
|
||||
padding: 0px 60px;
|
||||
font-size: 20px;
|
||||
letter-spacing: 0.7em;
|
||||
font-family: "ROBOTO", sans-serif;
|
||||
font-weight: 300;
|
||||
color: #faebd7;
|
||||
z-index: 4;
|
||||
transform: translateX(10%);
|
||||
}
|
||||
|
||||
|
||||
.loader span {
|
||||
color: #faebd7;
|
||||
text-shadow: 0 0 0 #faebd7;
|
||||
-webkit-animation: loading 1s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
to {
|
||||
text-shadow: 20px 0 70px #ff0202;
|
||||
color: #ff0266;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.loader span:nth-child(2) {
|
||||
-webkit-animation-delay: 0.1s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(3) {
|
||||
-webkit-animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(4) {
|
||||
-webkit-animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(5) {
|
||||
-webkit-animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(6) {
|
||||
-webkit-animation-delay: 0.5s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(7) {
|
||||
-webkit-animation-delay: 0.6s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(8) {
|
||||
-webkit-animation-delay: 0.7s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(9) {
|
||||
-webkit-animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(10) {
|
||||
-webkit-animation-delay: 0.9s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(11) {
|
||||
-webkit-animation-delay: 1s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(12) {
|
||||
-webkit-animation-delay: 1.1s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(13) {
|
||||
-webkit-animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(14) {
|
||||
-webkit-animation-delay: 1.3s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(15) {
|
||||
-webkit-animation-delay: 1.4s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(16) {
|
||||
-webkit-animation-delay: 1.5s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(17) {
|
||||
-webkit-animation-delay: 1.6s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(18) {
|
||||
-webkit-animation-delay: 1.7s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(19) {
|
||||
-webkit-animation-delay: 1.8s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(20) {
|
||||
-webkit-animation-delay: 1.9s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(21) {
|
||||
-webkit-animation-delay: 2s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(22) {
|
||||
-webkit-animation-delay: 2.1s;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,97 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="body">
|
||||
<!-- <el-divider></el-divider> -->
|
||||
<p>Copyright ©2023 Xubx</p>
|
||||
<a href="https://beian.miit.gov.cn/#/Integrated/index">闽ICP备2023011424号</a>
|
||||
<br>
|
||||
<div class="stars" ref="starsRef">
|
||||
<div class="star" v-for="(item, index) in starsCount" :key="index"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
let starsRef = ref(null);
|
||||
|
||||
const starsCount = 800; //星星数量
|
||||
const distance = 900; //间距
|
||||
|
||||
onMounted(() => {
|
||||
let starNodes = Array.from(starsRef.value.children);
|
||||
starNodes.forEach((item) => {
|
||||
let speed = 0.2 + Math.random() * 1;
|
||||
let thisDistance = distance + Math.random() * 300;
|
||||
item.style.transformOrigin = `0 0 ${thisDistance}px`;
|
||||
item.style.transform = `
|
||||
translate3d(0,0,-${thisDistance}px)
|
||||
rotateY(${Math.random() * 360}deg)
|
||||
rotateX(${Math.random() * -50}deg)
|
||||
scale(${speed},${speed})`;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
starsRef,
|
||||
starsCount,
|
||||
};
|
||||
},
|
||||
name: "FooterView"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.body {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: radial-gradient(200% 100% at bottom center,
|
||||
#f7f7b6,
|
||||
#e96f92,
|
||||
#1b2947);
|
||||
background: radial-gradient(200% 105% at top center,
|
||||
#1b2947 10%,
|
||||
#75517d 40%,
|
||||
#e96f92 65%,
|
||||
#f7f7b6);
|
||||
background-attachment: fixed;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
0% {
|
||||
transform: perspective(400px) rotateZ(20deg) rotateX(-40deg) rotateY(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: perspective(400px) rotateZ(20deg) rotateX(-40deg) rotateY(-360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.stars {
|
||||
transform: perspective(500px);
|
||||
transform-style: preserve-3d;
|
||||
position: absolute;
|
||||
perspective-origin: 50% 100%;
|
||||
left: 45%;
|
||||
animation: rotate 90s infinite linear;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.star {
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
background: #f7f7b6;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,190 @@
|
|||
<template>
|
||||
<div class="background-container">
|
||||
<Menu></Menu>
|
||||
<div class="centered-text">
|
||||
<h3>博客详情</h3>
|
||||
<h13 class="span loader">
|
||||
<span class="m">W</span><span class="m">E</span><span class="m">L</span><span class="m">C</span><span
|
||||
class="m">O</span><span class="m">M</span><span class="m">E</span> <span class="m">T</span><span
|
||||
class="m"></span><span class="m">O</span> <span class="m">X</span><span class="m"></span><span
|
||||
class="m">u</span><span class="m">b</span><span class="m">x</span><span class="m">'s</span> <span
|
||||
class="m">B</span><span class="m">L</span><span class="m">O</span><span class="m">G</span>
|
||||
</h13>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Menu from './Menu.vue'
|
||||
export default {
|
||||
components: {
|
||||
Menu,
|
||||
},
|
||||
name: "HeaderView",
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.background-container {
|
||||
/* z-index: 9999; */
|
||||
position: relative;
|
||||
height: 420px;
|
||||
width: 100%;
|
||||
background-image: url("../assets/link-bg.jpeg");
|
||||
background-size: cover;
|
||||
opacity: 0;
|
||||
/* 初始时设置透明度为0 */
|
||||
animation: fade-in 1s forwards;
|
||||
/* 使用动画效果渐变显示背景图 */
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0.5;
|
||||
/* 动画开始时透明度为0 */
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
/* 动画结束时透明度为1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* 首页文字 */
|
||||
.centered-text {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
}
|
||||
|
||||
.centered-text h3 {
|
||||
margin: 0px;
|
||||
font-family: "Montserrat", sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 50px;
|
||||
color: #03dac6;
|
||||
transition: all 0.3s ease;
|
||||
text-shadow: 5px 5px 10px black;
|
||||
/* transform: translateX(19%); */
|
||||
}
|
||||
|
||||
.centered-text h3:hover {
|
||||
/* transform: translate3d(182px, -5px, 0px); */
|
||||
transform: translateY(-5px);
|
||||
color: #ff0266;
|
||||
}
|
||||
|
||||
.centered-text h13.span {
|
||||
padding: 0px 60px;
|
||||
font-size: 20px;
|
||||
letter-spacing: 0.7em;
|
||||
font-family: "ROBOTO", sans-serif;
|
||||
font-weight: 300;
|
||||
color: #faebd7;
|
||||
z-index: 4;
|
||||
transform: translateX(10%);
|
||||
}
|
||||
|
||||
|
||||
.loader span {
|
||||
color: #faebd7;
|
||||
text-shadow: 0 0 0 #faebd7;
|
||||
-webkit-animation: loading 1s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
to {
|
||||
text-shadow: 20px 0 70px #ff0202;
|
||||
color: #ff0266;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.loader span:nth-child(2) {
|
||||
-webkit-animation-delay: 0.1s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(3) {
|
||||
-webkit-animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(4) {
|
||||
-webkit-animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(5) {
|
||||
-webkit-animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(6) {
|
||||
-webkit-animation-delay: 0.5s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(7) {
|
||||
-webkit-animation-delay: 0.6s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(8) {
|
||||
-webkit-animation-delay: 0.7s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(9) {
|
||||
-webkit-animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(10) {
|
||||
-webkit-animation-delay: 0.9s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(11) {
|
||||
-webkit-animation-delay: 1s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(12) {
|
||||
-webkit-animation-delay: 1.1s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(13) {
|
||||
-webkit-animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(14) {
|
||||
-webkit-animation-delay: 1.3s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(15) {
|
||||
-webkit-animation-delay: 1.4s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(16) {
|
||||
-webkit-animation-delay: 1.5s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(17) {
|
||||
-webkit-animation-delay: 1.6s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(18) {
|
||||
-webkit-animation-delay: 1.7s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(19) {
|
||||
-webkit-animation-delay: 1.8s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(20) {
|
||||
-webkit-animation-delay: 1.9s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(21) {
|
||||
-webkit-animation-delay: 2s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(22) {
|
||||
-webkit-animation-delay: 2.1s;
|
||||
}
|
||||
</style>
|
|
@ -1,60 +0,0 @@
|
|||
<template>
|
||||
<div class="hello">
|
||||
<h1>{{ msg }}</h1>
|
||||
<p>
|
||||
For a guide and recipes on how to configure / customize this project,<br>
|
||||
check out the
|
||||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
|
||||
</p>
|
||||
<h3>Installed CLI Plugins</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
|
||||
</ul>
|
||||
<h3>Essential Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
|
||||
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
|
||||
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
|
||||
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
|
||||
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
|
||||
</ul>
|
||||
<h3>Ecosystem</h3>
|
||||
<ul>
|
||||
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
|
||||
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
|
||||
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
|
||||
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'HelloWorld',
|
||||
props: {
|
||||
msg: String
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
h3 {
|
||||
margin: 40px 0 0;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
li {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
a {
|
||||
color: #42b983;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,188 @@
|
|||
<template>
|
||||
<div class="background-container">
|
||||
<Menu></Menu>
|
||||
<div class="centered-text" >
|
||||
<h3>欢迎来到Xubx的博客</h3>
|
||||
<h13 class="span loader">
|
||||
<span class="m">W</span><span class="m">E</span><span class="m">L</span><span class="m">C</span><span
|
||||
class="m">O</span><span class="m">M</span><span class="m">E</span> <span class="m">T</span><span
|
||||
class="m"></span><span class="m">O</span> <span class="m">X</span><span class="m"></span><span
|
||||
class="m">u</span><span class="m">b</span><span class="m">x</span><span class="m">'s</span> <span
|
||||
class="m">B</span><span class="m">L</span><span class="m">O</span><span class="m">G</span>
|
||||
|
||||
</h13>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Menu from './Menu.vue'
|
||||
export default {
|
||||
components: {
|
||||
Menu,
|
||||
},
|
||||
name: "HeaderView",
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.background-container {
|
||||
/* z-index: 0; */
|
||||
position: relative;
|
||||
height: 720px;
|
||||
width: 100%;
|
||||
background-image: url("../assets/home-bg.jpeg");
|
||||
background-size: cover;
|
||||
opacity: 0;
|
||||
/* 初始时设置透明度为0 */
|
||||
animation: fade-in 1s forwards;
|
||||
/* 使用动画效果渐变显示背景图 */
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0.5;
|
||||
/* 动画开始时透明度为0 */
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
/* 动画结束时透明度为1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* 首页文字 */
|
||||
.centered-text {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
}
|
||||
|
||||
.centered-text h3 {
|
||||
margin: 0px;
|
||||
font-family: "Montserrat", sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 70px;
|
||||
color: #03dac6;
|
||||
transition: all 0.3s ease;
|
||||
text-shadow: 5px 5px 10px black;
|
||||
/* transform: translateX(19%); */
|
||||
}
|
||||
|
||||
.centered-text h3:hover {
|
||||
/* transform: translate3d(182px, -5px, 0px); */
|
||||
transform: translateY(-5px);
|
||||
color: #ff0266;
|
||||
}
|
||||
|
||||
.centered-text h13.span {
|
||||
padding: 0px 60px;
|
||||
font-size: 2vw;
|
||||
letter-spacing: 0.7em;
|
||||
font-family: "ROBOTO", sans-serif;
|
||||
font-weight: 400;
|
||||
color: #faebd7;
|
||||
z-index: 4;
|
||||
transform: translateX(10%);
|
||||
}
|
||||
|
||||
|
||||
.loader span {
|
||||
color: #faebd7;
|
||||
text-shadow: 0 0 0 #faebd7;
|
||||
-webkit-animation: loading 1s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
to {
|
||||
text-shadow: 20px 0 70px #ff0202;
|
||||
color: #ff0266;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.loader span:nth-child(2) {
|
||||
-webkit-animation-delay: 0.1s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(3) {
|
||||
-webkit-animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(4) {
|
||||
-webkit-animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(5) {
|
||||
-webkit-animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(6) {
|
||||
-webkit-animation-delay: 0.5s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(7) {
|
||||
-webkit-animation-delay: 0.6s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(8) {
|
||||
-webkit-animation-delay: 0.7s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(9) {
|
||||
-webkit-animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(10) {
|
||||
-webkit-animation-delay: 0.9s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(11) {
|
||||
-webkit-animation-delay: 1s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(12) {
|
||||
-webkit-animation-delay: 1.1s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(13) {
|
||||
-webkit-animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(14) {
|
||||
-webkit-animation-delay: 1.3s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(15) {
|
||||
-webkit-animation-delay: 1.4s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(16) {
|
||||
-webkit-animation-delay: 1.5s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(17) {
|
||||
-webkit-animation-delay: 1.6s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(18) {
|
||||
-webkit-animation-delay: 1.7s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(19) {
|
||||
-webkit-animation-delay: 1.8s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(20) {
|
||||
-webkit-animation-delay: 1.9s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(21) {
|
||||
-webkit-animation-delay: 2s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(22) {
|
||||
-webkit-animation-delay: 2.1s;
|
||||
}</style>
|
|
@ -0,0 +1,464 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="menu">
|
||||
<div class="brand">
|
||||
<h3 class="red">BIG</h3>
|
||||
<h3 class="white">DATA</h3>
|
||||
</div>
|
||||
<div class="main-nav">
|
||||
<router-link to="/" type="primary" class="button-container">
|
||||
<h2>主页</h2>
|
||||
</router-link>
|
||||
<router-link to="/time" type="primary" class="button-container">
|
||||
<h2>归档</h2>
|
||||
</router-link>
|
||||
<router-link to="/add" type="success" class="button-container">
|
||||
<h2>发布博客</h2>
|
||||
</router-link>
|
||||
|
||||
</div>
|
||||
<div class="right-nav">
|
||||
<el-dropdown @command="handleCommand" class="el-dropdown-link">
|
||||
<span>
|
||||
<el-avatar v-if="imageUrl" :src="imageUrl" style="width: 50px; height: 50px;"
|
||||
class="avatar flip animated"></el-avatar>
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<p>{{ this.username }}</p>
|
||||
<el-upload action="http://124.71.135.249:8081/uploadAvatar/" :show-file-list="false"
|
||||
:on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
|
||||
<el-dropdown-item divided icon="el-icon-picture-outline-round">更换头像</el-dropdown-item>
|
||||
</el-upload>
|
||||
<a @click="nameChangeVisible = true">
|
||||
<el-dropdown-item divided icon="el-icon-user">
|
||||
修改昵称
|
||||
</el-dropdown-item>
|
||||
</a>
|
||||
<a @click="passwordChangeVisible = true">
|
||||
<el-dropdown-item divided icon="el-icon-edit-outline">
|
||||
修改密码
|
||||
</el-dropdown-item>
|
||||
</a>
|
||||
<router-link to="/login" class="right-nav">
|
||||
<el-dropdown-item divided icon="el-icon-switch-button">退出登录</el-dropdown-item>
|
||||
</router-link>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog title="修改昵称" :visible="nameChangeVisible" width="400px" @close="nameChangeVisible = false">
|
||||
<el-form :model="usernameForm" :rules="usernameRules">
|
||||
<el-form-item label="请输入昵称" :label-width="200" prop="usernameChange">
|
||||
<el-input v-model="usernameForm.usernameChange" style="width: 350px;"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="nameChangeVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="usernameChange()">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog title="修改密码" :destroy-on-close="true" :visible="passwordChangeVisible" width="550px"
|
||||
@close="passwordChangeVisible = false">
|
||||
<el-form :model="passwordForm" label-width="100px" :rules="passwordRules">
|
||||
<el-form-item label="原密码" prop="oldPassword">
|
||||
<el-input v-model="passwordForm.oldPassword" style="width: 350px;"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码" prop="newPassword">
|
||||
<el-input v-model="passwordForm.newPassword" style="width: 350px;"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认新密码" prop="configurePassword">
|
||||
<el-input v-model="passwordForm.configurePassword" style="width: 350px;"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="passwordChangeVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="passwordChange()">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
export default {
|
||||
data() {
|
||||
//自定义表单校准规则
|
||||
var validateConfigurePassword = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请再次输入密码")); //callback的作用是显示那个图标的
|
||||
} else if (value !== this.passwordForm.newPassword) {
|
||||
callback(new Error("两次输入密码不一致!"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
var validateUsername = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入用户名"));
|
||||
} else if (value.length < 3) {
|
||||
callback(new Error("长度不够"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
imageUrl: '',
|
||||
username: '',
|
||||
nameChangeVisible: false,
|
||||
passwordChangeVisible: false,
|
||||
usernameForm: {
|
||||
usernameChange: ''
|
||||
},
|
||||
passwordForm: {
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
configurePassword: ''
|
||||
},
|
||||
passwordRules: {
|
||||
oldPassword: [
|
||||
{ required: true, message: '请输入原密码', trigger: 'blur' },
|
||||
],
|
||||
newPassword: [
|
||||
{ required: true, message: '请输入新密码', trigger: 'blur' },
|
||||
],
|
||||
configurePassword: [
|
||||
{ validator: validateConfigurePassword, trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
usernameRules: {
|
||||
usernameChange: [
|
||||
{ validator: validateUsername, trigger: 'blur' }, //trigger: 'blur'失去焦点时触发
|
||||
],
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleAvatarSuccess(res, file) {
|
||||
this.imageUrl = URL.createObjectURL(file.raw);
|
||||
//刷新页面
|
||||
window.location.reload();
|
||||
console.log("自动生成的url:" + URL.createObjectURL(file.raw) + '+this.imageUrl:' + this.imageUrl);
|
||||
},
|
||||
beforeAvatarUpload(file) {
|
||||
const isJPG = file.type === 'image/jpeg';
|
||||
const isLt2M = file.size / 1024 / 1024 < 2;
|
||||
|
||||
if (!isJPG) {
|
||||
this.$message.error('上传头像图片只能是 JPG 格式!');
|
||||
}
|
||||
if (!isLt2M) {
|
||||
this.$message.error('上传头像图片大小不能超过 2MB!');
|
||||
}
|
||||
return isJPG && isLt2M;
|
||||
},
|
||||
getAvatar() {
|
||||
axios.get("/getAvatar").then((res) => {
|
||||
this.imageUrl = 'http://124.71.135.249:8081' + res.data;
|
||||
console.log("接收的url:" + this.imageUrl)
|
||||
})
|
||||
},
|
||||
getUsername() {
|
||||
axios.get("/getUsername").then((res) => {
|
||||
this.username = res.data;
|
||||
console.log(this.username);
|
||||
})
|
||||
},
|
||||
usernameChange() {
|
||||
axios.get("/usernameChange", {
|
||||
params: {
|
||||
username: this.usernameForm.usernameChange
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data === "修改成功!") {
|
||||
this.$message.success(res.data)
|
||||
} else {
|
||||
this.$message.error(res.data)
|
||||
}
|
||||
this.nameChangeVisible = false;
|
||||
this.getUsername();
|
||||
//清空表单
|
||||
this.usernameForm.usernameChange = '';
|
||||
})
|
||||
},
|
||||
passwordChange() {
|
||||
axios.get("/passwordChange", {
|
||||
params: {
|
||||
oldPassword: this.passwordForm.oldPassword,
|
||||
newPassword: this.passwordForm.newPassword,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data === "修改成功!") {
|
||||
this.$message.success(res.data);
|
||||
this.passwordChangeVisible = false;
|
||||
//清空表单
|
||||
this.passwordForm.oldPassword = '';
|
||||
this.passwordForm.newPassword = '';
|
||||
this.passwordForm.configurePassword = '';
|
||||
} else {
|
||||
this.$message.error(res.data)
|
||||
}
|
||||
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getAvatar();
|
||||
this.getUsername();
|
||||
},
|
||||
|
||||
name: "MenuView",
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/*base code*/
|
||||
.animated {
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.animated.infinite {
|
||||
-webkit-animation-iteration-count: infinite;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.animated.hinge {
|
||||
-webkit-animation-duration: 2s;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
/*the animation definition*/
|
||||
@-webkit-keyframes flip {
|
||||
0% {
|
||||
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out
|
||||
}
|
||||
|
||||
40% {
|
||||
-webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
|
||||
transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out
|
||||
}
|
||||
|
||||
50% {
|
||||
-webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
|
||||
transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in
|
||||
}
|
||||
|
||||
80% {
|
||||
-webkit-transform: perspective(400px) scale3d(.95, .95, .95);
|
||||
transform: perspective(400px) scale3d(.95, .95, .95);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: perspective(400px);
|
||||
transform: perspective(400px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes flip {
|
||||
0% {
|
||||
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
|
||||
-ms-transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out
|
||||
}
|
||||
|
||||
40% {
|
||||
-webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
|
||||
-ms-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
|
||||
transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out
|
||||
}
|
||||
|
||||
50% {
|
||||
-webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
|
||||
-ms-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
|
||||
transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in
|
||||
}
|
||||
|
||||
80% {
|
||||
-webkit-transform: perspective(400px) scale3d(.95, .95, .95);
|
||||
-ms-transform: perspective(400px) scale3d(.95, .95, .95);
|
||||
transform: perspective(400px) scale3d(.95, .95, .95);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: perspective(400px);
|
||||
-ms-transform: perspective(400px);
|
||||
transform: perspective(400px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in
|
||||
}
|
||||
}
|
||||
|
||||
.animated.flip {
|
||||
-webkit-backface-visibility: visible;
|
||||
-ms-backface-visibility: visible;
|
||||
backface-visibility: visible;
|
||||
-webkit-animation-name: flip;
|
||||
animation-name: flip
|
||||
}
|
||||
|
||||
|
||||
.el-dropdown-link {
|
||||
cursor: pointer;
|
||||
color: #e9ecee;
|
||||
}
|
||||
|
||||
.el-icon-arrow-down {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.background-container {
|
||||
/* z-index: 0; */
|
||||
position: relative;
|
||||
height: 720px;
|
||||
width: 100%;
|
||||
background-image: url("../assets/home-bg.jpeg");
|
||||
background-size: cover;
|
||||
opacity: 0;
|
||||
/* 初始时设置透明度为0 */
|
||||
animation: fade-in 1s forwards;
|
||||
/* 使用动画效果渐变显示背景图 */
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0.5;
|
||||
/* 动画开始时透明度为0 */
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
/* 动画结束时透明度为1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* 首页导航 */
|
||||
.menu {
|
||||
/* position: absolute;
|
||||
background-color: transparent; */
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
height: 70px;
|
||||
background-color: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
/* z-index: 10000; */
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.menu:hover {
|
||||
background-color: rgba(51, 51, 51, 1);
|
||||
/* box-shadow: 0px 2px 10px black; */
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.menu .brand {
|
||||
margin-left: 25px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.menu .brand h3 {
|
||||
font-family: "Anton", sans-serif;
|
||||
font-size: 35px;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: #f90606;
|
||||
}
|
||||
|
||||
.white {
|
||||
/* color: rgba(230, 230, 230, 1); */
|
||||
color: #efefef;
|
||||
|
||||
}
|
||||
|
||||
.menu .brand h1 {
|
||||
font-family: "Anton", sans-serif;
|
||||
font-size: 35px;
|
||||
}
|
||||
|
||||
.main-nav {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.main-nav .button-container {
|
||||
height: calc(100% - 10px);
|
||||
margin-top: 5px;
|
||||
padding: 0px 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-bottom: 5px solid transparent;
|
||||
border-bottom-color: transparent;
|
||||
transition: border-bottom-color 0.3s;
|
||||
}
|
||||
|
||||
.main-nav .button-container:hover {
|
||||
cursor: pointer;
|
||||
border-bottom-color: #ed0909;
|
||||
transition: border-bottom-color 0.3s;
|
||||
}
|
||||
|
||||
.main-nav .button-container h2 {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-size: 26px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.menu .right-nav {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #409EFF;
|
||||
}
|
||||
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,188 @@
|
|||
<template>
|
||||
<div class="background-container-Time">
|
||||
<Menu></Menu>
|
||||
<div class="centered-text">
|
||||
<h3>归档</h3>
|
||||
<h13 class="span loader">
|
||||
<span class="m">W</span><span class="m">E</span><span class="m">L</span><span class="m">C</span><span
|
||||
class="m">O</span><span class="m">M</span><span class="m">E</span> <span class="m">T</span><span
|
||||
class="m"></span><span class="m">O</span> <span class="m">X</span><span class="m"></span><span
|
||||
class="m">u</span><span class="m">b</span><span class="m">x</span><span class="m">'s</span> <span
|
||||
class="m">B</span><span class="m">L</span><span class="m">O</span><span class="m">G</span>
|
||||
</h13>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Menu from './Menu.vue'
|
||||
export default {
|
||||
components: {
|
||||
Menu,
|
||||
},
|
||||
name: "TimeHeaderView",
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.background-container-Time {
|
||||
/* z-index: 9999; */
|
||||
position: relative;
|
||||
height: 750px;
|
||||
width: 100%;
|
||||
background-image: url("../assets/archieve.jpeg");
|
||||
background-size: cover;
|
||||
opacity: 0;
|
||||
/* 初始时设置透明度为0 */
|
||||
animation: fade-in 1s forwards;
|
||||
/* 使用动画效果渐变显示背景图 */
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0.5;
|
||||
/* 动画开始时透明度为0 */
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
/* 动画结束时透明度为1 */
|
||||
}
|
||||
}
|
||||
/* 首页文字 */
|
||||
.centered-text {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
}
|
||||
|
||||
.centered-text h3 {
|
||||
margin: 0px;
|
||||
font-family: "Montserrat", sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 70px;
|
||||
color: #03dac6;
|
||||
transition: all 0.3s ease;
|
||||
text-shadow: 5px 5px 10px black;
|
||||
/* transform: translateX(19%); */
|
||||
}
|
||||
|
||||
.centered-text h3:hover {
|
||||
/* transform: translate3d(182px, -5px, 0px); */
|
||||
transform: translateY(-5px);
|
||||
color: #ff0266;
|
||||
}
|
||||
|
||||
.centered-text h13.span {
|
||||
padding: 0px 60px;
|
||||
font-size: 2vw;
|
||||
letter-spacing: 0.7em;
|
||||
font-family: "ROBOTO", sans-serif;
|
||||
font-weight: 400;
|
||||
color: #faebd7;
|
||||
z-index: 4;
|
||||
transform: translateX(10%);
|
||||
}
|
||||
|
||||
|
||||
.loader span {
|
||||
color: #faebd7;
|
||||
text-shadow: 0 0 0 #faebd7;
|
||||
-webkit-animation: loading 1s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
to {
|
||||
text-shadow: 20px 0 70px #ff0202;
|
||||
color: #ff0266;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.loader span:nth-child(2) {
|
||||
-webkit-animation-delay: 0.1s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(3) {
|
||||
-webkit-animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(4) {
|
||||
-webkit-animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(5) {
|
||||
-webkit-animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(6) {
|
||||
-webkit-animation-delay: 0.5s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(7) {
|
||||
-webkit-animation-delay: 0.6s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(8) {
|
||||
-webkit-animation-delay: 0.7s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(9) {
|
||||
-webkit-animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(10) {
|
||||
-webkit-animation-delay: 0.9s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(11) {
|
||||
-webkit-animation-delay: 1s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(12) {
|
||||
-webkit-animation-delay: 1.1s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(13) {
|
||||
-webkit-animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(14) {
|
||||
-webkit-animation-delay: 1.3s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(15) {
|
||||
-webkit-animation-delay: 1.4s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(16) {
|
||||
-webkit-animation-delay: 1.5s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(17) {
|
||||
-webkit-animation-delay: 1.6s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(18) {
|
||||
-webkit-animation-delay: 1.7s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(19) {
|
||||
-webkit-animation-delay: 1.8s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(20) {
|
||||
-webkit-animation-delay: 1.9s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(21) {
|
||||
-webkit-animation-delay: 2s;
|
||||
}
|
||||
|
||||
.loader span:nth-child(22) {
|
||||
-webkit-animation-delay: 2.1s;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,5 @@
|
|||
body, div, dl,dt,dd,ul,ol,li,h2,h3,h4,h5,h6,pre,form,fieldset,legend,input,textarea{
|
||||
margin: 0;padding:0;}
|
||||
body{text-align: center;}
|
||||
a{ text-decoration: none;}
|
||||
li{ list-style: none;}
|
24
src/main.js
|
@ -2,9 +2,33 @@ import Vue from 'vue'
|
|||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import axios from 'axios'
|
||||
import "./css/common.css"
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
import ElementUI from 'element-ui';
|
||||
import 'element-ui/lib/theme-chalk/index.css';
|
||||
Vue.use(ElementUI);
|
||||
|
||||
//导入mavon-editor,用户Markdown编辑器
|
||||
import mavonEditor from 'mavon-editor'
|
||||
//解决Markdown编辑器的图标不出现问题
|
||||
import "mavon-editor/dist/css/index.css"
|
||||
Vue.use(mavonEditor)
|
||||
|
||||
axios.defaults.baseURL="http://localhost:8081"
|
||||
|
||||
//修改标题
|
||||
router.beforeEach((to, from, next) => {
|
||||
/* 路由发生变化修改页面title */
|
||||
if (to.meta.title) {
|
||||
document.title = to.meta.title
|
||||
}
|
||||
next()
|
||||
})
|
||||
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
|
|
|
@ -1,29 +1,109 @@
|
|||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import HomeView from '../views/HomeView.vue'
|
||||
import Login from '../views/LoginView.vue'
|
||||
import BlogHome from '../views/BlogHomeView.vue'
|
||||
import BlogDetail from '../views/BlogDetailView.vue'
|
||||
import BlogEdit from '../views/BlogEditView.vue'
|
||||
import BlogAdd from '../views/BlogAddView.vue'
|
||||
import jwt_decode from "jwt-decode";
|
||||
import BlogTime from '../views/BlogTimeView.vue'
|
||||
import ProjectWall from '../views/ProjectWallView.vue'
|
||||
import MobileLogin from '../views/MobileLoginView.vue'
|
||||
import store from "../store/index.js"
|
||||
|
||||
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: HomeView
|
||||
name: 'Blogs',
|
||||
component: BlogHome,
|
||||
meta: {
|
||||
title: 'Xubx的博客'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
name: 'about',
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (about.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
|
||||
}
|
||||
path: '/login',
|
||||
name: 'Login',
|
||||
component: window.innerWidth < 768 ? MobileLogin : Login ,
|
||||
meta: {
|
||||
title: 'Xubx的博客'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/blog/:blogId',
|
||||
name: 'BlogDetail',
|
||||
component: BlogDetail,
|
||||
meta: {
|
||||
title: 'Xubx的博客'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/blog/:blogId/edit',
|
||||
name: 'BlogEdit',
|
||||
component: BlogEdit,
|
||||
meta: {
|
||||
title: 'Xubx的博客'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/add',
|
||||
name: 'BlogAdd',
|
||||
component: BlogAdd,
|
||||
meta: {
|
||||
title: 'Xubx的博客'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/time',
|
||||
name: 'BlogTest',
|
||||
component: BlogTime,
|
||||
meta: {
|
||||
title: 'Xubx的博客'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/test',
|
||||
name: 'ProjectWall',
|
||||
component: ProjectWall,
|
||||
meta: {
|
||||
title: 'Xubx的博客'
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
base: process.env.BASE_URL,
|
||||
mode: 'hash',
|
||||
routes
|
||||
})
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
//to 将要访问的路径
|
||||
//from 代表从哪个路径而来
|
||||
//next() 代表放行 next('xxx') 强制放行的xxx的路径
|
||||
if (to.path === '/login') {
|
||||
next();
|
||||
} else {
|
||||
const tokenStr = window.localStorage.getItem('token');
|
||||
console.log(tokenStr);
|
||||
if (!tokenStr) {
|
||||
alert("请你先登陆")
|
||||
return next('/login')
|
||||
}
|
||||
const token = jwt_decode(tokenStr);
|
||||
const currentTime = Date.now() / 1000;
|
||||
if (currentTime > token.exp) {
|
||||
store.commit("delToken"); //删除token
|
||||
console.log("已超时");
|
||||
alert("登陆过期,请你重新登陆")
|
||||
return next('/login')
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
export default router
|
||||
|
|
|
@ -5,13 +5,19 @@ Vue.use(Vuex)
|
|||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
},
|
||||
getters: {
|
||||
},
|
||||
mutations: {
|
||||
},
|
||||
actions: {
|
||||
},
|
||||
modules: {
|
||||
}
|
||||
//定义一个state存储token信息
|
||||
token: localStorage.getItem('token') ? localStorage.getItem('token') : ''
|
||||
},
|
||||
mutations: {
|
||||
//登录后通过setToken存入token token保存在state和localStorage中
|
||||
setToken (state,token) {
|
||||
state.token =token;
|
||||
localStorage.setItem("token",token.token); //存储token
|
||||
},
|
||||
//登出后通过delToken清除token
|
||||
delToken (state) {
|
||||
state.token = '';
|
||||
localStorage.removeItem("token"); //删除token
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<template>
|
||||
<div class="about">
|
||||
<h1>This is an about page</h1>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,111 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- 引用导航 -->
|
||||
<AddHeader></AddHeader>
|
||||
<br>
|
||||
<div class="m_content">
|
||||
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
|
||||
<el-form-item label="标题" prop="title">
|
||||
<el-input v-model="ruleForm.title"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="摘要" prop="description">
|
||||
<el-input type="textarea" v-model="ruleForm.description"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="内容" prop="content">
|
||||
<!-- 特殊组件 -->
|
||||
<mavon-editor v-model="ruleForm.content"></mavon-editor>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm('ruleForm')">立即发布</el-button>
|
||||
<!-- <el-button @click="resetForm('ruleForm')">重置</el-button> -->
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<br>
|
||||
<Footer></Footer>
|
||||
<br>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import AddHeader from "../components/AddHeader";
|
||||
import Footer from "../components/Footer";
|
||||
|
||||
export default {
|
||||
components: {AddHeader, Footer},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
// 在组件进入之前,将页面滚动到顶部
|
||||
window.scrollTo(0, 0);
|
||||
next();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ruleForm: {
|
||||
id: "",
|
||||
title: "",
|
||||
description: "",
|
||||
content: "",
|
||||
},
|
||||
rules: {
|
||||
title: [
|
||||
{ required: true, message: "请输入标题", trigger: "blur" },
|
||||
{
|
||||
min: 5,
|
||||
max: 100,
|
||||
message: "长度在 5 到 100 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
description: [
|
||||
{ required: true, message: "请输入摘要", trigger: "blur" },
|
||||
],
|
||||
content: [{ required: true, message: "请输入内容", trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
submitForm(formName) {
|
||||
//提交表单
|
||||
this.$refs[formName].validate((valid) => {
|
||||
if (valid) {
|
||||
//提交表单
|
||||
axios.post('/addBlog', {
|
||||
// id: this.ruleForm.id,
|
||||
title: this.ruleForm.title,
|
||||
description: this.ruleForm.description,
|
||||
content: this.ruleForm.content,
|
||||
created: new Date()
|
||||
}).then(function (response) {
|
||||
console.log(response.data)
|
||||
//跳转到主页
|
||||
window.location.href = "/"
|
||||
})
|
||||
} else {
|
||||
console.log("error submit!!");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
resetForm(formName) {
|
||||
console.log(formName)
|
||||
this.$refs[formName].resetFields();//Element的一个方法,用于重置表单为初始值。
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
name: "BlogEditView",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
|
||||
.m_content {
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,353 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- 引用导航 -->
|
||||
<Header></Header>
|
||||
<div style="text-align: left;padding-left: 40px; width: 96%;" class="mblog">
|
||||
<br>
|
||||
<h2>{{ blog.title }}</h2>
|
||||
<br>
|
||||
<div>
|
||||
<el-link icon="el-icon-edit">
|
||||
<!--携带博客ID跳转到编辑页面,对博客进行修改-->
|
||||
<router-link :to="{ name: 'BlogEdit', params: { blogId: blog.id } }">
|
||||
编辑
|
||||
</router-link>
|
||||
</el-link>
|
||||
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
|
||||
<el-link type="danger" @click="messageHandel" icon="el-icon-delete">
|
||||
删除
|
||||
</el-link>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
|
||||
<el-button type="text" @click="commentGet()" icon="el-icon-chat-line-round">评论区</el-button>
|
||||
|
||||
<el-drawer title="评论区" :visible.sync="commentVisible" width="30%">
|
||||
<!-- 评论功能 -->
|
||||
<div>
|
||||
<el-form :model="commentForm" status-icon :rules="rules" label-width="80px" ref="commentForm">
|
||||
<el-tag style="font-size: 15px;" v-if="showReply">回复@{{ replyComent.replyName }}
|
||||
<el-button type="text" @click="replyCancel()" icon="el-icon-close"
|
||||
size="medium"></el-button>
|
||||
</el-tag>
|
||||
|
||||
<el-form-item label="评论" prop="content">
|
||||
<el-input type="text" v-model="commentForm.content"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitCommentForm()">评论</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<!-- 评论区展示功能 -->
|
||||
<div v-for="comment in comments" :key="comment.comment_id">
|
||||
<div v-if="!comment.parent_id">
|
||||
<div class="comment-container">
|
||||
<div class="comment-top">
|
||||
<el-avatar class="comment-avatar" shape="circle" size="medium"
|
||||
:src="comment.avatar" />
|
||||
<el-tag class="comment-username" style="font-size: 17px;">{{ comment.username
|
||||
}}</el-tag>
|
||||
<span class="comment-time"> {{ comment.created }}</span>
|
||||
<!-- 回复评论 -->
|
||||
<el-button class="reply-button" type="text" icon="el-icon-chat-line-round"
|
||||
@click="replyVisible(comment)">回复</el-button>
|
||||
</div>
|
||||
<span class="comment-content">" {{ comment.content }} "</span>
|
||||
</div>
|
||||
<el-divider content-position="center">
|
||||
<el-button v-if="isClickId !== comment.comment_id" type="text"
|
||||
@click="viewReplys(comment)">查看回复</el-button>
|
||||
<el-button v-else type="text" @click="viewReplysCollapse(comment)">收起回复</el-button>
|
||||
</el-divider>
|
||||
<!-- 评论回复展示功能 -->
|
||||
<div v-for="commentReply in commentReplys" :key="commentReply.comment_id">
|
||||
<div
|
||||
v-if="(commentReply.parent_id == comment.comment_id) && isClickId === comment.comment_id">
|
||||
<div class="comment-reply">
|
||||
<div class="comment-top">
|
||||
<el-tag class="comment-username" style="font-size: 17px;">{{
|
||||
commentReply.username }} 回复 @{{
|
||||
commentReply.parent_name }}</el-tag>
|
||||
<span class="comment-time"> {{ commentReply.created }}</span>
|
||||
<el-button class="reply-button" type="text" icon="el-icon-chat-line-round"
|
||||
@click="replyCommentVisible(commentReply, comment, comments)">回复</el-button>
|
||||
</div>
|
||||
<span class="comment-content">" {{ commentReply.content }} "</span>
|
||||
<br>
|
||||
<!-- 回复评论 -->
|
||||
<!-- <el-input v-if="showReplyInput()"></el-input> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
|
||||
<el-divider></el-divider>
|
||||
|
||||
<div class="markdown-body" v-html="blog.content"></div>
|
||||
<br>
|
||||
</div>
|
||||
<br>
|
||||
<Footer></Footer>
|
||||
<br>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
//为了让markdown转换的文本更好看,使用这个文件进行渲染
|
||||
import "github-markdown-css/github-markdown.css"
|
||||
import Header from "../components/Header.vue";
|
||||
import Footer from "../components/Footer.vue";
|
||||
|
||||
export default {
|
||||
components: { Header, Footer },
|
||||
beforeRouteEnter(to, from, next) {
|
||||
// 在组件进入之前,将页面滚动到顶部
|
||||
window.scrollTo(0, 0);
|
||||
next();
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
viewReply: false, //查看回复显示
|
||||
showReply: false, //回复评论按钮显示
|
||||
blog: {}, //博客对象
|
||||
username: '', //用户名
|
||||
comments: {}, //评论区
|
||||
commentForm: { //评论表单
|
||||
id: '',
|
||||
username: '',
|
||||
content: '',
|
||||
created: ''
|
||||
},
|
||||
commentVisible: false, //评论区显示
|
||||
replyComent: {
|
||||
comment_id: '',
|
||||
replyName: '',
|
||||
},
|
||||
commentReplys: [],
|
||||
isClickId: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
viewReplys(comment) {
|
||||
this.isClickId = comment.comment_id
|
||||
const commentReplyAdd = []
|
||||
this.comments.forEach((commentReply) => {
|
||||
if ((commentReply.parent_id === comment.comment_id)) {
|
||||
commentReplyAdd.push(commentReply);
|
||||
}
|
||||
});
|
||||
this.commentReplys = commentReplyAdd
|
||||
|
||||
},
|
||||
viewReplysCollapse() {
|
||||
this.isClickId = ''
|
||||
},
|
||||
replyCancel() {
|
||||
//取消回复
|
||||
this.showReply = false
|
||||
this.replyComent.replyName = ''
|
||||
this.replyComent.comment_id = ''
|
||||
|
||||
},
|
||||
replyVisible(comment) {
|
||||
this.replyComent.replyName = comment.username
|
||||
this.replyComent.comment_id = comment.comment_id
|
||||
console.log("replyComent.comment_id" + this.replyComent.comment_id + "replyComent.replyName" + this.replyComent.replyName)
|
||||
this.showReply = true
|
||||
},
|
||||
replyCommentVisible(commentReply, comment) {
|
||||
console.log("comment:" + comment + "commentReply:" + commentReply)
|
||||
this.replyComent.replyName = commentReply.username
|
||||
this.replyComent.comment_id = comment.comment_id
|
||||
this.showReply = true
|
||||
const commentReplyAdd = []
|
||||
this.comments.forEach((commentReply) => {
|
||||
if ((commentReply.parent_id === comment.comment_id)) {
|
||||
commentReplyAdd.push(commentReply);
|
||||
}
|
||||
});
|
||||
this.commentReplys = commentReplyAdd
|
||||
//刷新展
|
||||
},
|
||||
showReplyInput() {
|
||||
if (this.showReply) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
messageHandel() {
|
||||
this.$confirm('此操作将永久删除该博客, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
//删除博客
|
||||
// axios.get('/deleteBlog', {
|
||||
// params: {
|
||||
// blogId: this.blog.id
|
||||
// }
|
||||
// }).then((res) => {
|
||||
// console.log(res.data)
|
||||
// this.$message({
|
||||
// type: 'success',
|
||||
// message: '删除成功!'
|
||||
// });
|
||||
// //跳转到主页
|
||||
// this.$router.push('/')
|
||||
|
||||
// })
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '该功能暂时不对外开发哦!'
|
||||
});
|
||||
}).catch(() => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '已取消删除'
|
||||
});
|
||||
});
|
||||
},
|
||||
commentGet() {
|
||||
this.commentVisible = true
|
||||
//获取评论区
|
||||
axios.get('/getComment', {
|
||||
params: {
|
||||
blogId: this.blog.id
|
||||
}
|
||||
}).then((res) => {
|
||||
console.log(res.data)
|
||||
this.comments = res.data
|
||||
for (let i = 0; i < this.comments.length; i++) {
|
||||
if (this.comments[i].avatar == null) {
|
||||
//如果头像为空,设置默认头像
|
||||
this.comments[i].avatar = 'http://124.71.135.249:8081' + '/images/avatar/default.jpg'
|
||||
} else {
|
||||
this.comments[i].avatar = 'http://124.71.135.249:8081' + this.comments[i].avatar
|
||||
}
|
||||
console.log("this.comments[i].parent_id" + this.comments[i].parent_id + "this.comments[i].username" + this.comments[i].username)
|
||||
}
|
||||
})
|
||||
},
|
||||
submitCommentForm() {
|
||||
//获取当前时间
|
||||
var date = new Date();
|
||||
var year = date.getFullYear();
|
||||
var month = date.getMonth() + 1;
|
||||
var day = date.getDate();
|
||||
var created = year + "-" + month + "-" + day;
|
||||
|
||||
this.commentForm.id = this.blog.id
|
||||
this.commentForm.username = this.username
|
||||
this.commentForm.created = created
|
||||
console.log(this.commentForm)
|
||||
//提交评论
|
||||
axios.post('/addComment', {
|
||||
article_id: this.commentForm.id,
|
||||
parent_id: this.replyComent.comment_id,
|
||||
parent_name: this.replyComent.replyName,
|
||||
content: this.commentForm.content,
|
||||
created: this.commentForm.created
|
||||
}).then((res) => {
|
||||
console.log(res.data)
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '评论成功!'
|
||||
});
|
||||
//刷新评论区
|
||||
this.commentGet()
|
||||
//清空评论框
|
||||
this.commentForm.content = ''
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
|
||||
},
|
||||
created() {
|
||||
const blogId = this.$route.params.blogId
|
||||
const that = this
|
||||
axios.get('/getBlogDetail', {
|
||||
params: {
|
||||
blogId: blogId
|
||||
}
|
||||
}).then((res) => {
|
||||
that.blog = res.data
|
||||
console.log(res.data)
|
||||
|
||||
/**
|
||||
* 将markdown的文本转为正常文本
|
||||
* */
|
||||
//拿到markdown渲染资源对象
|
||||
var markDownIT = require("markdown-it")
|
||||
var md = new markDownIT() //获取到markdown-it的对象
|
||||
var result = md.render(that.blog.content) //将markdown文本渲染成html文本
|
||||
that.blog.content = result //将正常文本赋值给页面显示
|
||||
|
||||
})
|
||||
// this.commentGet(blogId)
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mblog {
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
width: 100%;
|
||||
min-height: 760px;
|
||||
margin: 10px 10px;
|
||||
}
|
||||
|
||||
.comment-container {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.comment-top {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.comment-avatar {
|
||||
margin-right: 10px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.comment-username {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.comment-time {
|
||||
margin-left: 5px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.reply-button {
|
||||
display: none;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.comment-container:hover .reply-button {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.comment-content {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.comment-reply {
|
||||
margin: 20px;
|
||||
padding-left: 20px
|
||||
}
|
||||
|
||||
.comment-reply:hover .reply-button {
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,139 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- 引用导航 -->
|
||||
<Header></Header>
|
||||
<br>
|
||||
<div class="m_content">
|
||||
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
|
||||
<el-form-item label="标题" prop="title">
|
||||
<el-input v-model="ruleForm.title"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="摘要" prop="description">
|
||||
<el-input type="textarea" v-model="ruleForm.description"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="内容" prop="content">
|
||||
<!-- 特殊组件 -->
|
||||
<mavon-editor v-model="ruleForm.content"></mavon-editor>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm('ruleForm')">编辑提交</el-button>
|
||||
<el-button @click="resetForm('ruleForm')">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<br>
|
||||
<Footer></Footer>
|
||||
<br>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import Header from "../components/Header";
|
||||
import Footer from "../components/Footer";
|
||||
|
||||
export default {
|
||||
components: { Header, Footer },
|
||||
beforeRouteEnter(to, from, next) {
|
||||
// 在组件进入之前,将页面滚动到顶部
|
||||
window.scrollTo(0, 0);
|
||||
next();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ruleForm: {
|
||||
id: "",
|
||||
title: "",
|
||||
description: "",
|
||||
content: "",
|
||||
},
|
||||
rules: {
|
||||
title: [
|
||||
{ required: true, message: "请输入标题", trigger: "blur" },
|
||||
{
|
||||
min: 5,
|
||||
max: 100,
|
||||
message: "长度在 5 到 100 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
description: [
|
||||
{ required: true, message: "请输入摘要", trigger: "blur" },
|
||||
],
|
||||
content: [{ required: true, message: "请输入内容", trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
submitForm(formName) {
|
||||
//提交表单
|
||||
// this.$refs[formName].validate((valid) => {
|
||||
// if (valid) {
|
||||
// //提交表单
|
||||
// axios.post('/updateBlog', {
|
||||
// id: this.ruleForm.id,
|
||||
// title: this.ruleForm.title,
|
||||
// description: this.ruleForm.description,
|
||||
// content: this.ruleForm.content,
|
||||
// created: new Date()
|
||||
// }).then(function (response) {
|
||||
// console.log(response.data)
|
||||
// //跳转到主页
|
||||
// window.location.href = "/"
|
||||
// })
|
||||
// } else {
|
||||
// console.log("error submit!!");
|
||||
// return false;
|
||||
// }
|
||||
// });
|
||||
console.log(formName);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '该功能暂时不对外开发哦!'
|
||||
});
|
||||
},
|
||||
resetForm(formName) {
|
||||
console.log(formName)
|
||||
// this.$refs[formName].resetFields();//Element的一个方法,用于重置表单为初始值。
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '该功能暂时不对外开发哦!'
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
//页面渲染前的后置方法
|
||||
created() {
|
||||
//将博客信息回显,作用在进行编辑的时候可以在编辑页面出现用户的信息
|
||||
//用户发送“/blog/{id}/edit”类型的请求才会回显
|
||||
//用户发送“/blog/add”添加博客的请求时,获取不到值
|
||||
const blogId = this.$route.params.blogId
|
||||
const that = this
|
||||
if (blogId !== undefined && blogId !== null && blogId !== '') {
|
||||
console.log(blogId)
|
||||
axios.get('/getBlogDetail', {
|
||||
params: {
|
||||
blogId: blogId
|
||||
}
|
||||
}).then(function (response) {
|
||||
console.log(response.data)
|
||||
that.ruleForm.id = response.data.id
|
||||
that.ruleForm.title = response.data.title
|
||||
that.ruleForm.description = response.data.description
|
||||
that.ruleForm.content = response.data.content
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
name: "BlogEditView",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.m_content {
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,314 @@
|
|||
<template>
|
||||
<div>
|
||||
<HomeHeader></HomeHeader>
|
||||
<br>
|
||||
<div class="container">
|
||||
<!-- 引用导航 -->
|
||||
<el-row>
|
||||
<div class="live2d-container">
|
||||
<el-col :span="1">
|
||||
<live2d style="position: absolute; left: 0; bottom: 0;"
|
||||
:model="['Potion-Maker/Pio', 'school-2017-costume-yellow']" :direction="direction" :size="size">
|
||||
</live2d>
|
||||
</el-col>
|
||||
</div>
|
||||
<el-col :span="23">
|
||||
<el-card :body-style="{ padding: '0px' }" v-for="blog in pagedBlogs" style="margin-bottom: 20px;"
|
||||
:key="blog.id">
|
||||
<el-col :span="12">
|
||||
<router-link :to="{ name: 'BlogDetail', params: { blogId: blog.id } }">
|
||||
<img :src="blog.imageUrl" class="pulse animated image" />
|
||||
</router-link>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<!-- 路由跳转 -->
|
||||
<br>
|
||||
<router-link :to="{ name: 'BlogDetail', params: { blogId: blog.id } }">
|
||||
<h4 style="font-size: 20px">{{ blog.title }} </h4>
|
||||
</router-link>
|
||||
<el-divider></el-divider>
|
||||
<div class="bottom">
|
||||
<p>{{ blog.description }}</p>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-pagination background layout="prev, pager, next" :total="total" :page-size="pageSize"
|
||||
:current-page="currentPage" hide-on-single-page="true" @current-change="handleCurrentChange">
|
||||
</el-pagination>
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<Footer></Footer>
|
||||
<br>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import HomeHeader from "../components/HomeHeader";
|
||||
import Footer from "../components/Footer";
|
||||
// 在组件中引入
|
||||
import live2d from 'vue-live2d'
|
||||
import { startSakura } from "../js/Sakura"
|
||||
export default {
|
||||
components: {
|
||||
HomeHeader,
|
||||
Footer,
|
||||
live2d
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
// 在组件进入之前,将页面滚动到顶部
|
||||
window.scrollTo(0, 0);
|
||||
next();
|
||||
},
|
||||
created() {
|
||||
this.getBlogs();
|
||||
},
|
||||
mounted() {
|
||||
this.show();
|
||||
this.note();
|
||||
startSakura()
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
// 清理操作,例如重置数据或取消订阅
|
||||
// 在离开该页面时执行
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
data() {
|
||||
|
||||
return {
|
||||
blogs: {},
|
||||
currentPage: 1, //当前页
|
||||
total: 0, //总共多少页
|
||||
pageSize: 3, //每一页的数据个数
|
||||
pagedBlogs: [],
|
||||
imageUrls: [
|
||||
require("../assets/gundam1.png"),
|
||||
require("../assets/gundam2.png"),
|
||||
require("../assets/gundam3.png"),
|
||||
require("../assets/gundam4.png"),
|
||||
require("../assets/gundam5.png"),
|
||||
require("../assets/gundam6.png"),
|
||||
require("../assets/gundam7.png"),
|
||||
require("../assets/gundam8.png"),
|
||||
],
|
||||
direction: 'right',
|
||||
width: 500,
|
||||
height: 500,
|
||||
size: 350,
|
||||
tips: {
|
||||
mouseover: [{
|
||||
selector: '.vue-live2d',
|
||||
texts: ['这样可以修改默认语句']
|
||||
}]
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getBlogs() {
|
||||
const that = this;
|
||||
axios.get("/getBlogs").then((response) => {
|
||||
that.blogs = response.data;
|
||||
for (let index in that.blogs) {
|
||||
that.blogs[index].imageUrl = this.imageUrls[index % 8];
|
||||
console.log(that.blogs[index].imageUrl);
|
||||
}
|
||||
that.total = that.blogs.length; //总博客数
|
||||
that.handleCurrentChange(that.currentPage); //初始化当前页
|
||||
});
|
||||
},
|
||||
handleCurrentChange(page) {
|
||||
const startIndex = (page - 1) * this.pageSize; //当前页的起始索引
|
||||
const endIndex = startIndex + this.pageSize; //当前页的结束索引
|
||||
this.pagedBlogs = this.blogs.slice(startIndex, endIndex); //通过分割获取当前页的数据
|
||||
|
||||
|
||||
},
|
||||
|
||||
show() {
|
||||
!function () {
|
||||
function n(n, e, t) {
|
||||
return n.getAttribute(e) || t
|
||||
}
|
||||
|
||||
function e(n) {
|
||||
return document.getElementsByTagName(n)
|
||||
}
|
||||
|
||||
function t() {
|
||||
var t = e("script"), o = t.length, i = t[o - 1];
|
||||
return { l: o, z: n(i, "zIndex", -1), o: n(i, "opacity", .5), c: n(i, "color", "0,0,0"), n: n(i, "count", 99) }
|
||||
}
|
||||
|
||||
function o() {
|
||||
a = m.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, c = m.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
|
||||
}
|
||||
|
||||
function i() {
|
||||
r.clearRect(0, 0, a, c);
|
||||
var n, e, t, o, m, l;
|
||||
s.forEach(function (i, x) {
|
||||
for (i.x += i.xa, i.y += i.ya, i.xa *= i.x > a || i.x < 0 ? -1 : 1, i.ya *= i.y > c || i.y < 0 ? -1 : 1, r.fillRect(i.x - .5, i.y - .5, 1, 1), e = x + 1; e < u.length; e++) n = u[e], null !== n.x && null !== n.y && (o = i.x - n.x, m = i.y - n.y, l = o * o + m * m, l < n.max && (n === y && l >= n.max / 2 && (i.x -= .03 * o, i.y -= .03 * m), t = (n.max - l) / n.max, r.beginPath(), r.lineWidth = t / 2, r.strokeStyle = "rgba(" + d.c + "," + (t + .2) + ")", r.moveTo(i.x, i.y), r.lineTo(n.x, n.y), r.stroke()))
|
||||
}), x(i)
|
||||
}
|
||||
|
||||
var a, c, u, m = document.createElement("canvas"), d = t(), l = "c_n" + d.l, r = m.getContext("2d"),
|
||||
x = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (n) {
|
||||
window.setTimeout(n, 1e3 / 45)
|
||||
}, w = Math.random, y = { x: null, y: null, max: 2e4 };
|
||||
m.id = l, m.style.cssText = "position:fixed;top:0;left:0;z-index:" + d.z + ";opacity:" + d.o, e("body")[0].appendChild(m), o(), window.onresize = o, window.onmousemove = function (n) {
|
||||
n = n || window.event, y.x = n.clientX, y.y = n.clientY
|
||||
}, window.onmouseout = function () {
|
||||
y.x = null, y.y = null
|
||||
};
|
||||
for (var s = [], f = 0; d.n > f; f++) {
|
||||
var h = w() * a, g = w() * c, v = 2 * w() - 1, p = 2 * w() - 1;
|
||||
s.push({ x: h, y: g, xa: v, ya: p, max: 6e3 })
|
||||
}
|
||||
u = s.concat([y]), setTimeout(function () {
|
||||
i()
|
||||
}, 100)
|
||||
}();
|
||||
},
|
||||
note() {
|
||||
(function () {
|
||||
var a_idx = 0;
|
||||
window.onclick = function (event) {
|
||||
var A = new Array("富强", "民主", "文明", "和谐", "自由", "平等", "公正", "法治", "爱国", "敬业", "诚信", "友善");
|
||||
|
||||
var heart = document.createElement("b"); //创建b元素
|
||||
heart.onselectstart = new Function('event.returnValue=false'); //防止拖动
|
||||
|
||||
document.body.appendChild(heart).innerHTML = A[a_idx]; //将b元素添加到页面上
|
||||
a_idx = (a_idx + 1) % A.length;
|
||||
heart.style.cssText = "position: fixed;left:-100%;"; //给p元素设置样式
|
||||
|
||||
var f = 16, // 字体大小
|
||||
x = event.clientX - f / 2, // 横坐标
|
||||
y = event.clientY - f, // 纵坐标
|
||||
c = randomColor(), // 随机颜色
|
||||
a = 1, // 透明度
|
||||
s = 1.2; // 放大缩小
|
||||
|
||||
var timer = setInterval(function () { //添加定时器
|
||||
if (a <= 0) {
|
||||
document.body.removeChild(heart);
|
||||
clearInterval(timer);
|
||||
} else {
|
||||
heart.style.cssText = "font-size:16px;cursor: default;position: fixed;color:" +
|
||||
c + ";left:" + x + "px;top:" + y + "px;opacity:" + a + ";transform:scale(" +
|
||||
s + ");";
|
||||
|
||||
y--;
|
||||
a -= 0.016;
|
||||
s += 0.002;
|
||||
}
|
||||
}, 15)
|
||||
|
||||
}
|
||||
// 随机颜色
|
||||
function randomColor() {
|
||||
|
||||
return "rgb(" + (~~(Math.random() * 255)) + "," + (~~(Math.random() * 255)) + "," + (~~(Math
|
||||
.random() * 255)) + ")";
|
||||
|
||||
}
|
||||
}());
|
||||
},
|
||||
},
|
||||
name: "BlogTestView",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/*base code*/
|
||||
.animated {
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.animated.infinite {
|
||||
-webkit-animation-iteration-count: infinite;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.animated.hinge {
|
||||
-webkit-animation-duration: 2s;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
/*the animation definition*/
|
||||
@-webkit-keyframes pulse {
|
||||
0% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
}
|
||||
|
||||
50% {
|
||||
-webkit-transform: scale3d(1.05, 1.05, 1.05);
|
||||
transform: scale3d(1.05, 1.05, 1.05)
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
-ms-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
}
|
||||
|
||||
50% {
|
||||
-webkit-transform: scale3d(1.05, 1.05, 1.05);
|
||||
-ms-transform: scale3d(1.05, 1.05, 1.05);
|
||||
transform: scale3d(1.05, 1.05, 1.05)
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
-ms-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
}
|
||||
}
|
||||
|
||||
.pulse:hover {
|
||||
-webkit-animation-name: pulse;
|
||||
animation-name: pulse
|
||||
}
|
||||
|
||||
.live2d-container {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.container {
|
||||
/* 居中显示 */
|
||||
margin: 0 auto;
|
||||
width: 60%;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.image {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,108 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- 引用导航 -->
|
||||
<TimeHeader></TimeHeader>
|
||||
<br>
|
||||
<div>
|
||||
<div class="live2d-container">
|
||||
<el-col :span="1">
|
||||
<live2d style="position: absolute; left: 0; bottom: 0;"
|
||||
:model="['Potion-Maker/Pio', 'school-2017-costume-yellow']" :direction="direction" :size="size">
|
||||
</live2d>
|
||||
</el-col>
|
||||
</div>
|
||||
<div class="block" style="width: 60%; margin: 0 auto">
|
||||
<el-timeline style="text-align: left" :reverse="false">
|
||||
<eltimeline-item :timestamp="new Date()" placement="bottom">
|
||||
<el-card>
|
||||
<h style="font-size: 15px">目前共计{{ total }}篇文章,继续加油</h>
|
||||
</el-card>
|
||||
</eltimeline-item>
|
||||
<br>
|
||||
<el-timeline-item :timestamp="new Date(blog.created)" placement="top" v-for="blog in pagedBlogs"
|
||||
:key="blog.title">
|
||||
<el-card>
|
||||
<!-- 路由跳转 -->
|
||||
<router-link :to="{ name: 'BlogDetail', params: { blogId: blog.id } }">
|
||||
<h4 style="font-size: 20px">{{ blog.title }}</h4>
|
||||
</router-link>
|
||||
<p>{{ blog.description }}</p>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
|
||||
<el-pagination background layout="prev, pager, next" :total="total" :page-size="pageSize"
|
||||
:current-page="currentPage" hide-on-single-page="true" @current-change="handleCurrentChange">
|
||||
</el-pagination>
|
||||
</div>
|
||||
<br>
|
||||
<Footer></Footer>
|
||||
<br>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import TimeHeader from "../components/TimeHeader.vue";
|
||||
import Footer from "../components/Footer.vue";
|
||||
import live2d from 'vue-live2d'
|
||||
|
||||
|
||||
export default {
|
||||
components: { TimeHeader, Footer, live2d },
|
||||
beforeRouteEnter(to, from, next) {
|
||||
// 在组件进入之前,将页面滚动到顶部
|
||||
window.scrollTo(0, 0);
|
||||
next();
|
||||
},
|
||||
created() {
|
||||
this.getBlogs();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
blogs: {},
|
||||
currentPage: 1, //当前页
|
||||
total: 0, //总共多少页
|
||||
pageSize: 5, //每一页的数据个数
|
||||
pagedBlogs: [],
|
||||
direction: 'right',
|
||||
width: 500,
|
||||
height: 500,
|
||||
size: 350,
|
||||
tips: {
|
||||
mouseover: [{
|
||||
selector: '.vue-live2d',
|
||||
texts: ['这样可以修改默认语句']
|
||||
}]
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
getBlogs() {
|
||||
const that = this;
|
||||
axios.get("/getBlogs").then((response) => {
|
||||
that.blogs = response.data;
|
||||
that.total = that.blogs.length; //总博客数
|
||||
that.handleCurrentChange(that.currentPage); //初始化当前页
|
||||
});
|
||||
},
|
||||
handleCurrentChange(page) {
|
||||
const startIndex = (page - 1) * this.pageSize; //当前页的起始索引
|
||||
const endIndex = startIndex + this.pageSize; //当前页的结束索引
|
||||
this.pagedBlogs = this.blogs.slice(startIndex, endIndex); //通过分割获取当前页的数据
|
||||
},
|
||||
},
|
||||
name: "BlogHomeView",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.live2d-container {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
}
|
||||
</style>
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="home">
|
||||
<img alt="Vue logo" src="../assets/logo.png">
|
||||
<HelloWorld msg="Welcome to Your Vue.js App"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// @ is an alias to /src
|
||||
import HelloWorld from '@/components/HelloWorld.vue'
|
||||
|
||||
export default {
|
||||
name: 'HomeView',
|
||||
components: {
|
||||
HelloWorld
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,239 @@
|
|||
<template>
|
||||
<!-- <div class="container">
|
||||
<div class="login"> -->
|
||||
<div class="body">
|
||||
<el-card class="box-card transparent-card">
|
||||
<div>
|
||||
<span>个人博客(正在开发)</span>
|
||||
</div>
|
||||
<div>
|
||||
<el-tabs stretch>
|
||||
<el-tab-pane label="登陆">
|
||||
<el-form :model="loginForm" status-icon :rules="rules" label-width="80px" ref="loginForm">
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input type="text" v-model="loginForm.username"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input type="password" v-model="loginForm.password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button style="margin-right: 50px;" type="primary"
|
||||
@click="submitLoginForm()">登陆</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="注册">
|
||||
<el-form :model="registerForm" status-icon :rules="rules" label-width="80px">
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input type="text" v-model="registerForm.username"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input type="password" v-model="registerForm.password"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="确认密码" prop="configurePassword">
|
||||
<el-input type="password" v-model="registerForm.configurePassword"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button style="margin-right: 50px;" type="primary"
|
||||
@click="submitRegisterForm()">注册</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</el-card>
|
||||
<div class="stars" ref="starsRef">
|
||||
<div class="star" v-for="(item, index) in starsCount" :key="index"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import { mapMutations } from 'vuex';//引入vuex下的方法
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
let starsRef = ref(null);
|
||||
|
||||
const starsCount = 2000; //星星数量
|
||||
const distance = 900; //间距
|
||||
|
||||
onMounted(() => {
|
||||
let starNodes = Array.from(starsRef.value.children);
|
||||
starNodes.forEach((item) => {
|
||||
let speed = 0.2 + Math.random() * 1;
|
||||
let thisDistance = distance + Math.random() * 300;
|
||||
item.style.transformOrigin = `0 0 ${thisDistance}px`;
|
||||
item.style.transform = `
|
||||
translate3d(0,0,-${thisDistance}px)
|
||||
rotateY(${Math.random() * 360}deg)
|
||||
rotateX(${Math.random() * -50}deg)
|
||||
scale(${speed},${speed})`;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
starsRef,
|
||||
starsCount,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
//自定义表单校准规则
|
||||
var validateUsername = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入用户名"));
|
||||
} else if (value.length < 3) {
|
||||
callback(new Error("长度不够"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
var validateConfigurePassword = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请再次输入密码'));
|
||||
} else if (value !== this.registerForm.password) {
|
||||
callback(new Error('两次输入密码不一致!'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
loginForm: {
|
||||
username: "",
|
||||
password: "",
|
||||
},
|
||||
registerForm: {
|
||||
username: "",
|
||||
password: "",
|
||||
configurePassword: "",
|
||||
},
|
||||
rules: {
|
||||
username: [
|
||||
{ validator: validateUsername, trigger: 'blur' }, //trigger: 'blur'失去焦点时触发
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||
],
|
||||
configurePassword: [
|
||||
{ validator: validateConfigurePassword, trigger: 'blur' },
|
||||
]
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
//映射mapMutations 辅助函数映射 Vuex mutations
|
||||
// - 让组件可以直接调用 Vuex 中的 mutations 方法
|
||||
...mapMutations(['setToken']),
|
||||
...mapMutations(['delToken']),
|
||||
|
||||
|
||||
submitLoginForm() {
|
||||
const that = this
|
||||
axios.post("/login", {
|
||||
username: this.loginForm.username,
|
||||
password: this.loginForm.password
|
||||
}).then(res => {
|
||||
var jsonObject = res.data;
|
||||
var jsonString = JSON.stringify(jsonObject)
|
||||
if (jsonString !== "false") {
|
||||
window.localStorage.setItem("token", jsonString);
|
||||
that.setToken({ token: jsonString })
|
||||
this.$router.push({ path: "/" })
|
||||
this.$message.success("登陆成功!")
|
||||
} else {
|
||||
alert("账号或密码错误!")
|
||||
}
|
||||
})
|
||||
},
|
||||
submitRegisterForm() {
|
||||
axios.post("/register", {
|
||||
username: this.registerForm.username,
|
||||
password: this.registerForm.password,
|
||||
}).then(res => {
|
||||
if (res.data === "注册成功") {
|
||||
this.$message.success(res.data)
|
||||
} else {
|
||||
this.$message.error(res.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
//删除token
|
||||
created() {
|
||||
const that = this
|
||||
that.delToken({ token: "123" })
|
||||
},
|
||||
|
||||
name: "LoginView",
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.body {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: radial-gradient(200% 100% at bottom center,
|
||||
#f7f7b6,
|
||||
#e96f92,
|
||||
#1b2947);
|
||||
background: radial-gradient(200% 105% at top center,
|
||||
#1b2947 10%,
|
||||
#75517d 40%,
|
||||
#e96f92 65%,
|
||||
#f7f7b6);
|
||||
background-attachment: fixed;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
0% {
|
||||
transform: perspective(400px) rotateZ(20deg) rotateX(-40deg) rotateY(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: perspective(400px) rotateZ(20deg) rotateX(-40deg) rotateY(-360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.stars {
|
||||
transform: perspective(500px);
|
||||
transform-style: preserve-3d;
|
||||
position: absolute;
|
||||
perspective-origin: 50% 100%;
|
||||
left: 45%;
|
||||
animation: rotate 90s infinite linear;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.star {
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
background: #f7f7b6;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
.box-card {
|
||||
width: 500px;
|
||||
margin: 0 auto;
|
||||
transform: translateY(150px);
|
||||
}
|
||||
|
||||
.transparent-card {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,26 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- //移动端未开发,请移步PC端 -->
|
||||
<p>移动端未开发,请移步PC端</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
p{
|
||||
text-align: center;
|
||||
margin-top: 100px;
|
||||
font-family: "Montserrat", sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 30px;
|
||||
color: #03dac6;
|
||||
transition: all 0.3s ease;
|
||||
text-shadow: 5px 5px 10px black;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,126 @@
|
|||
<!-- <template>
|
||||
<div id="imgwrap">
|
||||
<img src="../assets/gundam1.png" alt="" />
|
||||
<img src="../assets/gundam2.png" alt="" />
|
||||
<img src="../assets/gundam3.png" alt="" />
|
||||
<img src="../assets/gundam4.png" alt="" />
|
||||
<img src="../assets/gundam5.png" alt="" />
|
||||
<img src="../assets/gundam6.png" alt="" />
|
||||
<img src="../assets/gundam7.png" alt="" />
|
||||
<img src="../assets/gundam8.png" alt="" />
|
||||
<img src="../assets/gundam1.png alt="" />
|
||||
<img src="../assets/gundam1.png" alt="" />
|
||||
<img src="../assets/gundam1.png" alt="" />
|
||||
<img src="../assets/gundam1.png" alt="" />
|
||||
<img src="../assets/gundam1.png" alt="" />
|
||||
<img src="../assets/gundam1.png" alt="" />
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="Act()">开始</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
allEnd: 0, //用来判断所有的图片是否都运动完了
|
||||
on: true, //用来判断是否可以点击
|
||||
imgs: document.querySelectorAll('#imgwrap img')
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
Act() {
|
||||
var endNum = 0; //运动完成的图片数量
|
||||
var on = false; //用来判断是否可以点击
|
||||
if (!on) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
(function (i) {
|
||||
setTimeout(function () {
|
||||
montion(imgs[i], '10ms', function () {
|
||||
this.style.transform = "scale(0)"; //缩放到0
|
||||
}, function () {
|
||||
//第二个运动要在这里写
|
||||
montion(this, '1s', function () {
|
||||
this.style.transform = "scale(1)";
|
||||
this.style.opacity = 0;
|
||||
}, function () {
|
||||
endNum++; //只要有一张图走完了,就让他加个1
|
||||
if (endNum == imgs.length) {
|
||||
toBig();
|
||||
}
|
||||
});
|
||||
});
|
||||
}, Math.random() * 1000); //500毫秒
|
||||
})(i)
|
||||
}
|
||||
},
|
||||
toBig() {
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
imgs[i].style.transition = "";
|
||||
//想要一个物体有css3中的一些变化,那就需要给他一个初始值
|
||||
imgs[i].style.transform = 'rotateY(0deg)translateZ(-' + Math.random() * 500 + 'px)';
|
||||
//用这种方式去写是因为想要在循环里找i的值
|
||||
(function (i) {
|
||||
setTimeout(function () {
|
||||
montion(imgs[i], '2s', function () {
|
||||
this.style.opacity = 1;
|
||||
this.style.transform = 'rotateY(-360deg) translateZ(0)';
|
||||
}, function () {
|
||||
allEnd++;
|
||||
if (allEnd == imgs.length) {
|
||||
//这个条件成立,说明所有图片都运动完了,可以让用户再次点击了
|
||||
on = true; //当所有运动完了以后才可以点
|
||||
}
|
||||
});
|
||||
}, Math.random() * 1000);
|
||||
})(i);
|
||||
}
|
||||
},
|
||||
montion(obj, time, doFn, callBack) {
|
||||
obj.style.transition = time;
|
||||
doFn.call(obj); //调用函数,并把this的指向给obj
|
||||
var called = false; //解决transitionend调用多次的bug
|
||||
obj.addEventListener('transitionend', function () {
|
||||
if (!called) {
|
||||
callBack && callBack.call(obj);
|
||||
called = true;
|
||||
}
|
||||
}, false);
|
||||
},
|
||||
|
||||
name: "ProjectWallView"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style type="text/css">
|
||||
#imgwrap {
|
||||
width: 1480px;
|
||||
height: 440px;
|
||||
margin: 50px auto;
|
||||
perspective: 880px;
|
||||
}
|
||||
|
||||
#imgwrap img {
|
||||
width: 358px;
|
||||
height: 188px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#btn {
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
font: 16px/40px "微软雅黑";
|
||||
color: white;
|
||||
padding: 0 20px;
|
||||
margin: 0 auto;
|
||||
border-radius: 5px;
|
||||
background: rgb(0, 100, 0);
|
||||
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
</style> -->
|
|
@ -2,3 +2,14 @@ const { defineConfig } = require('@vue/cli-service')
|
|||
module.exports = defineConfig({
|
||||
transpileDependencies: true
|
||||
})
|
||||
module.exports = {
|
||||
pwa: {
|
||||
iconPaths: {
|
||||
favicon32: 'favicon.ico',
|
||||
favicon16: 'favicon.ico',
|
||||
appleTouchIcon: 'favicon.ico',
|
||||
maskIcon: 'favicon.ico',
|
||||
msTileImage: 'favicon.ico'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|