├── static └── .gitkeep ├── config ├── prod.env.js ├── dev.env.js └── index.js ├── src ├── assets │ └── logo.png ├── App.vue ├── api │ └── index.js ├── router │ └── index.js ├── main.js ├── styles │ └── common.less └── pages │ ├── login.vue │ ├── users.vue │ └── home.vue ├── 笔记(汇总) ├── img │ ├── vuex.png │ ├── day01 │ │ ├── MVVM.png │ │ ├── 添加数据.png │ │ ├── 回车添加数据.png │ │ ├── 案例效果图.png │ │ └── 为什么学习vue.png │ ├── day02 │ │ ├── 响应报文.png │ │ ├── 请求报文.png │ │ ├── jsonp跨域原理解析.png │ │ └── transition结合css实现过渡.png │ └── day03 │ │ ├── 动态组件.png │ │ ├── 父子组件.png │ │ ├── 路由入门.png │ │ ├── 路由嵌套.png │ │ ├── 动态组件页面.png │ │ ├── 路由入门页面.png │ │ ├── 路由嵌套页面.png │ │ ├── 子组件传值给父组件.png │ │ ├── 父组件传值给子组件.png │ │ ├── webpack是什么.png │ │ ├── 子组件传值给父组件页面.png │ │ ├── 父组件传值给子组件页面.png │ │ ├── 组件中指令和事件的使用.png │ │ ├── template创建组件.png │ │ ├── vue-router传参.png │ │ ├── vue-router传参页面.png │ │ ├── vuecomponent创建组件.png │ │ └── vue.extend和vuecomponent创建组件.png ├── vue基础大纲.xmind ├── Vue基础-day05.md ├── Vue基础-day04.md ├── Vue基础-day03.md ├── Vue项目.md ├── Vue基础-day02.md └── Vue基础-day01.md ├── .editorconfig ├── .gitignore ├── .babelrc ├── .postcssrc.js ├── index.html ├── README.md └── package.json /static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/src/assets/logo.png -------------------------------------------------------------------------------- /笔记(汇总)/img/vuex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/vuex.png -------------------------------------------------------------------------------- /笔记(汇总)/vue基础大纲.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/vue基础大纲.xmind -------------------------------------------------------------------------------- /笔记(汇总)/img/day01/MVVM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day01/MVVM.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day01/添加数据.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day01/添加数据.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day02/响应报文.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day02/响应报文.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day02/请求报文.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day02/请求报文.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/动态组件.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/动态组件.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/父子组件.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/父子组件.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/路由入门.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/路由入门.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/路由嵌套.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/路由嵌套.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day01/回车添加数据.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day01/回车添加数据.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day01/案例效果图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day01/案例效果图.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/动态组件页面.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/动态组件页面.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/路由入门页面.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/路由入门页面.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/路由嵌套页面.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/路由嵌套页面.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day01/为什么学习vue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day01/为什么学习vue.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/子组件传值给父组件.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/子组件传值给父组件.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/父组件传值给子组件.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/父组件传值给子组件.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day02/jsonp跨域原理解析.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day02/jsonp跨域原理解析.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/webpack是什么.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/webpack是什么.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/子组件传值给父组件页面.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/子组件传值给父组件页面.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/父组件传值给子组件页面.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/父组件传值给子组件页面.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/组件中指令和事件的使用.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/组件中指令和事件的使用.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/template创建组件.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/template创建组件.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/vue-router传参.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/vue-router传参.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/vue-router传参页面.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/vue-router传参页面.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/vuecomponent创建组件.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/vuecomponent创建组件.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day02/transition结合css实现过渡.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day02/transition结合css实现过渡.png -------------------------------------------------------------------------------- /笔记(汇总)/img/day03/vue.extend和vuecomponent创建组件.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TianchengLee/login-interceptor/master/笔记(汇总)/img/day03/vue.extend和vuecomponent创建组件.png -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-vue-jsx", "transform-runtime"] 12 | } 13 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | login-interceptor 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # login-interceptor 2 | 3 | > just login demo 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | ``` 20 | 21 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 22 | -------------------------------------------------------------------------------- /src/api/index.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1'; 4 | 5 | // 添加请求拦截器 6 | axios.interceptors.request.use(function (config) { 7 | const token = localStorage.getItem('token') 8 | if (token) config.headers.Authorization = token 9 | // 在发送请求之前做些什么 10 | return config; 11 | }, function (error) { 12 | // 对请求错误做些什么 13 | return Promise.reject(error); 14 | }); 15 | 16 | export const login = (username, password) => axios.post("/login", { username, password }) 17 | 18 | export const getUsers = (pagenum, pagesize) => axios.get("/users", { params: { pagenum, pagesize } }) 19 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import loginComponent from '@/pages/login' 4 | import homeComponent from '@/pages/home' 5 | import usersComponent from '@/pages/users' 6 | 7 | Vue.use(Router) 8 | 9 | export default new Router({ 10 | routes: [ 11 | { 12 | path: '/', 13 | redirect: '/login' 14 | }, 15 | { path: '/login', component: loginComponent }, 16 | { 17 | path: '/home', 18 | component: homeComponent, 19 | redirect: '/users', 20 | children: [ 21 | { path: '/users', component: usersComponent }, 22 | ] 23 | }, 24 | 25 | ] 26 | }) 27 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | import router from './router' 4 | 5 | Vue.config.productionTip = false 6 | 7 | import './styles/common.less' 8 | 9 | import ElementUI from 'element-ui'; 10 | import 'element-ui/lib/theme-chalk/index.css'; 11 | Vue.use(ElementUI); 12 | 13 | router.beforeEach((to, from, next) => { 14 | let token = localStorage.getItem('token') 15 | if (!token && to.path !== '/login') { 16 | return next({ path: '/login' }) 17 | } 18 | next() 19 | // let token = localStorage.getItem('token') 20 | // // 如果已经登录,那我不干涉你,让你随便访问 21 | // if (token) { 22 | // next() 23 | // } else { 24 | // if (to.path !== '/login') { 25 | // // 如果没有登录,但你访问其他需要登录的页面,那我就让你跳到登录页面去 26 | // next({path: '/login'}) 27 | // } else { 28 | // // 如果没有登录,但你访问的login,那就不干涉你,让你访问 29 | // next() 30 | // } 31 | // } 32 | }) 33 | 34 | /* eslint-disable no-new */ 35 | new Vue({ 36 | el: '#app', 37 | router, 38 | render: h => h(App) 39 | }) 40 | -------------------------------------------------------------------------------- /src/styles/common.less: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | body { 32 | line-height: 1; 33 | } 34 | ol, ul { 35 | list-style: none; 36 | } 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | blockquote:before, blockquote:after, 41 | q:before, q:after { 42 | content: ''; 43 | content: none; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } -------------------------------------------------------------------------------- /src/pages/login.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 45 | 46 | -------------------------------------------------------------------------------- /src/pages/users.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 45 | 46 | -------------------------------------------------------------------------------- /src/pages/home.vue: -------------------------------------------------------------------------------- 1 | 24 | 55 | 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "login-interceptor", 3 | "version": "1.0.0", 4 | "description": "just login demo", 5 | "author": "TianchengLee ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "build": "node build/build.js" 11 | }, 12 | "dependencies": { 13 | "axios": "^0.18.0", 14 | "element-ui": "^2.4.11", 15 | "vue": "^2.5.2", 16 | "vue-router": "^3.0.1" 17 | }, 18 | "devDependencies": { 19 | "autoprefixer": "^7.1.2", 20 | "babel-core": "^6.22.1", 21 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 22 | "babel-loader": "^7.1.1", 23 | "babel-plugin-syntax-jsx": "^6.18.0", 24 | "babel-plugin-transform-runtime": "^6.22.0", 25 | "babel-plugin-transform-vue-jsx": "^3.5.0", 26 | "babel-preset-env": "^1.3.2", 27 | "babel-preset-stage-2": "^6.22.0", 28 | "chalk": "^2.0.1", 29 | "copy-webpack-plugin": "^4.0.1", 30 | "css-loader": "^0.28.0", 31 | "extract-text-webpack-plugin": "^3.0.0", 32 | "file-loader": "^1.1.4", 33 | "friendly-errors-webpack-plugin": "^1.6.1", 34 | "html-webpack-plugin": "^2.30.1", 35 | "less": "^3.8.1", 36 | "less-loader": "^4.1.0", 37 | "node-notifier": "^5.1.2", 38 | "optimize-css-assets-webpack-plugin": "^3.2.0", 39 | "ora": "^1.2.0", 40 | "portfinder": "^1.0.13", 41 | "postcss-import": "^11.0.0", 42 | "postcss-loader": "^2.0.8", 43 | "postcss-url": "^7.2.1", 44 | "rimraf": "^2.6.0", 45 | "semver": "^5.3.0", 46 | "shelljs": "^0.7.6", 47 | "uglifyjs-webpack-plugin": "^1.1.1", 48 | "url-loader": "^0.5.8", 49 | "vue-loader": "^13.3.0", 50 | "vue-style-loader": "^3.0.1", 51 | "vue-template-compiler": "^2.5.2", 52 | "webpack": "^3.6.0", 53 | "webpack-bundle-analyzer": "^2.9.0", 54 | "webpack-dev-server": "^2.9.1", 55 | "webpack-merge": "^4.1.0" 56 | }, 57 | "engines": { 58 | "node": ">= 6.0.0", 59 | "npm": ">= 3.0.0" 60 | }, 61 | "browserslist": [ 62 | "> 1%", 63 | "last 2 versions", 64 | "not ie <= 8" 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.3.1 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | 24 | /** 25 | * Source Maps 26 | */ 27 | 28 | // https://webpack.js.org/configuration/devtool/#development 29 | devtool: 'cheap-module-eval-source-map', 30 | 31 | // If you have problems debugging vue-files in devtools, 32 | // set this to false - it *may* help 33 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 34 | cacheBusting: true, 35 | 36 | cssSourceMap: true 37 | }, 38 | 39 | build: { 40 | // Template for index.html 41 | index: path.resolve(__dirname, '../dist/index.html'), 42 | 43 | // Paths 44 | assetsRoot: path.resolve(__dirname, '../dist'), 45 | assetsSubDirectory: 'static', 46 | assetsPublicPath: '/', 47 | 48 | /** 49 | * Source Maps 50 | */ 51 | 52 | productionSourceMap: true, 53 | // https://webpack.js.org/configuration/devtool/#production 54 | devtool: '#source-map', 55 | 56 | // Gzip off by default as many popular static hosts such as 57 | // Surge or Netlify already gzip all static assets for you. 58 | // Before setting to `true`, make sure to: 59 | // npm install --save-dev compression-webpack-plugin 60 | productionGzip: false, 61 | productionGzipExtensions: ['js', 'css'], 62 | 63 | // Run the build command with an extra argument to 64 | // View the bundle analyzer report after build finishes: 65 | // `npm run build --report` 66 | // Set to `true` or `false` to always turn it on or off 67 | bundleAnalyzerReport: process.env.npm_config_report 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /笔记(汇总)/Vue基础-day05.md: -------------------------------------------------------------------------------- 1 | Vue基础-day05 2 | === 3 | 4 | 5 | 6 | - [单文件组件](#单文件组件) 7 | - [结合webpack处理单文件组件](#结合webpack处理单文件组件) 8 | - [配置webpack相关loader](#配置webpack相关loader) 9 | - [使用vue文件创建vue组件](#使用vue文件创建vue组件) 10 | - [引入组件,并将组件渲染到页面](#引入组件并将组件渲染到页面) 11 | - [路由配置](#路由配置) 12 | - [vue-cli 脚手架工具](#vue-cli-脚手架工具) 13 | - [element-ui](#element-ui) 14 | - [项目相关](#项目相关) 15 | - [团队角色](#团队角色) 16 | - [开发流程](#开发流程) 17 | - [技术选型](#技术选型) 18 | - [前端](#前端) 19 | - [后端](#后端) 20 | - [项目业务分析](#项目业务分析) 21 | - [项目初始化](#项目初始化) 22 | 23 | 24 | 25 | ## 单文件组件 26 | 27 | [单文件组件](https://cn.vuejs.org/v2/guide/single-file-components.html) 28 | 29 | ### 结合webpack处理单文件组件 30 | 31 | #### 配置webpack相关loader 32 | 33 | 1. `npm install vue --save` 34 | 2. `npm install vue-loader vue-template-compiler --save-dev` 35 | 36 | 37 | ```js 38 | { 39 | test: /\.vue$/, 40 | loader: 'vue-loader' 41 | } 42 | 43 | // 如果使用的是webpack1.x,还需要安装 `babel-plugin-transform-runtime`,并添加一下配置;如果是webpack2.x以上请忽略一下配置 44 | { 45 | test: /\.js$/, 46 | include: [path.resolve(__dirname, 'src')], 47 | use: { 48 | loader: 'babel-loader', 49 | // options里面的东西可以放到.babelrc文件中去 50 | options: { 51 | presets: ['env'] 52 | // plugins: ['transform-runtime'] 53 | } 54 | } 55 | } 56 | 57 | ``` 58 | 59 | #### 使用vue文件创建vue组件 60 | 61 | ```html 62 | 63 | 64 | 67 | 76 | 81 | ``` 82 | 83 | #### 引入组件,并将组件渲染到页面 84 | 85 | ```js 86 | // app.js 87 | import Vue from 'vue' 88 | import App from './App.vue' 89 | 90 | new Vue({ 91 | el: '#app', 92 | render: h=> h(App) 93 | }) 94 | ``` 95 | 96 | #### 路由配置 97 | 98 | 1. `npm install vue-router --save` 99 | 100 | ```js 101 | // app.js 102 | import Vue from 'vue' 103 | import App from './App.vue' 104 | 105 | import Login from './Login.vue' 106 | 107 | // 1. 引入vue-router 108 | import VueRouter from 'vue-router' 109 | 110 | // 2. 表示使用路由插件 111 | Vue.use(VueRouter) 112 | 113 | //3. 配置路由规则 114 | var router = new VueRouter({ 115 | routes: [ 116 | { name: 'login', path: '/login', component: Login } 117 | ] 118 | }) 119 | 120 | new Vue({ 121 | el: '#app', 122 | // 挂载路由 123 | router, 124 | // 这是个渲染函数,指定渲染组件 125 | render: h => h(App) 126 | }) 127 | ``` 128 | 129 | ## vue-cli 脚手架工具 130 | 131 | vue-cli是官方的一个脚手架工具,所谓脚手架呢就是一个架子,什么架子呢?项目结构的架子,里面有一些最基本的结构配置。利用vue-cli呢,我们可以生成这样的一个脚手架,所以呢它就被称为vue脚手架工具。 132 | 133 | `npm install vue-cli -g` 134 | 135 | `vue init webpack admin` 136 | 137 | ## element-ui 138 | 139 | 安装:`npm i element-ui -S` 140 | 141 | [element-ui使用](http://element-cn.eleme.io/2.0/#/zh-CN/component/quickstart) 142 | 143 | ## 项目相关 144 | 145 | [电商后台管理系统](http://47.96.21.88/#/login) (不要随便删) 146 | 147 | ### 团队角色 148 | 149 | - 产品经理 150 | - 项目经理 151 | - UI/UE 152 | - 前端 153 | - 后端(php/java/python/Node.js/.net) 154 | - 测试(单元测试、黑盒测试、白盒测试、集成测试、压力测试) 155 | - DBA 数据库管理员 156 | - 实施/运维 负责程序的上线和运行监控 157 | - 全栈工程师 158 | 159 | ### 开发流程 160 | 161 | - 需求分析 162 | - 概要设计 163 | - 详细设计 164 | - 编码 165 | - 测试 166 | - 上线 167 | - 运维-迭代更新 168 | 169 | ### 技术选型 170 | 171 | #### 前端 172 | 173 | - vue 174 | - vue-router 175 | - axios 176 | - Element-UI 177 | - webpack 178 | 179 | #### 后端 180 | 181 | - node.js 182 | - express 183 | - mysql 184 | 185 | ### 项目业务分析 186 | 187 | - 电商业务 188 | + 对外网站(用户购买) 189 | + 后台管理端(用于运营人员) 190 | + 移动Web 191 | + APP 192 | + 数据分析(用户行为分析) 193 | + 数据统计系统(财务) 194 | 195 | ### 项目初始化 196 | 197 | - styles 198 | - element.scss 用于覆盖element中的样式 199 | - reset.scss 用于重置一些标签的默认样式 200 | - index.scss 引入其他scss文件,写一些通用样式 201 | - 安装处理sass相关的loader 202 | - views 203 | 204 | 205 | [码云](https://gitee.com/login) 206 | 1. 码云上创建一个空的项目(不能选readme文件选项) 207 | 2. 创建本地的git仓库`git init` 208 | 3. 将本地仓库关联到远端 209 | 4. `git add .` 210 | 5. `git commit -m 'init project'` 211 | 6. `git push` (这里有可能报错,按提示 git push --set-upstream origin master)(会提示输入码云的账户密码 ) 212 | 7. 创建并切换到新分支`git checkout -b xx分支` 213 | 8. `git add .` 214 | 9. `git commit -m "xxxx"` 215 | 10. `git push` (可能会报错,按照提示push) 216 | 11. `git checkout master` 217 | 12. `git merge xx分支` 218 | 13. `git branch -d xx分支` 219 | 14. `git add .` 220 | 15. `git commit -m "xxx"` 221 | 16. `git push` -------------------------------------------------------------------------------- /笔记(汇总)/Vue基础-day04.md: -------------------------------------------------------------------------------- 1 | Vue基础-day04 2 | === 3 | 4 | 5 | 6 | - [webpack](#webpack) 7 | - [什么是webpack](#什么是webpack) 8 | - [为什么需要webpack](#为什么需要webpack) 9 | - [webpack安装](#webpack安装) 10 | - [使用webpack](#使用webpack) 11 | - [01-webpack-cli](#01-webpack-cli) 12 | - [02-webpack-config](#02-webpack-config) 13 | - [03-webpack-dev-server](#03-webpack-dev-server) 14 | - [04-webpack-css](#04-webpack-css) 15 | - [05-webpack-less&webpack-sass](#05-webpack-lesswebpack-sass) 16 | - [06-webpack-图片&字体](#06-webpack-图片字体) 17 | - [07-webpack-html](#07-webpack-html) 18 | - [08-webpack-babel](#08-webpack-babel) 19 | 20 | 21 | 22 | ## webpack 23 | 24 | ### 什么是webpack 25 | 26 | webpack 是一个现代 JavaScript 应用程序的模块打包器(module bundler),分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Sass,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。 27 | 28 | ![webpack是什么](./img/day03/webpack是什么.png) 29 | 30 | ### 为什么需要webpack 31 | 32 | 现在的前端,越来越复杂,特别是SPA(single page web application)流行之后,一个应用程序往往会依赖很多其他的模块,或者编译scss、less、stylus等,如果仅仅是靠人来管理是不可能的,这个时候我们必须依赖于webpack来解决。 33 | 34 | 现在最流行的三个SPA的框架,都于webpack紧密相连。 35 | * React.js + webpack 36 | * Vue.js + webpack 37 | * Angular.js + webpack 38 | 39 | 学习webpack有4个重点内容: 40 | * 入口(entry) 41 | * 输出(output) 42 | * 加载器(loader) 43 | * 插件(plugins) 44 | 45 | ### webpack安装 46 | 47 | 注意:请先安装node环境 48 | 49 | `npm install webpack@3.11.0 -g` 50 | 51 | 建议大家这样操作(随时切换镜像源): 52 | 1. npm install nrm -g // 安装nrm 53 | 2. nrm ls // 查看镜像源 54 | 3. nrm use taobao // 选择淘宝镜像,也可以选择cnpm 55 | 56 | ### 使用webpack 57 | 58 | #### 01-webpack-cli 59 | 60 | 使用命令:`webpack 输入文件路径 打包后文件路径`将一个文件打包成另外一个文件 61 | 62 | #### 02-webpack-config 63 | 64 | 1. 配置webpack.config.js 65 | 2. 运行`webpack` 66 | 67 | ```js 68 | var path = require('path') 69 | 70 | module.exports = { 71 | // 入口文件配置 72 | entry: "./src/app.js", 73 | 74 | // 出口文件配置项 75 | output: { 76 | // 输出的路径,webpack2起就规定必须是绝对路径 77 | path: path.join(__dirname, 'dist'), 78 | // 输出文件名字 79 | filename: "bundle.js" 80 | } 81 | } 82 | ``` 83 | 84 | #### 03-webpack-dev-server 85 | 86 | 默认为--inline模式 87 | 88 | 1. 运行:`npm init -y` 89 | 2. 运行:`npm i webpack-dev-server@2.9.7 webpack@3.11.0 -D` 90 | ```js 91 | var path = require('path') 92 | 93 | module.exports = { 94 | // 入口文件配置 95 | entry: "./src/app.js", 96 | 97 | // 输出配置 98 | output: { 99 | // 输出的路径 100 | path: path.join(__dirname, 'dist'), 101 | // 静态资源在服务器上运行时的访问路径,可以直接http://localhost:8080/dist/bundle.js访问到服务器中的bundle.js文件 102 | publicPath: '/dist', 103 | // 输出文件名字 104 | filename: "bundle.js" 105 | } 106 | } 107 | ``` 108 | 3. index.html中修改 `` 109 | 110 | 4. 运行:`webpack-dev-server` 111 | 5. 运行:`webpack-dev-server --inline --hot --open --port 8090` 112 | 6. 配置script:`"dev": "webpack-dev-server --inline --hot --open --port 8090"` 113 | 7. `npm run dev` 114 | 115 | #### 04-webpack-css 116 | 117 | 1. 安装`npm install css-loader style-loader --save-dev` 118 | 119 | ```js 120 | module: { 121 | rules: [ 122 | // 配置的是用来解析.css文件的loader(style-loader和css-loader) 123 | { 124 | // 1.0 用正则匹配当前访问的文件的后缀名是 .css 125 | test: /\.css$/, 126 | use: ['style-loader', 'css-loader'] //webpack底层调用这些包的顺序是从右到左 127 | } 128 | ] 129 | } 130 | ``` 131 | 132 | #### 05-webpack-less&webpack-sass 133 | 134 | `npm install less less-loader sass-loader node-sass --save-dev` 135 | 136 | ```js 137 | { 138 | test: /\.less$/, 139 | use: [{ 140 | loader: 'style-loader' 141 | }, { 142 | loader: 'css-loader' 143 | }, { 144 | loader: 'less-loader' 145 | }] 146 | }, 147 | ``` 148 | 149 | ```js 150 | { 151 | test: /\.scss$/, 152 | use: [{ 153 | loader: 'style-loader' 154 | }, { 155 | loader: 'css-loader' 156 | }, { 157 | loader: 'sass-loader' 158 | }] 159 | } 160 | ``` 161 | 162 | 163 | #### 06-webpack-图片&字体 164 | 165 | 1. `npm install file-loader url-loader --save-dev` 166 | 167 | url-loader封装了file-loader 168 | 169 | ```js 170 | { 171 | test: /\.(png|jpg|gif)/, 172 | use: [{ 173 | loader: 'url-loader', 174 | options: { 175 | // limit表示如果图片大于50000byte,就以路径形式展示,小于的话就用base64格式展示 176 | limit: 50000 177 | } 178 | }] 179 | } 180 | ``` 181 | 182 | #### 07-webpack-html 183 | 184 | 1. `npm install html-webpack-plugin --save-dev` 185 | 186 | 2. 如果添加了title,需要在模板中添加`<%= htmlWebpackPlugin.options.title %>` 187 | 188 | ```js 189 | // 注意需要注释掉publicPath,不然会冲突 190 | 191 | var HtmlWebpackPlugin = require('html-webpack-plugin') 192 | 193 | plugins: [ 194 | new HtmlWebpackPlugin({ 195 | filename: 'index.html', 196 | template: 'template.html' 197 | }) 198 | ] 199 | ``` 200 | 201 | #### 08-webpack-babel 202 | 203 | 1. `npm install babel-core babel-loader babel-preset-env --save-dev` 204 | 205 | 注意: 206 | 207 | webpack 1.x | babel-loader <= 6.x 208 | 209 | webpack 2.x | babel-loader >= 7.x (推荐) (^6.2.10 也能用, 但是会出现不推荐使用的警告) 210 | 211 | webpack 3.x | babel-loader >= 7.1 212 | 213 | ```js 214 | { 215 | test: /\.js$/, 216 | // Webpack2建议尽量避免exclude,更倾向于使用include 217 | // exclude: /(node_modules)/, // node_modules下面的.js文件会被排除 218 | include: [path.resolve(__dirname, 'src')] 219 | use: { 220 | loader: 'babel-loader', 221 | // options里面的东西可以放到.babelrc文件中去 222 | options: { 223 | presets: ['env'] 224 | } 225 | } 226 | } 227 | 228 | // .babelrc文件内的配置 229 | { 230 | "presets":["env"] 231 | } 232 | ``` 233 | 234 | 235 | -------------------------------------------------------------------------------- /笔记(汇总)/Vue基础-day03.md: -------------------------------------------------------------------------------- 1 | Vue基础-day03 2 | === 3 | 4 | 5 | 6 | - [Vue组件](#vue组件) 7 | - [Vue组件的创建](#vue组件的创建) 8 | - [vue.extend结合vue.component创建](#vueextend结合vuecomponent创建) 9 | - [vue.component创建](#vuecomponent创建) 10 | - [template方式创建](#template方式创建) 11 | - [组件中的指令以及事件绑定](#组件中的指令以及事件绑定) 12 | - [父子组件创建](#父子组件创建) 13 | - [父子组件通信](#父子组件通信) 14 | - [父组件传值给子组件(props)](#父组件传值给子组件props) 15 | - [子组件传值给父组件($emit)](#子组件传值给父组件emit) 16 | - [利用component组件和is属性实现动态组件](#利用component组件和is属性实现动态组件) 17 | - [组件生命周期](#组件生命周期) 18 | - [vue-router(路由)](#vue-router路由) 19 | - [vue-router入门](#vue-router入门) 20 | - [vur-router传参](#vur-router传参) 21 | - [vue-router嵌套](#vue-router嵌套) 22 | 23 | 24 | 25 | ## Vue组件 26 | 27 | 组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。 28 | 29 | ### Vue组件的创建 30 | 31 | #### vue.extend结合vue.component创建 32 | 33 | ![vue.extend和vuecomponent创建组件](./img/day03/vue.extend和vuecomponent创建组件.png) 34 | 35 | #### vue.component创建 36 | 37 | ![vuecomponent创建组件](./img/day03/vuecomponent创建组件.png) 38 | 39 | #### template方式创建 40 | 41 | ![template创建组件](./img/day03/template创建组件.png) 42 | 43 | ### 组件中的指令以及事件绑定 44 | 45 | ![组件间指令和事件的使用](./img/day03/组件中指令和事件的使用.png) 46 | 47 | ### 父子组件创建 48 | 49 | ![父子组件](./img/day03/父子组件.png) 50 | 51 | ### 父子组件通信 52 | 53 | #### 父组件传值给子组件(props) 54 | 55 | ![父组件传值给子组件页面.png](./img/day03/父组件传值给子组件页面.png) 56 | 57 | ![父组件传值给子组件](./img/day03/父组件传值给子组件.png) 58 | 59 | #### 子组件传值给父组件($emit) 60 | 61 | ![子组件传值给父组件](./img/day03/子组件传值给父组件页面.png) 62 | 63 | ![子组件传值给父组件](./img/day03/子组件传值给父组件.png) 64 | 65 | ### 利用component组件和is属性实现动态组件 66 | 67 | ![动态组件](./img/day03/动态组件页面.png) 68 | 69 | ![动态组件](./img/day03/动态组件.png) 70 | 71 | ## 组件生命周期 72 | 73 | ```js 74 | 75 |
76 |

{{info}}

77 | 78 | 79 |
80 | 150 | 151 | ``` 152 | 153 | ## vue-router(路由) 154 | 155 | [vue-router文档](https://router.vuejs.org/zh-cn/) 156 | 157 | 在一个系统中会由很多页面组成,在Vue开发中这些页面通常使用的是Vue中的组件来实现的,那么当在一个页面要跳转到另外一个页面的时候是通过改变url路径来实现的,那么这个时候Vue需要知道当前url对应的是哪个组件页面,这个控制着就是vue-router接下来,学习vue-router的相关写法,注意的是:vue-router 在vue2.0版本中做了很大的改动,所以要注意Vue的版本来选择预期对应的vue-router版本我们主讲vue-router2的使用 158 | 159 | ### vue-router入门 160 | 161 | ![路由入门页面](./img/day03/路由入门页面.png) 162 | ![路由入门](./img/day03/路由入门.png) 163 | 164 | ### vur-router传参 165 | 166 | ![vue-router传参页面](./img/day03/vue-router传参页面.png) 167 | 168 | ![vue-router传参](./img/day03/vue-router传参.png) 169 | 170 | ### vue-router嵌套 171 | 172 | ![路由嵌套页面](./img/day03/路由嵌套页面.png) 173 | 174 | ![路由嵌套](./img/day03/路由嵌套.png) 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /笔记(汇总)/Vue项目.md: -------------------------------------------------------------------------------- 1 | Vue项目 2 | === 3 | 4 | 5 | 6 | - [登录](#登录) 7 | - [登录页面](#登录页面) 8 | - [表单校验](#表单校验) 9 | - [登录状态保存](#登录状态保存) 10 | - [axios拦截器](#axios拦截器) 11 | - [导航守卫](#导航守卫) 12 | - [首页布局](#首页布局) 13 | - [侧边栏部分](#侧边栏部分) 14 | - [头部部分](#头部部分) 15 | - [中间内容部分](#中间内容部分) 16 | - [Vuex](#vuex) 17 | - [Vuex是什么](#vuex是什么) 18 | - [Vuex使用场景](#vuex使用场景) 19 | - [Vuex 核心内容](#vuex-核心内容) 20 | - [使用vuex](#使用vuex) 21 | - [用户管理](#用户管理) 22 | - [用户列表](#用户列表) 23 | - [权限管理](#权限管理) 24 | - [权限列表](#权限列表) 25 | - [角色列表](#角色列表) 26 | - [商品管理](#商品管理) 27 | - [商品分类](#商品分类) 28 | - [商品列表](#商品列表) 29 | 30 | 31 | 32 | ******** 33 | 34 | [项目接口文档](http://47.96.21.88:8082/) 35 | 36 | [项目地址](http://47.96.21.88/#/login) 37 | 38 | ## 登录 39 | 40 | ### 登录页面 41 | 42 | ```scss 43 | .login { 44 | position: fixed; 45 | width: 100%; 46 | height: 100%; 47 | background-color: #2f4050; 48 | 49 | .container { 50 | position: absolute; 51 | left: 0; 52 | right: 0; 53 | width: 400px; 54 | padding: 0px 40px 15px 40px; 55 | margin: 200px auto; 56 | background: white; 57 | .avatar { 58 | position: relative; 59 | left: 50%; 60 | width: 120px; 61 | height: 120px; 62 | margin-left: -60px; 63 | margin-top: -60px; 64 | box-sizing: border-box; 65 | border-radius: 50%; 66 | border: 10px solid #fff; 67 | box-shadow: 0 1px 5px #ccc; 68 | overflow: hidden; 69 | } 70 | .login-btn { 71 | width: 100%; 72 | } 73 | } 74 | } 75 | ``` 76 | 77 | ### 表单校验 78 | 79 | ### 登录状态保存 80 | 81 | HTTP请求是无状态的 82 | 83 | - cookie 84 | - 保存在客户端 85 | - 数据量小(很多站点对cookie的大小和数量都进行了限制) 86 | - 不安全(别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,也可能被拦截) 87 | - session 88 | - 服务器端 89 | - 安全 90 | - session可以依赖cookie,也可以不依赖使用url 91 | - 访问量增多,占用服务器资源,如果服务器挂了,所有保存的信息都没了 92 | - token 93 | - 服务器不存用户状态,定义通用算法 94 | - 客户端第一次登录之后,服务器会生成一个token,返回给客户端 95 | - 后续所有请求都会带着token 96 | - 服务器根据算法校验token的合法性 97 | 98 | ### axios拦截器 99 | 100 | [axios](https://github.com/axios/axios) --> Interceptors 101 | 102 | ```js 103 | // 添加请求拦截器 104 | axios.interceptors.request.use(function (config) { 105 | // 将token给到一个前后台约定好的key中,作为请求发送 106 | let token = localStorage.getItem('mytoken') 107 | if (token) { 108 | config.headers['Authorization'] = token 109 | } 110 | return config 111 | }, function (error) { 112 | // Do something with request error 113 | return Promise.reject(error) 114 | }) 115 | ``` 116 | 117 | ### 导航守卫 118 | 119 | [导航守卫](https://router.vuejs.org/zh-cn/advanced/navigation-guards.html) 120 | 121 | ```js 122 | router.beforeEach((to, from, next) => { 123 | let token = localStorage.getItem('mytoken') 124 | // 如果已经登录,那我不干涉你,让你随便访问 125 | if (token) { 126 | next() 127 | } else { 128 | if (to.path !== '/login') { 129 | // 如果没有登录,但你访问其他需要登录的页面,那我就让你跳到登录页面去 130 | next({path: '/login'}) 131 | } else { 132 | // 如果没有登录,但你访问的login,那就不干涉你,让你访问 133 | next() 134 | } 135 | } 136 | }) 137 | ``` 138 | 139 | ## 首页布局 140 | 141 | ### 侧边栏部分 142 | 143 | ### 头部部分 144 | 145 | ### 中间内容部分 146 | 147 | ```scss 148 | .home { 149 | height: 100%; 150 | background-color: #E5E5E5; 151 | .el-menu-admin:not(.el-menu--collapse) { 152 | width: 200px; 153 | min-height: 400px; 154 | } 155 | .el-container { 156 | height: 100%; 157 | } 158 | .el-aside { 159 | background-color: #545c64; 160 | } 161 | .el-header { 162 | display: flex; 163 | justify-content: space-between; 164 | align-items: center; 165 | background-color: #009688; 166 | } 167 | .logo { 168 | height:60px; 169 | background: url(../assets/logo.png); 170 | background-size: cover; 171 | background-color: white; 172 | } 173 | .toggle-btn { 174 | padding: 0 10px; 175 | margin-left: -20px; 176 | font-size: 36px; 177 | line-height: 60px; 178 | color: white; 179 | cursor: pointer; 180 | &:hover { 181 | background-color: #00635a; 182 | } 183 | } 184 | .system-title { 185 | font-size: 28px; 186 | color: white; 187 | } 188 | .welcome, { 189 | color: white; 190 | } 191 | } 192 | ``` 193 | 194 | ## Vuex 195 | 196 | ### Vuex是什么 197 | 198 | Vuex是一个针对Vue.js开发的状态管理模式。说简单点儿就是一个工具,可以管理(修改或设置)所有组件用到的数据,而不需要借助之前的event bus或者props在组件间传值。 199 | 200 | ### Vuex使用场景 201 | 202 | 大型单页应用程序,存在多组件共享数据的时候,需要用到 203 | 204 | ### Vuex 核心内容 205 | 206 | ![vuex](./img/vuex.png) 207 | 208 | store (一个容器对象,存储Vuex中的state,mutations,actions,getters等) 209 | - state (一个保存数据的对象,对象中的数据可以供所有组件使用) 210 | ```js 211 | // 1. 定义 212 | const state = { 213 | count: 0 214 | } 215 | 216 | // 2. 获取state中的值 217 | this.$store.state.count 218 | 219 | // mapState 辅助函数获取多个state的值 220 | import { mapState } from 'vuex' 221 | computed: mapState({ 222 | // 箭头函数可使代码更简练 223 | count: state => state.count, 224 | // 传字符串参数 'count' 等同于 `state => state.count` 225 | countAlias: 'count', 226 | }) 227 | computed: mapState([ 228 | // 映射 this.count 为 store.state.count 229 | 'count' 230 | ]) 231 | 232 | // 3. 与组件的计算属性混合使用 233 | computed: { 234 | localComputed () { /* ... */ }, 235 | // 使用对象展开运算符将此对象混入到外部对象中 236 | ...mapState({ 237 | // ... 238 | }) 239 | } 240 | ``` 241 | - mutations(一个对象,保存的是更改state的函数,也只有它能更改state中的值,触发方式this.$store.commit('函数名',参数)) 242 | ```js 243 | // 1. 定义 244 | const mutations = { 245 | increment (state) { 246 | state.count++ 247 | } 248 | } 249 | 250 | // 2. 触发 251 | this.$store.commit('increment') 252 | 253 | // 3. 传递参数,通常参数应该是一个对象 254 | mutations: { 255 | increment (state, n) { 256 | state.count += n 257 | } 258 | } 259 | this.$store.commit('increment', 10) 260 | 261 | // 4. 在组件的方法中使用 262 | methods: { 263 | ...mapMutations([ 264 | 'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')` 265 | 266 | // `mapMutations` 也支持载荷: 267 | 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)` 268 | ]), 269 | ...mapMutations({ 270 | add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')` 271 | }) 272 | } 273 | ``` 274 | - actions(一个对象,保存的是触发mutations的函数,让mutations去修改state中的值) 275 | ```js 276 | // 1. 定义 277 | const actions = { 278 | increment: ({ commit }) => commit('increment') 279 | } 280 | 281 | // 2. 触发 282 | this.$store.dispatch('increment') 283 | 284 | // 3. 参数支持 285 | this.$store.dispatch('incrementAsync', { 286 | amount: 10 287 | }) 288 | 289 | // 4. 组件的方法中使用 290 | methods: { 291 | ...mapActions([ 292 | 'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')` 293 | 294 | // `mapActions` 也支持载荷: 295 | 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)` 296 | ]), 297 | ...mapActions({ 298 | add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')` 299 | }) 300 | } 301 | ``` 302 | - getters(一个对象,保存的是一些类似与计算属性的函数,可以通过他们得到任何依赖于state的新的数据) 303 | ```js 304 | // 1. 定义 305 | const getters = { 306 | evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd' 307 | } 308 | 309 | // 2. 使用 310 | this.$store.getters.evenOrOdd 311 | 312 | // 3. 使用其他getters作为参数 313 | getters: { 314 | // ... 315 | doneTodosCount: (state, getters) => { 316 | return getters.doneTodos.length 317 | } 318 | } 319 | 320 | // 4. 组件内使用 321 | export default { 322 | // ... 323 | computed: { 324 | // 使用对象展开运算符将 getter 混入 computed 对象中 325 | ...mapGetters([ 326 | 'doneTodosCount', 327 | 'anotherGetter', 328 | // ... 329 | ]) 330 | } 331 | } 332 | ``` 333 | 334 | ### 使用vuex 335 | 336 | `npm install vuex -S` 337 | 338 | ```js 339 | 340 | // store.js 341 | import Vue from 'vue' 342 | import Vuex from 'vuex' 343 | 344 | Vue.use(Vuex) 345 | const state = {} 346 | const mutations = {} 347 | const actions = {} 348 | const getters = {} 349 | export default new Vuex.Store({ 350 | state, 351 | getters, 352 | actions, 353 | mutations 354 | }) 355 | 356 | // app.js 357 | import store from './store' 358 | 359 | new Vue({ 360 | el: '#app', 361 | store, 362 | render: h => h(Counter) 363 | }) 364 | ``` 365 | 366 | ## 用户管理 367 | 368 | ### 用户列表 369 | ```scss 370 | /* 覆盖element导航菜单的样式 */ 371 | .el-breadcrumb { 372 | background-color: #D3DCE6; 373 | height: 45px; 374 | font-size: 15px; 375 | padding-left: 10px; 376 | line-height: 45px; 377 | margin-bottom: 15px; 378 | } 379 | ``` 380 | 381 | ```scss 382 | .user { 383 | .search-input { 384 | width: 300px; 385 | } 386 | .page { 387 | padding: 5px 0; 388 | background-color: #D3DCE6; 389 | } 390 | } 391 | ``` 392 | 393 | ```js 394 | // 添加用户的表单验证 395 | rules: { 396 | username: [ 397 | { required: true, message: '请输入用户名', trigger: 'blur' } 398 | ], 399 | password: [ 400 | { required: true, message: '请输入密码', trigger: 'blur' } 401 | ], 402 | email: [ 403 | { required: true, message: '请输入邮箱地址', trigger: 'blur' }, 404 | { type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur,change' } 405 | ], 406 | mobile: [ 407 | { required: true, message: '电话不能为空' } 408 | ] 409 | } 410 | ``` 411 | 412 | ## 权限管理 413 | 414 | ### 权限列表 415 | 416 | ```js 417 | getSeletedRights (role) { 418 | let lastRole, 419 | if (role.children && role.children.length !== 0) { 420 | role.children.map(item => { 421 | this.getSeletedRights(item) 422 | }) 423 | } else { 424 | lastRole = role 425 | this.seletedRights.push(lastRole.id) 426 | } 427 | } 428 | 429 | grantRightSubmit () { 430 | let treeData = this.$refs.tree.getCheckedNodes() 431 | treeData = treeData.map((item) => { 432 | return item.id + ',' + item.pid 433 | }) 434 | treeData = treeData.join(',').split(',') 435 | let rightIds = [...new Set(treeData)] 436 | grantRight(this.currentRole.id, {rids: rightIds.join(',')}).then(res => { 437 | console.log(res) 438 | }) 439 | } 440 | ``` 441 | 442 | ### 角色列表 443 | 444 | ## 商品管理 445 | 446 | ### 商品分类 447 | 448 | ### 商品列表 449 | -------------------------------------------------------------------------------- /笔记(汇总)/Vue基础-day02.md: -------------------------------------------------------------------------------- 1 | Vue基础-day02 2 | === 3 | 4 | 5 | - [computed](#computed) 6 | - [watch](#watch) 7 | - [案例-利用系统指令实现品牌案例管理](#案例-利用系统指令实现品牌案例管理) 8 | - [功能-实现品牌列表数据过滤功能](#功能-实现品牌列表数据过滤功能) 9 | - [功能-利用vue的动画实现删除提示框动画呈现和离开](#功能-利用vue的动画实现删除提示框动画呈现和离开) 10 | - [axios(基于 promise 的 HTTP 库)](#axios基于-promise-的-http-库) 11 | - [get请求示例](#get请求示例) 12 | - [post请求示例](#post请求示例) 13 | - [案例-品牌管理API](#案例-品牌管理api) 14 | - [案例-axios版获取及删除数据](#案例-axios版获取及删除数据) 15 | - [vue-resource(不推荐使用)](#vue-resource不推荐使用) 16 | - [vue过渡&动画](#vue过渡动画) 17 | - [transition的作用](#transition的作用) 18 | - [transition结合css实现过渡](#transition结合css实现过渡) 19 | - [transition结合animate.css实现过渡](#transition结合animatecss实现过渡) 20 | - [transition结合钩子函数实现过渡](#transition结合钩子函数实现过渡) 21 | 22 | 23 | 24 | ## computed 25 | 26 | 计算属性出现的目的是解决模板中放入过多的逻辑会让模板过重且难以维护的问题;计算属性是基于它们的依赖进行缓存的 27 | 28 | ```js 29 | computed: { 30 | fullName: function () { 31 | console.log(this.firstName + this.lastName) 32 | return this.firstName + this.lastName 33 | } 34 | } 35 | ``` 36 | 37 | ## watch 38 | 39 | 侦听器(watch)用来观察和响应 Vue 实例上的数据变动 40 | 41 | ```js 42 | watch: { 43 | firstName: function (val) { 44 | this.fullName = val + ' ' + this.lastName 45 | }, 46 | lastName: function (val) { 47 | this.fullName = this.firstName + ' ' + val 48 | } 49 | } 50 | ``` 51 | 52 | 注意:通常情况下用computed,当需要在数据变化时**执行异步**或**开销较大**的操作时,用watch 53 | 54 | ## 案例-利用系统指令实现品牌案例管理 55 | 56 | ### 功能-实现品牌列表数据过滤功能 57 | 58 | 利用两种方式实现: 59 | 1. watch 监听器 60 | 61 | ```js 62 | 1. 在data(){}中定义searchvalue变量,作为存储用户是输入搜索值 63 | new Vue({ 64 | // vm控制的区块为id为app的div,此div中的所有vue指令均可以被vm解析 65 | el: '#app', 66 | data: { 67 | searchvalue:'' 68 | listold:[ 69 | {id:1,name:'宝马',ctime:Date()}, 70 | {id:2,name:'奔驰',ctime:Date()} 71 | ], 72 | list:[ 73 | {id:1,name:'宝马',ctime:Date()}, 74 | {id:2,name:'奔驰',ctime:Date()} 75 | ] 76 | }, 77 | methods: { 78 | adddata(){ 79 | this.product.ctime = Date(); 80 | this.list.push(this.product); 81 | this.product = {id:0,name:'',ctime:Date()}; 82 | // 为了防止搜索出来的新数组覆盖list,需要利用listold来存储一个list中完整的值 83 | this.listold = this.list; 84 | } 85 | }, 86 | }); 87 | 88 | 89 | 2. 双向数据绑定searchvalue 90 |
91 | 品牌名称: 92 |
93 | 94 | 3. 在watch中监控searchvalue变量的值,当值有改变,则触发方法searchvalue 95 | new Vue({ 96 | watch:{ 97 | // 监控searchvalue变量的值,当值有改变,则触发方法 98 | // newval:searchvalue变量改变以后的值 99 | //oldval:searchvalue变量改变之前的值 100 | 'searchvalue':function(newval,oldval){ 101 | // 为了防止搜索出来的新数组覆盖list,需要利用listold来存储一个list中完整的值 102 | this.list= this.listold.filter(item=>item.name.indexOf(newval)!=-1); 103 | } 104 | } 105 | }); 106 | ``` 107 | 108 | 2. computed 计算属性 109 | 110 | ```js 111 | 1. 在data(){}中定义searchvalue变量,作为存储用户是输入搜索值,利用computed定义计算属性来实现按照条件筛选数据逻辑 112 | new Vue({ 113 | // vm控制的区块为id为app的div,此div中的所有vue指令均可以被vm解析 114 | el: '#app', 115 | data: { 116 | searchvalue:'' 117 | }, 118 | computed:{ 119 | listdata(){ 120 | return this.list.filter(item=>item.name.indexOf(this.searchvalue)!=-1); 121 | } 122 | } 123 | }); 124 | 125 | 2. 在v-for中遍历计算属性listdata数组中的值 126 | 127 | 128 | 由计算属性的特点可以知道:当改变了list数组中的值以后,会自动触发计算属性listdata的执行,从而更新v-for对于的列表 129 | ``` 130 | 131 | ### 功能-利用vue的动画实现删除提示框动画呈现和离开 132 | 133 | [transition官方文档](https://cn.vuejs.org/v2/guide/transitions.html) 134 | 135 | 1. transition结合css实现 136 | 137 | ```html 138 | // 1. 用transition组件包裹需要添加过渡的元素,并添加name属性 139 | 140 | hello 黑马 141 | 142 | 143 | // 2. 定义以slide开头的css类 144 | 160 | 161 | // 3. 在点击事件中控制元素显示与隐藏 162 | 163 | 164 | // 4. 定义一个isshow变量,用来控制元素显示或隐藏,并在点击事件中改变它的值 165 | // 实例化vue对象(MVVM中的View Model) 166 | new Vue({ 167 | // vm控制的区块为id为app的div,此div中的所有vue指令均可以被vm解析 168 | el: '#app', 169 | data: { 170 | // 数据 (MVVM中的Model) 171 | isshow: false 172 | }, 173 | methods: { 174 | toggleShow: function () { 175 | this.isshow = !this.isshow; 176 | } 177 | } 178 | }) 179 | ``` 180 | 181 | 2. transition结合animate.css实现 182 | 183 | ```html 184 | // 1. 导入animate.css 185 | 186 | // 2. 使用 187 | 188 | 192 | 193 | hello 黑马 194 | 195 | 196 | // 利用methods中的方法去控制data中的isshow属性,实现元素的显示与隐藏 197 | ``` 198 | 199 | 3. transition结合动画钩子函数实现 200 | 201 | > 注意:enter和leave钩子中,当动画结束一定要调用done()函数,不然后续钩子函数不会被调用 202 | 203 | ```html 204 | 205 |
206 | 207 |
208 | 209 | 216 | 221 | hello 黑马 222 | 223 |
224 | 225 | 226 | 227 | 273 | ``` 274 | 275 | ## axios(基于 promise 的 HTTP 库) 276 | 277 | [axios文档](https://github.com/axios/axios) 278 | 279 | 1. http请求报文 280 | 281 | 浏览器与服务器数据交互是遵循http协议的,当浏览器要访问服务器的时候,浏览器需要将相关请求数据提交给服务器(例如:浏览器信息,url地址,参数等),通常是通过请求报文来提交的 282 | 283 | * 请求报文的格式分为: 284 | 1. 请求报文行 285 | 2. 请求报文头 286 | 3. 请求报文体 287 | 288 | ![请求报文](./img/day02/请求报文.png) 289 | 290 | 2. http响应报文 291 | 292 | 当浏览器请求服务器的时候,服务器需要将数据返回给浏览器,这种数据是通过响应报文响应回浏览器的 293 | 294 | * 响应报文的格式分为: 295 | 1. 响应报文行 296 | 2. 响应报文头 297 | 3. 响应报文体 298 | 299 | ![响应报文](./img/day02/响应报文.png) 300 | 301 | ### get请求示例 302 | 303 | ```js 304 | axios.get('/user?ID=12345') 305 | .then(function (response) { 306 | console.log(response); 307 | }) 308 | .catch(function (error) { 309 | console.log(error); 310 | }); 311 | 312 | // 或者 313 | axios.get('/user', { 314 | params: { 315 | ID: 12345 316 | } 317 | }) 318 | .then(function (response) { 319 | console.log(response); 320 | }) 321 | .catch(function (error) { 322 | console.log(error); 323 | }); 324 | ``` 325 | 演示代码 326 | 327 | ```js 328 | methods: { 329 | getData: function () { 330 | var url = 'http://157.122.54.189:9093/api/getprodlist' 331 | axios.get(url) 332 | .then(res => { 333 | this.list = res.data.message 334 | console.log(this.list); 335 | }) 336 | .catch(error => { 337 | console.log(error); 338 | }) 339 | } 340 | } 341 | ``` 342 | 343 | ### post请求示例 344 | 345 | ```js 346 | axios.post('/user', { 347 | firstName: 'Fred', 348 | lastName: 'Flintstone' 349 | }) 350 | .then(function (response) { 351 | console.log(response); 352 | }) 353 | .catch(function (error) { 354 | console.log(error); 355 | }); 356 | ``` 357 | 演示代码 358 | 359 | ```js 360 | methods: { 361 | getData: function () { 362 | var url = 'http://157.122.54.189:9093/api/addproduct' 363 | axios.post(url, "name=hello") 364 | .then(res => { 365 | console.log(res); 366 | }) 367 | .catch(error => { 368 | console.log(error); 369 | }) 370 | } 371 | } 372 | ``` 373 | 374 | ## 案例-品牌管理API 375 | 376 | 377 | | 接口说明 | URL | 请求方式 | 参数 | 成功返回 | 失败返回 | 378 | | ---------------- | --------------------------------------------- | -------- | ------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- | 379 | | 获取品牌数据列表 | http://157.122.54.189:9093/api/getprodlist | GET | searchvalue(可选) | {"status": 0,"message": [{"id": 104772,"name": "LV","ctime": "2017-12-05T08:35:57.000Z"}]} | 未做处理 | 380 | | 添加品牌数据 | http://157.122.54.189:9093/api/addproduct | POST | name(必填) | {"status": 0,"message": "新增品牌成功"} | 未做处理 | 381 | | 删除品牌数据 | http://157.122.54.189:9093/api/delproduct/:id | GET | id(必填) | {"status": 0, "message": "删除品牌数据ok"} | {"status": 1,"message": "ER_BAD_FIELD_ERROR: Unknown column 'xxx' in 'where clause'"} | 382 | 383 | ## 案例-axios版获取及删除数据 384 | 385 | ```html 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | Document 394 | 395 | 396 | 425 | 426 | 427 | 428 |
429 |
430 | 编号: 431 | 品牌名称: 432 | 433 | 434 |
435 | 436 |
437 | 品牌名称: 438 | 439 |
440 | 441 |
442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 456 | 457 | 458 | 459 | 460 | 461 |
编号品牌名称创立时间操作
{{item.id}}{{item.title}}{{item.ctime}} 454 | 455 |
没有品牌数据
462 |
463 |
464 | 465 | 498 | 499 | 500 | ``` 501 | 502 | ## vue-resource(不推荐使用) 503 | 504 | 一个使用 XMLHttpRequest 或者 JSONP处理请求的vue插件 505 | 506 | [vue-resource文档](https://github.com/pagekit/vue-resource) 507 | 508 | 509 | * 书写步骤 510 | ```js 511 | 1. 通过 https://cdn.jsdelivr.net/vue.resource/1.2.1/vue-resource.min.js 下载到vue-resource文件 512 | 513 | 2. 在html页面中通过script标签导入vue-resource.min.js 文件后,就会自动的在Vue对象实例上初始化 $http 514 | 515 | 3. 使用 516 | // 全局Vue构造器写法 517 | Vue.http.get('/someUrl', [options]).then(successCallback, errorCallback); 518 | Vue.http.post('/someUrl', [body], [options]).then(successCallback, errorCallback); 519 | 520 | // 在Vue实例中的写法 521 | this.$http.get('/someUrl', [options]).then(successCallback, errorCallback); 522 | this.$http.post('/someUrl', [body], [options]).then(successCallback, errorCallback); 523 | ``` 524 | 525 | * vue-resource get请求 526 | 527 | ```js 528 | 写法格式: 529 | this.$http.get('请求的url', [可选参数对象,使用{}传参]).then(成功回调函数, 失败回调函数); 530 | 531 | 成功回调函数参数对象主要属性说明: 532 | 1. url : 请求的原始url 533 | 2. body: 响应报文体中的数据(我们通常用这个属性获取服务器返回的数据) 534 | 3. 其他属性请看文档 535 | 536 | 举例: 537 | this.$http.get('http://vuecms.ittun.com/api/getlunbo?id=1').then(function(res){console.log(res.body)}, function(err){//err是异常数据}); 538 | ``` 539 | 540 | * vue-resource post请求 541 | 542 | ```js 543 | 写法格式: 544 | this.$http.post('请求的url',[可选参数请求报文体对象body,使用{}传参], [可选参数对象,使用{}传参]).then(成功回调函数, 失败回调函数); 545 | 546 | 成功回调函数参数对象主要属性说明: 547 | 1. url : 请求的原始url 548 | 2. body: 响应报文体中的数据(我们通常用这个属性获取服务器返回的数据) 549 | 3. 其他属性请看文档 550 | 551 | 注意点: 552 | $http.post()方法中的第二个参数固定写成:{emulateJSON:true},否则可能造成服务器无法接收到请求报文体中的参数值 553 | 554 | 举例: 555 | this.$http.post('http://vuecms.ittun.com/api/adddata?id=1' //请求的url 556 | ,{content:'hello'} //请求报文体中传入的参数对象,多个使用逗号分隔 557 | ,{emulateJSON:true} //固定写法,保证服务器可以获取到请求报文体参数值 558 | ).then(function(res){console.log(res.body)}, function(err){//err是异常数据}); 559 | ``` 560 | 561 | * vue-resource jsonp请求 562 | 563 | ![jsonp跨域原理解析](./img/day02/jsonp跨域原理解析.png) 564 | 565 | ```js 566 | jsonp请求主要用来解决ajax跨域请求问题,使用jsonp实现跨域首先要保证服务器api支持jsonp请求的格式 567 | 568 | 写法格式: 569 | this.$http.jsonp('请求的url', [可选参数对象,使用{}传参]).then(成功回调函数, 失败回调函数); 570 | 571 | 成功回调函数参数对象主要属性说明: 572 | 1. url : 请求的原始url 573 | 2. body: 响应报文体中的数据(我们通常用这个属性获取服务器返回的数据) 574 | 3. 其他属性请看文档 575 | 576 | 举例: 577 | this.$http.jsonp('http://157.122.54.189:9093/jsonp').then(function(res){console.log(res.body)}, function(err){//err是异常数据}); 578 | ``` 579 | 580 | ## vue过渡&动画 581 | 582 | Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入或离开的过渡 583 | * 条件渲染 (使用 v-if) 584 | * 条件展示 (使用 v-show) 585 | * 动态组件 586 | 587 | ### transition的作用 588 | 589 | 将需要添加过渡的元素用transition组件包裹起来,结合css或者js钩子函数就能实现该元素进入或者离开的动画效果 590 | 591 | ### transition结合css实现过渡 592 | 593 | ```html 594 | 610 | 611 | 612 | hello 黑马 613 | 614 | ``` 615 | 动画图解
616 | ![transition结合css实现过渡](./img/day02/transition结合css实现过渡.png) 617 | 618 | ### transition结合animate.css实现过渡 619 | 620 | ```html 621 | 622 | 623 | 624 | 634 | 635 | hello 黑马 636 | 637 | ``` 638 | 639 | ### transition结合钩子函数实现过渡 640 | 641 | 1. 过渡动画进入 642 | before-enter 过渡动画进入之前,一般在这个方法中定义目标元素的初始位置 643 | enter 过渡动画进入中,在这个方法中定义目标元素的结束位置 644 | after-enter 过渡动画结束后,通常在这个方法里面重置初始值 645 | enter-cancelled 取消过渡动画时被调用 646 | 647 | 2. 过渡动画离开 648 | before-leave 动画离开之前触发 649 | leave 过渡动画进入中触发 650 | after-leave 过渡动画离开结束后 651 | leave-cancelled 取消过渡动画时被调用 652 | 653 | ```html 654 | 659 | hello 黑马 660 | 661 | ``` 662 | ```js 663 | methods: { 664 | // 1.0 动画进入前 665 | beforeEnter: function (el) { 666 | console.log('1.0 beforeEnter'); 667 | 668 | // 在这个方法中设定当前动画元素的起始位置 669 | el.style = "padding-left:100px"; 670 | }, 671 | // 2.0 动画执行中 672 | // el:动画的元素dom对象 673 | // done:enter事件执行完以后的回调,执行了它之后,afterEnter事件才会执行 674 | enter: function (el, done) { 675 | console.log('2.0 enter'); 676 | 677 | var step = 3; 678 | var interval = setInterval(() => { 679 | el.style.paddingLeft = (100 - step) + 'px'; 680 | step++; 681 | if (parseInt(el.style.paddingLeft) <= 0) { 682 | clearInterval(interval) 683 | // 动画结束后必须执行done()函数 684 | done() 685 | } 686 | }, 10) 687 | }, 688 | // 3.0 动画执行完毕 689 | afterEnter: function (el) { 690 | console.log('3.0 afterEnter'); 691 | // 将isshow重置为false即可 692 | this.isshow = false; 693 | }, 694 | showhide: function () { 695 | this.isshow = !this.isshow; 696 | } 697 | } 698 | ``` -------------------------------------------------------------------------------- /笔记(汇总)/Vue基础-day01.md: -------------------------------------------------------------------------------- 1 | Vue基础-day01 2 | === 3 | 4 | 5 | - [课前准备](#课前准备) 6 | - [浏览器插件](#浏览器插件) 7 | - [VS Code插件](#vs-code插件) 8 | - [玩转Vs code](#玩转vs-code) 9 | - [课程介绍](#课程介绍) 10 | - [为什么学习Vue](#为什么学习vue) 11 | - [什么是MVVM](#什么是mvvm) 12 | - [Vue初体验](#vue初体验) 13 | - [Vue常用系统指令](#vue常用系统指令) 14 | - [插值表达式](#插值表达式) 15 | - [v-text](#v-text) 16 | - [v-html](#v-html) 17 | - [v-bind](#v-bind) 18 | - [v-for](#v-for) 19 | - [v-model](#v-model) 20 | - [v-on](#v-on) 21 | - [v-on按键修饰符](#v-on按键修饰符) 22 | - [v-if](#v-if) 23 | - [v-show](#v-show) 24 | - [v-cloak](#v-cloak) 25 | - [案例-利用系统指令实现品牌案例管理](#案例-利用系统指令实现品牌案例管理) 26 | - [目的](#目的) 27 | - [资源准备](#资源准备) 28 | - [功能-数据展示实现](#功能-数据展示实现) 29 | - [功能-数据删除](#功能-数据删除) 30 | - [功能-数据添加](#功能-数据添加) 31 | - [功能-按回车键添加数据](#功能-按回车键添加数据) 32 | - [功能-输入框自动聚焦](#功能-输入框自动聚焦) 33 | - [ref](#ref) 34 | - [功能-时间格式化](#功能-时间格式化) 35 | - [过滤器](#过滤器) 36 | 37 | 38 | 39 | ## 课前准备 40 | 41 | ### 浏览器插件 42 | 43 | * Vue.js devtools 44 | 45 | ### VS Code插件 46 | 47 | 自动补全标签 48 | * Auto Close Tag 49 | * Auto Complete Tag 50 | * Auto Rename Tag 51 | 52 | 开启一个服务器浏览HTML网页,第一次使用需要Ctrl + Shift + p输入 live server选择open 53 | * Live Server 54 | 55 | 路径自动补全 56 | * Path Intellisense 57 | 58 | vue语法高亮和自动补全代码 59 | * Vetur 60 | * VueHelper 61 | 62 | ### 玩转Vs code 63 | 64 | * [Vs Code奇淫技巧](https://github.com/Microsoft/vscode-tips-and-tricks) 65 | 66 | * Vs Code设置 67 | 68 | 文件--->首选项--->设置,然后添加如下代码: 69 | 70 | ```json 71 | "emmet.syntaxProfiles": { 72 | "vue-html": "html", 73 | "vue": "html" 74 | }, 75 | "emmet.includeLanguages": { 76 | "vue-html": "html", 77 | "vue": "html" 78 | } 79 | ``` 80 | ## 课程介绍 81 | 82 | ### 为什么学习Vue 83 | 84 | ![为什么学习vue](./img/day01/为什么学习vue.png) 85 | 86 | ### 什么是MVVM 87 | 88 | - M => Model(数据模型) 89 | - V => View(视图模型,负责将数据模型转化成UI展现出来,就是那些DOM结构) 90 | - VM => ViewModel(一个同步View和Model的对象) 91 | 92 | ![MVVM](./img/day01/MVVM.png) 93 | 94 | ### Vue初体验 95 | 96 | ```html 97 | 98 | 99 | 100 | 101 | 102 | 103 | Document 104 | 105 | 106 | 107 | 108 | 109 |
{{msg}}
110 |
111 | 112 |

{{msg}}

113 |
114 | 125 | 126 | 127 | ``` 128 | ## Vue常用系统指令 129 | 130 | ### 插值表达式 131 | 132 | ```html 133 | 数据绑定最常见的形式,其中最常见的是使用插值表达式,写法是{{}} 中写表达式 134 | 例如:Message: {{ msg }} 135 | Mustache 标签将会被替代为对应数据对象上 msg 属性(msg定义在data对象中)的值。 136 | 无论何时,绑定的数据对象上 msg 属性发生了改变,插值处的内容都会更新。 137 | 138 | {{}}对JavaScript 表达式支持,例如: 139 | {{ number + 1 }} 140 | {{ ok ? 'YES' : 'NO' }} 141 | {{ message.split('').reverse().join('') }} 142 | 143 | 但是有个限制就是,每个绑定都只能包含单个表达式,如下表达式无效: 144 | 145 | {{ var a = 1 }} 146 | 147 | 148 | {{ number++ }} 会报警告:vue2.js:482 [Vue warn]: You may have an infinite update loop in a component render function. 149 | 150 | 151 | {{ if (ok) { return message } }} 152 | ``` 153 | 154 | ### v-text 155 | 156 | ```html 157 | 158 |
159 | new Vue({ 160 | data:{ 161 | msg:'hello world' 162 | } 163 | }); 164 | 165 | 166 |
hello world
167 | ``` 168 | 169 | ### v-html 170 | 171 | ```html 172 | 差值表达式和v-text会将数据解释为纯文本,而非 HTML 。 173 | 为了输出真正的 HTML ,你需要使用 v-html 指令: 174 | 例如: 175 |
176 | new Vue({ 177 | data:{ 178 | rawHtml:'

hello world

' 179 | } 180 | }) 181 | 182 | 被插入的内容都会被当做 HTML,但是对于没有HTML标签的数据绑定时作用同v-text和{{}} 183 | ``` 184 | 185 | ### v-bind 186 | 187 | ```html 188 | 1、作用:可以给html元素或者组件动态地绑定一个或多个特性,例如动态绑定style和class 189 | 190 | 2、举例: 191 | 1、img的src从imageSrc变量中取得 192 | 193 | 194 | 2、从classA, classB两个变量的值作为class的值, 195 | 结果是:
classA, classB
196 |
classA, classB
197 | 198 | 3、isRed变量如果为true,则class的值为red,否则没有 199 |
isred
200 | 201 | 4、div的class属性值一定有classA变量的值,而是否有classB和classC变量的值取决于isB和isC是否为true,二者一一对应 202 |
数组对象
203 | 204 | 5、变量加常量 205 |
size22
206 | 207 | 6、变量加常量的另一种写法 208 | 209 | 210 | 7、对象数组 211 |
styleObjectA, styleObjectB
212 | 213 | 3、缩写形式 214 | 215 |
classA, classB
216 |
isred
217 |
数组对象
218 |
size22
219 | 220 |
styleObjectA, styleObjectB
221 | 222 | 223 | vue对象初始化 224 | 246 | ``` 247 | 248 | ### v-for 249 | 250 | ```html 251 | 268 | 275 | 292 | ``` 293 | 294 | ### v-model 295 | 296 | ```html 297 | 1、在表单控件或者组件上创建双向绑定 298 | 2、v-model仅能在如下元素中使用: 299 | input 300 | select 301 | textarea 302 | components(Vue中的组件) 303 | 304 | 3、举例: 305 | 306 | 307 | new Vue({ 308 | data:{ 309 | uname:'' //这个属性值和input元素的值相互一一对应,二者任何一个的改变都会联动的改变对方 310 | } 311 | }) 312 | ``` 313 | 314 | ### v-on 315 | 316 | ```html 317 | 1、作用:绑定事件监听,表达式可以是一个方法的名字或一个内联语句, 318 | 如果没有修饰符也可以省略,用在普通的html元素上时,只能监听 原生 319 | DOM 事件。用在自定义元素组件上时,也可以监听子组件触发的自定义事件。 320 | 321 | 2、常用事件: 322 | v-on:click 323 | v-on:keydown 324 | v-on:keyup 325 | v-on:mousedown 326 | v-on:mouseover 327 | v-on:submit 328 | .... 329 | 330 | 3、示例: 331 | 332 | 333 | 334 | 335 | 336 | 337 |
338 | 339 | 5、v-on的缩写形式:可以使用@替代 v-on: 340 | 341 | 342 | 343 | 6、按键修饰符 344 | 触发像keydown这样的按键事件时,可以使用按键修饰符指定按下特殊的键后才触发事件 345 | 346 | 写法: 347 | 当按下回车键时才触发kd1事件 348 | 349 | 由于回车键对应的keyCode是13,也可以使用如下替代 350 | 当按下回车键时才触发kd1事件 351 | 352 | 但是如果需要按下字母a(对应的keyCode=65)才触发kd1事件,有两种写法: 353 | 1、由于默认不支持a这个按键修饰符,需要Vue.config.keyCodes.a = 65 添加一个对应,所以这种写法为: 354 | 355 | Vue.config.keyCodes.a = 65 356 | 这样即可触发 357 | 358 | 2、也可以之间加上a对应的数字65作为按键修饰符 359 | 这样即可触发 360 | 361 | 键盘上对应的每个按键可以通过 http://keycode.info/ 获取到当前按下键所对应的数字 362 | ``` 363 | 364 | ### v-on按键修饰符 365 | 366 | * 作用说明 367 | 368 | ```html 369 | 文档地址:https://cn.vuejs.org/v2/guide/events.html#键值修饰符 370 | 371 | 在监听键盘事件时,我们经常需要监测常见的键值。 Vue 允许为 v-on 在监听键盘事件时添加按键修饰符: 372 | .enter 373 | .tab 374 | .delete (捕获 “删除” 和 “退格” 键) 375 | .esc 376 | .space 377 | .up 378 | .down 379 | .left 380 | .right 381 | ``` 382 | 383 | * 可以自定义按键别名 384 | 385 | ```html 386 | // 在Vue2.0版本中扩展一个f1的按键修饰符写法: 387 | Vue.config.keyCodes.f1 = 112 388 | 389 | // 使用 390 | 391 | ``` 392 | 393 | ### v-if 394 | 395 | ```html 396 | 1、作用:根据表达式的值的真假条件来决定是否渲染元素,如果条件为false不渲染(达到隐藏元素的目的),为true则渲染。在切换时元素及它的数据绑定被销毁并重建 397 | 398 | 2、示例: 399 | 400 | {{#if isShow}} 401 |

Yes

402 | {{/if}} 403 | 404 | 通常我们使用写法居多: 405 |

Yes

406 | 407 | 也可以用 v-else 添加一个 “else” 块: 408 |

Yes

409 |

No

410 | 411 | 注意:v-else 元素必须紧跟在 v-if 元素否则它不能被识别。 412 | 413 | new Vue({ 414 | data:{ 415 | isShow:true 416 | } 417 | }); 418 | ``` 419 | 420 | ### v-show 421 | 422 | ```html 423 | 1、根据表达式的真假值,切换元素的 display CSS 属性,如果为false,则在元素上添加 display:none来隐藏元素,否则移除display:none实现显示元素 424 | 425 | 2、示例: 426 |

Yes

427 | 428 | new Vue({ 429 | data:{ 430 | isShow:true 431 | } 432 | }); 433 | 434 | 3、v-if和v-show的总结: 435 | v-if和v-show 都能够实现对一个元素的隐藏和显示操作,但是v-if是将这个元素添加或者移除到dom中,而v-show 436 | 是在这个元素上添加 style="display:none"和移除它来控制元素的显示和隐藏的 437 | ``` 438 | 439 | ### v-cloak 440 | 441 | ```html 442 | v-cloak指令保持在元素上直到关联实例结束编译后自动移除,v-cloak和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。 443 | 通常用来防止{{}}表达式闪烁问题 444 | 例如: 445 | 448 | 449 | 450 | {{msg}} 451 | 452 | new Vue({ 453 | data:{ 454 | msg:'hello ivan' 455 | } 456 | }) 457 | ``` 458 | 459 | ## 案例-利用系统指令实现品牌案例管理 460 | 461 | ### 目的 462 | 463 | 通过案例熟悉Vue系统指令的用法和结构的写法练习,做到知识点的巩固和学会 464 | 应用,并且在案例的扩展需求中,学习Vue新知识点,做到先有需求,再有知识点 465 | 学习,最后到知识点的应用,让学员学习知识点的同时学会知识点的应用 466 | 467 | ### 资源准备 468 | 469 | * 效果图
470 | ![效果图](./img/day01/案例效果图.png) 471 | 472 | * 案例html结构 473 | ```html 474 | 475 |
476 |
477 | 编号: 478 | 品牌名称: 479 | 480 |
481 | 482 |
483 | 品牌名称: 484 |
485 | 486 |
487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 |
编号品牌名称创立时间操作
没有品牌数据
499 |
500 |
501 | 502 | ``` 503 | 504 | * 案例css样式 505 | 506 | ```html 507 | 534 | ``` 535 | 536 | ### 功能-数据展示实现 537 | 538 | 1. 在 data 中添加 一个名称为 list的变量,类型为数组,存放品牌数据的对象,格式为:{id:1,name:'宝马',ctime:Date()} 539 | 540 | ```js 541 | var vm = new Vue({ 542 | el: '#app', 543 | data: { 544 | list: [ 545 | {id: 1, title: 'LV', ctime: new Date()}, 546 | {id: 2, title: 'CC', ctime: new Date()}, 547 | {id: 3, title: 'CK', ctime: new Date()}, 548 | ] 549 | } 550 | }) 551 | ``` 552 | 553 | 2. 在table中的“动态生成内容tr”位置使用v-for指令遍历list数组数据生成表格内容行,注意要写`:key` 554 | 555 | ```html 556 | 557 | {{item.id}} 558 | {{item.title}} 559 | {{item.ctime}} 560 | 561 | 删除 562 | 563 | 564 | ``` 565 | 566 | 3. 处理 “没有品牌数据” 提示问题,代码如下 567 | 568 | ```html 569 | 利用:v-if进行判断,当list为空时,才显示没有品牌数据 570 | 571 | 572 | 没有品牌数据 573 | 574 | ``` 575 | 576 | ### 功能-数据删除 577 | 578 | 1. 给按钮绑定删除方法,并传入一个id 579 | 580 | ```html 581 | 删除 582 | ``` 583 | 584 | 2. Vue实例中定义删除的方法 585 | ```js 586 | methods: { 587 | deleteData(id) { 588 | // 返回满足函数条件的数组的项的index 589 | var index = this.list.findIndex(item => { 590 | return item.id === id 591 | }) 592 | // 删除该索引对应的值 593 | this.list.splice(index, 1) 594 | } 595 | } 596 | ``` 597 | 598 | ### 功能-数据添加 599 | 600 | * 效果图
601 | ![添加数据](./img/day01/添加数据.png) 602 | 603 | 1. 实现步骤1:在Vue对象实例的data中添加一个product对象{id:0,name:'',ctime:Date()} 604 | 605 | ```js 606 | new Vue({ 607 | el: '#app', 608 | data: { 609 | product:{id:0,name:'',ctime:Date()}, 610 | list:[ 611 | {id:1,name:'宝马',ctime:Date()}, 612 | {id:2,name:'奔驰',ctime:Date()} 613 | ] 614 | }, 615 | methods: { 616 | } 617 | }) 618 | ``` 619 | 620 | 2. 实现步骤2:在编号和品牌名称文本框中利用v-model对product对象中的id和name属性进行一一绑定 同时在添加按钮上利用 v-on:click注册事件addData 621 | 622 | ```html 623 | 编号: 624 | 品牌名称: 625 | 626 | ``` 627 | 628 | 3. 实现步骤3:在Vue对象实例的methods中添加一个 addData的方法实现添加逻辑即可完成 629 | 630 | ```js 631 | new Vue({ 632 | // vm控制的区块为id为app的div,此div中的所有vue指令均可以被vm解析 633 | el: '#app', 634 | data: { 635 | product:{id:0,name:'',ctime:Date()}, 636 | list:[ 637 | {id:1,name:'宝马',ctime:Date()}, 638 | {id:2,name:'奔驰',ctime:Date()} 639 | ] 640 | }, 641 | methods: { 642 | addData(){ 643 | // 修改品牌添加时间为当前时间 644 | this.product.ctime = Date(); 645 | 646 | // 添加数据到品牌列表中 647 | this.list.push(this.product); 648 | 649 | // 清空product 650 | this.product = {id:0,name:'',ctime:Date()}; 651 | } 652 | } 653 | }) 654 | ``` 655 | 656 | ### 功能-按回车键添加数据 657 | 658 | **关键点:利用v-on的.enter按键修饰符实现,回车键的keycode=13**
659 | ![回车添加数据](./img/day01/回车添加数据.png) 660 | 661 | ```html 662 | 品牌名称: 663 | 664 | 665 | 品牌名称: 666 | ``` 667 | ### 功能-输入框自动聚焦 668 | 669 | 在vue中实现这个需求有三种方式: 670 | * 可以使用document.getElementById()获取到文本框元素对象后调用其focus()方法和设置style属性 671 | * 可以在文本框上元素上增加一个 ref="自定义名称",再使用this.$refs.自定义名称.focus()和 672 | this.$refs.自定义名称.style="color:red" 设置style属性 673 | * 使用自定义指令实现封装 674 | 675 | > 注意:前两种方式的代码需要写到生命周期事件:mounted(){}中 676 | 677 | 1. 原生js操作DOM实现 678 | 679 | ```html 680 | // html代码 681 | 编号: 682 | 683 | // vue对象mounted(){}中代码 684 | mounted(){ 685 | document.getElementById('id').focus(); 686 | document.getElementById('id').style="color:red"; 687 | } 688 | ``` 689 | 690 | 2. ref方式实现 691 | 692 | ```html 693 | // html代码: 694 | 编号: 695 | 696 | // vue对象mounted(){}中代码 697 | mounted(){ 698 | this.$refs.id.focus(); 699 | this.$refs.id.style="color:red"; 700 | } 701 | ``` 702 | 3. 使用自定义指令 703 | 704 | * 使用说明 705 | 706 | - 利用Vue.directive('指令id',{inserted:function(el,binding){}}) 707 | - 参数说明 708 | + 指令id可由程序员自行定义,注意和系统指令名称有所区别,例如: 709 | focus,在某个元素上具体使用的时候请在 指令id前面再加上v-,例如 710 | `` 711 | 712 | + 第二个参数是一个对象,其中inserted是一个函数,表示 “被绑定元素插入父节点时调用” 713 | * inserted的参数: 714 | - el参数:表示使用此自定义指令的dom对象 715 | - binding参数:一个对象,包含以下属性: 716 | + name:指令名,不包括 v- 前缀。 717 | + value:指令的绑定值,例如:v-focus="colorvalue", value 的值是colorvalue这个变量的值,colorvalue定义在data(){}中 718 | + expression:绑定值的字符串形式。例如 v-focus="colorvalue" ,expression 的值是 "colorvalue" 719 | 720 | * 开始使用Vue.directive()封装自定义指令v-focus实现光标自动定位 721 | 722 | ```html 723 | 1、定义指令color 724 | Vue.directive('color',{ 725 | inserted:function(el,binding){ 726 | //将颜色设置给使用v-color指令的元素上 727 | el.style.color=binding.value; 728 | } 729 | }); 730 | 731 | 732 | 2、 在dom元素上使用指令,注意加上前缀 v- 733 | 编号: 734 | 735 | 3、在Vue对象实例中的data(){}中定义colorvalue 736 | new Vue({ 737 | data: { 738 | colorvalue:'red' 739 | } 740 | }); 741 | ``` 742 | 743 | ### ref 744 | 745 | ref的作用类似于document.getElementByID,在vue中想要获取一个dom对象或者组件对象,则只需要 在此元素上添加一个 ref="自定义名称" ,再使用 this.$refs.自定义名称即可获取 746 | 747 | ```html 748 | 749 | 750 | 751 | 752 | 753 |
754 | 755 |
756 | 757 | 769 | 770 | ``` 771 | 772 | ### 功能-时间格式化 773 | 774 | ```html 775 | // 定义全局过滤器datefmt 776 | Vue.filter('datefmt',function(input){ 777 | var date = new Date(input); 778 | var year = date.getFullYear(); 779 | var m = date.getMonth() + 1; 780 | var d = date.getDate(); 781 | var fmtStr = year+'-'+m +'-'+d; 782 | return fmtStr; //返回输出结果 783 | }); 784 | 785 | // 调用, 注意datefmt的第一个参数默认就是管道符左边的值 786 | {{item.ctime | datefmt }} 787 | ``` 788 | 789 | ### 过滤器 790 | 791 | 1. 私有过滤器 792 | 793 | * 定义方式 794 | 795 | 可以在 new Vue({filters:{}})中的filters中注册一个私有过滤器 796 | 797 | 定义格式: 798 | new Vue({ 799 | el:'#app', 800 | filters:{ 801 | '过滤器名称':function(管道符号|左边对象的值,参数1,参数2,....) { 802 | return 对管道符号|左边参数的值做处理以后的值 803 | }) 804 | } 805 | }); 806 | 807 | Vue2.0 调用过滤器传参写法: 808 | {{ msg | 过滤器id('参数1','参数2' ....) }} 809 | 810 | * (应用示例)自定义私有过滤器实现日期格式化 811 | 812 | ```html 813 | 1、 定义私有的日期格式化过滤器: 814 | new Vue({ 815 | el:'#app', 816 | data:{ 817 | time:new Date() 818 | }, 819 | filters:{ 820 | //定义在 VM中的filters对象中的所有过滤器都是私有过滤器 821 | datefmt:function(input,splicchar){ 822 | var date = new Date(input); 823 | var year = date.getFullYear(); 824 | var m = date.getMonth() + 1; 825 | var d = date.getDate(); 826 | var fmtStr = year+splicchar+m +splicchar+d; 827 | return fmtStr; //返回输出结果 828 | } 829 | } 830 | }); 831 | 2、使用 832 |
833 | {{ time | datefmt('-') }} //Vue2.0传参写法 834 |
835 | ``` 836 | 837 | 2. 全局过滤器 838 | 839 | * 定义方式 840 | 841 | 可以用全局方法 Vue.filter() 注册一个全局自定义过滤器,它接收两个参数:过滤器 ID 和过滤器函数。过滤器函数以值为参数,返回转换后的值 842 | 843 | 定义格式: 844 | Vue.filter('过滤器名称', function (管道符号|左边参数的值,其他参数1,其他参数2,....) { 845 | return 对管道符号|左边参数的值做处理以后的值 846 | }) 847 | 848 | Vue2.0 使用:参数调用时用(),多个参数中间使用逗号分开 849 | {{ msg | 过滤器名称('参数1','参数2' ....) }} 850 | 851 | * (应用示例)自定义全局过滤器实现日期格式化 852 | 853 | ```html 854 | 1、 定义全局的日期格式化过滤器: 855 | Vue.filter('datefmt',function(input,splicchar){ 856 | var date = new Date(input); 857 | var year = date.getFullYear(); 858 | var m = date.getMonth() + 1; 859 | var d = date.getDate(); 860 | var fmtStr = year+splicchar+m +splicchar+d; 861 | return fmtStr; //返回输出结果 862 | }); 863 | 864 | 2、使用 865 |
866 | {{ time | datefmt('-') }} //Vue2.0传参写法 867 |
868 | 869 | 877 | ``` 878 | --------------------------------------------------------------------------------