├── .eslintrc.js
├── .gitignore
├── .postcssrc.js
├── .vscode
└── settings.json
├── README.md
├── _config.yml
├── babel.config.js
├── conf.json
├── gulpfile.js
├── jsconfig.json
├── package-lock.json
├── package.json
├── public
├── index.html
└── static
│ ├── TweenMax.min.js
│ └── iconfont
│ ├── iconfont.css
│ ├── iconfont.eot
│ ├── iconfont.js
│ ├── iconfont.svg
│ ├── iconfont.ttf
│ └── iconfont.woff
├── src
├── App.vue
├── api
│ ├── app.js
│ ├── blog.convert.js
│ ├── blog.js
│ ├── news.convert.js
│ ├── news.js
│ └── user.js
├── assets
│ ├── icon
│ │ └── 404.png
│ ├── logo.png
│ └── styles
│ │ ├── base.scss
│ │ └── variable.scss
├── components
│ ├── 404
│ │ └── blogger404.vue
│ ├── index.js
│ ├── item
│ │ ├── blogItem.vue
│ │ ├── bloggerItem.vue
│ │ ├── commentItem.vue
│ │ └── newsItem.vue
│ ├── layout
│ │ ├── back.vue
│ │ └── home.vue
│ ├── loading
│ │ └── loading.vue
│ ├── markdown
│ │ └── index.vue
│ ├── notice
│ │ └── updateApp.vue
│ ├── share
│ │ └── index.vue
│ └── waves
│ │ └── index.vue
├── config
│ └── conf.js
├── filters
│ └── index.js
├── language
│ ├── cn.js
│ ├── en.js
│ └── index.js
├── main.js
├── registerServiceWorker.js
├── router
│ ├── index.js
│ └── router.js
├── store
│ ├── app.js
│ ├── index.js
│ └── user.js
├── utils
│ ├── $cookie.js
│ ├── $http.js
│ ├── $news.http.js
│ ├── $official.http.js
│ ├── $storage.js
│ ├── native.js
│ └── user.js
└── views
│ ├── About.vue
│ ├── BlogApp.vue
│ ├── BlogCollection.vue
│ ├── BlogDetail.vue
│ ├── BloggerRank.vue
│ ├── BloggerSearch.vue
│ ├── Home.vue
│ ├── News.vue
│ ├── NewsDetail.vue
│ ├── Theme.vue
│ └── User.vue
└── vue.config.js
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // https://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 |
6 | parserOptions: {
7 | parser: 'babel-eslint'
8 | },
9 |
10 | env: {
11 | browser: true,
12 | node: true
13 | },
14 |
15 | extends: [
16 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
17 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
18 | 'plugin:vue/essential',
19 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md
20 | 'standard'
21 | ],
22 |
23 | // required to lint *.vue files
24 | plugins: [
25 | 'vue'
26 | ],
27 |
28 | // add your custom rules here
29 | rules: {
30 | rules: {
31 | 'no-var': 'error',
32 | 'init-declarations': 2,
33 | quotes: [
34 | 'error',
35 | 'single'
36 | ],
37 | semi: [
38 | 'error',
39 | 'never'
40 | ],
41 | 'no-extra-semi': 'error',
42 | 'linebreak-style': [
43 | 'error',
44 | 'unix'
45 | ],
46 | indent: [
47 | 'error',
48 | 2,
49 | {
50 | SwitchCase: 1
51 | }
52 | ],
53 | 'array-bracket-spacing': [
54 | 2,
55 | 'never'
56 | ],
57 | 'block-scoped-var': 0,
58 | 'brace-style': [
59 | 2,
60 | '1tbs',
61 | {
62 | allowSingleLine: true
63 | }
64 | ],
65 | camelcase: 2,
66 | 'comma-dangle': [
67 | 2,
68 | 'never'
69 | ],
70 | 'comma-spacing': [
71 | 2,
72 | {
73 | before: false,
74 | after: true
75 | }
76 | ],
77 | 'comma-style': [
78 | 2,
79 | 'last'
80 | ],
81 | complexity: [
82 | 2,
83 | 9
84 | ],
85 | 'computed-property-spacing': [
86 | 2,
87 | 'never'
88 | ]
89 | },
90 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
91 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
92 | },
93 |
94 | 'extends': [
95 | 'plugin:vue/essential',
96 | '@vue/standard'
97 | ]
98 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 |
13 | # Editor directories and files
14 | .idea
15 | .vscode
16 | *.suo
17 | *.ntvs*
18 | *.njsproj
19 | *.sln
20 | *.sw*
21 |
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "git.ignoreLimitWarning": true
3 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | CnBlogApp
2 |
3 | 此项目,本地运行能够使用,本地运行所有接口都做了代理,图片也做了中转处理,此项目引用了部分cordova功能,
4 | 譬如原生复制,返回事件,Webview的cookie写入(Cordova中document.cookie不生效).
5 |
6 | 命令
7 |
8 | npm install
9 | npm run start 本地运行
10 | npm run build 本地编译
11 |
12 | 基于 vue-cli@3.0: https://cli.vuejs.org/
13 |
14 | UI 库使用 vant: https://youzan.github.io/vant/#/zh-CN/intro/
15 |
16 | /src/utils 下提供了 http 请求,localstorage 存储,cookie 操作
17 |
18 | 提供了this.push和this.goBack方法,调用这两个方法才能实现切换动画效果
19 |
20 | 监控了原始backbutton事件,让其调用提供的goBack方法
21 |
22 | 我已经将vue.config 里面的跨域配置去掉的,可以使用chrome插件crods domain来处理跨域问题。
23 |
24 | Cordova打包的时候需要引入如下Plugin,如果觉得运行慢可以自行引入inter的crosswalk或者腾讯的x5引擎提升性能
25 |
26 |
28 |
29 |
30 |
31 | 登录:
32 |
33 | 
34 |
35 | 1.个人中心有登录按钮,登录功能里面有一个博客昵称和cookie输入框,
36 | 其中博客昵称只是用来获取用户信息跟用户登录相关操作没直接联系,
37 | 用于昵称请输入准确的不然可能无法匹配,到时获取错误的用户信息。【用户昵称请看我的截图箭头】
38 |
39 | 2.只有.CNBlogsCookie才是真正评论推荐功能需要使用的。.CNBlogsCookie请用Chrome登陆后在cookie里面查看。
40 |
41 | 3.登录Cookie会过期,如果过期了请重新更新
42 |
43 | 4.博客ID请输入完整准确的,不然接口可能匹配不到。
44 |
45 | 接口:
46 |
47 | 1.非登录的接口来源于: http://wcf.open.cnblogs.com/news/help / http://wcf.open.cnblogs.com/blog/help
48 |
49 | 2.登录后操作的接口来源于博客园PC断原有接口
50 |
51 | 实现功能:
52 |
53 | 1.新闻列表
54 |
55 | 2.博客列表
56 |
57 | 3.博客详情[评论功能,推荐功能]
58 |
59 | 4.新闻详情[新闻详情不提供评论和推荐功能,原因是新闻的接口,居然需要把所有的cookie都加进去,
60 |
61 | 而博客的操作只需要加入.CNBlogsCookie这个cookie,个人觉得没太大必要了。基本上也就只有博客评论和推荐的人多,
62 |
63 | 所以登录界面我也就只提供了.CNBlogsCookie的设置输入框。
64 |
65 |
66 | 下载链接:
67 |
68 | https://fir.im/cnblog
69 |
70 | 更新历史:【app发布历史,请前往下载链接自动更新】
71 |
72 | 2018/09/14 ---- 新增博客/新闻图片预览
73 |
74 | 2018/09/02 ---- [1]登录界面新增帮助提示 [2] 解决如果自己用户名被其他人的用户名包含了导致无法登录。譬如我叫做FrankZC如果还有一个叫做FrankZC92,我将无法登录 【此次版本更新不修改版本号,不对用户进行提醒,未有用户反馈】
75 |
76 | 2018/08/22 ---- 新增皮肤切换功能,部分图片修改,改用阿里iconfont维护
77 |
78 | 2018/08/18 ---- 新增了App版本更新检查,配置读取的是项目里面的conf.json文件。
79 |
80 | 2018/08/11 ---- 新增本地博客收藏和回复评论功能,本地收藏存储手机缓存里面。
81 |
82 | 2018/08/09 ---- 隐藏Mathjax.js加载界面提示,个人中心优化
83 |
84 | 2018/08/02 ---- 解决数学表达式不支持左右滑动展示
85 |
86 | 反馈:
87 |
88 | 1.有任何问题可以在Issue里面反馈
89 |
90 | 2.或者去我的博客下面评论. https://www.cnblogs.com/FourLeafCloverZc/p/9380895.html
91 |
92 | 打赏:
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-architect
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": {
3 | "id": "2018.09.14",
4 | "message": "新增博客/新闻内容点击图片预览",
5 | "forceUpdate": false
6 | }
7 | }
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | var gulp = require('gulp')
3 | var GulpSSH = require('gulp-ssh')
4 |
5 | let config = {
6 | version: '1.0.0',
7 | ssh: {
8 | host: 'xxxx', // 服务器ip地址
9 | port: 22, // 端口号
10 | username: 'root', // 用户名
11 | password: 'xxxx' // 密码
12 | },
13 | remoteDir: `/usr/local/xxx`, // 部署路径
14 | commands: [
15 | `rm -rf ` // 部署前需要执行的脚本。譬如重新发布后需要清空发布包之前的js和css
16 | ]
17 | }
18 |
19 | var gulpSSH = new GulpSSH({
20 | ignoreErrors: false,
21 | sshConfig: config.ssh
22 | })
23 |
24 | gulp.task('default', ['deployFile'], function () {})
25 |
26 | /**
27 | * 上传文件
28 | */
29 | gulp.task('deployFile', ['execSSH'], () => {
30 | return gulp
31 | .src(['./dist/**'])
32 | .pipe(gulpSSH.dest(config.remoteDir))
33 | })
34 |
35 | /**
36 | * 执行命令
37 | */
38 | gulp.task('execSSH', () => {
39 | console.log('删除服务器上现有文件...')
40 | return gulpSSH.shell(config.commands, {
41 | filePath: 'commands.log'
42 | })
43 | .pipe(gulp.dest('logs'))
44 | })
45 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "emitDecoratorMetadata": true,
4 | "experimentalDecorators": true,
5 | //"module": "amd",
6 | //"target": "ES6",
7 | "baseUrl": "./",
8 | "paths": {
9 | "@/*": ["src/*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-template",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "vue-cli-service build",
7 | "lint": "vue-cli-service lint",
8 | "deploy": "gulp",
9 | "start": "vue-cli-service serve"
10 | },
11 | "dependencies": {
12 | "axios": "^0.18.0",
13 | "register-service-worker": "^1.0.0",
14 | "vant": "^1.1.9",
15 | "vue": "^2.5.16",
16 | "vue-i18n": "^8.0.0",
17 | "vue-router": "^3.0.1",
18 | "vuex": "^3.0.1",
19 | "xmltojson": "git+https://github.com/metatribal/xmlToJSON.git"
20 | },
21 | "devDependencies": {
22 | "@vue/cli-plugin-babel": "^3.0.0-beta.15",
23 | "@vue/cli-plugin-eslint": "^3.0.0-rc.3",
24 | "@vue/cli-plugin-pwa": "^3.0.0-beta.15",
25 | "@vue/cli-service": "^3.0.0-beta.15",
26 | "@vue/eslint-config-standard": "^3.0.0-rc.3",
27 | "gulp": "^3.9.1",
28 | "gulp-ssh": "^0.7.0",
29 | "node-sass": "^4.9.0",
30 | "sass-loader": "^7.0.1",
31 | "vue-template-compiler": "^2.5.16"
32 | },
33 | "browserslist": [
34 | "> 1%",
35 | "last 2 versions",
36 | "not ie <= 8"
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Cnblog
9 |
14 |
15 |
16 |
17 |
18 |
72 |
73 |
74 |
75 |
78 |
79 |
80 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/public/static/iconfont/iconfont.css:
--------------------------------------------------------------------------------
1 |
2 | @font-face {font-family: "iconfont";
3 | src: url('iconfont.eot?t=1534902662584'); /* IE9*/
4 | src: url('iconfont.eot?t=1534902662584#iefix') format('embedded-opentype'), /* IE6-IE8 */
5 | url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),
6 | url('iconfont.ttf?t=1534902662584') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
7 | url('iconfont.svg?t=1534902662584#iconfont') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .iconfont {
11 | font-family:"iconfont" !important;
12 | font-size:16px;
13 | font-style:normal;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | .icon-like:before { content: "\e799"; }
19 |
20 | .icon-emaxcitygerenxinxitubiaoji02:before { content: "\e61d"; }
21 |
22 | .icon-update:before { content: "\ed7d"; }
23 |
24 | .icon-setting:before { content: "\e608"; }
25 |
26 | .icon-blogger:before { content: "\e6a4"; }
27 |
28 | .icon-comment:before { content: "\e634"; }
29 |
30 | .icon-exit:before { content: "\e7cb"; }
31 |
32 | .icon-about:before { content: "\e602"; }
33 |
34 | .icon-share:before { content: "\e615"; }
35 |
36 | .icon-ego-blog:before { content: "\e632"; }
37 |
38 | .icon-account:before { content: "\e603"; }
39 |
40 | .icon-news_hot:before { content: "\e622"; }
41 |
42 | .icon-qzone:before { content: "\e604"; }
43 |
44 | .icon-paihangbang:before { content: "\e66e"; }
45 |
46 | .icon-account1:before { content: "\e649"; }
47 |
48 | .icon-theme:before { content: "\e600"; }
49 |
50 |
--------------------------------------------------------------------------------
/public/static/iconfont/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frank-C-Zhang/CNBlogApp/74e17454688284145a31d5f512acc6fee9101f36/public/static/iconfont/iconfont.eot
--------------------------------------------------------------------------------
/public/static/iconfont/iconfont.js:
--------------------------------------------------------------------------------
1 | (function(window){var svgSprite='';var script=function(){var scripts=document.getElementsByTagName("script");return scripts[scripts.length-1]}();var shouldInjectCss=script.getAttribute("data-injectcss");var ready=function(fn){if(document.addEventListener){if(~["complete","loaded","interactive"].indexOf(document.readyState)){setTimeout(fn,0)}else{var loadFn=function(){document.removeEventListener("DOMContentLoaded",loadFn,false);fn()};document.addEventListener("DOMContentLoaded",loadFn,false)}}else if(document.attachEvent){IEContentLoaded(window,fn)}function IEContentLoaded(w,fn){var d=w.document,done=false,init=function(){if(!done){done=true;fn()}};var polling=function(){try{d.documentElement.doScroll("left")}catch(e){setTimeout(polling,50);return}init()};polling();d.onreadystatechange=function(){if(d.readyState=="complete"){d.onreadystatechange=null;init()}}}};var before=function(el,target){target.parentNode.insertBefore(el,target)};var prepend=function(el,target){if(target.firstChild){before(el,target.firstChild)}else{target.appendChild(el)}};function appendSvg(){var div,svg;div=document.createElement("div");div.innerHTML=svgSprite;svgSprite=null;svg=div.getElementsByTagName("svg")[0];if(svg){svg.setAttribute("aria-hidden","true");svg.style.position="absolute";svg.style.width=0;svg.style.height=0;svg.style.overflow="hidden";prepend(svg,document.body)}}if(shouldInjectCss&&!window.__iconfont__svg__cssinject__){window.__iconfont__svg__cssinject__=true;try{document.write("")}catch(e){console&&console.log(e)}}ready(appendSvg)})(window)
--------------------------------------------------------------------------------
/public/static/iconfont/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
75 |
--------------------------------------------------------------------------------
/public/static/iconfont/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frank-C-Zhang/CNBlogApp/74e17454688284145a31d5f512acc6fee9101f36/public/static/iconfont/iconfont.ttf
--------------------------------------------------------------------------------
/public/static/iconfont/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frank-C-Zhang/CNBlogApp/74e17454688284145a31d5f512acc6fee9101f36/public/static/iconfont/iconfont.woff
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
50 |
51 |
95 |
--------------------------------------------------------------------------------
/src/api/app.js:
--------------------------------------------------------------------------------
1 | import $http from '../utils/$http'
2 | export function getConf () {
3 | return $http.get('https://raw.githubusercontent.com/FourLeafClover/CNBlogApp/master/conf.json')
4 | }
5 |
--------------------------------------------------------------------------------
/src/api/blog.convert.js:
--------------------------------------------------------------------------------
1 |
2 | let getText = function (obj) {
3 | return (obj && obj._text) ? obj._text : ''
4 | }
5 |
6 | let getBlogApp = function (item) {
7 | let blogApp = getText(item.blogapp)
8 | if (blogApp.length === 0) {
9 | let link = item.link._attr.href._value
10 | if (link) {
11 | blogApp = link.split('/p/')[0].replace('http://www.cnblogs.com/', '')
12 | }
13 | }
14 | return blogApp
15 | }
16 |
17 | export function getHomePageConvert (data) {
18 | let entry = data.feed.entry
19 | let result = []
20 | entry.map(item => {
21 | try {
22 | let convertItem = {
23 | id: getText(item.id),
24 | author: {
25 | name: getText(item.author.name),
26 | avatar: getText(item.author.avatar),
27 | uri: getText(item.author.uri),
28 | blogapp: getBlogApp(item)
29 | },
30 | blogapp: getBlogApp(item),
31 | summary: getText(item.summary),
32 | views: getText(item.views),
33 | title: getText(item.title),
34 | published: getText(item.published),
35 | comments: getText(item.comments),
36 | link: item.link._attr.href._value,
37 | diggs: getText(item.diggs) ? getText(item.diggs) : 0
38 | }
39 | result.push(convertItem)
40 | } catch (error) {
41 | }
42 | })
43 | return result
44 | }
45 |
46 | export function getCommentConvert (data) {
47 | let entry = data.feed.entry
48 | if (entry) {
49 | if (!Array.isArray(entry)) {
50 | entry = [entry]
51 | }
52 | return entry.map(item => {
53 | return {
54 | id: getText(item.id),
55 | author: {
56 | name: getText(item.author.name),
57 | avatar: getText(item.author.uri)
58 | },
59 | content: getText(item.content),
60 | published: getText(item.published),
61 | updated: getText(item.updated)
62 | }
63 | })
64 | } else {
65 | return null
66 | }
67 | }
68 |
69 | export function bloggerConvert (data) {
70 | const entry = data.feed.entry
71 | if (entry) {
72 | if (Array.isArray(entry)) {
73 | return entry.map(item => {
74 | return {
75 | blogapp: getText(item.blogapp),
76 | postcount: getText(item.postcount),
77 | avatar: getText(item.avatar),
78 | name: getText(item.title),
79 | updated: getText(item.updated)
80 | }
81 | })
82 | } else {
83 | return [
84 | {
85 | blogapp: getText(entry.blogapp),
86 | postcount: getText(entry.postcount),
87 | avatar: getText(entry.avatar),
88 | name: getText(entry.title),
89 | updated: getText(entry.updated)
90 | }
91 | ]
92 | }
93 | } else {
94 | return null
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/api/blog.js:
--------------------------------------------------------------------------------
1 | import $http from '../utils/$http'
2 | import { getHomePageConvert, getCommentConvert, userConvert, bloggerConvert } from '@/api/blog.convert'
3 | import Axios from '../../node_modules/axios'
4 | const xmltojson = require('xmltojson')
5 | const options = {
6 | mergeCDATA: true,
7 | grokAttr: true,
8 | grokText: true,
9 | normalize: true,
10 | xmlns: true,
11 | namespaceKey: '_ns',
12 | textKey: '_text',
13 | valueKey: '_value',
14 | attrKey: '_attr',
15 | cdataKey: '_cdata',
16 | attrsAsObject: true,
17 | stripAttrPrefix: true,
18 | stripElemPrefix: true,
19 | childrenAsArray: false
20 | }
21 | export function getHomePage (page, pageSize = 50) {
22 | return $http.get(`/blog/sitehome/paged/${page}/${pageSize}`).then((res) => {
23 | const data = getHomePageConvert(xmltojson.parseString(res, options))
24 | return Promise.resolve(data)
25 | }).catch((err) => {
26 | return Promise.reject(err)
27 | })
28 | }
29 |
30 | export function get48Top () {
31 | return $http.get('/blog/48HoursTopViewPosts/1000').then(res => {
32 | const data = getHomePageConvert(xmltojson.parseString(res, options))
33 | return Promise.resolve(data)
34 | }).catch(err => {
35 | return Promise.reject(err)
36 | })
37 | }
38 |
39 | export function get10TopDigg () {
40 | return $http.get('blog/TenDaysTopDiggPosts/1000').then(res => {
41 | const data = getHomePageConvert(xmltojson.parseString(res, options))
42 | return Promise.resolve(data)
43 | }).catch(err => {
44 | return Promise.reject(err)
45 | })
46 | }
47 |
48 | export function loadBlogBody (id) {
49 | return $http.get(`/blog/post/body/${id}`).then(res => {
50 | const data = res
51 | return Promise.resolve(data)
52 | }).catch(err => {
53 | return Promise.reject(err)
54 | })
55 | }
56 |
57 | export function getBlogComment (id, page, pageSize) {
58 | return $http.get(`/blog/post/${id}/comments/${page}/${pageSize}`).then(res => {
59 | const data = getCommentConvert(xmltojson.parseString(res, options))
60 | return Promise.resolve(data == null ? [] : data)
61 | }).catch(err => {
62 | return Promise.reject(err)
63 | })
64 | }
65 |
66 | export function loadUser (name) {
67 | return $http.get(`/blog/bloggers/search?t=${name}`).then(res => {
68 | const data = bloggerConvert(xmltojson.parseString(res, options))
69 | let user = data.find(item => item.name.toLocaleLowerCase() === name.toLocaleLowerCase())
70 | return Promise.resolve(user)
71 | }).catch(err => {
72 | return Promise.reject(err)
73 | })
74 | }
75 |
76 | export function loadBlogApp (blogapp, page, pageSize) {
77 | return $http.get(`/blog/u/${blogapp}/posts/${page}/${pageSize}`).then(res => {
78 | const data = getHomePageConvert(xmltojson.parseString(res, options))
79 | return Promise.resolve(data)
80 | }).catch(err => {
81 | return Promise.reject(err)
82 | })
83 | }
84 |
85 | export function loadBloggerRank (count) {
86 | return $http.get(`/blog/bloggers/recommend/1/${count}`).then(res => {
87 | const data = bloggerConvert(xmltojson.parseString(res, options))
88 | return Promise.resolve(data)
89 | }).catch(err => {
90 | return Promise.reject(err)
91 | })
92 | }
93 |
94 | export function searchBloggers (keyword) {
95 | return $http.get(`/blog/bloggers/search?t=${keyword}`).then(res => {
96 | const data = bloggerConvert(xmltojson.parseString(res, options))
97 | return Promise.resolve(data)
98 | }).catch(err => {
99 | return Promise.reject(err)
100 | })
101 | }
102 |
103 | // WCF获取body接口不稳定.直接从博客园PC端通过连接获取博文body
104 | export function loadBlogBodyFromPC (url) {
105 | return Axios.get(url).then(res => {
106 | let body = ''
107 | if (res.data) {
108 | let element = document.createElement('div')
109 | element.innerHTML = res.data
110 | body = element.querySelector('#cnblogs_post_body').innerHTML
111 | /* diggCount = Number(element.querySelector('#digg_count').innerHTML)
112 | buryCount = Number(element.querySelector('#bury_count').innerHTML)
113 | let diggElem = element.querySelector('#digg_tips')
114 | if (diggElem) {
115 | isDigg = diggElem.html().indexOf('您已推荐') >= 0
116 | isBury = diggElem.html().indexOf('您已反对') >= 0
117 | } */
118 | }
119 | return Promise.resolve(body)
120 | }).catch(err => {
121 | return Promise.reject(err)
122 | })
123 | }
124 |
--------------------------------------------------------------------------------
/src/api/news.convert.js:
--------------------------------------------------------------------------------
1 | let getText = function (obj) {
2 | return (obj && obj._text) ? obj._text : ''
3 | }
4 |
5 | export function newsItemConvert (data) {
6 | let entry = data.feed.entry
7 | if (entry) {
8 | return entry.map(item => {
9 | return {
10 | id: getText(item.id),
11 | sourceName: getText(item.sourceName),
12 | summary: getText(item.summary),
13 | title: getText(item.title),
14 | updated: getText(item.updated),
15 | views: getText(item.views),
16 | published: getText(item.published),
17 | diggs: getText(item.diggs),
18 | comments: getText(item.comments)
19 | }
20 | })
21 | } else {
22 | return []
23 | }
24 | }
25 |
26 | export function newsCommentConvert (data) {
27 | let entry = data.feed.entry
28 | if (entry) {
29 | return entry.map(item => {
30 | return {
31 | id: getText(item.id),
32 | author: {
33 | name: getText(item.author.name),
34 | avatar: getText(item.author.uri)
35 | },
36 | content: getText(item.content),
37 | published: getText(item.published),
38 | updated: getText(item.updated)
39 | }
40 | })
41 | } else {
42 | return []
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/api/news.js:
--------------------------------------------------------------------------------
1 | import { newsItemConvert, newsCommentConvert } from '@/api/news.convert'
2 | import $http from '../utils/$http'
3 | const xmltojson = require('xmltojson')
4 | const options = {
5 | mergeCDATA: true,
6 | grokAttr: true,
7 | grokText: true,
8 | normalize: true,
9 | xmlns: true,
10 | namespaceKey: '_ns',
11 | textKey: '_text',
12 | valueKey: '_value',
13 | attrKey: '_attr',
14 | cdataKey: '_cdata',
15 | attrsAsObject: true,
16 | stripAttrPrefix: true,
17 | stripElemPrefix: true,
18 | childrenAsArray: false
19 | }
20 | export function getLastNews (page, pageSize = 50) {
21 | return $http.get(`/news/recent/paged/${page}/${pageSize}`).then((res) => {
22 | const data = newsItemConvert(xmltojson.parseString(res, options))
23 | return Promise.resolve(data)
24 | }).catch((err) => {
25 | return Promise.reject(err)
26 | })
27 | }
28 |
29 | export function getRecommendNews (page, pageSize) {
30 | return $http.get(`/news/recommend/paged/${page}/${pageSize}`).then((res) => {
31 | const data = newsItemConvert(xmltojson.parseString(res, options))
32 | return Promise.resolve(data)
33 | }).catch((err) => {
34 | return Promise.reject(err)
35 | })
36 | }
37 |
38 | export function getHotNews () {
39 | return $http.get(`/news/hot/100`).then((res) => {
40 | const data = newsItemConvert(xmltojson.parseString(res, options))
41 | return Promise.resolve(data)
42 | }).catch((err) => {
43 | return Promise.reject(err)
44 | })
45 | }
46 |
47 | export function getNewsDetail (id) {
48 | return $http.get(`/news/item/${id}`).then((res) => {
49 | return Promise.resolve(res)
50 | }).catch((err) => {
51 | return Promise.reject(err)
52 | })
53 | }
54 |
55 | export function getNewsComment (id, page, pageSize) {
56 | return $http.get(`/news/item/${id}/comments/${page}/${pageSize}`).then((res) => {
57 | const data = newsCommentConvert(xmltojson.parseString(res, options))
58 | return Promise.resolve(data)
59 | }).catch((err) => {
60 | return Promise.reject(err)
61 | })
62 | }
63 |
--------------------------------------------------------------------------------
/src/api/user.js:
--------------------------------------------------------------------------------
1 | import officalHttp from '@/utils/$official.http'
2 | import newsHttp from '@/utils/$news.http'
3 |
4 | export function addComment (blogapp, postid, content, parentCommentId = 0) {
5 | // {"blogApp":"FourLeafCloverZc","postId":6118617,"body":"mark1","parentCommentId":0}
6 | return officalHttp({
7 | method: 'post',
8 | url: '/mvc/PostComment/Add.aspx',
9 | data: {
10 | blogApp: blogapp,
11 | postid: postid,
12 | body: content,
13 | parentCommentId: parentCommentId
14 | }
15 | })
16 | }
17 |
18 | export function voteBlog (blogapp, postid, isDigg) {
19 | return officalHttp({
20 | method: 'post',
21 | url: '/mvc/vote/VoteBlogPost.aspx',
22 | data: {
23 | blogApp: blogapp,
24 | postid: postid,
25 | voteType: isDigg ? 'Digg' : 'Bury',
26 | isAbandoned: false
27 | }
28 | })
29 | }
30 |
31 | export function addNewsComment (content, contentid) {
32 | return newsHttp({
33 | url: '/Comment/InsertComment',
34 | method: 'post',
35 | data: {
36 | content: content,
37 | contentId: contentid,
38 | parentCommentId: ''
39 | }
40 | })
41 | }
42 |
43 | export function voteNews (contentId) {
44 | return newsHttp({
45 | url: '/News/VoteNews',
46 | method: 'post',
47 | data: {
48 | contentId: contentId,
49 | action: 'agree'
50 | }
51 | })
52 | }
53 |
--------------------------------------------------------------------------------
/src/assets/icon/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frank-C-Zhang/CNBlogApp/74e17454688284145a31d5f512acc6fee9101f36/src/assets/icon/404.png
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frank-C-Zhang/CNBlogApp/74e17454688284145a31d5f512acc6fee9101f36/src/assets/logo.png
--------------------------------------------------------------------------------
/src/assets/styles/base.scss:
--------------------------------------------------------------------------------
1 | @import './variable.scss';
2 | * {
3 | -webkit-text-size-adjust: none !important;
4 | -webkit-touch-callout: none !important;
5 | -webkit-user-select: none !important;
6 | user-select: none !important;
7 | }
8 |
9 | html,
10 | body,
11 | div,
12 | ul,
13 | li,
14 | h1,
15 | h2,
16 | h3,
17 | h4,
18 | h5,
19 | h6,
20 | p,
21 | dl,
22 | dt,
23 | dd,
24 | ol,
25 | form,
26 | input,
27 | textarea,
28 | th,
29 | td,
30 | select {
31 | margin: 0;
32 | padding: 0;
33 | }
34 |
35 | html,body{
36 | height: 100%;
37 | width: 100%;
38 | overflow-x: hidden;
39 | }
40 |
41 | div {
42 | -webkit-overflow-scrolling: touch;
43 | box-sizing: border-box;
44 | }
45 | div,
46 | video,
47 | img {
48 | outline-width: 0px;
49 | vertical-align: top;
50 | }
51 |
52 | .van-tab--active {
53 | @include themify{
54 | color:themed('color')
55 | };
56 | font-size: 18px;
57 | }
58 | .van-tab:active{
59 | background-color: white
60 | }
61 | .van-tabs__line{
62 | display: none;
63 | }
64 |
65 | .markdown{
66 | width: 100%;
67 | padding: 0 10px;
68 | box-sizing: border-box;
69 | display: block;
70 | word-break: break-all;
71 | letter-spacing: 0.1em;
72 | h1,h2,h3,h4,h5,h6{
73 | margin: 10px 0px;
74 | font-size: 18px;
75 | padding: 0px;
76 | }
77 | p{
78 | color: gray;
79 | margin: 10px 0px;
80 | line-height: 22px;
81 | font-size: 16px;
82 | margin-left: 0px !important;
83 | }
84 | img{
85 | width: 100%;
86 | padding: 0 important;
87 | margin: 10px 0px !important;
88 | height: auto !important;
89 | }
90 | .cnblogs_code{
91 | box-shadow: 0px 0px 5px #c9c9c9;
92 | padding: 10px;
93 | box-sizing: border-box;
94 | }
95 | pre{
96 | width: 100%;
97 | box-sizing: border-box;
98 | overflow-x: auto;
99 | box-shadow: 1 1 2px gray;
100 | margin: 0 !important;
101 | padding: 0 !important;
102 | }
103 | li{
104 | margin-left: 10px !important;
105 | padding: 0px !important;
106 | }
107 | }
108 |
109 |
110 | .van-switch--on{
111 | @include themify{
112 | background-color:themed('color')
113 | };
114 | }
115 |
116 | .van-button--primary{
117 | @include themify{
118 | background-color:themed('color');
119 | border:1px solid themed('color')
120 | }
121 | }
--------------------------------------------------------------------------------
/src/assets/styles/variable.scss:
--------------------------------------------------------------------------------
1 | $themes: (
2 | dodgerblue: (
3 | color:dodgerblue
4 | ),
5 | green:(
6 | color:green
7 | ),
8 | red:(
9 | color:red
10 | ),
11 | gray:(
12 | color:gray
13 | ),
14 | purple:(
15 | color:purple
16 | ),
17 | orange:(
18 | color:orange
19 | )
20 | );
21 |
22 | @mixin themify($themes: $themes) {
23 | @each $theme, $map in $themes {
24 | .theme-#{$theme} & {
25 | $theme-map: () !global;
26 | @each $key, $submap in $map {
27 | $value: map-get(map-get($themes, $theme), '#{$key}');
28 | $theme-map: map-merge($theme-map, ($key: $value)) !global;
29 | }
30 | @content;
31 | $theme-map: null !global;
32 | }
33 | }
34 | }
35 |
36 | @function themed($key) {
37 | @return map-get($theme-map, $key);
38 | }
39 |
40 | .van-switch--on{
41 | background-color: !important;
42 | }
43 |
44 | .van-button--primary{
45 | @include themify{
46 | background-color:themed('color') !important;
47 | border: 1px solid themed('color') !important;
48 | }
49 | }
50 |
51 | .van-icon{
52 | @include themify{
53 | color:themed('color') !important;
54 | }
55 | }
56 |
57 | .van-nav-bar__title{
58 | @include themify{
59 | color:themed('color') !important;
60 | }
61 | }
--------------------------------------------------------------------------------
/src/components/404/blogger404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
{{message}}
5 |
6 |
7 |
8 |
16 |
17 |
32 |
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import home from './layout/home.vue'
3 | import blogItem from './item/blogItem'
4 | import newsItem from './item/newsItem'
5 | import markdown from './markdown'
6 | import commentItem from './item/commentItem'
7 | import loading from './loading/loading'
8 | import back from './layout/back'
9 | import share from './share'
10 | import bloggerItem from './item/bloggerItem'
11 | import empty from './404/blogger404.vue'
12 | import waves from './waves'
13 | import updateApp from './notice/updateApp'
14 | Vue.component(waves.name, waves)
15 | Vue.component(home.name, home)
16 | Vue.component(blogItem.name, blogItem)
17 | Vue.component(newsItem.name, newsItem)
18 | Vue.component(markdown.name, markdown)
19 | Vue.component(commentItem.name, commentItem)
20 | Vue.component(loading.name, loading)
21 | Vue.component(back.name, back)
22 | Vue.component(share.name, share)
23 | Vue.component(bloggerItem.name, bloggerItem)
24 | Vue.component(empty.name, empty)
25 | Vue.component(waves.name, waves)
26 | Vue.component(updateApp.name, updateApp)
27 |
--------------------------------------------------------------------------------
/src/components/item/blogItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
{{item.title}}
8 |
9 |
{{item.summary}}
10 |
11 |
{{item.author.name}} 阅读: {{ item.views }} 推荐: {{item.diggs}} 发布于: {{ item.published | dateFormat }}
12 |
13 |
14 |
15 |
58 |
89 |
--------------------------------------------------------------------------------
/src/components/item/bloggerItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
![]()
4 |
{{item.name}}
5 |
博客ID: {{item.blogapp}} 博客:{{item.postcount}}篇
6 |
7 |
8 |
9 |
31 |
32 |
77 |
--------------------------------------------------------------------------------
/src/components/item/commentItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
33 |
34 |
77 |
--------------------------------------------------------------------------------
/src/components/item/newsItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{item.title}}
4 |
{{item.summary}}
5 |
6 |
{{item.sourceName}} 阅读: {{ item.views }} 发布于: {{ item.published | dateFormat }}
7 |
8 |
9 |
10 |
27 |
28 |
59 |
--------------------------------------------------------------------------------
/src/components/layout/back.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
28 |
43 |
--------------------------------------------------------------------------------
/src/components/layout/home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 更新
10 |
11 |
12 |
13 | 首页
14 |
15 |
16 |
17 | 新闻
18 |
19 |
20 |
21 | 排行榜
22 |
23 |
24 |
25 | 我的
26 |
27 |
28 |
29 |
30 |
31 |
50 |
51 |
59 |
71 |
--------------------------------------------------------------------------------
/src/components/loading/loading.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
73 |
--------------------------------------------------------------------------------
/src/components/markdown/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
69 |
70 |
278 |
--------------------------------------------------------------------------------
/src/components/notice/updateApp.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
45 |
46 |
55 |
--------------------------------------------------------------------------------
/src/components/share/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 关闭
5 |
6 |
7 |
8 |
54 |
67 |
--------------------------------------------------------------------------------
/src/components/waves/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
117 |
118 |
124 |
--------------------------------------------------------------------------------
/src/config/conf.js:
--------------------------------------------------------------------------------
1 | // export const WCF_API = process.env.NODE_ENV === 'deveploment' ? '' : ''
2 | // export const OFFICAL_API = process.env.NODE_ENV === 'deveploment' ? '' : ''
3 | export const ENV = 'prod' // process.env.NODE_ENV
4 | export const WCF_API = ENV === 'development' ? '' : 'http://wcf.open.cnblogs.com'
5 | export const OFFICAL_API = ENV === 'development' ? '' : 'https://www.cnblogs.com'
6 | export const NEWS_API = ENV === 'development' ? '' : 'https://news.cnblogs.com'
7 | export const Version = '2018.09.14'
8 |
--------------------------------------------------------------------------------
/src/filters/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import { ENV } from '@/config/conf'
3 | const dateFormat = (str) => {
4 | var date = new Date(str)
5 | var dateGetTime = date.getTime()
6 | var nowGetTime = new Date().getTime()
7 | if ((nowGetTime - dateGetTime) < (60 * 1000)) {
8 | return '1分钟前'
9 | } else if ((nowGetTime - dateGetTime) < (60 * 60 * 1000)) {
10 | return '1小时内发布'
11 | } else {
12 | return date.toLocaleDateString()
13 | }
14 | }
15 |
16 | const imgConvert = (str) => {
17 | // 开发模式图片要做中转,不然没有权限访问
18 | if (ENV === 'development') {
19 | str = str.replace('http://', '')
20 | return `https://images.weserv.nl/?url=${str}`
21 | } else {
22 | return str
23 | }
24 | }
25 |
26 | Vue.filter('dateFormat', dateFormat)
27 | Vue.filter('imgConvert', imgConvert)
28 |
--------------------------------------------------------------------------------
/src/language/cn.js:
--------------------------------------------------------------------------------
1 | export default {
2 | App: {
3 | Home: '首页',
4 | About: '关于',
5 | Back: '返回'
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/language/en.js:
--------------------------------------------------------------------------------
1 | export default {
2 | App: {
3 | Home: 'Home',
4 | About: 'About',
5 | Back: 'Back'
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/language/index.js:
--------------------------------------------------------------------------------
1 | import en from './en'
2 | import cn from './cn'
3 | import VueI18n from 'vue-i18n'
4 | import Vue from 'vue'
5 | import { getItem } from '@/utils/$storage'
6 | Vue.use(VueI18n)
7 |
8 | const messages = {
9 | en: en,
10 | cn: cn
11 | }
12 | let storeageLocale = getItem('vue.locale')
13 | const i18n = new VueI18n({
14 | locale: storeageLocale || 'cn',
15 | messages
16 | })
17 |
18 | export default i18n
19 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import store from './store'
5 | import './registerServiceWorker'
6 | import vant from 'vant'
7 | import 'vant/lib/vant-css/index.css'
8 | import i18n from './language'
9 | require('./filters')
10 | require('./components')
11 | require('./assets/styles/base.scss')
12 | Vue.prototype.push = function (location) {
13 | this.$store.dispatch('app/UPDATE_PAGEANIMATION', 1)
14 | this.$router.push(location)
15 | }
16 | Vue.prototype.goBack = function (index) {
17 | this.$store.dispatch('app/UPDATE_PAGEANIMATION', -1)
18 | this.$router.go(index)
19 | }
20 | Vue.use(vant)
21 | Vue.config.productionTip = false
22 | let $vm = new Vue({
23 | router,
24 | i18n,
25 | store,
26 | render: h => h(App)
27 | }).$mount('#app')
28 | window.$vm = $vm
29 | document.addEventListener('deviceready', function () {
30 | document.addEventListener('backbutton', function () {
31 | if (window.$vm.$router.currentRoute.name === 'page-home') {
32 | window.navigator.app.exitApp()
33 | } else {
34 | window.$vm.goBack(-1)
35 | }
36 | }, false)
37 | }, false)
38 |
--------------------------------------------------------------------------------
/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | import { register } from 'register-service-worker'
3 |
4 | if (process.env.NODE_ENV === 'production') {
5 | register(`${process.env.BASE_URL}service-worker.js`, {
6 | ready () {
7 | console.log(
8 | 'App is being served from cache by a service worker.\n' +
9 | 'For more details, visit https://goo.gl/AFskqB'
10 | )
11 | },
12 | cached () {
13 | console.log('Content has been cached for offline use.')
14 | },
15 | updated () {
16 | console.log('New content is available; please refresh.')
17 | },
18 | offline () {
19 | console.log('No internet connection found. App is running in offline mode.')
20 | },
21 | error (error) {
22 | console.error('Error during service worker registration:', error)
23 | }
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import config from './router'
4 | Vue.use(Router)
5 | // import store from '@/store'
6 | let routers = new Router({
7 | routes: config
8 | })
9 |
10 | routers.beforeEach((to, from, next) => {
11 | next()
12 | })
13 |
14 | export default routers
15 |
--------------------------------------------------------------------------------
/src/router/router.js:
--------------------------------------------------------------------------------
1 | let configs = [{
2 | path: '/',
3 | name: 'page-home',
4 | component: () =>
5 | import('@/views/Home.vue'),
6 | meta: {
7 | needAuth: false,
8 | cache: true
9 | }
10 | },
11 | {
12 | path: '/user',
13 | name: 'page-user',
14 | component: () =>
15 | import('@/views/User.vue'),
16 | meta: {
17 | needAuth: false,
18 | cache: true
19 | }
20 | }, {
21 | path: '/news',
22 | name: 'page-news',
23 | component: () =>
24 | import('@/views/News.vue'),
25 | meta: {
26 | needAuth: false,
27 | cache: true
28 | }
29 | }, {
30 | path: '/blogdetail',
31 | name: 'page-blogdetail',
32 | component: () => import('@/views/BlogDetail.vue'),
33 | meta: {
34 | needAuth: false,
35 | cache: false
36 | }
37 | }, {
38 | path: '/newsdetail',
39 | name: 'page-newsdetail',
40 | component: () => import('@/views/NewsDetail.vue'),
41 | meta: {
42 | needAuth: false,
43 | cache: false
44 | }
45 | }, {
46 | path: '/blogapp',
47 | name: 'page-blogapp',
48 | component: () => import('@/views/BlogApp.vue'),
49 | meta: {
50 | needAuth: false,
51 | cache: true
52 | }
53 | }, {
54 | path: '/about',
55 | name: 'page-about',
56 | component: () => import('@/views/About.vue'),
57 | meta: {
58 | needAuth: false,
59 | cache: true
60 | }
61 | }, {
62 | path: '/bloggerrank',
63 | name: 'page-bloggerrank',
64 | component: () => import('@/views/BloggerRank.vue'),
65 | meta: {
66 | needAuth: false,
67 | cache: true
68 | }
69 | }, {
70 | path: '/bloggersearch',
71 | name: 'page-bloggersearch',
72 | component: () => import('@/views/BloggerSearch.vue'),
73 | meta: {
74 | needAuth: false,
75 | cache: true
76 | }
77 | }, {
78 | path: '/collection',
79 | name: 'page-blogCollection',
80 | component: () => import('@/views/BlogCollection'),
81 | meta: {
82 | needAuth: false,
83 | cache: true
84 | }
85 | }, {
86 | path: '/theme',
87 | name: 'page-theme',
88 | component: () => import('@/views/Theme'),
89 | meta: {
90 | needAuth: false,
91 | cache: true
92 | }
93 | }
94 | ]
95 |
96 | export default configs
97 |
--------------------------------------------------------------------------------
/src/store/app.js:
--------------------------------------------------------------------------------
1 | import { getItem, setItem } from '@/utils/$storage'
2 | import { Version } from '@/config/conf'
3 | import { getConf } from '@/api/app'
4 | let theme = getItem('cnblog.theme')
5 | const state = {
6 | pageAnimation: 0,
7 | openPageAnimation: getItem('cnblog.openPageAnimation') !== null ? getItem('cnblog.openPageAnimation') : true, // 是否开启页面过渡动画,默认开启
8 | version: Version,
9 | serveConf: null, // 服务端配置
10 | openUpdateAppNotice: false,
11 | readVersion: getItem('cnblog.readVersion'), // 记录是否已经关闭某个版本更新的弹窗,
12 | isHaveUpdate: false,
13 | theme: theme || 'dodgerblue',
14 | themeList: ['dodgerblue', 'green', 'red', 'gray', 'purple', 'orange']
15 | }
16 | const mutations = {
17 | UPDATE_PAGEANIMATION (state, animation) {
18 | state.pageAnimation = animation
19 | },
20 | OPEN_PAGEANIMATION (state, isOpen) {
21 | state.openPageAnimation = isOpen
22 | },
23 | GET_SERVECONF (state, conf) {
24 | state.serveConf = conf
25 | if (state.serveConf.version.id !== state.version) {
26 | state.isHaveUpdate = true
27 | if (state.serveConf.version.forceUpdate) {
28 | state.openUpdateAppNotice = true
29 | } else {
30 | if (state.readVersion !== state.serveConf.version.id) {
31 | state.openUpdateAppNotice = true
32 | }
33 | }
34 | }
35 | },
36 | CLOSE_UPDATEAPP_NOTICE (state) {
37 | setItem('cnblog.readVersion', state.serveConf.version.id)
38 | state.openUpdateAppNotice = false
39 | },
40 | CHANGE_THEME (state, theme) {
41 | state.theme = theme
42 | }
43 | }
44 | const actions = {
45 | UPDATE_PAGEANIMATION ({ commit }, animation) {
46 | commit('UPDATE_PAGEANIMATION', animation)
47 | },
48 | OPEN_PAGEANIMATION ({ commit }, isOpen) {
49 | setItem('cnblog.openPageAnimation', isOpen)
50 | commit('OPEN_PAGEANIMATION', isOpen)
51 | },
52 | GET_SERVECONF ({ commit }) {
53 | getConf().then(res => {
54 | if (res) {
55 | commit('GET_SERVECONF', res)
56 | }
57 | })
58 | },
59 | CLOSE_UPDATEAPP_NOTICE ({ commit }) {
60 | commit('CLOSE_UPDATEAPP_NOTICE')
61 | },
62 | CHANGE_THEME ({ commit }, theme) {
63 | setItem('cnblog.theme', theme)
64 | commit('CHANGE_THEME', theme)
65 | }
66 | }
67 |
68 | export const app = { namespaced: true, state: state, mutations: mutations, actions: actions }
69 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import { app } from './app'
4 | import { user } from './user'
5 | Vue.use(Vuex)
6 | export default new Vuex.Store({
7 | modules: {
8 | app,
9 | user
10 | }
11 | })
12 |
--------------------------------------------------------------------------------
/src/store/user.js:
--------------------------------------------------------------------------------
1 | import { getUser, removeUser, setUser, setBlogColl, unCollectBlog, getBlogColl } from '@/utils/user'
2 |
3 | const state = {
4 | user: getUser(),
5 | blog_coll: getBlogColl()
6 | }
7 |
8 | const mutations = {
9 | SET_USER (state, user) {
10 | state.user = user
11 | },
12 | REMOVE_USER (state) {
13 | state.user = null
14 | },
15 | COLLECT_BLOG (state, blog) {
16 | state.blog_coll.unshift(blog)
17 | setBlogColl(blog)
18 | },
19 | UNCOLLECT_BLOG (state, blog) {
20 | const index = state.blog_coll.findIndex(x => x.id === blog.id)
21 | if (index >= 0) {
22 | state.blog_coll.splice(index, 1)
23 | unCollectBlog(blog)
24 | }
25 | }
26 | }
27 |
28 | const actions = {
29 | SET_USER ({ commit }, user) {
30 | setUser(user)
31 | commit('SET_USER', user)
32 | },
33 | REMOVE_USER ({ commit }) {
34 | removeUser()
35 | commit('REMOVE_USER')
36 | },
37 | COLLECT_BLOG ({ commit }, blog) {
38 | commit('COLLECT_BLOG', blog)
39 | },
40 | UNCOLLECT_BLOG ({ commit }, blog) {
41 | commit('UNCOLLECT_BLOG', blog)
42 | }
43 | }
44 |
45 | export const user = { namespaced: true, state: state, mutations: mutations, actions: actions }
46 |
--------------------------------------------------------------------------------
/src/utils/$cookie.js:
--------------------------------------------------------------------------------
1 | export function setCookie (name, value) {
2 | var Days = 30
3 | var exp = new Date()
4 | exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000)
5 | document.cookie = name + '=' + escape(value) + ';expires=' + exp.toGMTString()
6 | }
7 |
8 | export function getCookie (name) {
9 | let reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)')
10 | let arr = document.cookie.match(reg)
11 | if (arr) {
12 | return unescape(arr[2])
13 | } else { return null }
14 | }
15 |
16 | export function delCookie (name) {
17 | var exp = new Date()
18 | exp.setTime(exp.getTime() - 1)
19 | var cval = getCookie(name)
20 | if (cval != null) { document.cookie = name + '=' + cval + ';expires=' + exp.toGMTString() }
21 | }
22 |
--------------------------------------------------------------------------------
/src/utils/$http.js:
--------------------------------------------------------------------------------
1 | import { WCF_API } from '../config/conf'
2 | import axios from 'axios'
3 |
4 | const instance = axios.create({
5 | baseURL: WCF_API,
6 | headers: {
7 | 'Content-Type': 'application/json'
8 | },
9 | timeout: 1000 * 60
10 | })
11 |
12 | instance.interceptors.request.use(function (config) {
13 | return config
14 | }, function (error) {
15 | return Promise.reject(error)
16 | })
17 |
18 | instance.interceptors.response.use(function (response) {
19 | return response.data
20 | }, function (error) {
21 | window.$vm.$toast({
22 | message: error.message
23 | })
24 | return Promise.reject(error)
25 | })
26 |
27 | export default instance
28 |
--------------------------------------------------------------------------------
/src/utils/$news.http.js:
--------------------------------------------------------------------------------
1 | import { NEWS_API } from '../config/conf'
2 | import axios from 'axios'
3 |
4 | const instance = axios.create({
5 | baseURL: NEWS_API,
6 | timeout: 1000 * 10,
7 | withCredentials: true
8 | })
9 |
10 | instance.interceptors.request.use(function (config) {
11 | config.headers['Accept'] = 'application/json'
12 | config.headers['Content-Type'] = 'application/json'
13 | return config
14 | }, function (error) {
15 | return Promise.reject(error)
16 | })
17 |
18 | instance.interceptors.response.use(function (response) {
19 | if (response.data.Message.indexOf('登录') >= 0) {
20 | response.data.Message = '请重新设置登录Cookie'
21 | }
22 | return response.data
23 | }, function (error) {
24 | window.$vm.$toast({
25 | message: error
26 | })
27 | return Promise.reject(error)
28 | })
29 |
30 | export default instance
31 |
--------------------------------------------------------------------------------
/src/utils/$official.http.js:
--------------------------------------------------------------------------------
1 | import { OFFICAL_API } from '../config/conf'
2 | import axios from 'axios'
3 |
4 | const instance = axios.create({
5 | baseURL: OFFICAL_API,
6 | timeout: 1000 * 10,
7 | withCredentials: true
8 | })
9 |
10 | instance.interceptors.request.use(function (config) {
11 | config.headers['Accept'] = 'application/json'
12 | config.headers['Content-Type'] = 'application/json'
13 |
14 | // loading 1.5s后太出现,请求快的话就不需要出现
15 | config.loadingTimeOut = setTimeout(() => {
16 | config.loading = window.$vm.$toast.loading({
17 | duration: 10000,
18 | forbidClick: true, // 禁用背景点击
19 | loadingType: 'spinner'
20 | })
21 | }, 500)
22 |
23 | return config
24 | }, function (error) {
25 | return Promise.reject(error)
26 | })
27 |
28 | instance.interceptors.response.use(function (response) {
29 | if (response.data.Message.indexOf('登录') >= 0) {
30 | response.data.Message = '请重新设置登录Cookie'
31 | }
32 | if (response.config.loading) {
33 | response.config.loading.clear()
34 | } else {
35 | clearTimeout(response.config.loadingTimeOut)
36 | }
37 | return response.data
38 | }, function (error) {
39 | window.$vm.$toast({
40 | message: error.message
41 | })
42 | if (error.config.loading) {
43 | error.config.loading.clear()
44 | } else {
45 | clearTimeout(error.config.loadingTimeOut)
46 | }
47 | return Promise.reject(error)
48 | })
49 |
50 | export default instance
51 |
--------------------------------------------------------------------------------
/src/utils/$storage.js:
--------------------------------------------------------------------------------
1 | export function getItem (key) {
2 | var data = window.localStorage.getItem(key)
3 | if (data) {
4 | var dataObj = JSON.parse(data)
5 | if (dataObj.type === 'string') {
6 | return dataObj.data
7 | } else if (dataObj.type === 'number') {
8 | return Number(dataObj.data)
9 | } else if (dataObj.type === 'object') {
10 | return JSON.parse(dataObj.data)
11 | } else if (dataObj.type === 'boolean') {
12 | return Boolean(dataObj.data)
13 | } else {
14 | return dataObj.data
15 | }
16 | } else {
17 | return null
18 | }
19 | }
20 |
21 | export function setItem (key, value) {
22 | let data = {
23 | type: '',
24 | data: null
25 | }
26 | if (typeof (value) === 'string') {
27 | data.type = 'string'
28 | data.data = value
29 | } else if (typeof (value) === 'number') {
30 | data.type = 'number'
31 | data.data = value
32 | } else if (typeof (value) === 'object') {
33 | data.type = 'object'
34 | data.data = JSON.stringify(value)
35 | } else if (typeof (value) === 'boolean') {
36 | data.type = 'boolean'
37 | data.data = value ? 1 : 0
38 | } else {
39 | data.type = 'unknow'
40 | data.data = value
41 | }
42 | window.localStorage.setItem(key, JSON.stringify(data))
43 | }
44 |
45 | export function clearItem (key) {
46 | window.localStorage.removeItem(key)
47 | }
48 |
--------------------------------------------------------------------------------
/src/utils/native.js:
--------------------------------------------------------------------------------
1 | export function copy (text, cb) {
2 | if (window.cordova && window.cordova.plugins.clipboard) {
3 | window.cordova.plugins.clipboard.copy(text)
4 | if (cb) {
5 | cb()
6 | }
7 | window.$vm.$toast({
8 | message: '复制成功'
9 | })
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/utils/user.js:
--------------------------------------------------------------------------------
1 | import { setItem, getItem, clearItem } from '@/utils/$storage'
2 | import { setCookie } from '@/utils/$cookie'
3 |
4 | export function setAuthCookie (cnblogsCookie) {
5 | // 存储到缓存
6 | setItem('cnblog.cookie', cnblogsCookie)
7 | // Cookie中添加
8 | if (window.cookieMaster) {
9 | window.cookieMaster.setCookieValue(
10 | 'www.cnblogs.com',
11 | '.CNBlogsCookie',
12 | cnblogsCookie
13 | )
14 | window.cookieMaster.setCookieValue('news.cnblogs.com', '.CNBlogsCookie', cnblogsCookie)
15 | } else {
16 | setCookie('.CNBlogsCookie', cnblogsCookie)
17 | }
18 | }
19 |
20 | export function initAuthCookie () {
21 | const cnblogsCookie = getItem('cnblog.cookie')
22 | if (cnblogsCookie) {
23 | if (window.cookieMaster) {
24 | window.cookieMaster.setCookieValue(
25 | 'www.cnblogs.com',
26 | '.CNBlogsCookie',
27 | cnblogsCookie
28 | )
29 | window.cookieMaster.setCookieValue('news.cnblogs.com', '.CNBlogsCookie', cnblogsCookie)
30 | } else {
31 | setCookie('.CNBlogsCookie', cnblogsCookie)
32 | }
33 | }
34 | }
35 |
36 | export function setUser (user) {
37 | setItem('cnblog.user', user)
38 | }
39 |
40 | export function removeUser (cookie) {
41 | clearItem('cnblog.user')
42 | }
43 |
44 | export function removeAuthCookie (cookie) {
45 | setAuthCookie('')
46 | }
47 |
48 | export function getUser () {
49 | return getItem('cnblog.user')
50 | }
51 |
52 | export function getBlogColl () {
53 | let coll = getItem('cnblog.blog.coll')
54 | return coll === null ? [] : coll
55 | }
56 |
57 | export function setBlogColl (blog) {
58 | let coll = getBlogColl()
59 | coll.unshift(blog)
60 | setItem('cnblog.blog.coll', coll)
61 | }
62 |
63 | export function unCollectBlog (blog) {
64 | let coll = getBlogColl()
65 | let index = coll.findIndex(x => x.id === blog.id)
66 | if (index >= 0) {
67 | coll.splice(index, 1)
68 | setItem('cnblog.blog.coll', coll)
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/views/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 | 中文名:张聪,英文名:Frank Zhang
9 |
10 |
11 |
12 |
15 |
16 | 因为没有翅膀,所以要努力奔跑
17 |
18 |
19 |
20 |
23 |
24 | 1992/02/02
25 |
26 |
27 |
28 |
31 |
32 | zc_smile@outlook.com
33 |
34 |
35 |
36 |
39 |
40 | https://github.com/FourLeafClover
41 |
42 |
43 |
44 |
47 |
48 | 骑自行车,旅游,回顾经典电视剧,电影
49 |
50 |
51 |
52 |
53 |
54 |
67 |
68 |
88 |
--------------------------------------------------------------------------------
/src/views/BlogApp.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 点击加载更多
8 |
9 |
10 |
11 |
--END--
12 |
13 |
14 |
15 |
16 |
66 |
67 |
75 |
--------------------------------------------------------------------------------
/src/views/BlogCollection.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{item.author}}
5 |
6 |
8 |
9 |
10 |
11 |
12 |
13 |
26 |
27 |
50 |
--------------------------------------------------------------------------------
/src/views/BlogDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
14 |
15 |
16 | showShare=true">
17 | 分享
18 |
19 |
20 |
21 | 评论
22 |
23 |
24 |
25 | 收藏
26 |
27 |
28 |
29 | 已收藏
30 |
31 |
32 |
33 | 推荐
34 |
35 |
36 |
37 |
38 |
39 |
46 |
51 |
52 |
59 |
60 |
61 |
62 |
233 |
234 |
310 |
--------------------------------------------------------------------------------
/src/views/BloggerRank.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
50 |
62 |
--------------------------------------------------------------------------------
/src/views/BloggerSearch.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
55 |
56 |
78 |
--------------------------------------------------------------------------------
/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | 点击加载更多
12 |
13 |
14 |
15 |
16 |
20 |
21 |
最近48小时阅读排行榜
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
110 |
111 |
161 |
--------------------------------------------------------------------------------
/src/views/News.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | 点击加载更多
12 |
13 |
14 | 加载完毕
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | 点击加载更多
23 |
24 |
25 | 加载完毕
26 |
27 |
28 |
29 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
138 |
139 |
188 |
--------------------------------------------------------------------------------
/src/views/NewsDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
14 | showShare=true">
15 | 分享
16 |
17 |
18 |
19 | 查看评论
20 |
21 |
22 |
23 |
24 |
25 |
32 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
114 |
115 |
174 |
--------------------------------------------------------------------------------
/src/views/Theme.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
20 |
21 |
30 |
--------------------------------------------------------------------------------
/src/views/User.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
16 | showLogin=true" is-link>
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | this.push('/theme')">
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | this.push('/about')">
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | 确定
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | 确定
63 |
64 |
65 |
66 |
67 |
68 |
69 | 登录名请使用个人资料里面的昵称
70 |
71 |
72 |
73 |
74 |
75 |
174 |
175 |
272 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | baseUrl: './',
3 | productionSourceMap: false,
4 | devServer: {
5 | port: 7878
6 | // 不再使用代理,在chrome中安装跨域插件
7 | /* proxy: {
8 | '/blog': {
9 | target: 'http://wcf.open.cnblogs.com',
10 | changeOrigin: true,
11 | secure: false
12 | },
13 | '/news': {
14 | target: 'http://wcf.open.cnblogs.com/',
15 | changeOrigin: true,
16 | secure: false
17 | },
18 | '/mvc': {
19 | target: 'https://www.cnblogs.com/mvc',
20 | changeOrigin: true,
21 | secure: false
22 | },
23 | '/Comment/InsertComment': {
24 | target: ' https://news.cnblogs.com',
25 | changeOrigin: true,
26 | secure: false
27 | },
28 | '/News/VoteNews': {
29 | target: ' https://news.cnblogs.com',
30 | changeOrigin: true,
31 | secure: false
32 | }
33 | } */
34 | },
35 | lintOnSave: false
36 | }
37 |
--------------------------------------------------------------------------------