├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── api │ ├── account.js │ ├── article.js │ ├── common.js │ ├── skill.js │ └── zone.js ├── assets │ ├── css │ │ ├── default.scss │ │ ├── mixin.scss │ │ └── reset.css │ ├── image │ │ ├── 404.jpg │ │ ├── Article-herader.jpg │ │ ├── Skill-header.jpg │ │ ├── active-acu.png │ │ ├── active-me.png │ │ ├── admin.png │ │ ├── bg.jpeg │ │ ├── blog.gif │ │ ├── github.jpg │ │ ├── normal-acu.png │ │ ├── normal-me.png │ │ ├── search.png │ │ ├── skill.png │ │ ├── touxiang.jpg │ │ ├── 书-2.png │ │ ├── 书.png │ │ ├── 奖杯.png │ │ ├── 文件.png │ │ ├── 日历.png │ │ ├── 星星.png │ │ ├── 检查.png │ │ ├── 灯泡.png │ │ ├── 蜡笔.png │ │ ├── 讲话气泡.png │ │ ├── 证书.png │ │ └── 铅笔.png │ └── js │ │ └── rem.js ├── components │ ├── count-up │ │ ├── count-to.vue │ │ └── index.js │ ├── dialogImg.vue │ ├── global.js │ ├── notFound.vue │ └── top │ │ └── index.vue ├── filters │ └── index.js ├── main.js ├── mixin │ ├── delTouch.js │ ├── loading.js │ └── touchMove.js ├── plugin │ ├── match-media │ │ ├── index.js │ │ ├── lib │ │ │ └── helper.js │ │ └── template │ │ │ └── mask.vue │ ├── top │ │ ├── index.js │ │ ├── lib │ │ │ └── helper.js │ │ └── template │ │ │ └── top.vue │ └── vue-load │ │ ├── index.js │ │ ├── lib │ │ ├── helper.js │ │ └── load.js │ │ └── template │ │ └── loading.vue ├── router │ ├── index.js │ └── routes.js ├── store │ ├── actions.js │ ├── index.js │ ├── mutation-types.js │ ├── mutations.js │ └── state.js ├── utils │ ├── code.js │ ├── fastClick.js │ ├── index.js │ ├── jsonp.js │ ├── request.js │ └── touchMove.js └── views │ ├── Article │ ├── List.vue │ ├── body │ │ ├── DesignPattern.vue │ │ ├── QuestionsCSS.vue │ │ ├── QuesttionsJS.vue │ │ └── vertualDom.vue │ ├── content │ │ └── index.vue │ └── index.vue │ ├── Home │ ├── Card │ │ ├── Calendar.vue │ │ ├── MenuIcon.vue │ │ └── index.vue │ └── index.vue │ ├── Menu │ ├── Me.vue │ ├── Nav.vue │ └── index.vue │ ├── Skill │ └── index.vue │ └── Zone │ ├── Acu.vue │ ├── Me.vue │ ├── Tabar.vue │ ├── TreeMenu.vue │ └── index.vue ├── study ├── Questions │ ├── index.css │ ├── index.html │ ├── 二分查找.js │ ├── 原型.js │ ├── 工厂模式.js │ ├── 设计模式之原型模式.js │ └── 设计模式之构建者模式.js └── diffDom │ ├── diffDom.js │ ├── index.html │ └── vertualDom.js ├── test.js └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | extends: ["plugin:vue/essential", "@vue/prettier"], 7 | rules: { 8 | "no-console": process.env.NODE_ENV === "production" ? "error" : "off", 9 | "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off" 10 | }, 11 | parserOptions: { 12 | parser: "babel-eslint" 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /.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 | ![image](https://github.com/z253573760/vue-blog/blob/master/src/assets/image/github.jpg?raw=true) 2 | 3 | ## vue-blog 4 | 5 | 前后端分离的个人博客 🛠️ 6 | 在线访问: 7 | [移动端](http://cc.ztsky.cn) 8 | [PC 端](http://cc.ztsky.cn:8011) 9 | 10 | ## 技术栈 11 | 12 | ``` 13 | 移动端: vue-cli3 vue2.x vant-ui 14 | PC 端 umi react antd-ui 15 | admin: vue-cli3 vue2.x element-ui 16 | 服务器: egg sequelize mysql redis nginx 17 | ``` 18 | 19 | ## 运行 20 | 21 | ``` 22 | 所需环境 node 23 | 下载依赖:npm install 24 | 项目启动:npm run serve 打开 localhost:8010 25 | 项目打包:npm run build 26 | ``` 27 | 28 | ## 客户端效果 29 | 30 | ![image](https://github.com/z253573760/vue-blog/blob/master/src/assets/image/blog.gif?raw=true) 31 | 32 | ## 后台管理 33 | 34 | ![image](https://github.com/z253573760/vue-blog/blob/master/src/assets/image/admin.png?raw=true) 35 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/app"] 3 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve ", 7 | "build": "vue-cli-service build", 8 | "build-load": "vue-cli-service build --target lib --name vue-load src/plugin/vue-load/index.js", 9 | "lint": "vue-cli-service lint" 10 | }, 11 | "dependencies": { 12 | "animate.css": "^3.7.0", 13 | "axios": "^0.18.0", 14 | "babel-preset-es2015": "^6.24.1", 15 | "countup": "^1.8.2", 16 | "fastclick": "^1.0.6", 17 | "mavon-editor": "^2.6.17", 18 | "optimize-css-assets-webpack-plugin": "^5.0.1", 19 | "postcss-px2rem": "^0.3.0", 20 | "uglifyjs-webpack-plugin": "1.3.0", 21 | "vant": "^1.4.8", 22 | "vue": "^2.5.17", 23 | "vue-js-grid": "^1.0.1", 24 | "vue-particles": "^1.0.9", 25 | "vue-router": "^3.0.1", 26 | "vuex": "^3.0.1" 27 | }, 28 | "devDependencies": { 29 | "@vue/cli-plugin-babel": "^3.0.3", 30 | "@vue/cli-plugin-eslint": "^3.0.3", 31 | "@vue/cli-service": "^3.0.3", 32 | "@vue/eslint-config-prettier": "^3.0.3", 33 | "babel-plugin-import": "^1.8.0", 34 | "babel-polyfill": "^6.26.0", 35 | "node-sass": "^4.9.3", 36 | "sass-loader": "^7.1.0", 37 | "vue-template-compiler": "^2.5.17" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | "postcss-px2rem": { 5 | remUnit: 37.5 6 | } 7 | } 8 | }; -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 灿灿's Blog 19 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 29 | 95 | 96 | 129 | -------------------------------------------------------------------------------- /src/api/account.js: -------------------------------------------------------------------------------- 1 | import axios from "../utils/request"; 2 | 3 | export const getUserInfo = function() { 4 | return axios.get(`/account/info`); 5 | }; 6 | -------------------------------------------------------------------------------- /src/api/article.js: -------------------------------------------------------------------------------- 1 | import axios from "../utils/request"; 2 | import qs from "qs"; 3 | export const getArticleList = function (pageOpts) { 4 | return axios.get(`/article?${qs.stringify(pageOpts)}`); 5 | }; 6 | 7 | export const getArticle = function (id) { 8 | return axios.get(`/article/${id}`); 9 | }; -------------------------------------------------------------------------------- /src/api/common.js: -------------------------------------------------------------------------------- 1 | import axios from "../utils/request"; 2 | 3 | export const getIp = function() { 4 | return axios.get(`/ip`); 5 | }; 6 | 7 | export const getWether = function() { 8 | return axios.get(`/wether`); 9 | }; 10 | -------------------------------------------------------------------------------- /src/api/skill.js: -------------------------------------------------------------------------------- 1 | import axios from "../utils/request"; 2 | 3 | export const getSkillList = function() { 4 | return axios.get(`/skill`); 5 | }; 6 | -------------------------------------------------------------------------------- /src/api/zone.js: -------------------------------------------------------------------------------- 1 | import axios from "../utils/request"; 2 | import qs from "qs"; 3 | export const getZoneList = function (pageSize, current) { 4 | const params = { pageSize, current }; 5 | return axios.get(`/zone?${qs.stringify(params)}`); 6 | }; 7 | -------------------------------------------------------------------------------- /src/assets/css/default.scss: -------------------------------------------------------------------------------- 1 | @function px2rem($px){ 2 | $rem: 37.5px; 3 | @return($px/$rem) + rem 4 | }; 5 | 6 | $fontSize:px2rem(16px); 7 | -------------------------------------------------------------------------------- /src/assets/css/mixin.scss: -------------------------------------------------------------------------------- 1 | @import "./default.scss"; 2 | 3 | .bg { 4 | height: 100%; 5 | background-size: 100% 100%; 6 | text-align: center; 7 | padding: px2rem(80px); 8 | } -------------------------------------------------------------------------------- /src/assets/css/reset.css: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-box-sizing: border-box; 3 | -moz-box-sizing: border-box; 4 | box-sizing: border-box; 5 | } 6 | *:before, 7 | *:after { 8 | -webkit-box-sizing: border-box; 9 | -moz-box-sizing: border-box; 10 | box-sizing: border-box; 11 | } 12 | body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, button, textarea, p, blockquote, th, td { 13 | margin: 0; 14 | padding: 0; 15 | } 16 | body,html{ 17 | background: #fff; 18 | color: #555; 19 | font-size: 14px; 20 | height:100%; 21 | width:100%; 22 | font-family: "Arial", "Microsoft YaHei", "黑体", "宋体", sans-serif; 23 | } 24 | td, th, caption { 25 | font-size: 14px; 26 | } 27 | h1, h2, h3, h4, h5, h6 { 28 | font-weight: normal; 29 | font-size: 100%; 30 | } 31 | address, caption, cite, code, dfn, em, strong, th, var { 32 | font-style: normal; 33 | font-weight: normal; 34 | } 35 | a { 36 | color: #555; 37 | text-decoration: none; 38 | } 39 | a:hover { 40 | text-decoration: underline; 41 | } 42 | img { 43 | border: none; 44 | vertical-align: middle; 45 | } 46 | ol, ul, li { 47 | list-style: none; 48 | } 49 | input, textarea, select, button { 50 | font: 14px "Arial", "Microsoft YaHei", "黑体", "宋体", sans-serif; 51 | } 52 | table { 53 | border-collapse: collapse; 54 | } 55 | html { 56 | overflow-y: scroll; 57 | } 58 | .clearfix:before, 59 | .clearfix:after { 60 | content: " "; 61 | display: inline-block; 62 | height: 0; 63 | clear: both; 64 | visibility: hidden; 65 | } 66 | .clearfix { 67 | *zoom: 1; 68 | } 69 | 70 | /*公共类*/ 71 | .fl { 72 | float: left 73 | } 74 | .fr { 75 | float: right 76 | } 77 | .al { 78 | text-align: left 79 | } 80 | .ac { 81 | text-align: center 82 | } 83 | .ar { 84 | text-align: right 85 | } 86 | .hide { 87 | display: none 88 | } -------------------------------------------------------------------------------- /src/assets/image/404.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/404.jpg -------------------------------------------------------------------------------- /src/assets/image/Article-herader.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/Article-herader.jpg -------------------------------------------------------------------------------- /src/assets/image/Skill-header.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/Skill-header.jpg -------------------------------------------------------------------------------- /src/assets/image/active-acu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/active-acu.png -------------------------------------------------------------------------------- /src/assets/image/active-me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/active-me.png -------------------------------------------------------------------------------- /src/assets/image/admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/admin.png -------------------------------------------------------------------------------- /src/assets/image/bg.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/bg.jpeg -------------------------------------------------------------------------------- /src/assets/image/blog.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/blog.gif -------------------------------------------------------------------------------- /src/assets/image/github.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/github.jpg -------------------------------------------------------------------------------- /src/assets/image/normal-acu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/normal-acu.png -------------------------------------------------------------------------------- /src/assets/image/normal-me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/normal-me.png -------------------------------------------------------------------------------- /src/assets/image/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/search.png -------------------------------------------------------------------------------- /src/assets/image/skill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/skill.png -------------------------------------------------------------------------------- /src/assets/image/touxiang.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/touxiang.jpg -------------------------------------------------------------------------------- /src/assets/image/书-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/书-2.png -------------------------------------------------------------------------------- /src/assets/image/书.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/书.png -------------------------------------------------------------------------------- /src/assets/image/奖杯.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/奖杯.png -------------------------------------------------------------------------------- /src/assets/image/文件.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/文件.png -------------------------------------------------------------------------------- /src/assets/image/日历.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/日历.png -------------------------------------------------------------------------------- /src/assets/image/星星.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/星星.png -------------------------------------------------------------------------------- /src/assets/image/检查.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/检查.png -------------------------------------------------------------------------------- /src/assets/image/灯泡.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/灯泡.png -------------------------------------------------------------------------------- /src/assets/image/蜡笔.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/蜡笔.png -------------------------------------------------------------------------------- /src/assets/image/讲话气泡.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/讲话气泡.png -------------------------------------------------------------------------------- /src/assets/image/证书.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/证书.png -------------------------------------------------------------------------------- /src/assets/image/铅笔.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z253573760/vue-blog/7c3396427bc3e9783b0a95c0e59db86d710d7bef/src/assets/image/铅笔.png -------------------------------------------------------------------------------- /src/assets/js/rem.js: -------------------------------------------------------------------------------- 1 | // !(function(n, e) { 2 | // var t = n.documentElement, 3 | // i = "orientationchange" in window ? "orientationchange" : "resize", 4 | // d = function() { 5 | // var n = t.clientWidth; 6 | // //n && (t.style.fontSize = (n > 750 ? 750 : n) / 750 * 100 + "px") 7 | // n && (t.style.fontSize = (n / 750) * 100 + "px"); 8 | // }; 9 | // n.addEventListener && 10 | // (e.addEventListener(i, d, !1), 11 | // d(), 12 | // n.addEventListener("DOMContentLoaded", d, !1)); 13 | // })(document, window); 14 | !(function(doc, win) { 15 | var docEl = doc.documentElement, 16 | resizeEvt = "orientationchange" in window ? "orientationchange" : "resize", 17 | recalc = function() { 18 | var clientWidth = docEl.clientWidth; 19 | if (!clientWidth) return; 20 | docEl.style.fontSize = 20 * (clientWidth / 320) + "px"; 21 | }; 22 | if (!doc.addEventListener) return; 23 | win.addEventListener(resizeEvt, recalc, false); 24 | doc.addEventListener("DOMContentLoaded", recalc, false); 25 | })(document, window); 26 | -------------------------------------------------------------------------------- /src/components/count-up/count-to.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 202 | 249 | -------------------------------------------------------------------------------- /src/components/count-up/index.js: -------------------------------------------------------------------------------- 1 | import countTo from "./count-to.vue"; 2 | export default countTo; 3 | -------------------------------------------------------------------------------- /src/components/dialogImg.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 21 | 25 | -------------------------------------------------------------------------------- /src/components/global.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | 3 | function capitalizeFirstLetter(string) { 4 | return string.charAt(0).toUpperCase() + string.slice(1); 5 | } 6 | 7 | const requireComponent = require.context( 8 | ".", 9 | false, 10 | /\.vue$/ 11 | //找到components文件夹下以.vue命名的文件 12 | ); 13 | 14 | requireComponent.keys().forEach(fileName => { 15 | const componentConfig = requireComponent(fileName); 16 | 17 | const componentName = capitalizeFirstLetter( 18 | fileName.replace(/^\.\//, "").replace(/\.\w+$/, "") 19 | //因为得到的filename格式是: './baseButton.vue', 所以这里我们去掉头和尾,只保留真正的文件名 20 | ); 21 | 22 | Vue.component(componentName, componentConfig.default || componentConfig); 23 | }); 24 | -------------------------------------------------------------------------------- /src/components/notFound.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | 16 | 17 | 25 | -------------------------------------------------------------------------------- /src/components/top/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 46 | 69 | -------------------------------------------------------------------------------- /src/filters/index.js: -------------------------------------------------------------------------------- 1 | export const fmtDate = function (obj) { 2 | var date = new Date(obj); 3 | var y = 1900 + date.getYear(); 4 | var m = "0" + (date.getMonth() + 1); 5 | var d = "0" + date.getDate(); 6 | return y + "-" + m.substring(m.length - 2, m.length) + "-" + d.substring(d.length - 2, d.length); 7 | } -------------------------------------------------------------------------------- /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 Vant from "vant"; 6 | import VueParticles from "vue-particles"; 7 | import "@/assets/css/reset.css"; 8 | import "@/assets/css/mixin.scss"; 9 | import "@/assets/js/rem.js"; 10 | import "@/utils/fastClick.js"; 11 | import "@/components/global.js"; 12 | import Grid from "vue-js-grid"; 13 | import * as filters from "./filters"; 14 | import mavonEditor from "mavon-editor"; 15 | import "mavon-editor/dist/css/index.css"; 16 | 17 | 18 | //自己封装的插件 19 | import Loading from "@/plugin/vue-load"; 20 | import MatchMedia from "@/plugin/match-media"; 21 | import Top from "@/plugin/top"; 22 | Vue.use(mavonEditor); 23 | Vue.use(Loading); 24 | Vue.use(MatchMedia); 25 | Vue.use(Top); 26 | Vue.use(Grid); 27 | Vue.use(Vant); 28 | Vue.use(VueParticles); 29 | 30 | Object.keys(filters).forEach(key => { 31 | Vue.filter(key, filters[key]); 32 | }); 33 | 34 | Vue.directive("color", { 35 | bind(el, bindding) { 36 | el.style.color = bindding.value; 37 | } 38 | }); 39 | 40 | Vue.config.productionTip = false; 41 | const vue = new Vue({ 42 | router, 43 | store, 44 | render: h => h(App) 45 | }).$mount("#app"); 46 | 47 | window.vue = vue; -------------------------------------------------------------------------------- /src/mixin/delTouch.js: -------------------------------------------------------------------------------- 1 | import handler from "@/utils/touchMove"; 2 | 3 | const delTouch = { 4 | created() { 5 | document.body.removeEventListener("touchmove", handler, false); 6 | }, 7 | activated() { 8 | document.body.removeEventListener("touchmove", handler, false); 9 | } 10 | }; 11 | export default delTouch; 12 | -------------------------------------------------------------------------------- /src/mixin/loading.js: -------------------------------------------------------------------------------- 1 | const loadding = { 2 | created() { 3 | this.$loading.show(); 4 | setTimeout(() => this.$loading.hide(), 1000); 5 | } 6 | }; 7 | export default loadding; 8 | -------------------------------------------------------------------------------- /src/mixin/touchMove.js: -------------------------------------------------------------------------------- 1 | import handler from "@/utils/touchMove"; 2 | 3 | const touchMove = { 4 | created() { 5 | document.body.addEventListener("touchmove", handler, false); 6 | }, 7 | activated() { 8 | document.body.addEventListener("touchmove", handler, false); 9 | } 10 | }; 11 | export default touchMove; 12 | -------------------------------------------------------------------------------- /src/plugin/match-media/index.js: -------------------------------------------------------------------------------- 1 | import Mask from "./template/mask"; 2 | const loadingPlugin = { 3 | install(Vue) { 4 | const MaskVue = Vue.extend(Mask); 5 | const $vm = new MaskVue({ 6 | el: document.createElement("div") 7 | }); 8 | 9 | document.body.appendChild($vm.$el); 10 | } 11 | }; 12 | export default loadingPlugin; 13 | -------------------------------------------------------------------------------- /src/plugin/match-media/lib/helper.js: -------------------------------------------------------------------------------- 1 | export function orientate(vm) { 2 | window.addEventListener( 3 | "onorientationchange" in window ? "orientationchange" : "resize", 4 | () => { 5 | if (window.orientation === 180 || window.orientation === 0) { 6 | // "竖屏状态! 7 | vm.show = false; 8 | } 9 | if (window.orientation === 90 || window.orientation === -90) { 10 | // "横屏屏状态! 11 | vm.show = true; 12 | } 13 | }, 14 | false 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/plugin/match-media/template/mask.vue: -------------------------------------------------------------------------------- 1 | 8 | 42 | 60 | -------------------------------------------------------------------------------- /src/plugin/top/index.js: -------------------------------------------------------------------------------- 1 | import Top from "./template/top"; 2 | const loadingPlugin = { 3 | install(Vue) { 4 | const TopVue = Vue.extend(Top); 5 | const $vm = new TopVue({ 6 | el: document.createElement("div") 7 | }); 8 | 9 | document.body.appendChild($vm.$el); 10 | } 11 | }; 12 | export default loadingPlugin; -------------------------------------------------------------------------------- /src/plugin/top/lib/helper.js: -------------------------------------------------------------------------------- 1 | export function smoothScroll() { 2 | const currentScroll = 3 | document.documentElement.scrollTop || document.body.scrollTop; 4 | if (currentScroll > 0) { 5 | window.requestAnimationFrame(smoothScroll); 6 | window.scrollTo(0, currentScroll - currentScroll / 5); 7 | } 8 | } -------------------------------------------------------------------------------- /src/plugin/top/template/top.vue: -------------------------------------------------------------------------------- 1 | 7 | 46 | 70 | -------------------------------------------------------------------------------- /src/plugin/vue-load/index.js: -------------------------------------------------------------------------------- 1 | import load from "./lib/load"; 2 | const loadingPlugin = { 3 | install(Vue) { 4 | load(Vue); 5 | } 6 | }; 7 | export default loadingPlugin; 8 | -------------------------------------------------------------------------------- /src/plugin/vue-load/lib/helper.js: -------------------------------------------------------------------------------- 1 | export function isString(str) { 2 | return Object.prototype.toString.call(str) === "[object string]"; 3 | } 4 | -------------------------------------------------------------------------------- /src/plugin/vue-load/lib/load.js: -------------------------------------------------------------------------------- 1 | import Load from "../template/loading"; 2 | export default function(Vue) { 3 | const Loading = Vue.extend(Load); 4 | const $vm = new Loading({ 5 | el: document.createElement("div") 6 | }); 7 | document.body.appendChild($vm.$el); 8 | const loading = { 9 | show() { 10 | $vm.show = true; 11 | }, 12 | hide() { 13 | $vm.show = false; 14 | } 15 | }; 16 | Vue.prototype.$loading = loading; 17 | } 18 | -------------------------------------------------------------------------------- /src/plugin/vue-load/template/loading.vue: -------------------------------------------------------------------------------- 1 | 11 | 21 | 102 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Router from "vue-router"; 3 | import routes from "./routes"; 4 | Vue.use(Router); 5 | 6 | export default new Router({ 7 | mode: "history", 8 | base: process.env.BASE_URL, 9 | routes 10 | }); 11 | -------------------------------------------------------------------------------- /src/router/routes.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | path: "/", 4 | // redirect: "/home", 5 | name: "home", 6 | meta: { 7 | title: "首页", 8 | icon: require("@/assets/image/日历.png") 9 | }, 10 | component: () => import("@/views/Home") 11 | }, 12 | { 13 | path: "*", 14 | redirect: "/" 15 | }, 16 | { 17 | path: "/404", 18 | name: "notFound", 19 | component: () => import("@/components/notFound") 20 | }, 21 | { 22 | path: "/skill", 23 | name: "skill", 24 | meta: { 25 | title: "学习", 26 | icon: require("@/assets/image/铅笔.png") 27 | }, 28 | component: () => import("@/views/Skill") 29 | }, 30 | { 31 | path: "/zone", 32 | name: "zone", 33 | meta: { 34 | title: "Zone", 35 | icon: require("@/assets/image/星星.png") 36 | }, 37 | component: () => import("@/views/Zone"), 38 | children: [ 39 | { 40 | path: "/", 41 | component: () => import("@/views/Zone/Acu") 42 | }, 43 | { 44 | path: "me", 45 | component: () => import("@/views/Zone/Me") 46 | } 47 | ] 48 | }, 49 | { 50 | path: "/article", 51 | name: "article", 52 | meta: { 53 | title: "笔记", 54 | icon: require("@/assets/image/书.png") 55 | }, 56 | component: () => import("@/views/Article"), 57 | children: [ 58 | { 59 | path: "/", 60 | component: () => import("@/views/Article/List") 61 | }, 62 | { 63 | path: ":id", 64 | component: () => import("@/views/Article/content/index") 65 | } 66 | ] 67 | }, 68 | { 69 | path: "component", 70 | name: "component", 71 | meta: { 72 | title: "暂无", 73 | icon: require("@/assets/image/蜡笔.png") 74 | } 75 | // component: () => import("@/views/Article") 76 | } 77 | ]; 78 | -------------------------------------------------------------------------------- /src/store/actions.js: -------------------------------------------------------------------------------- 1 | import { getIp } from "@/api/common"; 2 | import { getUserInfo } from "@/api/account"; 3 | const actions = { 4 | async getIp({ commit }) { 5 | const { data } = await getIp(); 6 | commit("saveIp", data); 7 | }, 8 | async getUser({ commit }) { 9 | const { 10 | data: { info } 11 | } = await getUserInfo(); 12 | commit("saveUser", info); 13 | } 14 | }; 15 | export default actions; 16 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | import state from "./state"; 4 | import mutations from "./mutations"; 5 | import actions from "./actions"; 6 | Vue.use(Vuex); 7 | 8 | export default new Vuex.Store({ 9 | state, 10 | mutations, 11 | actions 12 | }); 13 | -------------------------------------------------------------------------------- /src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const CHANGE_MENU = "CHANGE_MENU"; 2 | -------------------------------------------------------------------------------- /src/store/mutations.js: -------------------------------------------------------------------------------- 1 | import * as types from "./mutation-types"; 2 | const mutations = { 3 | [types.CHANGE_MENU](state) { 4 | state.menuShow = !state.menuShow; 5 | }, 6 | saveSubjects(state, data) { 7 | state.subjectList = data; 8 | }, 9 | saveIp(state, data) { 10 | state.count = data.count; 11 | state.isNew = data.isNew; 12 | state.ip = data; 13 | }, 14 | saveUser(state, data) { 15 | state.user = data; 16 | }, 17 | changeNavShow(state, data) { 18 | state.navShow = data; 19 | } 20 | }; 21 | 22 | export default mutations; 23 | -------------------------------------------------------------------------------- /src/store/state.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | menuShow: false, 3 | subjectList: [], 4 | count: 0, 5 | isNew: false, 6 | navShow: true, 7 | ip: { 8 | city: "厦门", 9 | region: "福建" 10 | }, 11 | user: { 12 | address: "", 13 | avatar: "", 14 | nick_name: "", 15 | remark: "", 16 | job: "" 17 | } 18 | }; 19 | 20 | export default state; 21 | -------------------------------------------------------------------------------- /src/utils/code.js: -------------------------------------------------------------------------------- 1 | export const SUCCESS = 0; 2 | export const ERROR = 1; 3 | -------------------------------------------------------------------------------- /src/utils/fastClick.js: -------------------------------------------------------------------------------- 1 | import FastClick from "fastclick"; //vue框架开发H5正确运用fastclick 2 | 3 | // if ("addEventListener" in document) { 4 | // document.addEventListener( 5 | // "DOMContentLoaded", 6 | // function() { 7 | // FastClick.attach(document.body); 8 | // }, 9 | // false 10 | // ); 11 | // } 12 | FastClick.attach(document.body); 13 | -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | export const fmtDate = function (obj) { 2 | var date = new Date(obj); 3 | var y = 1900 + date.getYear(); 4 | var m = "0" + (date.getMonth() + 1); 5 | var d = "0" + date.getDate(); 6 | return ( 7 | y + 8 | "-" + 9 | m.substring(m.length - 2, m.length) + 10 | "-" + 11 | d.substring(d.length - 2, d.length) 12 | ); 13 | }; 14 | 15 | 16 | function smoothScroll() { 17 | const currentScroll = 18 | document.documentElement.scrollTop || document.body.scrollTop; 19 | if (currentScroll > 0) { 20 | window.requestAnimationFrame(smoothScroll); 21 | window.scrollTo(0, currentScroll - currentScroll / 5); 22 | } 23 | } 24 | export const goScrollTop = smoothScroll -------------------------------------------------------------------------------- /src/utils/jsonp.js: -------------------------------------------------------------------------------- 1 | import orginJSONP from "jsonp"; 2 | import qs from "qs"; 3 | export default function jsonp(url, data, option) { 4 | url = `${url}?${qs.stringify(data)}`; 5 | return new Promise((resolve, reject) => { 6 | orginJSONP(url, option, (err, data) => { 7 | if (!err) { 8 | resolve(data); 9 | } else { 10 | reject(err); 11 | } 12 | }); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /src/utils/request.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | import { 4 | Notify 5 | } from "vant"; 6 | import router from "../router"; 7 | import { 8 | ERROR, 9 | SUCCESS 10 | } from "@/utils/code"; 11 | axios.defaults.timeout = 10000; 12 | // const baseURL = 13 | // process.env.NODE_ENV === "development" 14 | // ? "/api" 15 | // : "http://www.zhoucanyu.cn/api"; 16 | axios.defaults.baseURL = "/api"; 17 | axios.defaults.headers.post["Content-Type"] = 18 | "application/x-www-form-urlencoded"; 19 | 20 | axios.interceptors.request.use( 21 | function (config) { 22 | // 在发送请求之前做些什么 23 | //config.headers['X-Token'] = getToken() // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改 24 | return config; 25 | }, 26 | function (error) { 27 | return Promise.reject(error); 28 | } 29 | ); 30 | axios.interceptors.response.use( 31 | function (response) { 32 | if (!(response.status >= 200 && response.status < 300)) { 33 | return response; 34 | } 35 | if (response.data.code !== SUCCESS) { 36 | window.vue.$loading.hide(); 37 | Notify("服务器错误"); 38 | throw "服务器错误"; 39 | } 40 | return response.data; 41 | }, 42 | function (error) { 43 | return Promise.reject(error); 44 | } 45 | ); 46 | 47 | export default axios; -------------------------------------------------------------------------------- /src/utils/touchMove.js: -------------------------------------------------------------------------------- 1 | function handler(event) { 2 | event.preventDefault(); 3 | } 4 | // window.onload = function() { 5 | // document.body.addEventListener("touchmove", handler, false); 6 | // }; 7 | export default handler; 8 | -------------------------------------------------------------------------------- /src/views/Article/List.vue: -------------------------------------------------------------------------------- 1 | 12 | 52 | 70 | 71 | -------------------------------------------------------------------------------- /src/views/Article/body/DesignPattern.vue: -------------------------------------------------------------------------------- 1 | 14 | 23 | 44 | -------------------------------------------------------------------------------- /src/views/Article/body/QuestionsCSS.vue: -------------------------------------------------------------------------------- 1 | 16 | 25 | 46 | -------------------------------------------------------------------------------- /src/views/Article/body/QuesttionsJS.vue: -------------------------------------------------------------------------------- 1 | 18 | 27 | 48 | -------------------------------------------------------------------------------- /src/views/Article/body/vertualDom.vue: -------------------------------------------------------------------------------- 1 | 18 | 40 | 70 | -------------------------------------------------------------------------------- /src/views/Article/content/index.vue: -------------------------------------------------------------------------------- 1 | 21 | 63 | 92 | -------------------------------------------------------------------------------- /src/views/Article/index.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 27 | 28 | 56 | -------------------------------------------------------------------------------- /src/views/Home/Card/Calendar.vue: -------------------------------------------------------------------------------- 1 | 13 | 53 | 100 | -------------------------------------------------------------------------------- /src/views/Home/Card/MenuIcon.vue: -------------------------------------------------------------------------------- 1 | 21 | 38 | 68 | -------------------------------------------------------------------------------- /src/views/Home/Card/index.vue: -------------------------------------------------------------------------------- 1 | 21 | 46 | 81 | -------------------------------------------------------------------------------- /src/views/Home/index.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 31 | 48 | -------------------------------------------------------------------------------- /src/views/Menu/Me.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 30 | 31 | 51 | -------------------------------------------------------------------------------- /src/views/Menu/Nav.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 38 | 39 | 69 | -------------------------------------------------------------------------------- /src/views/Menu/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | 20 | 29 | -------------------------------------------------------------------------------- /src/views/Skill/index.vue: -------------------------------------------------------------------------------- 1 | 26 | 58 | 59 | 102 | -------------------------------------------------------------------------------- /src/views/Zone/Acu.vue: -------------------------------------------------------------------------------- 1 | 15 | 60 | 61 | 77 | -------------------------------------------------------------------------------- /src/views/Zone/Me.vue: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 48 | 49 | 57 | -------------------------------------------------------------------------------- /src/views/Zone/Tabar.vue: -------------------------------------------------------------------------------- 1 | 15 | 39 | 53 | -------------------------------------------------------------------------------- /src/views/Zone/TreeMenu.vue: -------------------------------------------------------------------------------- 1 | 27 | 61 | 85 | -------------------------------------------------------------------------------- /src/views/Zone/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 56 | 64 | -------------------------------------------------------------------------------- /study/Questions/index.css: -------------------------------------------------------------------------------- 1 | /* 1.CSS的盒模型,绝对定位和相对定位 */ 2 | box-sizing属性可以为三个值之一. 3 | content-box[default]: border和padding不计算入width之内 4 | border-box : padding计算入width内 5 | padding-box: border和padding计算入width之内,其实就是怪异模式了 6 | 7 | 绝对定位相对定位 都是相对于父级元素所做的位移动,只不过绝对定位会 8 | 脱离文档流 9 | 10 | 1.利用flexbox布局 11 | 2.利用绝对定位与transform 12 | 3.利用定位与margin:auto 13 | 4.margin-left:0 margin-left:0 14 | 15 | 1.样式的层级关系:公有样式,私有样式 16 | 2.选择器优先级:(!important>)id选择器> 17 | class选择器(属性选择器/伪类选择器)>标签选择器(伪元素选择器) 18 | 3.样式冲突:如果同个元素有两个或以上冲突的CSS规则 19 | 20 | 1.px:浏览器像素单位 21 | 2.em:继承父级元素的字体大小 22 | 3.rem:相对HTML根节点 23 | 4.:link加载优先@import,@import可以同时加载其他CSS -------------------------------------------------------------------------------- /study/Questions/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 | 12 |
13 |

14 |

15 |

16 |

17 |

18 |

19 |

20 |
21 | 22 | 23 | 24 | 52 | 53 | -------------------------------------------------------------------------------- /study/Questions/二分查找.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 二分查找 3 | * @param {*} arr 4 | * @param {*} item 5 | * @param {*} start 6 | * @param {*} end 7 | */ 8 | 9 | function findIndex(arr, item, start = 0, end = arr.length - 1) { 10 | if (start >= end) { 11 | return -1; 12 | } 13 | const midd = parseInt((start + end) / 2); 14 | if (arr[midd] === item) { 15 | return midd; 16 | } 17 | if (item < arr[midd]) { 18 | return findIndex(arr, item, start, midd - 1); 19 | } else { 20 | return findIndex(arr, item, midd + 1, end); 21 | } 22 | } 23 | const result = findIndex([1, 2, 3, 4, 5], 3); 24 | 25 | /** 26 | * 快排 27 | */ 28 | function qucikSort(_arr) { 29 | if (_arr.length < 1) return _arr; 30 | // const midd = parseInt(arr.length / 2); 31 | const [base, ...arr] = _arr; 32 | const left = []; 33 | const right = []; 34 | for (const item of arr) { 35 | if (item < base) left.push(item); 36 | else right.push(item); 37 | } 38 | return [...qucikSort(left), base, ...qucikSort(right)]; 39 | } 40 | const arr = qucikSort([3, 9, 5, 2, 4, -1]); 41 | console.log(arr); 42 | /** 43 | * 冒泡 44 | */ 45 | function bubbleSort(arr) { 46 | for (let i = 0; i < arr.length; i++) { 47 | for (let j = 0; j < arr.length - 1 - i; j++) { 48 | if (arr[j] > arr[j + 1]) { 49 | [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; 50 | } 51 | } 52 | } 53 | return arr; 54 | } 55 | const arr2 = bubbleSort([3, 9, 5, 2, 4, -1]); 56 | console.log(arr2); 57 | -------------------------------------------------------------------------------- /study/Questions/原型.js: -------------------------------------------------------------------------------- 1 | let _undefined; 2 | console.log(_undefined); //undefined 3 | const num = 1; 4 | console.log(num); //1 5 | const str = "helloworld"; 6 | console.log(str); //"helloworld" 7 | const bool = false || true; 8 | console.log(bool); //true 9 | // 以上为基础类型 原始数据类型 10 | const arr = []; 11 | console.log(arr); //[] 12 | const obj = { a: 1 }; 13 | console.log(obj); //{ a: 1 }; 14 | function name(params) { 15 | return params; 16 | } 17 | console.log(name); 18 | // 以上为引用类型 19 | 20 | console.log(null === false); //false 21 | console.log(null === true); //false 22 | console.log(undefined === false); //false 23 | console.log(undefined === true); //false 24 | console.log(undefined === null); //false 25 | console.log(undefined === undefined); //true 26 | console.log(null === null); //true 27 | /** 28 | * null表示空指针对象 且typeof(null) == 'object' 29 | * undefined 表示声明未定义 30 | */ 31 | const _null = null; 32 | let __undefined; 33 | if (_null || __undefined) { 34 | console.log("null 和 undefined 在逻辑运算符中均为false"); 35 | } 36 | console.log("-----------------"); 37 | console.log(1 === Number(1)); 38 | var a = Number(1); // 1 39 | var b = new Number(1); // Number {[[PrimitiveValue]]: 1} 40 | var c = 1; 41 | console.log(typeof a); // number 42 | console.log(typeof b); // object 由构造函数构建的是一个Object 43 | console.log(typeof c); // number 44 | console.log(a === b); // false 45 | 46 | /** 47 | * 每个函数都有一个prototype属性, 48 | * 这个属性是指向一个对象的引用, 49 | * 这个对象称为原型对象,原型对象 50 | * 包含函数实例共享的方法和属性, 51 | * 也就是说将函数用作构造函数调用 52 | * (使用new操作符调用)的时候, 53 | * 新创建的对象会从原型对象上继承属 54 | * 性和方法。不像传统的面向对象语言, 55 | * Javascript的继承机制基于原型,而 56 | * 不是Class类。 57 | */ 58 | function Bar() { 59 | let a = 1; // 私有属性 60 | // 私有方法 61 | const fn = function() { 62 | console.log(a); 63 | }; 64 | } 65 | const bar = new Bar(); 66 | console.log(bar.a); //undefined 67 | console.log(bar.fn); //undefined 68 | /** 69 | * 把私有变量变成静态类型变量 70 | * 但是从构造函数中实例出来的 71 | * 对象还是没办法拿到 属性和方法 72 | */ 73 | function Bar2() { 74 | Bar2.a = 1; // 私有属性 75 | // 私有方法 76 | Bar2.fn = function() { 77 | console.log(a); 78 | }; 79 | } 80 | 81 | Bar2.speak(); 82 | console.log(Bar2.a); //1 83 | console.log(Bar2.fn); //func 84 | const bar2 = new Bar2(); 85 | console.log(bar2.a); //undefined 86 | console.log(bar2.fn); //undefined 87 | /** 88 | * 接下来实例出2个对象 89 | * 只对一个 实例进行属性的更改 90 | * 发现另外一个实例的属性没有被改变 91 | */ 92 | function Bar3() { 93 | this.a = 1; 94 | this.fn = function() {}; 95 | } 96 | const bar3_1 = new Bar3(); 97 | const bar3_2 = new Bar3(); 98 | bar3_2.a = 100; 99 | bar3_2.fn = []; 100 | console.log(bar3_1.a); //100 101 | console.log(bar3_1.fn); //[] 102 | console.log(bar3_2.a); //1 103 | console.log(bar3_2.fn); //func 104 | /** 105 | * 换一种写法 106 | * 把构造函数的属性 107 | * 挂到ProtoType中 108 | * 结果一致 109 | * prototype的作用 : 110 | * 我们在创建对象之后来改变对象的属性和方法 111 | * 所有 实例共享prototype上的所有属性 112 | * 并且每个实例改变自身属性的同时,与其他实例互不影响 113 | * 当我们引用别人的 类时 有时候会需要添加一些属性 114 | * 就可以直接使用prototype方法 为每个通过类实例出来的 115 | * 对象添加属性和方法 116 | */ 117 | function Bar4() {} 118 | Bar4.prototype.a = 1; 119 | Bar4.prototype.fn = function() {}; 120 | console.log(Bar4.prototype); 121 | const bar4_1 = new Bar4(); 122 | const bar4_2 = new Bar4(); 123 | bar4_2.a = 100; 124 | bar4_2.fn = []; 125 | console.log(bar4_1.a); //1 126 | console.log(bar4_1.fn); //func 127 | console.log(bar4_2.a); //100 128 | console.log(bar4_2.fn); //[] 129 | -------------------------------------------------------------------------------- /study/Questions/工厂模式.js: -------------------------------------------------------------------------------- 1 | function Student() {} 2 | function Teacher() {} 3 | 4 | function studentFactory() { 5 | return new Student(); 6 | } 7 | 8 | function teacherFactory() { 9 | return new Teacher(); 10 | } 11 | function school(type) { 12 | let factory = null; 13 | switch (type) { 14 | case "student": 15 | factory = studentFactory; 16 | break; 17 | case "teacher": 18 | factory = teacherFactory; 19 | break; 20 | default: 21 | throw "没有这个工厂"; 22 | } 23 | return factory; 24 | } 25 | var _student = school("student")(); 26 | var _teacher = school("teacher")(); 27 | console.log(_student); 28 | console.log(_teacher); 29 | -------------------------------------------------------------------------------- /study/Questions/设计模式之原型模式.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 1构造器模式 3 | */ 4 | function Student1ES5(name, sex, age) { 5 | this.math = 100; 6 | this.english = 80; 7 | this.name = name; 8 | this.sex = sex; 9 | this.age = age; 10 | this.sumSubject = function() { 11 | return this.math + this.english; 12 | }; 13 | } 14 | class Student1ES6 { 15 | constructor(name, sex, age) { 16 | this.name = name; 17 | this.sex = sex; 18 | this.age = age; 19 | this.math = 100; 20 | this.english = 80; 21 | } 22 | sumSubject() { 23 | return this.math + this.english; 24 | } 25 | } 26 | const cc1 = new Student1ES5("灿灿", "男", 18); 27 | console.log(cc1); 28 | const cc2 = new Student1ES6("灿灿", "男", 18); 29 | console.log(cc2); 30 | /** 31 | * 2 原型模式 32 | * es6的没变化和构造器一样 33 | */ 34 | function Student2ES5(name, sex, age) { 35 | this.math = 100; 36 | this.english = 80; 37 | this.name = name; 38 | this.sex = sex; 39 | this.age = age; 40 | } 41 | Student2ES5.prototype.sumSubject = function() { 42 | return this.math + this.english; 43 | }; 44 | class Student2ES6 { 45 | constructor(name, sex, age) { 46 | this.name = name; 47 | this.sex = sex; 48 | this.age = age; 49 | this.math = 100; 50 | this.english = 80; 51 | } 52 | sumSubject() { 53 | return this.math + this.english; 54 | } 55 | } 56 | console.log(Student2ES6); 57 | -------------------------------------------------------------------------------- /study/Questions/设计模式之构建者模式.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 构建者模式 3 | * es5 4 | */ 5 | function Student() {} 6 | 7 | function BuildStudent() { 8 | this.student = new Student(); 9 | } 10 | BuildStudent.prototype.setName = function(name) { 11 | this.student.name = name; 12 | }; 13 | BuildStudent.prototype.setSex = function(sex) { 14 | if (sex != "男" && sex != "女") { 15 | throw "性别错误"; 16 | } 17 | this.student.sex = sex; 18 | }; 19 | BuildStudent.prototype.setHairLength = function(length) { 20 | if ( 21 | (this.student.sex === "男" && length > 1) || 22 | (this.student.sex === "女" && length > 25) 23 | ) { 24 | throw "头发太长"; 25 | } 26 | this.student.length = length; 27 | }; 28 | BuildStudent.prototype.build = function() { 29 | return this.student; 30 | }; 31 | var builder = new BuildStudent(); 32 | try { 33 | builder.setName("灿灿"); 34 | builder.setSex("男"); 35 | builder.setHairLength(1); 36 | var student = builder.build(); 37 | } catch (err) { 38 | throw err; 39 | } 40 | console.log(student); 41 | -------------------------------------------------------------------------------- /study/diffDom/diffDom.js: -------------------------------------------------------------------------------- 1 | class Diff { 2 | /** 3 | * 比较2个虚拟DOM 4 | * @param { Element } oldTree 旧虚拟DOM 5 | * @param { Element } newTree 新虚拟DOM 6 | */ 7 | constructor(oldTree, newTree) { 8 | const patches = {}; //补丁集合 9 | this.index = 0; 10 | this.walk(oldTree, newTree, this.index, patches); 11 | this.patches = patches; //补丁集合 12 | } 13 | get ATTR() { 14 | return "ATTR"; 15 | } 16 | get TEXT() { 17 | return "TEXT"; 18 | } 19 | diffChildren(oldChildren, newChildren, patches) { 20 | oldChildren.forEach((child, idx) => { 21 | this.index += 1; 22 | this.walk(child, newChildren[idx], this.index, patches); 23 | }); 24 | } 25 | /** 26 | * 27 | * @param { Element } oldNode 旧虚拟DOM 28 | * @param { Element } newNode 新虚拟DOM 29 | * @param { int } index 索引 30 | * @param { object } patches 补丁对象 31 | */ 32 | walk(oldNode, newNode, index, patches) { 33 | const curPatches = []; 34 | // 判断2个节点是否为文本类型 35 | if (this.isString(oldNode) && this.isString(newNode)) { 36 | // 判断2个文本类型的文本是否一样 37 | if (oldNode !== newNode) { 38 | curPatches.push({ type: this.TEXT, text: newNode }); 39 | patches[index] = curPatches; 40 | } 41 | return; 42 | } 43 | if (oldNode.type === newNode.type) { 44 | const attrs = this.diffAttr(oldNode.props, newNode.props); 45 | // 如果attr有值 新旧节点有改变 把改变的属性 添加到补丁数组中 46 | if (Object.keys(attrs).length > 0) { 47 | curPatches.push({ type: this.ATTR, attrs }); 48 | } 49 | this.diffChildren(oldNode.children, newNode.children, patches); 50 | // 将元素和补丁对应起来放入大补丁包中 51 | curPatches.length && (patches[index] = curPatches); 52 | } 53 | } 54 | /** 55 | * 比较属性 56 | * @param { Element } oldNode 旧虚拟DOM 57 | * @param { Element } newNode 新虚拟DOM 58 | * @return { object } patch 补丁对象 59 | */ 60 | diffAttr(oldAttrs, newAttrs) { 61 | const patch = {}; 62 | for (const key in oldAttrs) { 63 | // 判断 oldAttrs 的属性是否有被改变 64 | // 若改变 则给patch记录这个属性 65 | oldAttrs[key] !== newAttrs[key] && (patch[key] = newAttrs[key]); 66 | } 67 | for (const key in newAttrs) { 68 | // 判断 newAttrs 的属性是否有添加 69 | // 若改变 则给patch记录这个属性 70 | !oldAttrs.hasOwnProperty(key) && (patch[key] = newAttrs[key]); 71 | } 72 | return patch; 73 | } 74 | 75 | isString(node) { 76 | return Object.prototype.toString.call(node) === "[object String]"; 77 | } 78 | } 79 | 80 | console.log(Diff); 81 | -------------------------------------------------------------------------------- /study/diffDom/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /study/diffDom/vertualDom.js: -------------------------------------------------------------------------------- 1 | class Element { 2 | /** 3 | * @param { string } type 标签类型 4 | * @param { object } props dom 属性 5 | * @param { array } children 子元素 6 | */ 7 | constructor(type, props, children) { 8 | this.type = type; 9 | this.props = props; 10 | this.children = children; 11 | } 12 | // 创建虚拟DOM 13 | static createElement(type, props, children) { 14 | return new this(type, props, children); 15 | } 16 | /** 17 | * 给虚拟DOM 创建属性 18 | * @param { DomElement } node 19 | * @param { string } key 20 | * @param { string } val 21 | */ 22 | setAttr(node, key, val) { 23 | switch (key) { 24 | case "value": //node 是一个Input 或者 Textarea 25 | if ( 26 | node.tagName.toUpperCase() === "INPUT" || 27 | node.tagName.toUpperCase() === "TEXTAREA" 28 | ) { 29 | node.value = val; 30 | } else { 31 | node.setAttribute(key, val); 32 | } 33 | break; 34 | case "style": 35 | node.style.cssText = val; 36 | break; 37 | default: 38 | node.setAttribute(key, val); 39 | break; 40 | } 41 | } 42 | // 将虚拟DOM 渲染为真是DOM 43 | /** 44 | * 45 | * @param { Element } vNode Element 的实例 虚拟DOM 46 | * @return { DomElement } el 真实DOM 47 | */ 48 | render(vNode = this) { 49 | let el = document.createElement(vNode.type); 50 | for (const key in vNode.props) { 51 | this.setAttr(el, key, vNode.props[key]); 52 | } 53 | vNode.children.forEach(child => { 54 | child = 55 | child instanceof Element 56 | ? this.render(child) 57 | : document.createTextNode(child); 58 | el.appendChild(child); 59 | }); 60 | return el; 61 | } 62 | } 63 | /** 64 | * dom diff 65 | * 1. js对象 模拟 vertualDom 66 | * 2. 把vertualDom 转成 真是DOM 67 | * 3. 如果有时间发生修改了vertualDom比较2个vertualDom的 68 | * 差异得到差异对象 69 | * 4. 把差异对象应用到真是DOM树上 70 | */ 71 | console.log(Element); 72 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | function flatten(arr) { 2 | return [].concat(...arr.map(_ => (Array.isArray(_) ? flatten(_) : _))); 3 | } 4 | class Group { 5 | constructor(list = []) { 6 | this.list = list; 7 | } 8 | // 将数据过滤整理 摊平 9 | get arr() { 10 | const arr = this.list.map((_, index) => { 11 | return _.boxList 12 | .filter(_ => _.checked === true) 13 | .map(_ => ({ 14 | value: _.value, 15 | key: index 16 | })); 17 | }); 18 | return flatten(arr); 19 | } 20 | get group() { 21 | const arr = this.list.map((_, index) => ({ id: index })); 22 | return arr; 23 | } 24 | 25 | get groupBy() { 26 | const groups = this.groups; 27 | const groupBy = this.arr.reduce((groups, item) => { 28 | groups[item.key] = [...(groups[item.key] || []), item]; 29 | return groups; 30 | }, {}); 31 | return groupBy; 32 | } 33 | get key() { 34 | if (!this.group.length) return null; 35 | return this.group[0].id; 36 | } 37 | 38 | render(key = this.key, index = 0, result = []) { 39 | if (key === null) return []; 40 | const bar = []; 41 | const data = this.arr.find(_ => _.key === key); 42 | const data2 = this.arr.filter(_ => _.key !== key); 43 | // console.log(data2); 44 | return [data, ...data2]; 45 | } 46 | get num() { 47 | const arr = []; 48 | for (let i in this.groupBy) { 49 | arr.push(this.groupBy[i].length); 50 | } 51 | let num = 1; 52 | for (const item of arr) { 53 | num = num * item; 54 | } 55 | return num; 56 | } 57 | } 58 | 59 | const list = [ 60 | { 61 | name: "规格名字1", 62 | val: "", 63 | boxList: [ 64 | { value: "Apple", checked: true }, 65 | { value: "Pear", checked: true } 66 | ] 67 | }, 68 | { 69 | name: "规格名字2", 70 | boxList: [ 71 | { value: "Orange", checked: true }, 72 | { value: "Grape", checked: true } 73 | ], 74 | val: "" 75 | }, 76 | { 77 | name: "规格名字3", 78 | boxList: [ 79 | { value: "Banner", checked: true }, 80 | { value: "Strawberry", checked: true } 81 | ], 82 | val: "" 83 | } 84 | ]; 85 | 86 | //const result = new Group(list); 87 | // console.log(result.arr); 88 | // console.log(result.groupBy); 89 | // console.log(result.num); 90 | // const foo = result.render(); 91 | // console.log(foo); 92 | 93 | const a = ["apple", "orange", "banner"]; 94 | const b = ["apple", "orange", "Strawberry"]; 95 | const c = ["apple", "Grape", "banner"]; 96 | const d = ["apple", "Grape", "Strawberry"]; 97 | const e = ["Pear", "orange", "banner"]; 98 | const f = ["Pear", "orange", "Strawberry"]; 99 | const g = ["Pear", "Grape", "banner"]; 100 | const h = ["Pear", "Grape", "Strawberry"]; 101 | 102 | const arr = [["Apple", "Pear"], ["Orange", "Grape"], ["Banner", "Apple"]]; 103 | 104 | let results = []; 105 | let result = []; 106 | 107 | function doExchange(arr, index) { 108 | for (var i = 0; i < arr[index].length; i++) { 109 | result[index] = arr[index][i]; 110 | if (index != arr.length - 1) { 111 | doExchange(arr, index + 1); 112 | } else { 113 | results.push(result.join(",")); 114 | } 115 | } 116 | } 117 | console.log(results); 118 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | // vue.config.js 2 | 3 | const path = require("path"); 4 | const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); 5 | // const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 6 | 7 | function resolve(dir) { 8 | return path.join(__dirname, dir); 9 | } 10 | 11 | module.exports = { 12 | runtimeCompiler: true, //是否使用包含运行时编译器的 Vue 构建版本 13 | baseUrl: process.env.NODE_ENV === "production" ? "/" : "/", 14 | // baseUrl: process.env.NODE_ENV === "production" ? "/" : "/", 15 | productionSourceMap: false, //不在production环境使用SourceMap 16 | css: { 17 | loaderOptions: { 18 | less: { 19 | javascriptEnabled: true 20 | } 21 | } 22 | }, 23 | lintOnSave: process.env.NODE_ENV !== "production", 24 | configureWebpack: config => { 25 | //入口文件 26 | config.entry.app = ["babel-polyfill", "./src/main.js"]; 27 | //删除console插件 28 | const plugins = [ 29 | new UglifyJsPlugin({ 30 | uglifyOptions: { 31 | compress: { 32 | warnings: false, 33 | drop_console: true, 34 | drop_debugger: true 35 | }, 36 | output: { 37 | // 去掉注释内容 38 | comments: true 39 | } 40 | }, 41 | sourceMap: false, 42 | parallel: true 43 | }) 44 | ]; 45 | config.externals = { 46 | vue: "Vue", 47 | "vue-router": "VueRouter", 48 | axios: "axios", 49 | vuex: "Vuex", 50 | Vant: "vant" 51 | }; 52 | config.performance = { 53 | maxAssetSize: 100000000, 54 | maxEntrypointSize: 400000000 55 | }; 56 | 57 | if (process.env.NODE_ENV == "production") { 58 | config.plugins = [...config.plugins, ...plugins]; 59 | } 60 | }, 61 | //允许对内部的 webpack 配置进行更细粒度的修改。 62 | chainWebpack: config => { 63 | //命名 64 | config.resolve.alias 65 | .set("SRC", resolve("src")) 66 | .set("ASSET", resolve("src/assets")) 67 | .set("VIEW", resolve("src/components/page")) 68 | .set("COMPONENT", resolve("src/components/common")) 69 | .set("UTIL", resolve("src/utils")) 70 | .set("SERVICE", resolve("src/services")); 71 | 72 | //打包文件带hash 73 | config.output.filename("[name].[hash].js").end(); 74 | 75 | //为了补删除换行而加的配置 76 | config.module 77 | .rule("vue") 78 | .use("vue-loader") 79 | .loader("vue-loader") 80 | .tap(options => { 81 | // modify the options... 82 | options.compilerOptions.preserveWhitespace = true; 83 | return options; 84 | }); 85 | }, 86 | devServer: { 87 | //跨域 88 | port: 8010, // 端口号 89 | open: false, //配置自动启动浏览器 90 | // host: "localhost", 91 | proxy: { 92 | // 配置跨域处理 可以设置多个 93 | "/api": { 94 | //target: "http://localhost:7001", 95 | target: "http://119.29.165.40:8010", 96 | changeOrigin: true 97 | } 98 | } 99 | } 100 | }; 101 | --------------------------------------------------------------------------------