├── .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 | 
4 | 
5 | 
6 | 
7 | ## 介绍
8 | 本项目利用 GitHub Gist 作为数据库,搭建了一个基于Vue纯前端却可保存数据的移动端个人博客。
9 |
10 | ## 效果
11 | 
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 |
2 |
3 |
24 |
25 |
26 |
27 |
29 |
32 | 绑定 GitHub 信息
33 |
35 |
37 |
38 |
39 |
42 | 注销账号
43 | 确定要注销吗?
44 |
45 |
46 |
47 |
48 |
110 |
111 |
171 |
--------------------------------------------------------------------------------
/src/assets/images/axios-0.18.0-orange.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/vue--router-3.0.1-brightgreen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/vue-2.6.6-brightgreen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/vuex-3.0.1-brightgreen.svg:
--------------------------------------------------------------------------------
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 |
2 |
27 |
28 |
29 |
61 |
62 |
--------------------------------------------------------------------------------
/src/components/Dialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
84 |
85 |
--------------------------------------------------------------------------------
/src/components/Input.vue:
--------------------------------------------------------------------------------
1 |
2 |
26 |
27 |
28 |
109 |
110 |
--------------------------------------------------------------------------------
/src/components/Note.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
18 |
19 | {{detail}}
20 |
21 |
22 |
23 |
24 |
25 |
56 |
57 |
--------------------------------------------------------------------------------
/src/components/Textarea.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
89 |
90 |
--------------------------------------------------------------------------------
/src/components/Tips/Tips.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 | {{message}}
10 |
11 |
12 |
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 |
2 |
3 |
16 |
17 |
18 |
19 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/views/Followers.vue:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
53 |
54 |
--------------------------------------------------------------------------------
/src/views/Following.vue:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
53 |
54 |
--------------------------------------------------------------------------------
/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
点击发表博客
8 |
11 |
12 |
13 |
23 |
24 |
25 |
28 |
29 |
32 | 发表博客
33 |
35 |
37 |
38 |
39 |
42 | 删除博客
43 | 确定要删除吗?
44 |
45 |
46 |
47 |
48 |
208 |
209 |
272 |
--------------------------------------------------------------------------------
/src/views/Read.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
79 |
80 |
81 |
82 | 介绍
83 |
84 |
85 | 本项目利用 GitHub Gist 作为数据库,搭建了一个基于Vue纯前端却可保存数据的移动端个人博客。
86 |
87 |
88 |
89 |
90 | 快速使用
91 |
92 |
点击右上方的
93 |
96 | 绑定 GitHub 信息。
97 |
98 | 用户名
99 |
100 | 用户名为 GitHub 的用户名。
101 |
102 | Token
103 |
104 | 在 GitHub > Settings > Developer Settings > Personal access tokens 勾选 gist 权限获取 Token。
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
146 |
147 |
--------------------------------------------------------------------------------
/src/views/Sociality.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
23 |
--------------------------------------------------------------------------------
/src/views/User.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
71 |
72 |
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 |
--------------------------------------------------------------------------------