├── .browserslistrc ├── .gitignore ├── README.md ├── as.json ├── babel.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ ├── images │ │ ├── axios-0.18.0-orange.svg │ │ ├── vue--router-3.0.1-brightgreen.svg │ │ ├── vue-2.6.6-brightgreen.svg │ │ └── vuex-3.0.1-brightgreen.svg │ ├── js │ │ └── iconfont.js │ └── styles │ │ ├── base │ │ └── normalize.scss │ │ └── helpers │ │ ├── _mixin.scss │ │ └── _variable.scss ├── components │ ├── Card.vue │ ├── Dialog.vue │ ├── Input.vue │ ├── Note.vue │ ├── Textarea.vue │ └── Tips │ │ ├── Tips.vue │ │ └── index.js ├── main.js ├── router.js ├── store.js ├── utils.js └── views │ ├── Detail.vue │ ├── Followers.vue │ ├── Following.vue │ ├── Home.vue │ ├── Read.vue │ ├── Sociality.vue │ └── User.vue └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 个人博客 2 | 3 | ![](https://img.shields.io/badge/vue-2.6.6-brightgreen.svg?style=flat-square) 4 | ![](https://img.shields.io/badge/vuex-2.6.6-brightgreen.svg?style=flat-square) 5 | ![](https://img.shields.io/badge/vue--router-3.0.3-brightgreen.svg?style=flat-square) 6 | ![](https://img.shields.io/badge/axios-0.18.0-orange.svg?style=flat-square) 7 | ## 介绍 8 | 本项目利用 GitHub Gist 作为数据库,搭建了一个基于Vue纯前端却可保存数据的移动端个人博客。 9 | 10 | ## 效果 11 | ![](https://img-blog.csdnimg.cn/20190311174058605.gif) 12 | 13 | ## 线上地址 14 | https://lkkkkkkg.github.io/lk.my-vue-blog.io/ 15 | 16 | ## 功能 17 | 发表博客
18 | 删除博客
19 | 个人中心
20 | 后续功能等待完善中…… 21 | 22 | ## 技术栈 23 | vue
24 | vuex
25 | vue-router
26 | axios 27 | 28 | ## 界面 29 | 界面采用简洁的风格,白色为主色调。 30 | 31 | ## 组件 32 | 使用自己编写的组件:
33 | my-input
34 | dialog
35 | my-textarea
36 | card
37 | note 38 | 39 | ## 快速使用 40 | 点击右上方的登陆图标,绑定 GitHub 信息。 41 | 42 | #### 用户名 43 | 用户名为 GitHub 的用户名。 44 | 45 | #### Token 46 | 在 GitHub > Settings > Developer Settings > Personal access tokens 勾选 gist 权限获取 Token。 47 | 48 | ## 最后 49 | 此项目适合刚刚接触 Vue 的初学者,本人也是接触 Vue 不久的前端er,项目中许多代码写的比较冗杂,后续会进行代码的优化,功能的完善。 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /as.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "avatar": "https://note.youdao.com/yws/api/image/normal/1550654475689?userId=qq094F466E920997D779D67291CA86C956", 5 | "author": "兔秀儿", 6 | "time": "1分钟前", 7 | "des": "震惊, 这是一个好房子呀", 8 | "imgs": [ 9 | "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1550849132501&di=9bf78867198f661b5823c0bfa6b71bc9&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F024f78f0f736afc30d51735fb819ebc4b74512ae.jpg", 10 | "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1550849132501&di=9bf78867198f661b5823c0bfa6b71bc9&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F024f78f0f736afc30d51735fb819ebc4b74512ae.jpg", 11 | "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1550849132501&di=9bf78867198f661b5823c0bfa6b71bc9&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F024f78f0f736afc30d51735fb819ebc4b74512ae.jpg" 12 | ], 13 | "visited": 2, 14 | "detail": "李世民发动玄武门之变是一场豪赌,在玄武门事件之前,曾有人上报皇帝,说是金星出现在了秦地的分野之上。秦王有帝王之气,李渊这个时候就有点慌了。古人都是非常迷信的,皇帝也不例外,要知道李建成是太子,李渊摆明了要传位给李建成而不是李世民。于是乎李渊将李世民喊来,给他暗示了一番,要剥夺李世民的所有权利防止他篡位。李世民非常聪明,当时立即转移话题说是太子和齐王将父王的妃子给睡了,李渊这个时候怒了,决定第二天让太子和李世民一起进宫当面对质。这就给了李世民喘息的机会,否则估计他当场就能被李渊拿走所有权力。当天晚上李世民就已经决定要篡位了,因为第二天的变数太大,而且自己输的几率明显是更高的。李渊压根就不想给他传位,那么为什么说李世民发动玄武门之变是豪赌呢?因为他不能直接动用军队,外面驻扎着勤王部队,发动政变明显不明智,而且他也没有实力来抵抗这些勤王部队。他在玄武门只带了二十来个士兵。" 15 | } 16 | ] -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-vue-blog", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build" 8 | }, 9 | "dependencies": { 10 | "vue": "^2.6.6", 11 | "vue-router": "^3.0.1", 12 | "vuex": "^3.0.1" 13 | }, 14 | "devDependencies": { 15 | "@vue/cli-plugin-babel": "^3.4.0", 16 | "@vue/cli-service": "^3.4.0", 17 | "axios": "^0.18.0", 18 | "fibers": "^3.1.1", 19 | "sass": "^1.16.0", 20 | "sass-loader": "^7.1.0", 21 | "vue-template-compiler": "^2.5.21" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lkzai/my-vue-blog/27bfacf6cf657c0e564699cd387e4f71d068ea95/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | my-vue-rent 10 | 11 | 12 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 47 | 48 | 110 | 111 | 171 | -------------------------------------------------------------------------------- /src/assets/images/axios-0.18.0-orange.svg: -------------------------------------------------------------------------------- 1 | axios0.18.0 -------------------------------------------------------------------------------- /src/assets/images/vue--router-3.0.1-brightgreen.svg: -------------------------------------------------------------------------------- 1 | vue-router3.0.1 -------------------------------------------------------------------------------- /src/assets/images/vue-2.6.6-brightgreen.svg: -------------------------------------------------------------------------------- 1 | vue2.6.6 -------------------------------------------------------------------------------- /src/assets/images/vuex-3.0.1-brightgreen.svg: -------------------------------------------------------------------------------- 1 | vuex3.0.1 -------------------------------------------------------------------------------- /src/assets/js/iconfont.js: -------------------------------------------------------------------------------- 1 | !function(s){var c,o='',l=(c=document.getElementsByTagName("script"))[c.length-1].getAttribute("data-injectcss");if(l&&!s.__iconfont__svg__cssinject__){s.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}!function(c){if(document.addEventListener)if(~["complete","loaded","interactive"].indexOf(document.readyState))setTimeout(c,0);else{var l=function(){document.removeEventListener("DOMContentLoaded",l,!1),c()};document.addEventListener("DOMContentLoaded",l,!1)}else document.attachEvent&&(t=c,a=s.document,h=!1,i=function(){h||(h=!0,t())},(o=function(){try{a.documentElement.doScroll("left")}catch(c){return void setTimeout(o,50)}i()})(),a.onreadystatechange=function(){"complete"==a.readyState&&(a.onreadystatechange=null,i())});var t,a,h,i,o}(function(){var c,l,t,a,h,i;(c=document.createElement("div")).innerHTML=o,o=null,(l=c.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",t=l,(a=document.body).firstChild?(h=t,(i=a.firstChild).parentNode.insertBefore(h,i)):a.appendChild(t))})}(window); -------------------------------------------------------------------------------- /src/assets/styles/base/normalize.scss: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in iOS. 9 | */ 10 | 11 | html { 12 | line-height: 1.15; /* 1 */ 13 | -webkit-text-size-adjust: 100%; /* 2 */ 14 | } 15 | 16 | /* Sections 17 | ========================================================================== */ 18 | 19 | /** 20 | * Remove the margin in all browsers. 21 | */ 22 | 23 | body { 24 | margin: 0; 25 | } 26 | 27 | /** 28 | * Render the `main` element consistently in IE. 29 | */ 30 | 31 | main { 32 | display: block; 33 | } 34 | 35 | /** 36 | * Correct the font size and margin on `h1` elements within `section` and 37 | * `article` contexts in Chrome, Firefox, and Safari. 38 | */ 39 | 40 | h1 { 41 | font-size: 2em; 42 | margin: 0.67em 0; 43 | } 44 | 45 | /* Grouping content 46 | ========================================================================== */ 47 | 48 | /** 49 | * 1. Add the correct box sizing in Firefox. 50 | * 2. Show the overflow in Edge and IE. 51 | */ 52 | 53 | hr { 54 | box-sizing: content-box; /* 1 */ 55 | height: 0; /* 1 */ 56 | overflow: visible; /* 2 */ 57 | } 58 | 59 | /** 60 | * 1. Correct the inheritance and scaling of font size in all browsers. 61 | * 2. Correct the odd `em` font sizing in all browsers. 62 | */ 63 | 64 | pre { 65 | font-family: monospace, monospace; /* 1 */ 66 | font-size: 1em; /* 2 */ 67 | } 68 | 69 | /* Text-level semantics 70 | ========================================================================== */ 71 | 72 | /** 73 | * Remove the gray background on active links in IE 10. 74 | */ 75 | 76 | a { 77 | background-color: transparent; 78 | } 79 | 80 | /** 81 | * 1. Remove the bottom border in Chrome 57- 82 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 83 | */ 84 | 85 | abbr[title] { 86 | border-bottom: none; /* 1 */ 87 | text-decoration: underline; /* 2 */ 88 | text-decoration: underline dotted; /* 2 */ 89 | } 90 | 91 | /** 92 | * Add the correct font weight in Chrome, Edge, and Safari. 93 | */ 94 | 95 | b, 96 | strong { 97 | font-weight: bolder; 98 | } 99 | 100 | /** 101 | * 1. Correct the inheritance and scaling of font size in all browsers. 102 | * 2. Correct the odd `em` font sizing in all browsers. 103 | */ 104 | 105 | code, 106 | kbd, 107 | samp { 108 | font-family: monospace, monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /** 113 | * Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /** 121 | * Prevent `sub` and `sup` elements from affecting the line height in 122 | * all browsers. 123 | */ 124 | 125 | sub, 126 | sup { 127 | font-size: 75%; 128 | line-height: 0; 129 | position: relative; 130 | vertical-align: baseline; 131 | } 132 | 133 | sub { 134 | bottom: -0.25em; 135 | } 136 | 137 | sup { 138 | top: -0.5em; 139 | } 140 | 141 | /* Embedded content 142 | ========================================================================== */ 143 | 144 | /** 145 | * Remove the border on images inside links in IE 10. 146 | */ 147 | 148 | img { 149 | border-style: none; 150 | } 151 | 152 | /* Forms 153 | ========================================================================== */ 154 | 155 | /** 156 | * 1. Change the font styles in all browsers. 157 | * 2. Remove the margin in Firefox and Safari. 158 | */ 159 | 160 | button, 161 | input, 162 | optgroup, 163 | select, 164 | textarea { 165 | font-family: inherit; /* 1 */ 166 | font-size: 100%; /* 1 */ 167 | line-height: 1.15; /* 1 */ 168 | margin: 0; /* 2 */ 169 | } 170 | 171 | /** 172 | * Show the overflow in IE. 173 | * 1. Show the overflow in Edge. 174 | */ 175 | 176 | button, 177 | input { /* 1 */ 178 | overflow: visible; 179 | } 180 | 181 | /** 182 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 183 | * 1. Remove the inheritance of text transform in Firefox. 184 | */ 185 | 186 | button, 187 | select { /* 1 */ 188 | text-transform: none; 189 | } 190 | 191 | /** 192 | * Correct the inability to style clickable types in iOS and Safari. 193 | */ 194 | 195 | button, 196 | [type="button"], 197 | [type="reset"], 198 | [type="submit"] { 199 | -webkit-appearance: button; 200 | } 201 | 202 | /** 203 | * Remove the inner border and padding in Firefox. 204 | */ 205 | 206 | button::-moz-focus-inner, 207 | [type="button"]::-moz-focus-inner, 208 | [type="reset"]::-moz-focus-inner, 209 | [type="submit"]::-moz-focus-inner { 210 | border-style: none; 211 | padding: 0; 212 | } 213 | 214 | /** 215 | * Restore the focus styles unset by the previous rule. 216 | */ 217 | 218 | button:-moz-focusring, 219 | [type="button"]:-moz-focusring, 220 | [type="reset"]:-moz-focusring, 221 | [type="submit"]:-moz-focusring { 222 | outline: 1px dotted ButtonText; 223 | } 224 | 225 | /** 226 | * Correct the padding in Firefox. 227 | */ 228 | 229 | fieldset { 230 | padding: 0.35em 0.75em 0.625em; 231 | } 232 | 233 | /** 234 | * 1. Correct the text wrapping in Edge and IE. 235 | * 2. Correct the color inheritance from `fieldset` elements in IE. 236 | * 3. Remove the padding so developers are not caught out when they zero out 237 | * `fieldset` elements in all browsers. 238 | */ 239 | 240 | legend { 241 | box-sizing: border-box; /* 1 */ 242 | color: inherit; /* 2 */ 243 | display: table; /* 1 */ 244 | max-width: 100%; /* 1 */ 245 | padding: 0; /* 3 */ 246 | white-space: normal; /* 1 */ 247 | } 248 | 249 | /** 250 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 251 | */ 252 | 253 | progress { 254 | vertical-align: baseline; 255 | } 256 | 257 | /** 258 | * Remove the default vertical scrollbar in IE 10+. 259 | */ 260 | 261 | textarea { 262 | overflow: auto; 263 | } 264 | 265 | /** 266 | * 1. Add the correct box sizing in IE 10. 267 | * 2. Remove the padding in IE 10. 268 | */ 269 | 270 | [type="checkbox"], 271 | [type="radio"] { 272 | box-sizing: border-box; /* 1 */ 273 | padding: 0; /* 2 */ 274 | } 275 | 276 | /** 277 | * Correct the cursor style of increment and decrement buttons in Chrome. 278 | */ 279 | 280 | [type="number"]::-webkit-inner-spin-button, 281 | [type="number"]::-webkit-outer-spin-button { 282 | height: auto; 283 | } 284 | 285 | /** 286 | * 1. Correct the odd appearance in Chrome and Safari. 287 | * 2. Correct the outline style in Safari. 288 | */ 289 | 290 | [type="search"] { 291 | -webkit-appearance: textfield; /* 1 */ 292 | outline-offset: -2px; /* 2 */ 293 | } 294 | 295 | /** 296 | * Remove the inner padding in Chrome and Safari on macOS. 297 | */ 298 | 299 | [type="search"]::-webkit-search-decoration { 300 | -webkit-appearance: none; 301 | } 302 | 303 | /** 304 | * 1. Correct the inability to style clickable types in iOS and Safari. 305 | * 2. Change font properties to `inherit` in Safari. 306 | */ 307 | 308 | ::-webkit-file-upload-button { 309 | -webkit-appearance: button; /* 1 */ 310 | font: inherit; /* 2 */ 311 | } 312 | 313 | /* Interactive 314 | ========================================================================== */ 315 | 316 | /* 317 | * Add the correct display in Edge, IE 10+, and Firefox. 318 | */ 319 | 320 | details { 321 | display: block; 322 | } 323 | 324 | /* 325 | * Add the correct display in all browsers. 326 | */ 327 | 328 | summary { 329 | display: list-item; 330 | } 331 | 332 | /* Misc 333 | ========================================================================== */ 334 | 335 | /** 336 | * Add the correct display in IE 10+. 337 | */ 338 | 339 | template { 340 | display: none; 341 | } 342 | 343 | /** 344 | * Add the correct display in IE 10. 345 | */ 346 | 347 | [hidden] { 348 | display: none; 349 | } 350 | 351 | //移动端清除默认样式 352 | body, html { 353 | width: 100%; 354 | height: 100%; 355 | font-family: "Helvetica", "SF Pro SC", "HanHei SC", "SF Pro Text", 356 | "Myriad Set Pro", "SF Pro Icons", "PingFang SC", "Helvetica Neue", "Arial", 357 | sans-serif; 358 | } 359 | 360 | a { 361 | text-decoration: none; 362 | color: #000; 363 | } 364 | 365 | ul,p { 366 | padding: 0; 367 | margin: 0; 368 | } 369 | 370 | li { 371 | list-style: none; 372 | } 373 | 374 | *, 375 | *:before, 376 | *:after { 377 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 378 | } 379 | 380 | *:focus { 381 | outline: none; 382 | } 383 | 384 | input,textarea { 385 | border: none; 386 | padding: 0; 387 | margin: 0; 388 | resize:none; 389 | -webkit-appearance: none; 390 | 391 | &::-webkit-search-cancel-button { 392 | -webkit-appearance: none; 393 | } 394 | background: none; 395 | } 396 | 397 | //锁定滚动 398 | .body-fix { 399 | #app { 400 | .home-wrap, 401 | .detail-wrap, 402 | .read-wrap, 403 | .user-wrap, 404 | .sociality-wrap, 405 | .followers-wrap, 406 | .following-wrap { 407 | overflow: hidden; 408 | } 409 | } 410 | } 411 | -------------------------------------------------------------------------------- /src/assets/styles/helpers/_mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin border($pos,$color) { 2 | @if $pos == bottom { 3 | &::after { 4 | position: absolute; 5 | z-index: 1; 6 | top: auto; 7 | right: auto; 8 | bottom: 0; 9 | left: 0; 10 | display: block; 11 | width: 100%; 12 | height: 1px; 13 | content: ''; 14 | -webkit-transform: scaleY(.5); 15 | transform: scaleY(.5); 16 | -webkit-transform-origin: 50% 100%; 17 | transform-origin: 50% 100%; 18 | background-color: $color; 19 | } 20 | } 21 | @if $pos == top { 22 | &::before { 23 | position: absolute; 24 | z-index: 1; 25 | top: auto; 26 | right: auto; 27 | top: 0; 28 | left: 0; 29 | display: block; 30 | width: 100%; 31 | height: 1px; 32 | content: ''; 33 | -webkit-transform: scaleY(.5); 34 | transform: scaleY(.5); 35 | -webkit-transform-origin: 50% 100%; 36 | transform-origin: 50% 100%; 37 | background-color: $color; 38 | } 39 | } 40 | @if $pos == right { 41 | &::after { 42 | position: absolute; 43 | z-index: 1; 44 | top: 0; 45 | right: 0; 46 | bottom: auto; 47 | left: auto; 48 | display: block; 49 | width: 1px; 50 | height: 100%; 51 | content: ''; 52 | -webkit-transform: scaleX(.5); 53 | transform: scaleX(.5); 54 | -webkit-transform-origin: 100% 50%; 55 | transform-origin: 100% 50%; 56 | background-color: $color; 57 | } 58 | } 59 | @if$pos == both { 60 | &::before { 61 | content: ""; 62 | position: absolute; 63 | left: 0; 64 | top: 0; 65 | width: 200%; 66 | height: 200%; 67 | border: 1px solid $color; 68 | -webkit-transform-origin: 0 0; 69 | -ms-transform-origin: 0 0; 70 | transform-origin: 0 0; 71 | -webkit-transform: scale(.5); 72 | -ms-transform: scale(.5); 73 | transform: scale(.5); 74 | -webkit-box-sizing: border-box; 75 | box-sizing: border-box; 76 | pointer-events: none; 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/assets/styles/helpers/_variable.scss: -------------------------------------------------------------------------------- 1 | $theme-color: rgba(0,0,0,.54); 2 | $border-color: #eee; 3 | 4 | $quick-time: 0.24s; 5 | $default-time: 0.42s; 6 | $function: cubic-bezier(0.32, 0.08, 0.24, 1) 7 | -------------------------------------------------------------------------------- /src/components/Card.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 61 | 62 | -------------------------------------------------------------------------------- /src/components/Dialog.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 84 | 85 | -------------------------------------------------------------------------------- /src/components/Input.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 109 | 110 | -------------------------------------------------------------------------------- /src/components/Note.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 56 | 57 | -------------------------------------------------------------------------------- /src/components/Textarea.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 89 | 90 | -------------------------------------------------------------------------------- /src/components/Tips/Tips.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 26 | 27 | -------------------------------------------------------------------------------- /src/components/Tips/index.js: -------------------------------------------------------------------------------- 1 | import TipsComponent from './Tips' 2 | 3 | const Tips = {}; 4 | 5 | // 注册Tips 6 | Tips.install = function (Vue) { 7 | // 生成一个Vue的子类 8 | // 同时这个子类也就是组件 9 | const TipsConstructor = Vue.extend(TipsComponent) 10 | // 生成一个该子类的实例 11 | const instance = new TipsConstructor(); 12 | 13 | // 将这个实例挂载在我创建的div上 14 | // 并将此div加入全局挂载点内部 15 | instance.$mount(document.createElement('div')) 16 | document.body.appendChild(instance.$el) 17 | 18 | // 通过Vue的原型注册一个方法 19 | // 让所有实例共享这个方法 20 | Vue.prototype.$tips = (msg, type, duration) => { 21 | instance.message = msg; 22 | instance.type = type; 23 | instance.visible = true; 24 | clearTimeout(window.timer); 25 | if(duration) { 26 | window.timer = setTimeout(() => { 27 | instance.visible = false; 28 | }, duration); 29 | } 30 | } 31 | } 32 | 33 | export default Tips -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import store from './store' 4 | import router from './router' 5 | import axios from 'axios' 6 | import util from './utils' 7 | import tips from './components/Tips/index' 8 | import './assets/styles/base/normalize.scss' 9 | import './assets/js/iconfont' 10 | 11 | Vue.prototype.$ajax= axios 12 | Vue.prototype.$util = util 13 | Vue.config.productionTip = false 14 | Vue.use(tips); 15 | 16 | new Vue({ 17 | store, 18 | router, 19 | render: h => h(App) 20 | }).$mount('#app') 21 | -------------------------------------------------------------------------------- /src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Home from './views/Home.vue' 4 | import Read from './views/Read.vue' 5 | import Detail from './views/Detail.vue' 6 | import User from './views/User.vue' 7 | import Sociality from './views/Sociality.vue' 8 | import Followers from './views/Followers.vue' 9 | import Following from './views/Following.vue' 10 | 11 | Vue.use(Router) 12 | 13 | const router = new Router({ 14 | routes: [ 15 | { 16 | path: '/', 17 | name: 'home', 18 | component: Home 19 | }, 20 | { 21 | path: '/read', 22 | name: 'read', 23 | component: Read 24 | }, 25 | { 26 | path: '/detail', 27 | name: 'detail', 28 | component: Detail 29 | }, 30 | { 31 | path: '/user', 32 | name: 'user', 33 | component: User 34 | }, 35 | { 36 | path: '/sociality', 37 | component: Sociality, 38 | children: [ 39 | { 40 | path: '/', 41 | name: 'followers', 42 | component: Followers 43 | }, 44 | { 45 | path: 'following', 46 | name: 'following', 47 | component: Following 48 | } 49 | ] 50 | } 51 | ] 52 | }) 53 | 54 | router.beforeEach((to, from, next) => { 55 | if (to.name !== 'read') { 56 | if (sessionStorage.getItem("token") && sessionStorage.getItem("token") !== '') { 57 | next(); 58 | } else { 59 | next('/read') 60 | } 61 | } else { 62 | next(); 63 | } 64 | }) 65 | 66 | 67 | export default router -------------------------------------------------------------------------------- /src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | scrollTops: {}, 9 | user: JSON.parse(sessionStorage.getItem("user")) || {}, 10 | blogs: [], 11 | details: {}, 12 | token: sessionStorage.getItem("token") || '', 13 | followers: [], 14 | following: [], 15 | }, 16 | mutations: { 17 | SET_SCROLLTOPS(state, value) { 18 | state.scrollTops[value.key] = value.value; 19 | }, 20 | SET_USER(state, value) { 21 | state.user = value; 22 | sessionStorage.setItem("user", JSON.stringify(value)); 23 | }, 24 | SET_TOKEN(state, value) { 25 | state.token = value; 26 | sessionStorage.setItem("token", value); 27 | }, 28 | SET_BLOGS(state, value) { 29 | state.blogs = value; 30 | }, 31 | ADD_BLOG(state, value) { 32 | state.blogs.unshift(value); 33 | state.user.public_gists++; 34 | }, 35 | DELETE_BLOG(state, value) { 36 | state.blogs.forEach((blog,index)=>{ 37 | if(blog.id === value) { 38 | state.blogs.splice(index,1); 39 | } 40 | }); 41 | state.user.public_gists--; 42 | }, 43 | SET_DETAILS(state, value) { 44 | Vue.set(state.details, value.key, value.value) 45 | }, 46 | DELETE_DETAILS(state,value) { 47 | Vue.delete(state.details, value) 48 | }, 49 | SET_FOLLOWERS(state, value) { 50 | state.followers = value; 51 | }, 52 | SET_FOLLOWING(state, value) { 53 | state.following = value; 54 | }, 55 | } 56 | }) 57 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | export default { 2 | getDateDiff(time) { 3 | let arr = time.split(/[^0-9]/); 4 | let worldDate = new Date(arr[0], arr[1] - 1, arr[2], arr[3], arr[4], arr[5]); 5 | let localDate = new Date(worldDate.getTime() + 8 * 60 * 60 * 1000); 6 | let localTimeStamp = Date.parse(localDate), 7 | nowTimeStamp = Date.parse(new Date()); 8 | let diffTimeStamp = nowTimeStamp - localTimeStamp, 9 | minute = 1000 * 60, 10 | hour = minute * 60, 11 | day = hour * 24, 12 | month = day * 30; 13 | let monthDiff = diffTimeStamp / month; 14 | let weekDiff = diffTimeStamp / (7 * day); 15 | let dayDiff = diffTimeStamp / day; 16 | let hourDiff = diffTimeStamp / hour; 17 | let minDiff = diffTimeStamp / minute; 18 | if(monthDiff >= 1) { 19 | return `${Math.floor(monthDiff)}个月前` 20 | }else if(weekDiff >= 1) { 21 | return `${Math.floor(weekDiff)}个星期前` 22 | }else if(dayDiff >= 1) { 23 | return `${Math.floor(dayDiff)}天前` 24 | }else if (hourDiff >= 1) { 25 | return `${Math.floor(hourDiff)}小时前` 26 | }else if(minDiff >=1) { 27 | return `${Math.floor(minDiff)}分钟前` 28 | }else { 29 | return `刚刚` 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/views/Detail.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/views/Followers.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 53 | 54 | -------------------------------------------------------------------------------- /src/views/Following.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 53 | 54 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 47 | 48 | 208 | 209 | 272 | -------------------------------------------------------------------------------- /src/views/Read.vue: -------------------------------------------------------------------------------- 1 | 112 | 113 | 146 | 147 | -------------------------------------------------------------------------------- /src/views/Sociality.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 23 | -------------------------------------------------------------------------------- /src/views/User.vue: -------------------------------------------------------------------------------- 1 | 73 | 74 | 79 | 80 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | publicPath: "./", 3 | css: { 4 | loaderOptions: { 5 | //全局变量scss 6 | sass: { 7 | data: ` 8 | @import "@/assets/styles/helpers/_variable.scss"; 9 | @import "@/assets/styles/helpers/_mixin.scss"; 10 | ` 11 | } 12 | } 13 | } 14 | }; 15 | --------------------------------------------------------------------------------