1. <template>
    2. <div>
    3. <!-- banner -->
    4. <div class="home-banner">
    5. <div class="banner-container">
    6. <!-- 联系方式 -->
    7. <h1 class="blog-title animated zoomIn">
    8. 星之卡比
    9. </h1>
    10. <!-- 一言 -->
    11. <div class="blog-intro">
    12. {{ obj.output }} <span class="typed-cursor">|</span>
    13. </div>
    14. <!-- 联系方式 -->
    15. <div class="blog-contact">
    16. <a
    17. class="iconfont iconqq"
    18. target="_blank"
    19. href="http://wpa.qq.com/msgrd?v=3&uin=1192176811&site=qq&menu=yes"
    20. />
    21. <a
    22. target="_blank"
    23. href="https://github.com/X1192176811"
    24. class="ml-5 mr-5 iconfont icongithub"
    25. />
    26. <a
    27. target="_blank"
    28. href="https://gitee.com/feng_meiyu"
    29. class="iconfont icongitee-fill-round"
    30. />
    31. </div>
    32. </div>
    33. <!-- 向下滚动 -->
    34. <div class="scroll-down" @click="scrollDown">
    35. <v-icon color="#fff" class="scroll-down-effects">
    36. mdi-chevron-down
    37. </v-icon>
    38. </div>
    39. </div>
    40. <!-- 主页文章 -->
    41. <v-row class="home-container">
    42. <v-col md="9" cols="12">
    43. <v-card
    44. class="animated zoomIn article-card"
    45. style="border-radius: 12px 8px 8px 12px"
    46. v-for="(item, index) of articleList"
    47. :key="item.id"
    48. >
    49. <!-- 文章封面图 -->
    50. <div :class="isRight(index)">
    51. <router-link :to="'/articles/' + item.id">
    52. <v-img
    53. class="on-hover"
    54. width="100%"
    55. height="100%"
    56. :src="item.articleCover"
    57. />
    58. </router-link>
    59. </div>
    60. <!-- 文章信息 -->
    61. <div class="article-wrapper">
    62. <div style="line-height:1.4">
    63. <router-link :to="'/articles/' + item.id">
    64. {{ item.articleTitle }}
    65. </router-link>
    66. </div>
    67. <div class="article-info">
    68. <!-- 是否置顶 -->
    69. <span v-if="item.isTop == 1">
    70. <span style="color:#ff7242">
    71. <i class="iconfont iconzhiding" /> 置顶
    72. </span>
    73. <span class="separator">|</span>
    74. </span>
    75. <!-- 发表时间 -->
    76. <v-icon size="14">mdi-calendar-month-outline</v-icon>
    77. {{ item.createTime | date }}
    78. <span class="separator">|</span>
    79. <!-- 文章分类 -->
    80. <router-link :to="'/categories/' + item.categoryId">
    81. <v-icon size="14">mdi-inbox-full</v-icon>
    82. {{ item.categoryName }}
    83. </router-link>
    84. <span class="separator">|</span>
    85. <!-- 文章标签 -->
    86. <router-link
    87. style="display:inline-block"
    88. :to="'/tags/' + tag.id"
    89. class="mr-1"
    90. v-for="tag of item.tagDTOList"
    91. :key="tag.id"
    92. >
    93. <v-icon size="14">mdi-tag-multiple</v-icon>{{ tag.tagName }}
    94. </router-link>
    95. </div>
    96. <!-- 文章内容 -->
    97. <div class="article-content">
    98. {{ item.articleContent }}
    99. </div>
    100. </div>
    101. </v-card>
    102. <!-- 无限加载 -->
    103. <infinite-loading >
    104. <div slot="no-more" />
    105. </infinite-loading>
    106. </v-col>
    107. <!-- 博主信息 -->
    108. <v-col md="3" cols="12" class="d-md-block d-none">
    109. <div class="blog-wrapper">
    110. <v-card class="animated zoomIn blog-card mt-5">
    111. <div class="author-wrapper">
    112. <!-- 博主头像 -->
    113. <v-avatar size="110">
    114. <img class="author-avatar" :src="blogInfo.avatar" />
    115. </v-avatar>
    116. <div style="font-size: 1.375rem">{{ blogInfo.nickname }}</div>
    117. <div style="font-size: 0.875rem;">{{ blogInfo.intro }}</div>
    118. </div>
    119. <!-- 博客信息 -->
    120. <div class="blog-info-wrapper">
    121. <div class="blog-info-data">
    122. <router-link to="/archives">
    123. <div style="font-size: 0.875rem">文章</div>
    124. <div style="font-size: 1.25rem">
    125. {{ blogInfo.articleCount }}
    126. </div>
    127. </router-link>
    128. </div>
    129. <div class="blog-info-data">
    130. <router-link to="/categories">
    131. <div style="font-size: 0.875rem">分类</div>
    132. <div style="font-size: 1.25rem">
    133. {{ blogInfo.categoryCount }}
    134. </div>
    135. </router-link>
    136. </div>
    137. <div class="blog-info-data">
    138. <router-link to="/tags">
    139. <div style="font-size: 0.875rem">标签</div>
    140. <div style="font-size: 1.25rem">{{ blogInfo.tagCount }}</div>
    141. </router-link>
    142. </div>
    143. </div>
    144. <!-- 收藏按钮 -->
    145. <a class="collection-btn" @click="tip = true">
    146. <v-icon color="#fff" size="18" class="mr-1">mdi-bookmark</v-icon>
    147. 加入书签
    148. </a>
    149. <div class="card-info-social">
    150. <a
    151. class="iconfont iconqq"
    152. target="_blank"
    153. href="http://wpa.qq.com/msgrd?v=3&uin=1192176811&site=qq&menu=yes"
    154. />
    155. <a
    156. target="_blank"
    157. href="https://github.com/X1192176811"
    158. class="ml-5 mr-5 iconfont icongithub"
    159. />
    160. <a
    161. target="_blank"
    162. href="https://gitee.com/feng_meiyu"
    163. class="iconfont icongitee-fill-round"
    164. />
    165. </div>
    166. </v-card>
    167. <!-- 网站信息 -->
    168. <v-card class="blog-card animated zoomIn mt-5 big">
    169. <div class="web-info-title">
    170. <v-icon size="18">mdi-bell</v-icon>
    171. 公告
    172. </div>
    173. <div style="font-size:0.875rem">
    174. {{ blogInfo.notice }}
    175. </div>
    176. </v-card>
    177. <!-- 网站信息 -->
    178. <v-card class="blog-card animated zoomIn mt-5">
    179. <div class="web-info-title">
    180. <v-icon size="18">mdi-chart-line</v-icon>
    181. 网站资讯
    182. </div>
    183. <div class="web-info">
    184. <div style="padding:4px 0 0">
    185. 运行时间:<span class="float-right">{{ time }}</span>
    186. </div>
    187. <div style="padding:4px 0 0">
    188. 总访问量:<span class="float-right">
    189. {{ blogInfo.viewsCount }}
    190. </span>
    191. </div>
    192. </div>
    193. </v-card>
    194. </div>
    195. </v-col>
    196. </v-row>
    197. <!-- 提示消息 -->
    198. <v-snackbar v-model="tip" top color="#49b1f5" :timeout="2000">
    199. 按CTRL+D 键将本页加入书签
    200. </v-snackbar>
    201. </div>
    202. </template>
    203. <script>
    204. import EasyTyper from "easy-typer-js";
    205. export default {
    206. created() {
    207. this.init();
    208. // this.getBlogInfo();
    209. this.timer = setInterval(this.runTime, 1000);
    210. },
    211. data: function() {
    212. return {
    213. tip: false,
    214. time: "",
    215. obj: {
    216. output: "",
    217. isEnd: false,
    218. speed: 300,
    219. singleBack: false,
    220. sleep: 0,
    221. type: "rollback",
    222. backSpeed: 40,
    223. sentencePause: true
    224. },
    225. articleList: [],
    226. blogInfo: {},
    227. current: 1
    228. };
    229. },
    230. methods: {
    231. // 初始化
    232. init() {
    233. document.title = this.$route.meta.title;
    234. // 一言Api进行打字机循环输出效果
    235. fetch("https://v1.hitokoto.cn?c=i")
    236. .then(res => {
    237. return res.json();
    238. })
    239. .then(({ hitokoto }) => {
    240. this.initTyped(hitokoto);
    241. });
    242. },
    243. initTyped(input, fn, hooks) {
    244. const obj = this.obj;
    245. // eslint-disable-next-line no-unused-vars
    246. const typed = new EasyTyper(obj, input, fn, hooks);
    247. },
    248. scrollDown() {
    249. window.scrollTo({
    250. behavior: "smooth",
    251. top: document.documentElement.clientHeight
    252. });
    253. },
    254. runTime() {
    255. var timeold =
    256. new Date().getTime() - new Date("December 12,2019").getTime();
    257. var msPerDay = 24 * 60 * 60 * 1000;
    258. var daysold = Math.floor(timeold / msPerDay);
    259. var str = "";
    260. var day = new Date();
    261. str += daysold + "天";
    262. str += day.getHours() + "时";
    263. str += day.getMinutes() + "分";
    264. str += day.getSeconds() + "秒";
    265. this.time = str;
    266. },
    267. // getBlogInfo() {
    268. // this.axios.get("/api/").then(({ data }) => {
    269. // this.blogInfo = data.data;
    270. // this.$store.commit("checkBlogInfo", data.data);
    271. // });
    272. // },
    273. // infiniteHandler($state) {
    274. // let md = require("markdown-it")();
    275. // this.axios
    276. // .get("/api/articles", {
    277. // params: {
    278. // current: this.current
    279. // }
    280. // })
    281. // .then(({ data }) => {
    282. // if (data.data.length) {
    283. // // 去除markdown标签
    284. // data.data.forEach(item => {
    285. // item.articleContent = md
    286. // .render(item.articleContent)
    287. // .replace(/<\/?[^>]*>/g, "")
    288. // .replace(/[|]*\n/, "")
    289. // .replace(/&npsp;/gi, "");
    290. // });
    291. // this.articleList.push(...data.data);
    292. // this.current++;
    293. // $state.loaded();
    294. // } else {
    295. // $state.complete();
    296. // }
    297. // });
    298. // }
    299. },
    300. computed: {
    301. isRight() {
    302. return function(index) {
    303. if (index % 2 == 0) {
    304. return "article-cover left-radius";
    305. }
    306. return "article-cover right-radius";
    307. };
    308. }
    309. }
    310. };
    311. </script>
    312. <style lang="stylus">
    313. .typed-cursor
    314. opacity: 1
    315. animation: blink 0.7s infinite
    316. @keyframes blink
    317. 0%
    318. opacity: 1
    319. 50%
    320. opacity: 0
    321. 100%
    322. opacity: 1
    323. </style>
    324. <style scoped>
    325. .home-banner {
    326. position: absolute;
    327. top: -60px;
    328. left: 0;
    329. right: 0;
    330. height: 100vh;
    331. background: url("../../assets/img/bg.png")
    332. center center / cover no-repeat;
    333. background-color: #49b1f5;
    334. background-attachment: fixed;
    335. text-align: center;
    336. color: #fff !important;
    337. animation: header-effect 1s;
    338. }
    339. .banner-container {
    340. margin-top: 43vh;
    341. line-height: 1.5;
    342. color: #eee;
    343. }
    344. .blog-contact a {
    345. color: #fff !important;
    346. }
    347. .card-info-social {
    348. line-height: 40px;
    349. text-align: center;
    350. font-size: 1.5rem;
    351. margin: 6px 0 -6px;
    352. }
    353. .left-radius {
    354. border-radius: 8px 0 0 8px !important;
    355. order: 0;
    356. }
    357. .right-radius {
    358. border-radius: 0 8px 8px 0 !important;
    359. order: 1;
    360. }
    361. .article-wrapper {
    362. font-size: 14px;
    363. }
    364. @media (min-width: 760px) {
    365. .blog-title {
    366. font-size: 2.5rem;
    367. }
    368. .blog-intro {
    369. font-size: 1.5rem;
    370. }
    371. .blog-contact {
    372. display: none;
    373. }
    374. .home-container {
    375. max-width: 1200px;
    376. margin: calc(100vh - 48px) auto 28px auto;
    377. padding: 0 5px;
    378. }
    379. .article-card {
    380. display: flex;
    381. align-items: center;
    382. height: 280px;
    383. width: 100%;
    384. margin-top: 20px;
    385. }
    386. .article-cover {
    387. overflow: hidden;
    388. height: 100%;
    389. width: 45%;
    390. }
    391. .on-hover {
    392. transition: all 0.6s;
    393. }
    394. .article-card:hover .on-hover {
    395. transform: scale(1.1);
    396. }
    397. .article-wrapper {
    398. padding: 0 2.5rem;
    399. width: 55%;
    400. }
    401. .article-wrapper a {
    402. font-size: 1.5rem;
    403. transition: all 0.3s;
    404. }
    405. }
    406. @media (max-width: 759px) {
    407. .blog-title {
    408. font-size: 26px;
    409. }
    410. .blog-contact {
    411. font-size: 1.25rem;
    412. line-height: 2;
    413. }
    414. .home-container {
    415. width: 100%;
    416. margin: calc(100vh - 66px) auto 0 auto;
    417. }
    418. .article-card {
    419. margin-top: 1rem;
    420. }
    421. .article-cover {
    422. border-radius: 8px 8px 0 0 !important;
    423. height: 230px !important;
    424. width: 100%;
    425. }
    426. .article-cover div {
    427. border-radius: 8px 8px 0 0 !important;
    428. }
    429. .article-wrapper {
    430. padding: 1.25rem 1.25rem 1.875rem;
    431. }
    432. .article-wrapper a {
    433. font-size: 1.25rem;
    434. transition: all 0.3s;
    435. }
    436. }
    437. .scroll-down {
    438. cursor: pointer;
    439. position: absolute;
    440. bottom: 0;
    441. width: 100%;
    442. }
    443. .scroll-down i {
    444. font-size: 2rem;
    445. }
    446. .article-wrapper a:hover {
    447. color: #8e8cd8;
    448. }
    449. .article-info {
    450. font-size: 95%;
    451. color: #858585;
    452. line-height: 2;
    453. margin: 0.375rem 0;
    454. }
    455. .article-info a {
    456. font-size: 95%;
    457. color: #858585 !important;
    458. }
    459. .article-content {
    460. line-height: 2;
    461. overflow: hidden;
    462. text-overflow: ellipsis;
    463. display: -webkit-box;
    464. -webkit-line-clamp: 3;
    465. -webkit-box-orient: vertical;
    466. }
    467. .blog-wrapper {
    468. position: sticky;
    469. top: 10px;
    470. }
    471. .blog-card {
    472. line-height: 2;
    473. padding: 1.25rem 1.5rem;
    474. }
    475. .author-wrapper {
    476. text-align: center;
    477. }
    478. .blog-info-wrapper {
    479. display: flex;
    480. justify-self: center;
    481. padding: 0.875rem 0;
    482. }
    483. .blog-info-data {
    484. flex: 1;
    485. text-align: center;
    486. }
    487. .blog-info-data a {
    488. text-decoration: none;
    489. }
    490. .collection-btn {
    491. text-align: center;
    492. z-index: 1;
    493. font-size: 14px;
    494. position: relative;
    495. display: block;
    496. background-color: #49b1f5;
    497. color: #fff !important;
    498. height: 32px;
    499. line-height: 32px;
    500. transition-duration: 1s;
    501. transition-property: color;
    502. }
    503. .collection-btn:before {
    504. position: absolute;
    505. top: 0;
    506. right: 0;
    507. bottom: 0;
    508. left: 0;
    509. z-index: -1;
    510. background: #ff7242;
    511. content: "";
    512. transition-timing-function: ease-out;
    513. transition-duration: 0.5s;
    514. transition-property: transform;
    515. transform: scaleX(0);
    516. transform-origin: 0 50%;
    517. }
    518. .collection-btn:hover:before {
    519. transition-timing-function: cubic-bezier(0.45, 1.64, 0.47, 0.66);
    520. transform: scaleX(1);
    521. }
    522. .author-avatar {
    523. transition: all 0.5s;
    524. }
    525. .author-avatar:hover {
    526. transform: rotate(360deg);
    527. }
    528. .web-info {
    529. padding: 0.25rem;
    530. font-size: 0.875rem;
    531. }
    532. .scroll-down-effects {
    533. color: #eee !important;
    534. text-align: center;
    535. text-shadow: 0.1rem 0.1rem 0.2rem rgba(0, 0, 0, 0.15);
    536. line-height: 1.5;
    537. display: inline-block;
    538. text-rendering: auto;
    539. -webkit-font-smoothing: antialiased;
    540. animation: scroll-down-effect 1.5s infinite;
    541. }
    542. @keyframes scroll-down-effect {
    543. 0% {
    544. top: 0;
    545. opacity: 0.4;
    546. filter: alpha(opacity=40);
    547. }
    548. 50% {
    549. top: -16px;
    550. opacity: 1;
    551. filter: none;
    552. }
    553. 100% {
    554. top: 0;
    555. opacity: 0.4;
    556. filter: alpha(opacity=40);
    557. }
    558. }
    559. .big i {
    560. color: #f00;
    561. animation: big 0.8s linear infinite;
    562. }
    563. @keyframes big {
    564. 0%,
    565. 100% {
    566. transform: scale(1);
    567. }
    568. 50% {
    569. transform: scale(1.2);
    570. }
    571. }
    572. </style>