├── vue10 └── demo │ ├── src │ ├── style.css │ ├── images │ │ └── image.png │ ├── title.vue │ ├── button.vue │ ├── app.vue │ └── index.js │ ├── .babelrc │ ├── index.html │ ├── index.ejs │ ├── package.json │ ├── webpack.prod.config.js │ └── webpack.config.js ├── vue11 ├── router │ ├── src │ │ ├── style.css │ │ ├── images │ │ │ └── image.png │ │ ├── views │ │ │ ├── index.vue │ │ │ ├── user.vue │ │ │ └── about.vue │ │ ├── app.vue │ │ └── index.js │ ├── .babelrc │ ├── index.html │ ├── index.ejs │ ├── webpack.prod.config.js │ ├── package.json │ └── webpack.config.js ├── vue-bus │ ├── src │ │ ├── style.css │ │ ├── images │ │ │ └── image.png │ │ ├── app.vue │ │ ├── views │ │ │ ├── user.vue │ │ │ ├── about.vue │ │ │ ├── Counter.vue │ │ │ └── index.vue │ │ ├── moduleA.js │ │ ├── vue-bus.js │ │ └── index.js │ ├── .babelrc │ ├── index.html │ ├── index.ejs │ ├── webpack.prod.config.js │ ├── package.json │ └── webpack.config.js └── vuex │ ├── src │ ├── style.css │ ├── images │ │ └── image.png │ ├── app.vue │ ├── views │ │ ├── user.vue │ │ ├── about.vue │ │ └── index.vue │ ├── moduleA.js │ └── index.js │ ├── .babelrc │ ├── index.html │ ├── index.ejs │ ├── webpack.prod.config.js │ ├── package.json │ └── webpack.config.js ├── vue07 ├── input_box │ ├── index.js │ ├── input-number.html │ └── input-number.js ├── vue7-02.html ├── vue7-26.html ├── vue7-07.html ├── vue7-04.html ├── label_page │ ├── pane.js │ ├── style.css │ ├── tabs.html │ └── tabs.js ├── vue7-01.html ├── vue7-09.html ├── vue7-11.html ├── vue7-03.html ├── vue7-05.html ├── vue7-06.html ├── vue7-18.html ├── vue7-10.html ├── vue7-23.html ├── vue7-29.html ├── vue7-27.html ├── vue7-20.html ├── vue7-08.html ├── vue7-24.html ├── vue7-30.html ├── vue7-16.html ├── vue7-17.html ├── vue7-25.html ├── vue7-19.html ├── vue7-14.html ├── vue7-21.html ├── vue7-15.html ├── vue7-28.html ├── vue7-22.html ├── vue7-13.html └── vue7-12.html ├── vue13 ├── daily │ ├── .babelrc │ ├── src │ │ ├── images │ │ │ └── image.png │ │ ├── index.js │ │ ├── title.vue │ │ ├── components │ │ │ ├── item.vue │ │ │ └── daily-article.vue │ │ ├── button.vue │ │ ├── libs │ │ │ └── util.js │ │ ├── directives │ │ │ └── time.js │ │ ├── style.css │ │ └── app.vue │ ├── index.html │ ├── index.ejs │ ├── webpack.prod.config.js │ ├── package.json │ ├── proxy.js │ └── webpack.config.js └── README13.md ├── vue14 └── shopping │ ├── .babelrc │ ├── src │ ├── images │ │ └── image.png │ ├── views │ │ ├── user.vue │ │ ├── about.vue │ │ ├── index.vue │ │ └── product.vue │ ├── router.js │ ├── app.vue │ ├── style.css │ ├── components │ │ └── product.vue │ ├── product.js │ └── index.js │ ├── index.html │ ├── index.ejs │ ├── webpack.prod.config.js │ ├── package.json │ └── webpack.config.js ├── vue08 ├── v-time │ ├── index.js │ ├── index.html │ └── time.js ├── menu │ ├── index.js │ ├── index.html │ ├── style.css │ └── clickoutside.js └── vue8-01.html ├── vue05 ├── shopping_trolley │ ├── shopping.css │ ├── shopping.js │ └── shopping.html ├── vue5-01.html ├── vue5-02.html ├── vue5-05.html ├── vue5-08.html ├── vue5-07.html ├── vue5-03.html ├── vue5-06.html ├── vue5-09.html ├── vue5-12.html ├── vue5-04.html ├── vue5-10.html └── vue5-11.html ├── vue02 ├── vue2-07.html ├── vue2-10.html ├── vue2-01.html ├── vue2-04.html ├── vue2-08.html ├── vue2-05.html ├── vue2-02.html ├── vue2-03.html ├── vue2-09.html └── vue2-06.html ├── vue04 ├── vue4-01.html ├── vue4-04.html ├── vue4-06.html ├── vue4-09.html ├── vue4-08.html ├── vue4-02.html ├── vue4-10.html ├── vue4-05.html ├── vue4-07.html └── vue4-03.html ├── vue01 ├── vue1-01.html └── vue1-02.html ├── vue09 ├── sort_form │ ├── index.html │ ├── style.css │ ├── index.js │ └── table.js ├── vue9-03.html ├── vue9-12.html ├── message_list │ ├── index.js │ ├── index.html │ ├── list.js │ ├── input.js │ └── style.css ├── vue9-08.html ├── vue9-07.html ├── vue9-02.html ├── vue9-04.html ├── vue9-09.html ├── vue9-10.html ├── vue9-05.html ├── vue9-11.html ├── vue9-01.html ├── vue9-06.html └── vue9-13.html ├── vue03 ├── vue3-01.html ├── vue3-04.html ├── vue3-03.html └── vue3-02.html ├── vue15 └── README15.md ├── vue06 ├── vue6-03.html ├── vue6-01.html ├── vue6-06.html ├── vue6-08.html ├── vue6-05.html ├── vue6-02.html ├── vue6-07.html └── vue6-04.html ├── vue12 └── README12.md └── README.md /vue10/demo/src/style.css: -------------------------------------------------------------------------------- 1 | #app{ 2 | font-size: 24px; 3 | color:#f50; 4 | } 5 | -------------------------------------------------------------------------------- /vue11/router/src/style.css: -------------------------------------------------------------------------------- 1 | #app{ 2 | font-size: 24px; 3 | color:#f50; 4 | } 5 | -------------------------------------------------------------------------------- /vue11/vue-bus/src/style.css: -------------------------------------------------------------------------------- 1 | #app{ 2 | font-size: 24px; 3 | color:#f50; 4 | } 5 | -------------------------------------------------------------------------------- /vue11/vuex/src/style.css: -------------------------------------------------------------------------------- 1 | #app{ 2 | font-size: 24px; 3 | color:#f50; 4 | } 5 | -------------------------------------------------------------------------------- /vue07/input_box/index.js: -------------------------------------------------------------------------------- 1 | var app = new Vue({ 2 | el:'#app', 3 | data:{ 4 | value:5 5 | } 6 | }) -------------------------------------------------------------------------------- /vue10/demo/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":["env"], 3 | "plugins":["transform-runtime"], 4 | "comments":false 5 | } -------------------------------------------------------------------------------- /vue11/router/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":["env"], 3 | "plugins":["transform-runtime"], 4 | "comments":false 5 | } -------------------------------------------------------------------------------- /vue11/vuex/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":["env"], 3 | "plugins":["transform-runtime"], 4 | "comments":false 5 | } -------------------------------------------------------------------------------- /vue13/daily/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":["env"], 3 | "plugins":["transform-runtime"], 4 | "comments":false 5 | } -------------------------------------------------------------------------------- /vue11/vue-bus/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":["env"], 3 | "plugins":["transform-runtime"], 4 | "comments":false 5 | } -------------------------------------------------------------------------------- /vue14/shopping/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":["env"], 3 | "plugins":["transform-runtime"], 4 | "comments":false 5 | } -------------------------------------------------------------------------------- /vue10/demo/src/images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zyf711/vue-combat-book/HEAD/vue10/demo/src/images/image.png -------------------------------------------------------------------------------- /vue11/vuex/src/images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zyf711/vue-combat-book/HEAD/vue11/vuex/src/images/image.png -------------------------------------------------------------------------------- /vue13/daily/src/images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zyf711/vue-combat-book/HEAD/vue13/daily/src/images/image.png -------------------------------------------------------------------------------- /vue11/router/src/images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zyf711/vue-combat-book/HEAD/vue11/router/src/images/image.png -------------------------------------------------------------------------------- /vue11/router/src/views/index.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /vue11/vue-bus/src/images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zyf711/vue-combat-book/HEAD/vue11/vue-bus/src/images/image.png -------------------------------------------------------------------------------- /vue14/shopping/src/images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zyf711/vue-combat-book/HEAD/vue14/shopping/src/images/image.png -------------------------------------------------------------------------------- /vue08/v-time/index.js: -------------------------------------------------------------------------------- 1 | var app = new Vue({ 2 | el:'#app', 3 | data:{ 4 | timeNow : (new Date()).getTime(), 5 | timeBefore : 1488930695721 6 | } 7 | }) -------------------------------------------------------------------------------- /vue08/menu/index.js: -------------------------------------------------------------------------------- 1 | var app = new Vue({ 2 | el:'#app', 3 | data:{ 4 | show:false 5 | }, 6 | methods:{ 7 | handleClose:function(){ 8 | this.show = false 9 | } 10 | } 11 | }) -------------------------------------------------------------------------------- /vue13/daily/src/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './app.vue'; 3 | import './style.css'; 4 | 5 | new Vue({ 6 | el: '#app', 7 | render: h => { 8 | return h(App); 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /vue14/shopping/src/views/user.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /vue11/vuex/src/app.vue: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /vue11/router/src/app.vue: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /vue11/vue-bus/src/app.vue: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /vue11/router/src/views/user.vue: -------------------------------------------------------------------------------- 1 | 4 | 11 | -------------------------------------------------------------------------------- /vue11/vuex/src/views/user.vue: -------------------------------------------------------------------------------- 1 | 4 | 11 | -------------------------------------------------------------------------------- /vue14/shopping/src/views/about.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /vue10/demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | webpack app 6 | 7 | 8 | 9 |
10 | Hello world 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /vue11/vue-bus/src/views/user.vue: -------------------------------------------------------------------------------- 1 | 4 | 11 | -------------------------------------------------------------------------------- /vue11/vuex/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | webpack app 6 | 7 | 8 | 9 |
10 | Hello world 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /vue10/demo/src/title.vue: -------------------------------------------------------------------------------- 1 | 4 | 13 | -------------------------------------------------------------------------------- /vue11/router/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | webpack app 6 | 7 | 8 | 9 |
10 | Hello world 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /vue11/vue-bus/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | webpack app 6 | 7 | 8 | 9 |
10 | Hello world 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /vue13/daily/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | webpack app 6 | 7 | 8 | 9 |
10 | Hello world 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /vue13/daily/src/title.vue: -------------------------------------------------------------------------------- 1 | 4 | 13 | -------------------------------------------------------------------------------- /vue14/shopping/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | webpack app 6 | 7 | 8 | 9 |
10 | Hello world 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /vue11/vue-bus/src/moduleA.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | useName: "sam", // 模块内部的state是局部的,所以任何组件通过this.$store.state.moduleA.useName读取 3 | count:10 4 | }; 5 | const getters ={ //模块内部getter、mutation和action,仍然注册在全局命名空间内 6 | sumCount(state,getters,rootState){ 7 | return state.count + rootState.count 8 | } 9 | } 10 | export default { 11 | state, 12 | getters 13 | } -------------------------------------------------------------------------------- /vue11/vuex/src/moduleA.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | useName: "sam", // 模块内部的state是局部的,所以任何组件通过this.$store.state.moduleA.useName读取 3 | count:10 4 | }; 5 | const getters ={ //模块内部getter、mutation和action,仍然注册在全局命名空间内 6 | sumCount(state,getters,rootState){ 7 | return state.count + rootState.count 8 | } 9 | } 10 | export default { 11 | state, 12 | getters 13 | } -------------------------------------------------------------------------------- /vue05/shopping_trolley/shopping.css: -------------------------------------------------------------------------------- 1 | [v-cloak]{display: none;} 2 | table{ 3 | border: 1px solid #e9e9e9; 4 | border-spacing: 0; 5 | empty-cells: show; 6 | } 7 | th,td{ 8 | padding: 8px 16px; 9 | text-align: left; 10 | border: 1px solid #e9e9e9; 11 | } 12 | th{ 13 | background: #f7f7f7; 14 | color:#5c6b77; 15 | font-weight: 600; 16 | white-space: nowrap; 17 | } -------------------------------------------------------------------------------- /vue10/demo/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webpack App 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /vue11/router/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webpack App 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /vue11/vuex/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webpack App 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /vue13/daily/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webpack App 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /vue11/vue-bus/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webpack App 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /vue14/shopping/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webpack App 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /vue11/vue-bus/src/vue-bus.js: -------------------------------------------------------------------------------- 1 | const install = function(Vue){ 2 | const Bus = new Vue({ 3 | methods:{ 4 | emit(event, ...args){ 5 | this.$emit(event, ...args); 6 | }, 7 | on(event,callback){ 8 | this.$on(event,callback); 9 | }, 10 | off(event,callback){ 11 | this.$off(event,callback); 12 | } 13 | } 14 | }); 15 | Vue.prototype.$bus = Bus; 16 | }; 17 | 18 | export default install; -------------------------------------------------------------------------------- /vue11/router/src/views/about.vue: -------------------------------------------------------------------------------- 1 | 7 | 16 | -------------------------------------------------------------------------------- /vue11/vue-bus/src/views/about.vue: -------------------------------------------------------------------------------- 1 | 7 | 16 | -------------------------------------------------------------------------------- /vue11/vuex/src/views/about.vue: -------------------------------------------------------------------------------- 1 | 7 | 16 | -------------------------------------------------------------------------------- /vue11/vue-bus/src/views/Counter.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /vue02/vue2-07.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue2-07 6 | 7 | 8 |
9 |

显示这段文本

10 |
11 | 12 | 13 | 21 | 22 | -------------------------------------------------------------------------------- /vue08/v-time/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 开发实时时间转换v-time 6 | 7 | 8 |
9 |
10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /vue07/input_box/input-number.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 数字输入框组件 6 | 7 | 8 |
9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /vue04/vue4-01.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue4-01 6 | 7 | 8 |
9 |
10 | 11 |
12 | 13 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /vue04/vue4-04.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue4-04 6 | 7 | 8 |
9 |
10 | 11 |
12 | 13 | 22 | 23 | -------------------------------------------------------------------------------- /vue04/vue4-06.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue4-06 6 | 7 | 8 |
9 |
10 | 11 |
12 | 13 | 22 | 23 | -------------------------------------------------------------------------------- /vue13/daily/src/components/item.vue: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /vue04/vue4-09.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue4-09 6 | 7 | 8 |
9 |
文本
10 |
11 | 12 | 24 | 25 | -------------------------------------------------------------------------------- /vue04/vue4-08.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue4-08 6 | 7 | 8 |
9 | 10 |
文本
11 |
12 | 13 | 14 | 23 | 24 | -------------------------------------------------------------------------------- /vue05/vue5-01.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue5-01 6 | 9 | 10 | 11 | 12 |
13 | {{message}} 14 |
15 | 16 | 24 | 25 | -------------------------------------------------------------------------------- /vue02/vue2-10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue2-10 6 | 7 | 8 |
9 | 10 | 11 | 25 | 26 | -------------------------------------------------------------------------------- /vue02/vue2-01.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue2-01 6 | 7 | 8 |
9 | 10 |

你好, {{ name }}

11 | 12 |
13 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /vue04/vue4-02.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue4-02 6 | 7 | 8 |
9 |
10 | 11 |
12 | 13 | 22 | 23 | -------------------------------------------------------------------------------- /vue05/vue5-02.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue5-02 6 | 7 | 8 |
9 | 10 | {{message}} 11 |
12 | {{message}} 13 |
14 |
15 | 16 | 24 | 25 | -------------------------------------------------------------------------------- /vue02/vue2-04.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue2-04 6 | 7 | 8 |
9 | 10 | {{这里的内容不会被编辑}} 11 |
12 | 13 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /vue04/vue4-10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue4-10 6 | 7 | 8 |
9 | 10 |
11 | 12 | 13 | 24 | 25 | -------------------------------------------------------------------------------- /vue07/vue7-02.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-02 6 | 7 | 8 |
9 | 10 |
11 | 12 | 24 | 25 | -------------------------------------------------------------------------------- /vue01/vue1-01.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue1-01 6 | 7 | 8 |
9 | 10 |
11 | 12 | 25 | 26 | -------------------------------------------------------------------------------- /vue01/vue1-02.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue1-02 6 | 7 | 8 |
9 | 12 |
13 | 14 | 26 | 27 | -------------------------------------------------------------------------------- /vue04/vue4-05.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue4-05 6 | 7 | 8 |
9 |
10 | 11 |
12 | 13 | 23 | 24 | -------------------------------------------------------------------------------- /vue07/vue7-26.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-26 6 | 7 | 8 |
9 | 10 | 11 |
12 | 13 | 14 | 24 | 25 | -------------------------------------------------------------------------------- /vue09/sort_form/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 可排序的表格组件 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /vue05/vue5-05.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue5-05 6 | 7 | 8 |
9 |

当status为1时显示该行

10 | 11 | 12 |
13 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /vue03/vue3-01.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue3-01 6 | 7 | 8 |
9 | {{ reversedText }} 10 |
11 | 12 | 13 | 26 | 27 | -------------------------------------------------------------------------------- /vue07/vue7-07.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-07 6 | 7 | 8 |
9 | 10 | 11 |
12 | 13 | 23 | 24 | -------------------------------------------------------------------------------- /vue08/vue8-01.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue8-01 6 | 7 | 8 |
9 | 10 |
11 | 12 | 24 | 25 | -------------------------------------------------------------------------------- /vue07/vue7-04.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-04 6 | 7 | 8 |
9 | 10 |
11 | 12 | 26 | 27 | -------------------------------------------------------------------------------- /vue07/label_page/pane.js: -------------------------------------------------------------------------------- 1 | Vue.component('pane',{ 2 | name:'pane', //为getTabs()遍历所有name为pane的子组件做准备,所以这里起个name 3 | template:'
\ 4 | \ 5 |
',//上边的slot是为了能显示标签里边的内容。 6 | data:function(){ 7 | return { sw:true } 8 | }, 9 | props:{ 10 | name:{ //pane的标识 11 | type:String 12 | }, 13 | label:{ //标签页标题 14 | type:String, 15 | default:'as' 16 | } 17 | }, 18 | methods:{ 19 | updateNav(){ 20 | this.$parent.updateNav(); 21 | } 22 | }, 23 | watch:{ 24 | label(){ 25 | this.updateNav(); 26 | } 27 | }, 28 | mounted(){ 29 | this.updateNav(); 30 | } 31 | }) -------------------------------------------------------------------------------- /vue08/menu/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 从外部关闭的下拉菜单 6 | 7 | 8 | 9 |
10 |
11 | 12 | 15 |
16 |
17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /vue07/vue7-01.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-01 6 | 7 | 8 | 9 |
10 | 11 |
12 | 13 | 24 | 25 | -------------------------------------------------------------------------------- /vue09/sort_form/style.css: -------------------------------------------------------------------------------- 1 | [v-cloak]{ 2 | display: none; 3 | } 4 | table{ 5 | width: 100%; 6 | margin-bottom: 24px; 7 | border-collapse: collapse; 8 | border-spacing: 0; 9 | empty-cells: show; 10 | border:1px solid #e9e9e9; 11 | } 12 | table th{ 13 | background: #f7f7f7; 14 | color: #5c6b77; 15 | font-weight: 600; 16 | white-space: nowrap; 17 | } 18 | table td,table th{ 19 | padding:8px 16px; 20 | border: 1px solid #e9e9e9; 21 | text-align:left; 22 | } 23 | table th a{ 24 | display: inline-block; 25 | margin: 0 4px; 26 | cursor: pointer; 27 | } 28 | table th a.on{ 29 | color: #3399ff; 30 | } 31 | table th a:hover{ 32 | color: #3399ff; 33 | } -------------------------------------------------------------------------------- /vue07/vue7-09.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-09 6 | 7 | 8 |
9 | 10 | 11 | 12 |
13 | 14 | 24 | 25 | -------------------------------------------------------------------------------- /vue03/vue3-04.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue3-04 6 | 7 | 8 |
9 |
{{ reversedText }}
10 | 11 | 28 | 29 | -------------------------------------------------------------------------------- /vue09/vue9-03.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-03 6 | 7 | 8 |
9 | 10 |
11 | 12 | 29 | 30 | -------------------------------------------------------------------------------- /vue09/vue9-12.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-12 6 | 7 | 8 |
9 | 10 |

slot的内容

11 |
12 | 13 | 27 | 28 | -------------------------------------------------------------------------------- /vue02/vue2-08.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue2-08 6 | 7 | 8 |
9 | 百度一下 10 | 11 | 12 |
13 | 14 | 15 | 24 | 25 | -------------------------------------------------------------------------------- /vue07/vue7-11.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-11 6 | 7 | 8 |
9 | 10 |
11 | 12 | 29 | 30 | -------------------------------------------------------------------------------- /vue02/vue2-05.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue2-05 6 | 7 | 8 |
9 | {{ number / 10 }} 10 | {{ isOK ? '确定' : '取消' }} 11 | {{ text.split(',').reverse().join(',') }} 12 | 19 |
20 | 21 | 31 | 32 | -------------------------------------------------------------------------------- /vue07/vue7-03.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-03 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 |
15 |
16 | 17 | 18 | 27 | 28 | -------------------------------------------------------------------------------- /vue10/demo/src/button.vue: -------------------------------------------------------------------------------- 1 | 6 | 28 | -------------------------------------------------------------------------------- /vue13/daily/src/button.vue: -------------------------------------------------------------------------------- 1 | 6 | 28 | -------------------------------------------------------------------------------- /vue02/vue2-02.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue2-02 6 | 7 | 8 |
9 | 10 | 24 | 25 | -------------------------------------------------------------------------------- /vue02/vue2-03.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue2-03 6 | 7 | 8 |
{{date}}
9 | 10 | 11 | 29 | 30 | -------------------------------------------------------------------------------- /vue08/menu/style.css: -------------------------------------------------------------------------------- 1 | [v-cloak]{ 2 | display: none; 3 | } 4 | .main{ 5 | width: 125px; 6 | } 7 | button{ 8 | display: block; 9 | width: 100%; 10 | color:#fff; 11 | background-color: #39f; 12 | border: 0; 13 | padding: 6px; 14 | text-align:center; 15 | font-size: 12px; 16 | border-radius: 4px; 17 | cursor: pointer; 18 | outline:none; 19 | position:relative; 20 | } 21 | button:active{ 22 | top: 1px; 23 | left:1px; 24 | } 25 | .dropdown{ 26 | width:100%; 27 | height: 150px; 28 | margin: 5px 0; 29 | font-size: 12px; 30 | background-color: #fff; 31 | border-radius: 4px; 32 | box-shadow: 0 1px 6px rgba(0,0,0,.2); 33 | /*display: none;*/ 34 | } 35 | .dropdown p{ 36 | display: inline-block; 37 | padding: 6px; 38 | } -------------------------------------------------------------------------------- /vue07/vue7-05.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-05 6 | 7 | 8 |
9 | 10 | 11 | 12 |
13 | 14 | 28 | 29 | -------------------------------------------------------------------------------- /vue14/shopping/src/router.js: -------------------------------------------------------------------------------- 1 | const routers = [ 2 | { 3 | path: '/list', 4 | meta: { 5 | title: '商品列表' 6 | }, 7 | component: (resolve) => require(['./views/list.vue'], resolve) 8 | }, 9 | { 10 | path: '/product/:id', 11 | meta: { 12 | title: '商品详情' 13 | }, 14 | component: (resolve) => require(['./views/product.vue'], resolve) 15 | }, 16 | { 17 | path: '/cart', 18 | meta: { 19 | title: '购物车' 20 | }, 21 | component: (resolve) => require(['./views/cart.vue'], resolve) 22 | }, 23 | { 24 | path: '*', 25 | redirect: '/list' 26 | } 27 | ]; 28 | export default routers; -------------------------------------------------------------------------------- /vue15/README15.md: -------------------------------------------------------------------------------- 1 | # 相关开源项目介绍 2 | 3 | ### 服务端渲染与Nuxt.js 4 | Vue.js2支持服务端渲染。 5 | 服务端渲染(SSR):指的是渲染内容。打开页面,查看源代码。文字都在源代码里面,就是SSR。或chrome的network面板查看有没有相关异步请求来调取内容来判断。 6 | 7 | 很多网站之所以用SSR,主要目的是做SEO。另一个目的是客户端的网络可能不稳定,通过SSR减少请求量和客户端渲染。可以相对快速看到内容。 8 | 9 | Nuxt.js:基于Vue.js的通用应用框架。为Node.js做Vue的服务端渲染提供了各种配置。快速搭建一套SSR框架。 10 | Nuxt.js构建的代码,UI在服务端渲染。查看代码所有模板内容直接渲染在其中。 11 | [Vue.js服务端渲染](https://ssr.vuejs.org/) 12 | [Nuxt.js文档](https://nuxtjs.org/) 13 | 14 | ### HTTP库axios 15 | [项目地址](https://github.com/mzabriskie/axios) 16 | axios是一个基于Promise,同时支持浏览器端和Node.js的HTTP库。常用语Ajax请求。 17 | 18 | ### 多语言插件 vue-i18n 19 | [项目地址](https://gitbub.com/kazupon/vue-i18n) 20 | vue-i18n是一个vue.js插件。提供了都语言解决方案。如果你的项目有多国语言的需求,可以使用它很快地实现。 21 | -------------------------------------------------------------------------------- /vue04/vue4-07.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue4-07 6 | 7 | 8 |
9 | 10 |
11 | 12 | 32 | 33 | -------------------------------------------------------------------------------- /vue06/vue6-03.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue6-03 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 27 | 28 | -------------------------------------------------------------------------------- /vue14/shopping/src/app.vue: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /vue05/vue5-08.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue5-08 6 | 7 | 8 |
9 | {{value}} 10 | 14 | {{n}} 15 | 16 |
17 | 18 | 30 | 31 | -------------------------------------------------------------------------------- /vue09/message_list/index.js: -------------------------------------------------------------------------------- 1 | var app = new Vue({ 2 | el:'#app', 3 | data:{ 4 | username:'', 5 | message:'', 6 | list:[] 7 | }, 8 | methods:{ 9 | // 给list添加一条留言数据 10 | handleSend:function(){ 11 | if( this.username === '' ){ window.alert('请输入昵称'); return } 12 | if( this.message === '' ){ window.alert('请输入留言内容'); return } 13 | this.list.push({ 14 | name:this.username, 15 | message:this.message 16 | }); 17 | this.message = ''; 18 | }, 19 | handleReply:function(index){ 20 | var name = this.list[index].name; 21 | this.message = '@回复' + name + ':'; 22 | // $refs不是响应式的,不应该用它绑定数据。只是方便取和操作DOM 23 | // $refs讲解 https://www.cnblogs.com/xumqfaith/p/7743387.html 24 | this.$refs.message.focus(); 25 | } 26 | } 27 | }) -------------------------------------------------------------------------------- /vue02/vue2-09.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue2-09 6 | 7 | 8 |
9 |

这是一段文本

10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 30 | 31 | -------------------------------------------------------------------------------- /vue04/vue4-03.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue4-03 6 | 7 | 8 |
9 |
10 | 11 |
12 | 13 | 31 | 32 | -------------------------------------------------------------------------------- /vue07/vue7-06.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-06 6 | 7 | 8 | 9 | 10 | 12 | 13 |
14 | 15 | 16 |
17 | 18 | 28 | 29 | -------------------------------------------------------------------------------- /vue07/vue7-18.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-18 6 | 7 | 8 | 9 |
10 | 11 | 12 |

分发的内容

13 |

更多分发的内容

14 |
15 |
16 | 17 | 27 | 28 | -------------------------------------------------------------------------------- /vue05/vue5-07.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue5-07 6 | 7 | 8 |
9 | 15 |
16 | 17 | 36 | 37 | -------------------------------------------------------------------------------- /vue07/vue7-10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-10 6 | 7 | 8 | 9 |
10 | 11 |
12 | 13 | 29 | 30 | -------------------------------------------------------------------------------- /vue07/vue7-23.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-23 6 | 7 | 8 |
9 | 10 |
11 | 12 | 30 | 31 | -------------------------------------------------------------------------------- /vue14/shopping/src/style.css: -------------------------------------------------------------------------------- 1 | *{ 2 | margin: 0; 3 | padding: 0; 4 | } 5 | a{ 6 | text-decoration: none; 7 | } 8 | body{ 9 | background: #f8f8f9; 10 | } 11 | .header{ 12 | height: 48px; 13 | line-height: 48px; 14 | background: rgba(0,0,0,.8); 15 | color: #fff; 16 | } 17 | .header-title{ 18 | padding: 0 32px; 19 | float: left; 20 | color: #fff; 21 | } 22 | .header-menu{ 23 | float: right; 24 | margin-right: 32px; 25 | } 26 | .header-menu-cart{ 27 | color: #fff; 28 | } 29 | .header-menu-cart span{ 30 | display: inline-block; 31 | width: 16px; 32 | height: 16px; 33 | line-height: 16px; 34 | text-align: center; 35 | border-radius: 50%; 36 | background: #ff5500; 37 | color: #fff; 38 | font-size: 12px; 39 | } -------------------------------------------------------------------------------- /vue05/vue5-03.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue5-03 6 | 7 | 8 |
9 | 10 |

当status全等于1显示该行

11 |

当status全等于2显示该行

12 |

否则显示该行

13 | 14 | 15 | 20 |
21 | 22 | 31 | 32 | -------------------------------------------------------------------------------- /vue09/message_list/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 留言列表 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /vue12/README12.md: -------------------------------------------------------------------------------- 1 | # iView经典组件剖析 2 | 3 | + iView:是一套基于Vue2的开源UI组件库。主要服务于PC界面的中后台产品。 4 | + 官网:https://www.iviewui.com/ 5 | + github:https://github.com/iview/iview 6 | 7 | 独立组件与业务组件最大的不同是,业务组件往往针对数据的获取、整理、可视化,逻辑清 晰简单,可以使用vuex:而独立组件的复杂度更多集中在细节、交互、性能优化、 API 设计上, 对原生 JavaScript 有一定考验。在使用过程中,可能会有新功能的不断添加,也会发现隐藏的 bug, 所以独立组件一开始逻辑和代码量并不复杂,多次选代后会越来越冗长,当然功能也更丰富,使用更稳定。万事开头难,组件 API 的设计和可扩展性决定了组件迭代的复杂性。一开始不可能考虑到所有的细节,但是整体架构要清晰可扩展,否则很有可能重构。 8 | 9 | https://github.com/iview/iview/blob/2.0/src/components里有他的组件源码 10 | 11 | 组件间通信可以通过$emit bus vuex来实现。但iView作为独立组件无法使用bus vuex,为了实现跨组件通讯,模拟了vue1的dispatch和broadcast 12 | 13 | 级联选择组件Cascader就是用了几个组件在一起实现: 14 | cascader.vue 15 | casitem.vue 16 | caspanel.vue 17 | 18 | iView内置工具函数,比如:findComponentUpward findComponentDownward findComponentsDownward -------------------------------------------------------------------------------- /vue07/vue7-29.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-29 6 | 7 | 8 |
9 | 10 | 11 | 18 |
19 | 20 | 31 | 32 | -------------------------------------------------------------------------------- /vue06/vue6-01.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue6-01 6 | 7 | 8 |
9 | 10 | 11 | 12 |

输入的内容是: {{ message }}

13 | 14 | 15 |

输入的内容是:{{ text }}

16 |
17 | 18 | 27 | 28 | -------------------------------------------------------------------------------- /vue07/vue7-27.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-27 6 | 7 | 8 |
9 | 10 |
11 | 12 | 28 | 29 | -------------------------------------------------------------------------------- /vue07/vue7-20.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-20 6 | 7 | 8 | 9 | 10 |
11 | 12 | 14 | 18 | 19 |
20 | 21 | 30 | 31 | -------------------------------------------------------------------------------- /vue07/vue7-08.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue-7-08 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 |
15 | 16 | 29 | 30 | -------------------------------------------------------------------------------- /vue07/vue7-24.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-24 6 | 7 | 8 |
9 | 10 | 11 |
12 |

在父组件中定义子组件的模板

13 |

{{ message }}

14 |

{{ msg }}

15 |
16 |
17 |
18 | 19 | 34 | 35 | -------------------------------------------------------------------------------- /vue07/label_page/style.css: -------------------------------------------------------------------------------- 1 | [v-cloak]:{ 2 | display: none; 3 | } 4 | .tabs{ 5 | font-size: 14px; 6 | color: #657180; 7 | } 8 | /*.tabs-bar:after{ 9 | content: ''; 10 | display: block;; 11 | width:100%; 12 | height: 1px; 13 | background: #d7dde4; 14 | margin-top: -1px; 15 | }*/ 16 | .-tabs-tab{ 17 | display: inline-block;; 18 | padding: 4px 16px; 19 | margin-right: 6px; 20 | background: #fff; 21 | border: 1px solid #d7dde4; 22 | cursor: pointer; 23 | position: relative; 24 | } 25 | .tabs-tab-active{ 26 | color: #3399ff; 27 | border-top: 1px solid #3399ff; 28 | border-bottom: 1px solid #fff; 29 | } 30 | /*.tabs-tab-active:before{ 31 | content: ''; 32 | display: block;; 33 | height: 1px; 34 | background: #3399ff; 35 | position: absolute; 36 | top: 0; 37 | left: 0; 38 | right: 0; 39 | }*/ 40 | .tabs-content{ 41 | padding: 8px 0; 42 | } -------------------------------------------------------------------------------- /vue10/demo/src/app.vue: -------------------------------------------------------------------------------- 1 | 2 | 12 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /vue06/vue6-06.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue6-06 6 | 7 | 8 |
9 | 10 | 13 |

选择的是:{{ selected }}

14 | 15 |
16 | 17 | 37 | 38 | -------------------------------------------------------------------------------- /vue07/vue7-30.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-30 6 | 7 | 8 | 9 |
10 | 11 | 31 | 32 | -------------------------------------------------------------------------------- /vue09/vue9-08.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-08 6 | 7 | 8 | 9 |
10 | 11 |
12 | 13 | 39 | 40 | -------------------------------------------------------------------------------- /vue08/menu/clickoutside.js: -------------------------------------------------------------------------------- 1 | Vue.directive('clickoutside',{ 2 | //bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作 3 | bind:function( el,binding,vnode ){ 4 | function documentHandler(e){ 5 | // 判断点击的区域是否在指令所载元素内部,是就跳出。el是指令所绑定的元素 6 | if( el.contains(e.target) ){ //contains方法用来判断A是否包含B,包含返回true 7 | return false; 8 | } 9 | if( binding.expression ){ //判断当前指令v-clickoutside有没有写表达式 10 | binding.value(e); //执行当前上下文methods中指定的函数handleClose 11 | } 12 | } 13 | //__vueClickOutside__ 是自己随便起的,el.__vueClickOutside__ 引用了documentHandler,这样就可以再后边移除监听事件 14 | el.__vueClickOutside__ = documentHandler; 15 | document.addEventListener('click',documentHandler); 16 | }, 17 | unbind:function( el,binding ){ 18 | document.removeEventListener('click',el.__vueClickOutside__) 19 | // 移除document的click事件监听。 20 | delete el.__vueClickOutside__; 21 | } 22 | 23 | }) -------------------------------------------------------------------------------- /vue06/vue6-08.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue6-08 6 | 7 | 8 |
9 | 10 | 11 |

{{ message1 }}

12 | 13 | 14 | 15 |

{{ typeof message2 }}

16 | 17 | 18 | 19 |

{{ message3 }}

20 |
21 | 22 | 32 | 33 | -------------------------------------------------------------------------------- /vue07/vue7-16.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-16 6 | 7 | 8 | 9 | 10 |
11 | {{ message }} 12 | 13 |
14 | 15 | 16 | 35 | 36 | -------------------------------------------------------------------------------- /vue05/vue5-06.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue5-06 6 | 7 | 8 |
9 | 14 | 18 |
19 | 20 | 37 | 38 | -------------------------------------------------------------------------------- /vue09/vue9-07.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-07 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 |
14 | 15 | 38 | 39 | -------------------------------------------------------------------------------- /vue03/vue3-03.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue3-03 6 | 7 | 8 |
9 | 姓名:{{ fullName }} 10 |
11 | 12 | 13 | 39 | 40 | -------------------------------------------------------------------------------- /vue07/vue7-17.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-17 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 |
14 | 15 | 36 | 37 | -------------------------------------------------------------------------------- /vue07/vue7-25.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-25 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 36 | 37 | -------------------------------------------------------------------------------- /vue06/vue6-05.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue6-05 6 | 7 | 8 |
9 | 10 | 15 |

选择的是:{{ selected }}

16 | 17 | 18 | 23 |

选择的是:{{ mul }}

24 | 25 |
26 | 27 | 36 | 37 | -------------------------------------------------------------------------------- /vue05/vue5-09.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue5-09 6 | 7 | 8 |
9 | 15 |
16 | 17 | 41 | 42 | -------------------------------------------------------------------------------- /vue05/vue5-12.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue5-12 6 | 7 | 8 |
9 | 点击次数:{{ counter }} 10 | 11 |
点击增加1
12 | 13 | 14 |
点击增加1
15 |
点击增加10
16 |
17 | 18 | 39 | 40 | -------------------------------------------------------------------------------- /vue05/shopping_trolley/shopping.js: -------------------------------------------------------------------------------- 1 | var app = new Vue({ 2 | el:'#app', 3 | data:{ 4 | list:[ 5 | { 6 | id:1, 7 | name:'iphone', 8 | price:6000, 9 | count:1 10 | },{ 11 | id:2, 12 | name:'ipad', 13 | price:2000, 14 | count:2 15 | },{ 16 | id:3, 17 | name:'macbook', 18 | price:18888, 19 | count:1 20 | } 21 | ] 22 | }, 23 | computed:{ 24 | totalPrice:function(){ 25 | var total = 0; 26 | for (var i = 0; i < this.list.length; i++) { 27 | var item = this.list[i] 28 | total += item.price * item.count 29 | } 30 | return total.toString().replace(/\B(?=(\d{3})+$)/g,',') //每三位数逗号隔开 31 | } 32 | }, 33 | methods:{ 34 | handleReduce:function(index){ 35 | if (this.list[index].count === 1) { return } 36 | this.list[index].count -- 37 | }, 38 | handleAdd:function(index){ 39 | this.list[index].count ++ 40 | }, 41 | handleRemove:function(index){ 42 | this.list.splice(index,1) 43 | } 44 | } 45 | }) -------------------------------------------------------------------------------- /vue07/vue7-19.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-19 6 | 7 | 8 | 9 |
10 | 11 |

标题

12 |
底部信息
13 |

内容正文

14 |

更多内容正文

15 |
16 |
17 | 18 | 34 | 35 | -------------------------------------------------------------------------------- /vue06/vue6-02.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue6-02 6 | 7 | 8 |
9 | 10 | 11 | 12 |

输入的内容是:{{ message }}

13 |
14 | 15 | 28 | 29 | 40 | 41 | -------------------------------------------------------------------------------- /vue09/vue9-02.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-02 6 | 7 | 8 |
9 | 特性 10 |
11 | 12 | 13 | 47 | 48 | -------------------------------------------------------------------------------- /vue07/vue7-14.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-14 6 | 7 | 8 | 9 | 12 |
13 |

总数:{{ total }}

14 | 15 | 16 |
17 | 18 | 40 | 41 | -------------------------------------------------------------------------------- /vue07/vue7-21.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-21 6 | 7 | 8 | 9 |
10 | 11 | 12 | 15 | 16 |
17 | 18 | 43 | 44 | -------------------------------------------------------------------------------- /vue07/vue7-15.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-15 6 | 7 | 8 | 9 |
10 | {{ message }} 11 | 12 |
13 | 14 | 15 | 42 | 43 | -------------------------------------------------------------------------------- /vue07/vue7-28.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-28 6 | 7 | 8 | 10 |
11 |
这是一段文本
12 | 13 |
14 | 15 | 33 | 34 | -------------------------------------------------------------------------------- /vue09/vue9-04.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-04 6 | 7 | 8 |
9 | 10 |
11 | 12 | 47 | 48 | -------------------------------------------------------------------------------- /vue09/sort_form/index.js: -------------------------------------------------------------------------------- 1 | var app = new Vue({ 2 | el:'#app', 3 | data:{ //key用来对应data中列内容的字段名 4 | columns:[ 5 | { 6 | title:'姓名', 7 | key:'name' 8 | }, 9 | { 10 | title:'年龄', 11 | key:'age', 12 | sortable:true 13 | }, 14 | { 15 | title:'出生日期', 16 | key:'birthday', 17 | sortable:true 18 | }, 19 | { 20 | title:'地址', 21 | key:'address' 22 | } 23 | ], 24 | data:[ 25 | { 26 | name:'王小明', 27 | age:19, 28 | birthday:'1999-02-21', 29 | address:'北京市朝阳区芍药居' 30 | }, 31 | { 32 | name:'张小刚', 33 | age:26, 34 | birthday:'1992-01-23', 35 | address:'北京市海淀区西二旗' 36 | }, 37 | { 38 | name:'李小红', 39 | age:31, 40 | birthday:'1987-05-21', 41 | address:'北京市石景山区苹果园' 42 | }, 43 | { 44 | name:'周小伟', 45 | age:27, 46 | birthday:'1991-10-10', 47 | address:'北京市丰台区王佐镇' 48 | } 49 | ] 50 | }, 51 | methods:{ 52 | handleAddData:function(){ 53 | this.data.push({ 54 | name:'刘小天', 55 | age:20, 56 | birthday:'1998-05-30', 57 | address:'北京市东城区东直门' 58 | }) 59 | } 60 | } 61 | }) -------------------------------------------------------------------------------- /vue06/vue6-07.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue6-07 6 | 7 | 8 |
9 | 10 | 11 | 12 |

{{ picked }}

13 |

{{ value }}

14 | 15 | 16 | 17 |

{{ toggle }}

18 |

{{ value1 }}

19 |

{{ value2 }}

20 | 21 | 24 | {{ selected.number }} 25 | 26 |
27 | 28 | 41 | 42 | -------------------------------------------------------------------------------- /vue09/vue9-09.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-09 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 |
14 | 15 | 50 | 51 | -------------------------------------------------------------------------------- /vue07/vue7-22.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-22 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 |

标题

14 |

内容正文

15 |

更多内容正文

16 |
底部信息
17 |
18 |
19 | 20 | 41 | 42 | -------------------------------------------------------------------------------- /vue05/vue5-04.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue5-04 6 | 7 | 8 | 9 | 11 |
12 | 17 | 22 | 23 |
24 | 25 | 38 | 39 | -------------------------------------------------------------------------------- /vue13/daily/src/libs/util.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | // 基本配置 3 | const Util = { 4 | imgPath:'http://127.0.0.1:8011/img/', 5 | apiPath:'http://127.0.0.1:8010/' 6 | } 7 | 8 | // ajax通用配置 9 | Util.ajax = axios.create({ //自定义配置新建一个 axios 实例 10 | baseURL:Util.apiPath 11 | }) 12 | 13 | // 添加响应拦截器 在响应被 then 或 catch 处理前拦截它们。 14 | Util.ajax.interceptors.response.use(res=>{ 15 | return res.data; 16 | }); 17 | 18 | // 获取今天的时间戳 19 | Util.getTodayTime = function () { 20 | const date = new Date(); 21 | date.setHours(0); 22 | date.setMinutes(0); 23 | date.setSeconds(0); 24 | date.setMilliseconds(0); 25 | return date.getTime(); 26 | }; 27 | 28 | //获取今天日期 。但在推荐列表api里日期要比真实日期多一天。所以获取今天就要加86400000 29 | Util.prevDay = function (timestamp = (new Date()).getTime()) { 30 | const date = new Date(timestamp); 31 | const year = date.getFullYear(); 32 | const month = date.getMonth() + 1 < 10 33 | ? '0' + (date.getMonth() + 1) 34 | : date.getMonth() + 1; 35 | const day = date.getDate() < 10 36 | ? '0' + date.getDate() 37 | : date.getDate(); 38 | return year + '' + month + '' + day; 39 | }; 40 | 41 | export default Util; -------------------------------------------------------------------------------- /vue14/shopping/src/views/index.vue: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /vue05/shopping_trolley/shopping.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | shopping 6 | 7 | 8 | 9 |
10 | 37 |
购物车为空
38 |
39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /vue07/vue7-13.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-13 6 | 7 | 8 | 9 | 10 | 11 |
12 |

总数:{{ total }}

13 | 14 |
15 | 16 | 38 | 39 | -------------------------------------------------------------------------------- /vue09/message_list/list.js: -------------------------------------------------------------------------------- 1 | Vue.component('list',{ 2 | props:{ 3 | list:{ 4 | type:Array, 5 | default:function(){ 6 | return [] 7 | } 8 | } 9 | }, 10 | render:function(h){ 11 | var _this = this; 12 | var list = []; 13 | this.list.forEach(function( msg,index ){ 14 | var node = h('div',{ 15 | attrs:{ 16 | class:'list-item' 17 | } 18 | },[ 19 | h('span',msg.name + ':'), 20 | h('div',{ 21 | attrs:{ 22 | class:'list-msg' 23 | } 24 | },[ 25 | h('p',msg.message), 26 | h('a',{ 27 | attrs:{ 28 | class:'list-reply' 29 | }, 30 | on:{ 31 | click:function(){ 32 | _this.handleReply(index) 33 | } 34 | } 35 | },'回复') 36 | ]) 37 | ]) 38 | list.push(node); 39 | }); 40 | 41 | if( this.list.length ){ 42 | return h('div',{ 43 | attrs:{ 44 | class:'list' 45 | } 46 | },list); 47 | }else{ 48 | return h('div',{ 49 | attrs:{ 50 | class:'list-nothing' 51 | } 52 | },'留言列表为空') 53 | } 54 | }, 55 | methods:{ 56 | // 直接向父组件(app)派发一个事件reply,父组件接收后,将当前list-item的昵称提取,并设置到v-textarea内 57 | handleReply:function(index){ 58 | this.$emit('reply',index) 59 | } 60 | } 61 | }) -------------------------------------------------------------------------------- /vue07/label_page/tabs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 标签页组件 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 |

标签一的内容

18 |

标签一的内容

19 |

标签一的内容

20 |
21 | 标签二的内容 22 | 标签三的内容 23 |
24 | 25 | 标签1的内容 26 | 标签2的内容 27 | 标签3的内容 28 | 29 |
30 | 31 | 32 | 33 | 42 | 43 | -------------------------------------------------------------------------------- /vue10/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "webpack-dev-server --mode development --open --config webpack.config.js", 8 | "build": "webpack --progress --mode production --hide-modules --config webpack.prod.config.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "babel": "^6.23.0", 14 | "babel-cli": "^6.26.0", 15 | "babel-core": "^6.26.3", 16 | "babel-loader": "^7.1.5", 17 | "babel-plugin-transform-runtime": "^6.23.0", 18 | "babel-preset-env": "^1.7.0", 19 | "babel-runtime": "^6.26.0", 20 | "css-loader": "^1.0.0", 21 | "file-loader": "^2.0.0", 22 | "html-webpack-plugin": "^3.2.0", 23 | "mini-css-extract-plugin": "^0.4.2", 24 | "style-loader": "^0.22.1", 25 | "url-loader": "^1.1.1", 26 | "vue-hot-reload-api": "^2.3.0", 27 | "vue-loader": "^15.4.0", 28 | "vue-style-loader": "^4.1.2", 29 | "vue-template-compiler": "^2.5.17", 30 | "webpack": "^4.17.1", 31 | "webpack-cli": "^3.1.0", 32 | "webpack-dev-server": "^3.1.5", 33 | "webpack-merge": "^4.1.4" 34 | }, 35 | "dependencies": { 36 | "vue": "^2.5.17" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vue09/vue9-10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-10 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 | 46 | 47 | -------------------------------------------------------------------------------- /vue09/message_list/input.js: -------------------------------------------------------------------------------- 1 | Vue.component('vInput',{ 2 | props:{ 3 | value:{ 4 | type:[String,Number], 5 | default:'' 6 | } 7 | }, 8 | render:function(h){ 9 | var _this = this; 10 | return h('div',[ 11 | h('span','昵称:'), 12 | h('input',{ 13 | attrs:{ 14 | type:'text' 15 | }, 16 | domProps:{ 17 | value:this.value 18 | }, 19 | on:{ 20 | input:function(event){ 21 | _this.value = event.target.value; 22 | _this.$emit('input',event.target.value); 23 | } 24 | } 25 | }) 26 | ]) 27 | } 28 | }); 29 | 30 | Vue.component('vTextarea',{ 31 | props:{ 32 | value:{ 33 | type:String, 34 | default:'' 35 | } 36 | }, 37 | render:function(h){ 38 | var _this = this; 39 | return h('div',[ 40 | h('span','留言内容'), 41 | h('textarea',{ 42 | attrs:{ 43 | placeholder:'请输入留言内容' 44 | }, 45 | domProps:{ 46 | value:this.value 47 | }, 48 | ref:'message', 49 | on:{ 50 | input:function(event){ 51 | _this.value = event.target.value; 52 | _this.$emit('input',event.target.value); 53 | } 54 | } 55 | }) 56 | ]) 57 | }, 58 | methods:{ 59 | focus:function(){ 60 | this.$refs.message.focus(); 61 | } 62 | } 63 | }) -------------------------------------------------------------------------------- /vue05/vue5-10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue5-10 6 | 7 | 8 |
9 | 15 |
16 | 17 | 53 | 54 | -------------------------------------------------------------------------------- /vue11/router/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | // const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | const { VueLoaderPlugin } = require('vue-loader'); 6 | const merge = require('webpack-merge'); 7 | const webpackBaseConfig = require('./webpack.config.js'); 8 | 9 | webpackBaseConfig.plugins = []; 10 | 11 | module.exports = merge(webpackBaseConfig,{ 12 | output:{ 13 | publicPath:'/dist/', 14 | filename:'[name].[hash].js' 15 | }, 16 | plugins:[ 17 | new ExtractTextPlugin({ 18 | filename:'[name].[hash].css', 19 | allChunks:true 20 | }), 21 | // new MiniCssExtractPlugin({ 22 | // filename:'[name].[hash].css' 23 | // }), 24 | new webpack.DefinePlugin({ 25 | 'process.env':{ 26 | NODE_ENV:'"production"' 27 | } 28 | }), 29 | // 压缩已经不用写UglifyJsPlugin 30 | // new webpack.optimize.UglifyJsPlugin({ 31 | // compress:{ 32 | // warnings:false 33 | // } 34 | // }), 35 | new HtmlWebpackPlugin({ 36 | filename:'../index_prod.html', 37 | template:'./index.ejs', 38 | inject:false 39 | }), 40 | new VueLoaderPlugin() //vue-loader,15的版本需要再添加plugin的配置 41 | ] 42 | }); -------------------------------------------------------------------------------- /vue11/vuex/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | // const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | const { VueLoaderPlugin } = require('vue-loader'); 6 | const merge = require('webpack-merge'); 7 | const webpackBaseConfig = require('./webpack.config.js'); 8 | 9 | webpackBaseConfig.plugins = []; 10 | 11 | module.exports = merge(webpackBaseConfig,{ 12 | output:{ 13 | publicPath:'/dist/', 14 | filename:'[name].[hash].js' 15 | }, 16 | plugins:[ 17 | new ExtractTextPlugin({ 18 | filename:'[name].[hash].css', 19 | allChunks:true 20 | }), 21 | // new MiniCssExtractPlugin({ 22 | // filename:'[name].[hash].css' 23 | // }), 24 | new webpack.DefinePlugin({ 25 | 'process.env':{ 26 | NODE_ENV:'"production"' 27 | } 28 | }), 29 | // 压缩已经不用写UglifyJsPlugin 30 | // new webpack.optimize.UglifyJsPlugin({ 31 | // compress:{ 32 | // warnings:false 33 | // } 34 | // }), 35 | new HtmlWebpackPlugin({ 36 | filename:'../index_prod.html', 37 | template:'./index.ejs', 38 | inject:false 39 | }), 40 | new VueLoaderPlugin() //vue-loader,15的版本需要再添加plugin的配置 41 | ] 42 | }); -------------------------------------------------------------------------------- /vue11/vue-bus/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | // const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | const { VueLoaderPlugin } = require('vue-loader'); 6 | const merge = require('webpack-merge'); 7 | const webpackBaseConfig = require('./webpack.config.js'); 8 | 9 | webpackBaseConfig.plugins = []; 10 | 11 | module.exports = merge(webpackBaseConfig,{ 12 | output:{ 13 | publicPath:'/dist/', 14 | filename:'[name].[hash].js' 15 | }, 16 | plugins:[ 17 | new ExtractTextPlugin({ 18 | filename:'[name].[hash].css', 19 | allChunks:true 20 | }), 21 | // new MiniCssExtractPlugin({ 22 | // filename:'[name].[hash].css' 23 | // }), 24 | new webpack.DefinePlugin({ 25 | 'process.env':{ 26 | NODE_ENV:'"production"' 27 | } 28 | }), 29 | // 压缩已经不用写UglifyJsPlugin 30 | // new webpack.optimize.UglifyJsPlugin({ 31 | // compress:{ 32 | // warnings:false 33 | // } 34 | // }), 35 | new HtmlWebpackPlugin({ 36 | filename:'../index_prod.html', 37 | template:'./index.ejs', 38 | inject:false 39 | }), 40 | new VueLoaderPlugin() //vue-loader,15的版本需要再添加plugin的配置 41 | ] 42 | }); -------------------------------------------------------------------------------- /vue13/daily/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | // const ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | const { VueLoaderPlugin } = require('vue-loader'); 6 | const merge = require('webpack-merge'); 7 | const webpackBaseConfig = require('./webpack.config.js'); 8 | 9 | webpackBaseConfig.plugins = []; 10 | 11 | module.exports = merge(webpackBaseConfig,{ 12 | output:{ 13 | publicPath:'/dist/', 14 | filename:'[name].[hash].js' 15 | }, 16 | plugins:[ 17 | // new ExtractTextPlugin({ 18 | // filename:'[name].[hash].css', 19 | // allChunks:true 20 | // }), 21 | new MiniCssExtractPlugin({ 22 | filename:'[name].[hash].css' 23 | }), 24 | new webpack.DefinePlugin({ 25 | 'process.env':{ 26 | NODE_ENV:'"production"' 27 | } 28 | }), 29 | // 压缩已经不用写UglifyJsPlugin 30 | // new webpack.optimize.UglifyJsPlugin({ 31 | // compress:{ 32 | // warnings:false 33 | // } 34 | // }), 35 | new HtmlWebpackPlugin({ 36 | filename:'../index_prod.html', 37 | template:'./index.ejs', 38 | inject:false 39 | }), 40 | new VueLoaderPlugin() //vue-loader,15的版本需要再添加plugin的配置 41 | ] 42 | }); -------------------------------------------------------------------------------- /vue14/shopping/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | // const ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | const { VueLoaderPlugin } = require('vue-loader'); 6 | const merge = require('webpack-merge'); 7 | const webpackBaseConfig = require('./webpack.config.js'); 8 | 9 | webpackBaseConfig.plugins = []; 10 | 11 | module.exports = merge(webpackBaseConfig,{ 12 | output:{ 13 | publicPath:'/dist/', 14 | filename:'[name].[hash].js' 15 | }, 16 | plugins:[ 17 | // new ExtractTextPlugin({ 18 | // filename:'[name].[hash].css', 19 | // allChunks:true 20 | // }), 21 | new MiniCssExtractPlugin({ 22 | filename:'[name].[hash].css' 23 | }), 24 | new webpack.DefinePlugin({ 25 | 'process.env':{ 26 | NODE_ENV:'"production"' 27 | } 28 | }), 29 | // 压缩已经不用写UglifyJsPlugin 30 | // new webpack.optimize.UglifyJsPlugin({ 31 | // compress:{ 32 | // warnings:false 33 | // } 34 | // }), 35 | new HtmlWebpackPlugin({ 36 | filename:'../index_prod.html', 37 | template:'./index.ejs', 38 | inject:false 39 | }), 40 | new VueLoaderPlugin() //vue-loader,15的版本需要再添加plugin的配置 41 | ] 42 | }); -------------------------------------------------------------------------------- /vue10/demo/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | // const ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | const { VueLoaderPlugin } = require('vue-loader'); 6 | const merge = require('webpack-merge'); 7 | const webpackBaseConfig = require('./webpack.config.js'); 8 | 9 | webpackBaseConfig.plugins = []; 10 | 11 | module.exports = merge(webpackBaseConfig,{ 12 | output:{ 13 | publicPath:'/dist/', 14 | filename:'[name].[chunkhash].js' 15 | }, 16 | plugins:[ 17 | // new ExtractTextPlugin({ 18 | // filename:'[name].[hash].css', 19 | // allChunks:true 20 | // }), 21 | new MiniCssExtractPlugin({ 22 | filename:'[name].[chunkhash].css' 23 | }), 24 | new webpack.DefinePlugin({ 25 | 'process.env':{ 26 | NODE_ENV:'"production"' 27 | } 28 | }), 29 | // 压缩已经不用写UglifyJsPlugin 30 | // new webpack.optimize.UglifyJsPlugin({ 31 | // compress:{ 32 | // warnings:false 33 | // } 34 | // }), 35 | new HtmlWebpackPlugin({ 36 | filename:'../index_prod.html', 37 | template:'./index.ejs', 38 | inject:false 39 | }), 40 | new VueLoaderPlugin() //vue-loader,15的版本需要再添加plugin的配置 41 | ] 42 | }); -------------------------------------------------------------------------------- /vue11/router/src/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; //导入vue框架 2 | import VueRouter from 'vue-router'; 3 | import App from './app.vue'; //导入app.vue组件 4 | 5 | Vue.use(VueRouter) 6 | 7 | const Routers = [ 8 | //resolve在请求页面时,才去加载这个页面的js。异步实现懒加载。 使用了异步路由后,编译出的每个页面的js都叫chunk(块) 9 | //如要一次性加载,可以: component:require('.views/index.vue') 10 | { 11 | path:'/index', 12 | meta:{ 13 | title:'首页' 14 | }, 15 | component:(resolve) => require(['./views/index.vue'],resolve) 16 | }, 17 | { 18 | path:'/about', 19 | meta:{ 20 | title:'关于' 21 | }, 22 | component:(resolve) => require(['./views/about.vue'],resolve) 23 | }, 24 | { 25 | path:'/user/:id', 26 | meta:{ 27 | title:'个人主页' 28 | }, 29 | component:(resolve) => require(['./views/user.vue'],resolve) 30 | }, 31 | // 当访问的路径不存在,重新定向到首页 32 | { 33 | path:'*', 34 | redirect:'/index' 35 | } 36 | ]; 37 | 38 | const router = new VueRouter({ 39 | //使用html的History路由模式 40 | mode:'history', 41 | routes: Routers 42 | }); 43 | 44 | 45 | router.beforeEach((to,from,next)=>{ 46 | //参数:即将要进入的目标的路由对象,当前导航即将要离开的路由对象,调用该方法后才能进入下一个钩子。 47 | window.document.title = to.meta.title; 48 | next(); //调用该方法才能进入下一个钩子 49 | }) 50 | 51 | new Vue({ 52 | el: '#app', 53 | router:router, 54 | render: h => { 55 | return h(App); 56 | } 57 | }); 58 | -------------------------------------------------------------------------------- /vue09/vue9-05.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-05 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 | 16 | 47 | 48 | -------------------------------------------------------------------------------- /vue09/vue9-11.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-11 6 | 7 | 8 |
9 | 10 |
11 | 12 | 51 | 52 | -------------------------------------------------------------------------------- /vue03/vue3-02.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue3-02 6 | 7 | 8 |
9 | 总价:{{ prices }} 10 |
11 | 12 | 57 | 58 | -------------------------------------------------------------------------------- /vue14/shopping/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "webpack-dev-server --mode development --history-api-fallback --open --config webpack.config.js", 8 | "build": "webpack --progress --mode production --hide-modules --config webpack.prod.config.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "babel": "^6.23.0", 14 | "babel-cli": "^6.26.0", 15 | "babel-core": "^6.26.3", 16 | "babel-loader": "^7.1.5", 17 | "babel-plugin-transform-runtime": "^6.23.0", 18 | "babel-preset-env": "^1.7.0", 19 | "babel-runtime": "^6.26.0", 20 | "css-loader": "^1.0.0", 21 | "file-loader": "^2.0.0", 22 | "html-webpack-plugin": "^3.2.0", 23 | "mini-css-extract-plugin": "^0.4.2", 24 | "style-loader": "^0.22.1", 25 | "url-loader": "^1.1.1", 26 | "vue-hot-reload-api": "^2.3.0", 27 | "vue-loader": "^15.4.0", 28 | "vue-style-loader": "^4.1.2", 29 | "vue-template-compiler": "^2.5.17", 30 | "webpack": "^4.17.1", 31 | "webpack-cli": "^3.1.0", 32 | "webpack-dev-server": "^3.1.5", 33 | "webpack-merge": "^4.1.4" 34 | }, 35 | "dependencies": { 36 | "vue": "^2.5.17", 37 | "vue-router": "^3.0.1", 38 | "vuex": "^3.0.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /vue10/demo/src/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; //导入vue框架 2 | import VueRouter from 'vue-router'; 3 | import App from './app.vue'; //导入app.vue组件 4 | 5 | Vue.use(VueRouter) 6 | 7 | const Routers = [ 8 | //resolve在请求页面时,才去加载这个页面的js。异步实现懒加载。 使用了异步路由后,编译出的每个页面的js都叫chunk(块).如要一次性加载,可以: 9 | //import index from "./views/index.vue"; 10 | // component:index 11 | //其他两个路由模仿上边的写法 12 | { 13 | path:'/index', 14 | meta:{ 15 | title:'首页' 16 | }, 17 | component:(resolve) => require(['./views/index.vue'],resolve) 18 | }, 19 | { 20 | path:'/about', 21 | meta:{ 22 | title:'关于' 23 | }, 24 | component:(resolve) => require(['./views/about.vue'],resolve) 25 | }, 26 | { 27 | path:'/user/:id', 28 | meta:{ 29 | title:'个人主页' 30 | }, 31 | component:(resolve) => require(['./views/user.vue'],resolve) 32 | }, 33 | // 当访问的路径不存在,重新定向到首页 34 | { 35 | path:'*', 36 | redirect:'/index' 37 | } 38 | ]; 39 | 40 | const router = new VueRouter({ 41 | //使用html的History路由模式 42 | mode:'history', 43 | routes: Routers 44 | }); 45 | 46 | 47 | router.beforeEach((to,from,next)=>{ 48 | //参数:即将要进入的目标的路由对象,当前导航即将要离开的路由对象,调用该方法后才能进入下一个钩子。 49 | window.document.title = to.meta.title; 50 | next(); //调用该方法才能进入下一个钩子 51 | }) 52 | 53 | new Vue({ 54 | el: '#app', 55 | router:router, 56 | render: h => { 57 | return h(App); 58 | } 59 | }); 60 | -------------------------------------------------------------------------------- /vue11/router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "webpack-dev-server --host 192.168.10.122 --mode development --history-api-fallback --open --config webpack.config.js", 8 | "build": "webpack --progress --mode production --hide-modules --config webpack.prod.config.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "babel": "^6.23.0", 14 | "babel-cli": "^6.26.0", 15 | "babel-core": "^6.26.3", 16 | "babel-loader": "^7.1.5", 17 | "babel-plugin-transform-runtime": "^6.23.0", 18 | "babel-preset-env": "^1.7.0", 19 | "babel-runtime": "^6.26.0", 20 | "css-loader": "^1.0.0", 21 | "extract-text-webpack-plugin": "^4.0.0-beta.0", 22 | "file-loader": "^2.0.0", 23 | "html-webpack-plugin": "^3.2.0", 24 | "mini-css-extract-plugin": "^0.4.2", 25 | "style-loader": "^0.22.1", 26 | "url-loader": "^1.1.1", 27 | "vue-hot-reload-api": "^2.3.0", 28 | "vue-loader": "^15.4.0", 29 | "vue-style-loader": "^4.1.2", 30 | "vue-template-compiler": "^2.5.17", 31 | "webpack": "^4.17.1", 32 | "webpack-cli": "^3.1.0", 33 | "webpack-dev-server": "^3.1.5", 34 | "webpack-merge": "^4.1.4" 35 | }, 36 | "dependencies": { 37 | "vue": "^2.5.17", 38 | "vue-router": "^3.0.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /vue05/vue5-11.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue5-11 6 | 7 | 8 | 9 |
10 | 16 | 22 |
23 | 24 | 25 | 57 | 58 | -------------------------------------------------------------------------------- /vue06/vue6-04.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue6-04 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | 32 | 41 | 42 | -------------------------------------------------------------------------------- /vue11/vuex/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "webpack-dev-server --host 192.168.10.122 --mode development --history-api-fallback --open --config webpack.config.js", 8 | "build": "webpack --progress --mode production --hide-modules --config webpack.prod.config.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "babel": "^6.23.0", 14 | "babel-cli": "^6.26.0", 15 | "babel-core": "^6.26.3", 16 | "babel-loader": "^7.1.5", 17 | "babel-plugin-transform-runtime": "^6.23.0", 18 | "babel-preset-env": "^1.7.0", 19 | "babel-runtime": "^6.26.0", 20 | "css-loader": "^1.0.0", 21 | "extract-text-webpack-plugin": "^4.0.0-beta.0", 22 | "file-loader": "^2.0.0", 23 | "html-webpack-plugin": "^3.2.0", 24 | "mini-css-extract-plugin": "^0.4.2", 25 | "style-loader": "^0.22.1", 26 | "url-loader": "^1.1.1", 27 | "vue-hot-reload-api": "^2.3.0", 28 | "vue-loader": "^15.4.0", 29 | "vue-style-loader": "^4.1.2", 30 | "vue-template-compiler": "^2.5.17", 31 | "webpack": "^4.17.1", 32 | "webpack-cli": "^3.1.0", 33 | "webpack-dev-server": "^3.1.5", 34 | "webpack-merge": "^4.1.4" 35 | }, 36 | "dependencies": { 37 | "vue": "^2.5.17", 38 | "vue-router": "^3.0.1", 39 | "vuex": "^3.0.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /vue11/vue-bus/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "webpack-dev-server --host 192.168.10.122 --mode development --history-api-fallback --open --config webpack.config.js", 8 | "build": "webpack --progress --mode production --hide-modules --config webpack.prod.config.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "babel": "^6.23.0", 14 | "babel-cli": "^6.26.0", 15 | "babel-core": "^6.26.3", 16 | "babel-loader": "^7.1.5", 17 | "babel-plugin-transform-runtime": "^6.23.0", 18 | "babel-preset-env": "^1.7.0", 19 | "babel-runtime": "^6.26.0", 20 | "css-loader": "^1.0.0", 21 | "extract-text-webpack-plugin": "^4.0.0-beta.0", 22 | "file-loader": "^2.0.0", 23 | "html-webpack-plugin": "^3.2.0", 24 | "mini-css-extract-plugin": "^0.4.2", 25 | "style-loader": "^0.22.1", 26 | "url-loader": "^1.1.1", 27 | "vue-hot-reload-api": "^2.3.0", 28 | "vue-loader": "^15.4.0", 29 | "vue-style-loader": "^4.1.2", 30 | "vue-template-compiler": "^2.5.17", 31 | "webpack": "^4.17.1", 32 | "webpack-cli": "^3.1.0", 33 | "webpack-dev-server": "^3.1.5", 34 | "webpack-merge": "^4.1.4" 35 | }, 36 | "dependencies": { 37 | "vue": "^2.5.17", 38 | "vue-router": "^3.0.1", 39 | "vuex": "^3.0.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /vue13/daily/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "webpack-dev-server --mode development --open --config webpack.config.js", 8 | "build": "webpack --progress --mode production --hide-modules --config webpack.prod.config.js", 9 | "start": "concurrently \"npm run dev\" \"node proxy.js\"" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "babel": "^6.23.0", 15 | "babel-cli": "^6.26.0", 16 | "babel-core": "^6.26.3", 17 | "babel-loader": "^7.1.5", 18 | "babel-plugin-transform-runtime": "^6.23.0", 19 | "babel-preset-env": "^1.7.0", 20 | "babel-runtime": "^6.26.0", 21 | "concurrently": "^4.0.1", 22 | "css-loader": "^1.0.0", 23 | "file-loader": "^2.0.0", 24 | "html-webpack-plugin": "^3.2.0", 25 | "mini-css-extract-plugin": "^0.4.2", 26 | "request": "^2.88.0", 27 | "style-loader": "^0.22.1", 28 | "url-loader": "^1.1.1", 29 | "vue-hot-reload-api": "^2.3.0", 30 | "vue-loader": "^15.4.0", 31 | "vue-style-loader": "^4.1.2", 32 | "vue-template-compiler": "^2.5.17", 33 | "webpack": "^4.17.1", 34 | "webpack-cli": "^3.1.0", 35 | "webpack-dev-server": "^3.1.5", 36 | "webpack-merge": "^4.1.4" 37 | }, 38 | "dependencies": { 39 | "axios": "^0.18.0", 40 | "vue": "^2.5.17" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /vue09/vue9-01.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-01 6 | 7 | 8 |
9 | 特性 10 | 44 |
45 | 46 | 66 | 67 | -------------------------------------------------------------------------------- /vue09/message_list/style.css: -------------------------------------------------------------------------------- 1 | *{margin: 0;padding: 0} 2 | [v-cloak]{ 3 | display: none; 4 | } 5 | .message{ 6 | width: 450px; 7 | text-align: right; 8 | } 9 | .message div{ 10 | margin-bottom: 12px; 11 | } 12 | .message span{ 13 | display: inline-block; 14 | width:100px; 15 | vertical-align: top; 16 | } 17 | .message input,.message textarea{ 18 | width: 300px; 19 | height: 32px; 20 | padding: 0 6px; 21 | color:#657180; 22 | border:1px solid #d7dde4; 23 | border-radius: 4px; 24 | cursor:text; 25 | outline: none; 26 | } 27 | .message input:focus, .message textarea:focus{ 28 | border: 1px solid #3399ff; 29 | } 30 | .message textarea{ 31 | height: 60px; 32 | padding: 4px 6px; 33 | } 34 | .message button{ 35 | display: inline-block; 36 | padding: 6px 15px; 37 | border: 1px solid #39f; 38 | border-radius:4px; 39 | color:#fff; 40 | background-color: #39f; 41 | cursor: pointer; 42 | outline:none; 43 | } 44 | .list{ 45 | margin-top: 50px; 46 | } 47 | .list-item{ 48 | padding: 10px; 49 | border-bottom: 1px solid #e3e8ee; 50 | overflow: hidden; 51 | } 52 | .list-item span{ 53 | display: block; 54 | width: 70px; 55 | float:left; 56 | color: #39f; 57 | } 58 | .list-msg{ 59 | display:block; 60 | margin-left: 60px; 61 | text-align: justify; 62 | } 63 | .list-msg a{ 64 | color: #9ea7b4; 65 | cursor: pointer; 66 | float:right; 67 | } 68 | .list-msg a:hover{ 69 | color:#39f; 70 | } 71 | .list-nothing{ 72 | text-align: center; 73 | color:#9ea7b4; 74 | padding: 20px; 75 | } -------------------------------------------------------------------------------- /vue11/vuex/src/views/index.vue: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /vue02/vue2-06.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue2-06 6 | 7 | 8 |
9 | {{ date | formatDate }} 10 | 16 |
17 | 18 | 52 | 53 | -------------------------------------------------------------------------------- /vue07/vue7-12.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue7-12 6 | 7 | 8 | 9 | 10 | 11 |
12 |

总数:{{ total }}

13 | 14 | 15 |
16 | 17 | 48 | 49 | -------------------------------------------------------------------------------- /vue09/vue9-06.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-06 6 | 7 | 8 | 9 |
10 | 11 |
12 | 13 |
14 |
15 |
16 | 17 | 63 | 64 | -------------------------------------------------------------------------------- /vue13/daily/proxy.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const request = require('request'); 3 | 4 | const hostname = '127.0.0.1'; 5 | const port = 8010; 6 | const imgPort = 8011; 7 | 8 | // 创建一个API 代理服务器 9 | const apiServer = http.createServer((req, res) => { 10 | const url = 'http://news-at.zhihu.com/api/4' + req.url; 11 | const options = { 12 | url: url 13 | }; 14 | 15 | function callback (error, response, body) { 16 | if (!error && response.statusCode === 200) { 17 | // 设置编码类型,否则中文会显示为乱码 18 | res.setHeader('Content-Type', 'text/plain;charset=UTF-8'); 19 | // 设置所有域允许跨域 20 | res.setHeader('Access-Control-Allow-Origin', '*'); 21 | // 返回代理后的内容 22 | res.end(body); 23 | } 24 | } 25 | request.get(options, callback); 26 | }); 27 | 28 | // 监听8010端口 29 | apiServer.listen(port, hostname, () => { 30 | console.log(`接口代理运行在 http://${hostname}:${port}/`); 31 | }); 32 | 33 | // 创建一个图片代理服务 34 | const imgServer = http.createServer((req, res) => { 35 | const url = req.url.split('/img/')[1]; 36 | const options = { 37 | url: url, 38 | encoding: null 39 | }; 40 | 41 | function callback (error, response, body) { 42 | if (!error && response.statusCode === 200) { 43 | const contentType = response.headers['content-type']; 44 | res.setHeader('Content-Type', contentType); 45 | res.setHeader('Access-Control-Allow-Origin', '*'); 46 | res.end(body); 47 | } 48 | } 49 | request.get(options, callback); 50 | }); 51 | 52 | // 监听8011端口 53 | imgServer.listen(imgPort,hostname,()=>{ 54 | console.log(`图片代理运行在http://${hostname}:${imgPort}/`); 55 | }) -------------------------------------------------------------------------------- /vue13/daily/src/components/daily-article.vue: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /vue11/vue-bus/src/views/index.vue: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /vue08/v-time/time.js: -------------------------------------------------------------------------------- 1 | var Time = { 2 | // 获取当前时间戳 3 | getUnix:function(){ 4 | var date = new Date(); 5 | return date.getTime(); 6 | }, 7 | // 获取今天0点0分0秒的时间戳 8 | getTodayUnix:function(){ 9 | var date = new Date(); 10 | date.setHours(0); //设置指定时间的小时字段 11 | date.setMinutes(0); 12 | date.setSeconds(0); 13 | date.setMilliseconds(0); 14 | return date.getTime(); 15 | }, 16 | // 获取今年1月1日0点0分0秒的时间戳 17 | getYearUnix:function(){ 18 | var date = new Date(); 19 | date.setMonth(0) 20 | date.setDate(1); 21 | date.setHours(0); 22 | date.setMinutes(0); 23 | date.setSeconds(0); 24 | date.setMilliseconds(0); 25 | return date.getTime(); 26 | }, 27 | // 获取标准年月日 28 | getLastDate:function(time){ 29 | var date = new Date(time); 30 | var month = date.getMonth() + 1 < 10 ? '0' + ( date.getMonth() + 1 ) : date.getMonth() + 1; 31 | var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate(); 32 | return date.getFullYear() + '-' + month + '-' + day 33 | }, 34 | // 转换时间 35 | getFormatTime:function(timestamp){ 36 | var now = this.getUnix(); //当前时间戳 37 | var today = this.getTodayUnix(); //今天0点时间戳 38 | var year = this.getYearUnix(); //今年0点时间戳 39 | var timer = ( now - timestamp ) / 1000; //转化为秒级时间戳 40 | var tip = ''; 41 | 42 | // 1分钟以前,显示“刚刚”。 43 | // 1分钟~1小时之间,显示“xx分钟前”。 44 | // 1小时~1天之间,显示“xx小时前”。 45 | // 1天~1个月(31天)之间,显示“xx天前”。 46 | // 大于1个月,显示“xx年xx月xx日”。 47 | 48 | if( timer <= 0 ){ 49 | tip = '刚刚'; 50 | }else if( Math.floor( timer / 60 ) <= 0 ){ 51 | tip = '刚刚' 52 | }else if( timer < 3600 ){ 53 | tip = Math.floor( timer / 60 ) + '分钟前'; 54 | }else if( timer >= 3600 && ( timestamp - today >= 0 ) ){ 55 | tip = Math.floor( timer/3600 ) + '小时前' 56 | }else if( timer/86400 <=31 ){ 57 | tip = Math.ceil( timer/86400 ) + '天前' 58 | }else{ 59 | tip = this.getLastDate(timestamp); 60 | } 61 | return tip; 62 | } 63 | } 64 | 65 | Vue.directive('time',{ 66 | bind:function( el,binding ){ 67 | el.innerHTML = Time.getFormatTime( binding.value ); 68 | el.__timeout__ = setInterval(function(){ 69 | el.innerHTML = Time.getFormatTime( binding.value ); 70 | },60000) 71 | }, 72 | unbind:function(el){ 73 | clearInterval( el.__timeout__ ); 74 | delete el.__timeout__; 75 | } 76 | }) -------------------------------------------------------------------------------- /vue10/demo/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 3 | const { VueLoaderPlugin } = require('vue-loader'); //vue-loader,15的版本需要再添加plugin的配置 4 | // var ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | 6 | const config = { 7 | //配置的单入口,webpack从index.js开始工作,webpack4默认entry 路径./src/index.js 8 | // 所以下边的entry可以不写 9 | // entry:{ 10 | // main:'./src/index' 11 | // }, 12 | output:{//打包后的文件会存储为demo/dist/main.js 在html中引用它就可以了 13 | path:path.join(__dirname,'./dist'), //打包后文件的输出目录 14 | publicPath:'/dist/', //指定资源文件引用目录,可以是CDN 15 | filename:'main.js' //输出文件的名称 16 | }, 17 | module:{ 18 | rules:[ 19 | { 20 | test:/\.vue$/, 21 | loader:'vue-loader', 22 | options:{ 23 | loaders:{ 24 | css:[ 25 | 'vue-style-loader', 26 | 'mini-css-extract-plugin', 27 | 'css-loader' 28 | ] 29 | } 30 | } 31 | }, 32 | { 33 | test: /\.css$/, 34 | use:[ //数组形式的话,编译是从后往前。 35 | MiniCssExtractPlugin.loader, 36 |       'css-loader' 37 | ] 38 | }, 39 | // { 40 | // test:/\.vue$/, 41 | // loader:'vue-loader', 42 | // options:{ 43 | // loaders:{ 44 | // css:ExtractTextPlugin.extract({ 45 | // use:'css-loader', 46 | // fallback:'vue-style-loader' 47 | // }) 48 | // } 49 | // } 50 | // }, 51 | // { 52 | // test: /\.css$/, 53 | // use: ExtractTextPlugin.extract({ 54 | // use: 'css-loader', 55 | // fallback: 'style-loader' 56 | // }) 57 | // }, 58 | // 除非您要自定义 entry point(入口点) ,否则无需指定babel-loader。 59 | // { 60 | // test:/\.js$/, 61 | // loader:'babel-loader', 62 | // exclude:/node_modules/ 63 | // }, 64 | { 65 | test:/\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/, 66 | loader:'url-loader?limit=1024' //文件小于1k就以base64形式加载 67 | } 68 | ] 69 | }, 70 | plugins:[ 71 | // new ExtractTextPlugin({ 72 | // filename:'main.css',//重命名提取后的css文件 73 | // allChunks: true //有了chunk,需要在此配置 74 | // }), 75 | new MiniCssExtractPlugin('main.css'), 76 | // new ExtractTextPlugin("main.css"), 77 | new VueLoaderPlugin() //vue-loader,15的版本需要再添加plugin的配置 78 | ] 79 | }; 80 | module.exports = config 81 | //ES6: export default config -------------------------------------------------------------------------------- /vue13/daily/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 3 | const { VueLoaderPlugin } = require('vue-loader'); //vue-loader,15的版本需要再添加plugin的配置 4 | // var ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | 6 | const config = { 7 | //配置的单入口,webpack从index.js开始工作,webpack4默认entry 路径./src/index.js 8 | // 所以下边的entry可以不写 9 | // entry:{ 10 | // main:'./src/index' 11 | // }, 12 | output:{//打包后的文件会存储为demo/dist/main.js 在html中引用它就可以了 13 | path:path.join(__dirname,'./dist'), //打包后文件的输出目录 14 | publicPath:'/dist/', //指定资源文件引用目录,可以是CDN 15 | filename:'main.js' //输出文件的名称 16 | }, 17 | module:{ 18 | rules:[ 19 | { 20 | test:/\.vue$/, 21 | loader:'vue-loader', 22 | options:{ 23 | loaders:{ 24 | css:[ 25 | 'vue-style-loader', 26 | 'mini-css-extract-plugin', 27 | 'css-loader' 28 | ] 29 | } 30 | } 31 | }, 32 | { 33 | test: /\.css$/, 34 | use:[ //数组形式的话,编译是从后往前。 35 | MiniCssExtractPlugin.loader, 36 |       'css-loader' 37 | ] 38 | }, 39 | // { 40 | // test:/\.vue$/, 41 | // loader:'vue-loader', 42 | // options:{ 43 | // loaders:{ 44 | // css:ExtractTextPlugin.extract({ 45 | // use:'css-loader', 46 | // fallback:'vue-style-loader' 47 | // }) 48 | // } 49 | // } 50 | // }, 51 | // { 52 | // test: /\.css$/, 53 | // use: ExtractTextPlugin.extract({ 54 | // use: 'css-loader', 55 | // fallback: 'style-loader' 56 | // }) 57 | // }, 58 | // 除非您要自定义 entry point(入口点) ,否则无需指定babel-loader。 59 | // { 60 | // test:/\.js$/, 61 | // loader:'babel-loader', 62 | // exclude:/node_modules/ 63 | // }, 64 | { 65 | test:/\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/, 66 | loader:'url-loader?limit=1024' //文件小于1k就以base64形式加载 67 | } 68 | ] 69 | }, 70 | plugins:[ 71 | // new ExtractTextPlugin({ 72 | // filename:'main.css',//重命名提取后的css文件 73 | // allChunks: true //有了chunk,需要在此配置 74 | // }), 75 | new MiniCssExtractPlugin('main.css'), 76 | // new ExtractTextPlugin("main.css"), 77 | new VueLoaderPlugin() //vue-loader,15的版本需要再添加plugin的配置 78 | ] 79 | }; 80 | module.exports = config 81 | //ES6: export default config -------------------------------------------------------------------------------- /vue14/shopping/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 3 | const { VueLoaderPlugin } = require('vue-loader'); //vue-loader,15的版本需要再添加plugin的配置 4 | // var ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | 6 | const config = { 7 | //配置的单入口,webpack从index.js开始工作,webpack4默认entry 路径./src/index.js 8 | // 所以下边的entry可以不写 9 | // entry:{ 10 | // main:'./src/index' 11 | // }, 12 | output:{//打包后的文件会存储为demo/dist/main.js 在html中引用它就可以了 13 | path:path.join(__dirname,'./dist'), //打包后文件的输出目录 14 | publicPath:'/dist/', //指定资源文件引用目录,可以是CDN 15 | filename:'main.js' //输出文件的名称 16 | }, 17 | module:{ 18 | rules:[ 19 | { 20 | test:/\.vue$/, 21 | loader:'vue-loader', 22 | options:{ 23 | loaders:{ 24 | css:[ 25 | 'vue-style-loader', 26 | 'mini-css-extract-plugin', 27 | 'css-loader' 28 | ] 29 | } 30 | } 31 | }, 32 | { 33 | test: /\.css$/, 34 | use:[ //数组形式的话,编译是从后往前。 35 | MiniCssExtractPlugin.loader, 36 |       'css-loader' 37 | ] 38 | }, 39 | // { 40 | // test:/\.vue$/, 41 | // loader:'vue-loader', 42 | // options:{ 43 | // loaders:{ 44 | // css:ExtractTextPlugin.extract({ 45 | // use:'css-loader', 46 | // fallback:'vue-style-loader' 47 | // }) 48 | // } 49 | // } 50 | // }, 51 | // { 52 | // test: /\.css$/, 53 | // use: ExtractTextPlugin.extract({ 54 | // use: 'css-loader', 55 | // fallback: 'style-loader' 56 | // }) 57 | // }, 58 | // 除非您要自定义 entry point(入口点) ,否则无需指定babel-loader。 59 | // { 60 | // test:/\.js$/, 61 | // loader:'babel-loader', 62 | // exclude:/node_modules/ 63 | // }, 64 | { 65 | test:/\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/, 66 | loader:'url-loader?limit=1024' //文件小于1k就以base64形式加载 67 | } 68 | ] 69 | }, 70 | plugins:[ 71 | // new ExtractTextPlugin({ 72 | // filename:'main.css',//重命名提取后的css文件 73 | // allChunks: true //有了chunk,需要在此配置 74 | // }), 75 | new MiniCssExtractPlugin('main.css'), 76 | // new ExtractTextPlugin("main.css"), 77 | new VueLoaderPlugin() //vue-loader,15的版本需要再添加plugin的配置 78 | ] 79 | }; 80 | module.exports = config 81 | //ES6: export default config -------------------------------------------------------------------------------- /vue13/daily/src/directives/time.js: -------------------------------------------------------------------------------- 1 | var Time = { 2 | // 获取当前时间戳 3 | getUnix: function () { 4 | var date = new Date(); 5 | return date.getTime(); 6 | }, 7 | // 获取今天0点0分0秒的时间戳 8 | getTodayUnix: function () { 9 | var date = new Date(); 10 | date.setHours(0); 11 | date.setMinutes(0); 12 | date.setSeconds(0); 13 | date.setMilliseconds(0); 14 | return date.getTime(); 15 | }, 16 | // 获取今年1月1日0点0分0秒的时间戳 17 | getYearUnix: function () { 18 | var date = new Date(); 19 | date.setMonth(0); 20 | date.setDate(1); 21 | date.setHours(0); 22 | date.setMinutes(0); 23 | date.setSeconds(0); 24 | date.setMilliseconds(0); 25 | return date.getTime(); 26 | }, 27 | // 获取标准年月日 28 | getLastDate: function(time) { 29 | var date = new Date(time); 30 | var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1; 31 | var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate(); 32 | return date.getFullYear() + '-' + month + "-" + day; 33 | }, 34 | // 转换时间 35 | getFormatTime: function(timestamp) { 36 | var now = this.getUnix(); //当前时间戳 37 | var today = this.getTodayUnix(); //今天0点时间戳 38 | var year = this.getYearUnix(); //今年0点时间戳 39 | var timer = (now - timestamp) / 1000; // 转换为秒级时间戳 40 | var tip = ''; 41 | 42 | if (timer <= 0) { 43 | tip = '刚刚'; 44 | } else if (Math.floor(timer/60) <= 0) { 45 | tip = '刚刚'; 46 | } else if (timer < 3600) { 47 | tip = Math.floor(timer/60) + '分钟前'; 48 | } else if (timer >= 3600 && (timestamp - today >= 0) ) { 49 | tip = Math.floor(timer/3600) + '小时前'; 50 | } else if (timer/86400 <= 31) { 51 | tip = Math.ceil(timer/86400) + '天前'; 52 | } else { 53 | tip = this.getLastDate(timestamp); 54 | } 55 | return tip; 56 | } 57 | }; 58 | 59 | export default { 60 | bind: function (el, binding) { 61 | el.innerHTML = Time.getFormatTime(binding.value * 1000); 62 | el.__timeout__ = setInterval(function() { 63 | el.innerHTML = Time.getFormatTime(binding.value * 1000); 64 | }, 60000); 65 | }, 66 | unbind: function (el) { 67 | clearInterval(el.__timeout__); 68 | delete el.__timeout__; 69 | } 70 | } -------------------------------------------------------------------------------- /vue11/vuex/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | // const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 3 | const { VueLoaderPlugin } = require('vue-loader'); //vue-loader,15的版本需要再添加plugin的配置 4 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | 6 | module.exports = { 7 | //配置的单入口,webpack从index.js开始工作,webpack4默认entry 路径./src/index.js 8 | // 所以下边的entry可以不写 9 | // entry:{ 10 | // main:'./src/index' 11 | // }, 12 | output:{//打包后的文件会存储为demo/dist/main.js 在html中引用它就可以了 13 | path:path.join(__dirname,'./dist'), //打包后文件的输出目录 14 | publicPath:'/dist/', //指定资源文件引用目录,可以是CDN 15 | filename:'main.js' //输出文件的名称 16 | }, 17 | // optimization: { 18 | // splitChunks: { 19 | // cacheGroups: { 20 | // styles: { 21 | // name: 'main', 22 | // test: /\.css$/, 23 | // chunks: 'all', // merge all the css chunk to one file 24 | // enforce: true 25 | // } 26 | // } 27 | // } 28 | // }, 29 | plugins:[ 30 | new ExtractTextPlugin({ 31 | filename:'main.css',//重命名提取后的css文件 32 | allChunks: true //有了chunk,需要在此配置 33 | }), 34 | // new MiniCssExtractPlugin({ 35 | // filename:'main.css', 36 | // }), 37 | new VueLoaderPlugin() //vue-loader,15的版本需要再添加plugin的配置 38 | ], 39 | module:{ 40 | rules:[ 41 | // { 42 | // test:/\.vue$/, 43 | // loader:'vue-loader', 44 | // options:{ 45 | // loaders:{ 46 | // css:[ 47 | // 'vue-style-loader', 48 | // 'mini-css-extract-plugin', 49 | // 'css-loader' 50 | // ] 51 | // } 52 | // } 53 | // }, 54 | // { 55 | // test: /\.css$/, 56 | // use:[ //数组形式的话,编译是从后往前。 57 | // MiniCssExtractPlugin.loader, 58 | //       'css-loader' 59 | // ] 60 | // }, 61 | { 62 | test:/\.vue$/, 63 | loader:'vue-loader', 64 | options:{ 65 | loaders:{ 66 | css:ExtractTextPlugin.extract({ 67 | use:'css-loader', 68 | fallback:'vue-style-loader' 69 | }) 70 | } 71 | } 72 | }, 73 | { 74 | test: /\.css$/, 75 | use: ExtractTextPlugin.extract({ 76 | use: 'css-loader', 77 | fallback: 'style-loader' 78 | }) 79 | }, 80 | { 81 | test:/\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/, 82 | loader:'url-loader?limit=1024' 83 | } 84 | ] 85 | } 86 | 87 | }; 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 《Vue.js实战》 笔记 2 | 3 | ## 项目起源 4 | 最近有时间研读了Aresn的《Vue.js实战》一书,收获颇丰。感觉是学习Vue的书籍里比较好的一本书了。在此做些笔记备忘。 5 | 6 | 关于本书 中有说明,示例代码已经存放在了[github](https://github.com/icarusion/vue-book)上,里边有购买途径和已知勘误。但进去发现代码是从"实战篇"开始有的。"基础篇"和"晋级篇"的代码并没有。 7 | 大胆猜测没有的原因一个是因为前期并没有结合前端工程化,代码还比较简单。另一个就是作者希望我们能自己敲一遍代码,加深对Vue的学习。 但对于Vue新手,甚至是前端新手,有时可能还是需要全部代码的。所以在笔记中加入了书中几乎所有代码供有需要的参考。另随着时间的迁移,或许有些技术点会发生改变,书中以webpack2为例。笔记项目中采用webpack4可直接npm install 跑通后几章代码。但毕竟一人精力和能力有限。所以有了这个GitHub项目。我们可以通过协作的方式来共同维护这个项目。Git的历史记录也可以见证前端行业的一些变迁。 8 | 9 | ## 项目目录结构 10 | + vue-combat-book ----- Vue.js实战 11 | + vue01 ----- 初识vue.js 12 | + vue02 ----- 数据绑定 13 | + vue03 ----- 计算属性 14 | + vue04 ----- v-bind及class与style绑定 15 | + vue05 ----- 基本指令 16 | + shopping_trolley ----- 开发购物车小功能 17 | + vue06 ----- 表单域v-model 18 | + vue07 ----- 组件详解 19 | + label_page ----- 标签页组件 20 | + input_box ----- 数字输入框组件 21 | + vue08 ----- 自定义指令 22 | + menu ----- 从外部关闭的下拉菜单 23 | + v-time ----- 开发实时时间转换v-time 24 | + vue09 ----- render函数 25 | + sort_form ----- 可排序表格组件 26 | + message_list ----- 留言列表 27 | + vue10 ----- 使用webpack 28 | + demo ----- demo代码 29 | + README10 ----- 第十章笔记 30 | + vue11 ----- 插件 31 | + router ----- router代码 32 | + vuex ----- vuex代码 33 | + vue-bus ----- vue-bus代码 34 | + README11 ----- 第十一章笔记 35 | + vue12 ----- iView经典组件剖析 36 | + README12 ----- 第十二章笔记 37 | + vue13 ----- 知乎日报项目开发 38 | + daily ----- daily代码 39 | + README13 ----- 第十三章笔记 40 | + vue14 ----- 电商网站项目开发 41 | + shopping ----- shopping代码 42 | + vue15 ----- 相关开源项目介绍 43 | +README15 ----- 第十五章笔记 44 | + README ----- 项目介绍 45 | 46 | ## 项目文件百度网盘 47 | 48 | ~~[项目代码 + 《Vue.js实战》电子版zip](https://pan.baidu.com/s/1tSWJceedc27EnfET5IX_xg)~~ 49 | 书籍电子版已删除,[项目代码](https://pan.baidu.com/s/1tSWJceedc27EnfET5IX_xg) 50 | PS:强烈建议购买正版书阅读,另外对着屏幕总是比看书费眼睛吧。 51 | 52 | 2018/11.01更新: 53 | 修改vue01-vue10部分文件代码 54 | [新增vue-devtools工具](https://pan.baidu.com/s/1tSWJceedc27EnfET5IX_xg),如何安装有人写的文章很清楚了,[戳这里](https://segmentfault.com/a/1190000009682735) 55 | [新增简单的在webpack4.23.1下对vue2.5.17的搭建](https://github.com/zyf711/webpack-quick) 56 | 57 | 2018/11.13更新: 58 | [新增vue+vue-router+vuex做的移动端小答题页面](https://github.com/zyf711/vue2-answer) 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /vue14/shopping/src/components/product.vue: -------------------------------------------------------------------------------- 1 | 13 | 35 | -------------------------------------------------------------------------------- /vue14/shopping/src/product.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | id: 1, 4 | name: 'AirPods', 5 | brand: 'Apple', 6 | image: 'http://ordfm6aah.bkt.clouddn.com/shop/1.jpeg', 7 | sales: 10000, 8 | cost: 1288, 9 | color: '白色' 10 | }, 11 | { 12 | id: 2, 13 | name: 'BeatsX 入耳式耳机', 14 | brand: 'Beats', 15 | image: 'http://ordfm6aah.bkt.clouddn.com/shop/2.jpeg', 16 | sales: 11000, 17 | cost: 1188, 18 | color: '白色' 19 | }, 20 | { 21 | id: 3, 22 | name: 'Beats Solo3 Wireless 头戴式式耳机', 23 | brand: 'Beats', 24 | image: 'http://ordfm6aah.bkt.clouddn.com/shop/3.jpeg', 25 | sales: 5000, 26 | cost: 2288, 27 | color: '金色' 28 | }, 29 | { 30 | id: 4, 31 | name: 'Beats Pill+ 便携式扬声器', 32 | brand: 'Beats', 33 | image: 'http://ordfm6aah.bkt.clouddn.com/shop/4.jpeg', 34 | sales: 3000, 35 | cost: 1888, 36 | color: '红色' 37 | }, 38 | { 39 | id: 5, 40 | name: 'Sonos PLAY:1 无线扬声器', 41 | brand: 'Sonos', 42 | image: 'http://ordfm6aah.bkt.clouddn.com/shop/5.jpeg', 43 | sales: 8000, 44 | cost: 1578, 45 | color: '白色' 46 | }, 47 | { 48 | id: 6, 49 | name: 'Powerbeats3 by Dr. Dre Wireless 入耳式耳机', 50 | brand: 'Beats', 51 | image: 'http://ordfm6aah.bkt.clouddn.com/shop/6.jpeg', 52 | sales: 12000, 53 | cost: 1488, 54 | color: '金色' 55 | }, 56 | { 57 | id: 7, 58 | name: 'Beats EP 头戴式耳机', 59 | brand: 'Beats', 60 | image: 'http://ordfm6aah.bkt.clouddn.com/shop/7.jpeg', 61 | sales: 25000, 62 | cost: 788, 63 | color: '蓝色' 64 | }, 65 | { 66 | id: 8, 67 | name: 'B&O PLAY BeoPlay A1 便携式蓝牙扬声器', 68 | brand: 'B&O', 69 | image: 'http://ordfm6aah.bkt.clouddn.com/shop/8.jpeg', 70 | sales: 15000, 71 | cost: 1898, 72 | color: '金色' 73 | }, 74 | { 75 | id: 9, 76 | name: 'Bose® QuietComfort® 35 无线耳机', 77 | brand: 'Bose', 78 | image: 'http://ordfm6aah.bkt.clouddn.com/shop/9.jpeg', 79 | sales: 14000, 80 | cost: 2878, 81 | color: '蓝色' 82 | }, 83 | { 84 | id: 10, 85 | name: 'B&O PLAY Beoplay H4 无线头戴式耳机', 86 | brand: 'B&O', 87 | image: 'http://ordfm6aah.bkt.clouddn.com/shop/10.jpeg', 88 | sales: 9000, 89 | cost: 2298, 90 | color: '金色' 91 | } 92 | ] -------------------------------------------------------------------------------- /vue11/vuex/src/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueRouter from 'vue-router'; 3 | import Vuex from 'vuex'; 4 | import App from './app.vue'; 5 | import moduleA from './moduleA' //vuex中modules分割出的模块 6 | 7 | Vue.use(VueRouter) 8 | Vue.use(Vuex) 9 | 10 | const Routers = [ 11 | { 12 | path:'/index', 13 | meta:{ 14 | title:'首页' 15 | }, 16 | component:(resolve) => require(['./views/index.vue'],resolve) 17 | }, 18 | { 19 | path:'/about', 20 | meta:{ 21 | title:'关于' 22 | }, 23 | component:(resolve) => require(['./views/about.vue'],resolve) 24 | }, 25 | { 26 | path:'/user/:id', 27 | meta:{ 28 | title:'个人主页' 29 | }, 30 | component:(resolve) => require(['./views/user.vue'],resolve) 31 | }, 32 | { 33 | path:'*', 34 | redirect:'/index' 35 | } 36 | ]; 37 | 38 | const router = new VueRouter({ 39 | mode:'history', 40 | routes: Routers 41 | }); 42 | 43 | 44 | router.beforeEach((to,from,next)=>{ 45 | window.document.title = to.meta.title; 46 | next(); 47 | }) 48 | 49 | const store = new Vuex.Store({ 50 | modules:{ moduleA:moduleA }, // 项目足够大,store内容过多时,modules把store里内容写到不同文件中 51 | state:{ //数据保存在state字段内 52 | count:0, //任何组件通过this.$store.state.count读取 53 | list:[1,5,8,10,30,50] 54 | }, 55 | mutations:{ //mutations改变state字段数据唯一途径 56 | increment(state){ 57 | state.count ++ ; //任何组件通过this.$store.commit('increment')提交事件名 58 | }, 59 | decrease(state,n=10){// mutations可以接受第二个参数,数字,字符串或对象等类型 60 | state.count -= n; 61 | }, 62 | custom(state,params){ 63 | state.count += params.count; 64 | } 65 | }, 66 | actions:{ //actions提交的是mutations 67 | //涉及改变数据的就用mutations,存在业务逻辑的就用actions,actions可以异步操作业务逻辑。 68 | asyncIncrement(context){ //任何组件this.$store.dispatch('asyncIncrement')触发 69 | return new Promise((resolve,reject) => { //Promise在2秒后提交mutations 70 | setTimeout(()=>{ 71 | const random = Math.random(); 72 | if( random >.5 ){ 73 | context.commit('increment'); 74 | console.log(random) 75 | resolve(); 76 | }else{ 77 | reject(random) 78 | } 79 | },2000) 80 | }); 81 | } 82 | }, 83 | getters:{ 84 | filteredList:state => { 85 | return state.list.filter(item => item < 10); //任何组件通过this.$store.getters.filteredList提交事件名 86 | }, 87 | listCount:(state,getters) => { 88 | return getters.filteredList.length; 89 | } 90 | } 91 | }) 92 | 93 | new Vue({ 94 | el: '#app', 95 | router:router, 96 | store:store, 97 | render: h => { 98 | return h(App); 99 | } 100 | }); -------------------------------------------------------------------------------- /vue07/label_page/tabs.js: -------------------------------------------------------------------------------- 1 | Vue.component('tabs',{ 2 | template:'
\ 3 |
\ 4 |
{{item.label}}
\ 5 |
\ 6 |
\ 7 | \ 8 |
\ 9 |
', //上边的slot是嵌套的pane 10 | props:{ 11 | // 这里value为了可以使用v-model 12 | value:{ 13 | type:[String,Number] 14 | } 15 | }, 16 | data:function(){ 17 | return { 18 | currentValue:this.value, // 因为不能修改value,所以复制一份自己维护 19 | navList:[] //用于渲染tabs的标题 20 | } 21 | }, 22 | methods:{ 23 | tabCls:function(item){ 24 | return [ 25 | 'tabs-tab', 26 | { 27 | // 给当前选中的tab,也就是item.name === this.currentValue为true的加一个class 28 | // 运算优先级=== 高于 条件: 29 | // 运算符优先级https://www.cnblogs.com/yy-hh/p/4624792.html 30 | 'tabs-tab-active':item.name === this.currentValue 31 | } 32 | ] 33 | }, 34 | getTabs(){ // 通过遍历子组件,得到所有的pane组件 35 | return this.$children.filter(function(item){ 36 | return item.$options.name === 'pane' 37 | }); 38 | }, 39 | updateNav(){ //更新标题 40 | this.navList = []; 41 | var _this = this; 42 | // 把pane的label和name提取出来,构成一个object并添加到数组navList里,后面会在template里用到 43 | this.getTabs().forEach(function( pane,index ){ 44 | _this.navList.push({ 45 | label:pane.label, 46 | name:pane.name || index 47 | }); 48 | // 如果没给pane设置name,(比如没给activeKey1设置初始选中哪个)默认设置它的索引 49 | if( !pane.name ) pane.name = index; 50 | // 设置当前选中的tab的索引,在此就是默认第一个显示 51 | if( index === 0 ){ 52 | if( !_this.currentValue ){ 53 | _this.currentValue = pane.name || index; 54 | } 55 | } 56 | }); 57 | this.updateStatus() 58 | }, 59 | updateStatus(){ // 显示当前选中的tab对应的pane组件,隐藏没选中的 60 | var tabs = this.getTabs(); 61 | var _this = this; 62 | tabs.forEach(function (tab){ 63 | // 这里是对所有pane里边的sw判断是true还是false 64 | // 运算优先级=== 高于= 先判断tab.name === _this.currentValue 是true还是false,再赋值给tab.sw 65 | return tab.sw = tab.name === _this.currentValue; 66 | }) 67 | }, 68 | handleChange:function(index){ //点击tab标题时触发 69 | var nav = this.navList[index]; 70 | var name = nav.name; 71 | // 改变当前选中的tab,并触发下面的watch 72 | this.currentValue = name; 73 | // 更新value 74 | this.$emit('input',name); 75 | // 触发一个自定义事件,供父级使用 76 | this.$emit('on-click',name); 77 | } 78 | }, 79 | watch:{ 80 | value:function(val){ 81 | this.currentValue = val; 82 | }, 83 | currentValue:function(){ 84 | // 在当前选中的tab发生变化时,更新pane的显示状态 85 | this.updateStatus() 86 | } 87 | } 88 | }) -------------------------------------------------------------------------------- /vue11/router/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | // const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 3 | const { VueLoaderPlugin } = require('vue-loader'); //vue-loader,15的版本需要再添加plugin的配置 4 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | 6 | module.exports = { 7 | //配置的单入口,webpack从index.js开始工作,webpack4默认entry 路径./src/index.js 8 | // 所以下边的entry可以不写 9 | // entry:{ 10 | // main:'./src/index' 11 | // }, 12 | output:{//打包后的文件会存储为demo/dist/main.js 在html中引用它就可以了 13 | path:path.join(__dirname,'./dist'), //打包后文件的输出目录 14 | publicPath:'/dist/', //指定资源文件引用目录,可以是CDN 15 | filename:'main.js' //输出文件的名称 16 | }, 17 | // optimization: { 18 | // splitChunks: { 19 | // cacheGroups: { 20 | // styles: { 21 | // name: 'main', 22 | // test: /\.css$/, 23 | // chunks: 'all', // merge all the css chunk to one file 24 | // enforce: true 25 | // } 26 | // } 27 | // } 28 | // }, 29 | plugins:[ 30 | new ExtractTextPlugin({ 31 | filename:'main.css',//重命名提取后的css文件 32 | allChunks: true //有了chunk,需要在此配置 33 | }), 34 | // new MiniCssExtractPlugin({ 35 | // filename:'main.css', 36 | // }), 37 | new VueLoaderPlugin() //vue-loader,15的版本需要再添加plugin的配置 38 | ], 39 | module:{ 40 | rules:[ 41 | // { 42 | // test:/\.vue$/, 43 | // loader:'vue-loader', 44 | // options:{ 45 | // loaders:{ 46 | // css:[ 47 | // 'vue-style-loader', 48 | // 'mini-css-extract-plugin', 49 | // 'css-loader' 50 | // ] 51 | // } 52 | // } 53 | // }, 54 | // { 55 | // test: /\.css$/, 56 | // use:[ //数组形式的话,编译是从后往前。 57 | // MiniCssExtractPlugin.loader, 58 | //       'css-loader' 59 | // ] 60 | // }, 61 | { 62 | test:/\.vue$/, 63 | loader:'vue-loader', 64 | options:{ 65 | loaders:{ 66 | css:ExtractTextPlugin.extract({ 67 | use:'css-loader', 68 | fallback:'vue-style-loader' 69 | }) 70 | } 71 | } 72 | }, 73 | { 74 | test: /\.css$/, 75 | use: ExtractTextPlugin.extract({ 76 | use: 'css-loader', 77 | fallback: 'style-loader' 78 | }) 79 | }, 80 | // { 81 | // test:/\.js$/, 82 | // loader:'babel-loader', 83 | // exclude:/node_modules/ 84 | // }, 85 | { 86 | test:/\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/, 87 | loader:'url-loader?limit=1024' 88 | } 89 | ] 90 | } 91 | 92 | }; -------------------------------------------------------------------------------- /vue11/vue-bus/src/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueRouter from 'vue-router'; 3 | import Vuex from 'vuex'; 4 | import App from './app.vue'; 5 | import moduleA from './moduleA' //vuex中modules分割出的模块 6 | import VueBus from './vue-bus'; 7 | 8 | Vue.use(VueRouter); 9 | Vue.use(Vuex); 10 | Vue.use(VueBus); 11 | 12 | const Routers = [ 13 | { 14 | path:'/index', 15 | meta:{ 16 | title:'首页' 17 | }, 18 | component:(resolve) => require(['./views/index.vue'],resolve) 19 | }, 20 | { 21 | path:'/about', 22 | meta:{ 23 | title:'关于' 24 | }, 25 | component:(resolve) => require(['./views/about.vue'],resolve) 26 | }, 27 | { 28 | path:'/user/:id', 29 | meta:{ 30 | title:'个人主页' 31 | }, 32 | component:(resolve) => require(['./views/user.vue'],resolve) 33 | }, 34 | { 35 | path:'*', 36 | redirect:'/index' 37 | } 38 | ]; 39 | 40 | const router = new VueRouter({ 41 | mode:'history', 42 | routes: Routers 43 | }); 44 | 45 | 46 | router.beforeEach((to,from,next)=>{ 47 | window.document.title = to.meta.title; 48 | next(); 49 | }) 50 | 51 | const store = new Vuex.Store({ 52 | modules:{ moduleA:moduleA }, // 项目足够大,store内容过多时,modules把store里内容写到不同文件中 53 | state:{ //数据保存在state字段内 54 | count:0, //任何组件通过this.$store.state.count读取 55 | list:[1,5,8,10,30,50] 56 | }, 57 | mutations:{ //mutations改变state字段数据唯一途径 58 | increment(state){ 59 | state.count ++ ; //任何组件通过this.$store.commit('increment')提交事件名 60 | }, 61 | decrease(state,n=10){// mutations可以接受第二个参数,数字,字符串或对象等类型 62 | state.count -= n; 63 | }, 64 | custom(state,params){ 65 | state.count += params.count; 66 | } 67 | }, 68 | actions:{ //actions提交的是mutations 69 | //涉及改变数据的就用mutations,存在业务逻辑的就用actions,actions可以异步操作业务逻辑。 70 | asyncIncrement(context){ //任何组件this.$store.dispatch('asyncIncrement')触发 71 | return new Promise((resolve,reject) => { //Promise在2秒后提交mutations 72 | setTimeout(()=>{ 73 | const random = Math.random(); 74 | if( random >.5 ){ 75 | context.commit('increment'); 76 | console.log(random) 77 | resolve(); 78 | }else{ 79 | reject(random) 80 | } 81 | },2000) 82 | }); 83 | } 84 | }, 85 | getters:{ 86 | filteredList:state => { 87 | return state.list.filter(item => item < 10); //任何组件通过this.$store.getters.filteredList提交事件名 88 | }, 89 | listCount:(state,getters) => { 90 | return getters.filteredList.length; 91 | } 92 | } 93 | }) 94 | 95 | new Vue({ 96 | el: '#app', 97 | router:router, 98 | store:store, 99 | render: h => { 100 | return h(App); 101 | } 102 | }); -------------------------------------------------------------------------------- /vue11/vue-bus/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | // const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 3 | const { VueLoaderPlugin } = require('vue-loader'); //vue-loader,15的版本需要再添加plugin的配置 4 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | 6 | module.exports = { 7 | //配置的单入口,webpack从index.js开始工作,webpack4默认entry 路径./src/index.js 8 | // 所以下边的entry可以不写 9 | // entry:{ 10 | // main:'./src/index' 11 | // }, 12 | output:{//打包后的文件会存储为demo/dist/main.js 在html中引用它就可以了 13 | path:path.join(__dirname,'./dist'), //打包后文件的输出目录 14 | publicPath:'/dist/', //指定资源文件引用目录,可以是CDN 15 | filename:'main.js' //输出文件的名称 16 | }, 17 | // optimization: { 18 | // splitChunks: { 19 | // cacheGroups: { 20 | // styles: { 21 | // name: 'main', 22 | // test: /\.css$/, 23 | // chunks: 'all', // merge all the css chunk to one file 24 | // enforce: true 25 | // } 26 | // } 27 | // } 28 | // }, 29 | plugins:[ 30 | new ExtractTextPlugin({ 31 | filename:'main.css',//重命名提取后的css文件 32 | allChunks: true //有了chunk,需要在此配置 33 | }), 34 | // new MiniCssExtractPlugin({ 35 | // filename:'main.css', 36 | // }), 37 | new VueLoaderPlugin() //vue-loader,15的版本需要再添加plugin的配置 38 | ], 39 | module:{ 40 | rules:[ 41 | // { 42 | // test:/\.vue$/, 43 | // loader:'vue-loader', 44 | // options:{ 45 | // loaders:{ 46 | // css:[ 47 | // 'vue-style-loader', 48 | // 'mini-css-extract-plugin', 49 | // 'css-loader' 50 | // ] 51 | // } 52 | // } 53 | // }, 54 | // { 55 | // test: /\.css$/, 56 | // use:[ //数组形式的话,编译是从后往前。 57 | // MiniCssExtractPlugin.loader, 58 | //       'css-loader' 59 | // ] 60 | // }, 61 | { 62 | test:/\.vue$/, 63 | loader:'vue-loader', 64 | options:{ 65 | loaders:{ 66 | css:ExtractTextPlugin.extract({ 67 | use:'css-loader', 68 | fallback:'vue-style-loader' 69 | }) 70 | } 71 | } 72 | }, 73 | { 74 | test: /\.css$/, 75 | use: ExtractTextPlugin.extract({ 76 | use: 'css-loader', 77 | fallback: 'style-loader' 78 | }) 79 | }, 80 | // 除非您要自定义 entry point(入口点) ,否则无需指定babel-loader。 81 | // { 82 | // test:/\.js$/, 83 | // loader:'babel-loader', 84 | // exclude:/node_modules/ 85 | // }, 86 | { 87 | test:/\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/, 88 | loader:'url-loader?limit=1024' //文件小于1k就以base64形式加载 89 | } 90 | ] 91 | } 92 | 93 | }; 94 | // module.exports = config 95 | //ES6: export default config -------------------------------------------------------------------------------- /vue07/input_box/input-number.js: -------------------------------------------------------------------------------- 1 | function isValueNumber(value){ 2 | return ( /(^-?[0-9]+\.{1}\d+$) | (^-?[1-9][0-9]*$) | (^-?0{1}$)/ ).test(value+''); 3 | } 4 | 5 | Vue.component('input-number',{ 6 | template:'
\ 7 | \ 8 | \ 9 | \ 10 |
', 11 | props:{ //因为是独立组件,所以应该对每个prop进行效验 12 | max:{ 13 | type:Number, 14 | default:Infinity 15 | }, 16 | min:{ 17 | type:Number, 18 | default:-Infinity 19 | }, 20 | value:{ 21 | type:Number, 22 | default:0 23 | }, 24 | step:{ 25 | type:Number, 26 | default:1 27 | } 28 | }, 29 | data:function(){ 30 | // var val = this.value; 31 | // if( val > this.max ) val = this.max; 32 | // if( val < this.min ) val = this.min; 33 | // return{ currentValue : val } 34 | return { 35 | // Vue组件是单向数据流,无法从组件内部直接修改prop,value值。解决办法:给组件声明一个data。默认引用value的值。 36 | //使得可以从组件内部直接修改prop和value的值。就解决了引用父组件value的问题。 37 | currentValue:this.value 38 | } 39 | }, 40 | watch:{ //用来监听某个prop或data的改变,改变时就会触发里边的函数 41 | currentValue:function(val){ 42 | this.$emit('input',val); //在使用v-model时改变value的 43 | this.$emit('on-change',val); //触发自定义事件on-change告知父组件数字输入框的值有所改变,例子中没用到 44 | }, 45 | value:function(val){ 46 | this.updateValue(val) 47 | } 48 | }, 49 | methods:{ 50 | updateValue:function(val){ //过滤出一个正确的currentValue 51 | if( val > this.max ) val = this.max; 52 | if( val < this.min ) val = this.min; 53 | this.currentValue = val 54 | }, 55 | handleDown:function(){ 56 | if( this.currentValue <= this.min ) return; 57 | this.currentValue -= this.step 58 | }, 59 | handleUp:function(){ 60 | if( this.currentValue >= this.max ) return; 61 | this.currentValue += this.step 62 | }, 63 | handleKeydown:function(event){ 64 | if(event.keyCode==38){ 65 | this.handleUp(); 66 | } 67 | if(event.keyCode==40){ 68 | this.handleDown() ; 69 | } 70 | }, 71 | handleChange:function(event){ //handleChange绑在了上边的原生change事件上。判断当前输入的是否是数字。 72 | var val = event.target.value.trim(); 73 | 74 | var max = this.max; 75 | var min = this.min; 76 | 77 | if( isValueNumber(val) ){ 78 | val = Number(val); 79 | this.currentValue = val; 80 | 81 | if( val > max ){ 82 | this.currentValue = max; 83 | }else if( val < min ){ 84 | this.currentValue = min; 85 | } 86 | }else{ 87 | event.target.value = this.currentValue; 88 | } 89 | } 90 | }, 91 | mounted:function(){ 92 | //在mounted钩子里调用updateValue()方法是因为第一次初始化时,也对value进行了过滤。 93 | // 还有种写法,在data选项里返回对象前进行过滤。参照data里的注释。 94 | this.updateValue(this.value) 95 | } 96 | }) -------------------------------------------------------------------------------- /vue14/shopping/src/views/product.vue: -------------------------------------------------------------------------------- 1 | 19 | 46 | -------------------------------------------------------------------------------- /vue13/daily/src/style.css: -------------------------------------------------------------------------------- 1 | html, body{ 2 | margin: 0; 3 | padding: 0; 4 | height: 100%; 5 | color: #657180; 6 | font-size: 16px; 7 | } 8 | .daily-menu{ 9 | width: 150px; 10 | position: fixed; 11 | top: 0; 12 | bottom: 0; 13 | left: 0; 14 | overflow: auto; 15 | background: #f5f7f9; 16 | } 17 | .daily-menu-item{ 18 | font-size: 18px; 19 | text-align: center; 20 | margin: 5px 0; 21 | padding: 10px 0; 22 | cursor: pointer; 23 | border-right: 2px solid transparent; 24 | transition: all .3s ease-in-out; 25 | } 26 | .daily-menu-item:hover{ 27 | background: #e3e8ee; 28 | } 29 | .daily-menu-item.on{ 30 | border-right: 2px solid #3399ff; 31 | } 32 | 33 | .daily-menu ul{ 34 | list-style: none; 35 | } 36 | .daily-menu ul li a{ 37 | display: block; 38 | color: inherit; 39 | text-decoration: none; 40 | padding: 5px 0; 41 | margin: 5px 0; 42 | cursor: pointer; 43 | } 44 | .daily-menu ul li a:hover, .daily-menu ul li a.on{ 45 | color: #3399ff; 46 | } 47 | 48 | .daily-list{ 49 | width: 300px; 50 | position: fixed; 51 | top: 0; 52 | bottom: 0; 53 | left: 150px; 54 | overflow: auto; 55 | border-right: 1px solid #d7dde4; 56 | } 57 | .daily-date{ 58 | text-align: center; 59 | margin: 10px 0; 60 | } 61 | .daily-item{ 62 | display: block; 63 | color: inherit; 64 | text-decoration: none; 65 | padding: 16px; 66 | overflow: hidden; 67 | cursor: pointer; 68 | transition: all .3s ease-in-out; 69 | } 70 | .daily-item:hover{ 71 | background: #e3e8ee; 72 | } 73 | .daily-img{ 74 | width: 80px; 75 | height: 80px; 76 | float: left; 77 | } 78 | .daily-img img{ 79 | width: 100%; 80 | height: 100%; 81 | border-radius: 3px; 82 | } 83 | .daily-title{ 84 | padding: 10px 5px 10px 90px; 85 | } 86 | .daily-title.noImg{ 87 | padding-left: 5px; 88 | } 89 | .daily-article{ 90 | margin-left: 450px; 91 | padding: 20px; 92 | } 93 | .daily-article-title{ 94 | font-size: 28px; 95 | font-weight: bold; 96 | color: #222; 97 | padding: 10px 0; 98 | } 99 | 100 | .view-more a{ 101 | display: block; 102 | cursor: pointer; 103 | background: #f5f7f9; 104 | text-align: center; 105 | color: inherit; 106 | text-decoration: none; 107 | padding: 4px 0; 108 | border-radius: 3px; 109 | } 110 | 111 | .daily-comments{ 112 | margin: 10px 0; 113 | } 114 | .daily-comments span{ 115 | display: block; 116 | margin: 10px 0; 117 | font-size: 20px; 118 | } 119 | .daily-comment{ 120 | overflow: hidden; 121 | margin-bottom: 20px; 122 | padding-bottom: 20px; 123 | border-bottom: 1px dashed #e3e8ee; 124 | } 125 | .daily-comment-avatar{ 126 | width: 50px; 127 | height: 50px; 128 | float: left; 129 | } 130 | .daily-comment-avatar img{ 131 | width: 100%; 132 | height: 100%; 133 | border-radius: 3px; 134 | } 135 | .daily-comment-content{ 136 | margin-left: 65px; 137 | } 138 | .daily-comment-name{ 139 | 140 | } 141 | .daily-comment-time{ 142 | color: #9ea7b4; 143 | font-size: 14px; 144 | margin-top: 5px; 145 | } 146 | .daily-comment-text{ 147 | margin-top: 10px; 148 | } -------------------------------------------------------------------------------- /vue09/vue9-13.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue9-13 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 |
14 | 15 | 118 | 119 | -------------------------------------------------------------------------------- /vue14/shopping/src/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueRouter from 'vue-router'; 3 | import Routers from './router'; 4 | import Vuex from 'vuex'; 5 | import App from './app.vue'; 6 | import './style.css'; 7 | 8 | import product_data from './product'; 9 | 10 | Vue.use(VueRouter); 11 | Vue.use(Vuex); 12 | 13 | // 路由配置 14 | const RouterConfig = { 15 | // 使用 HTML5 的 History 路由模式 16 | mode: 'history', 17 | routes: Routers 18 | }; 19 | const router = new VueRouter(RouterConfig); 20 | 21 | router.beforeEach((to, from, next) => { 22 | window.document.title = to.meta.title; 23 | next(); 24 | }); 25 | 26 | router.afterEach((to, from, next) => { 27 | window.scrollTo(0, 0); 28 | }); 29 | 30 | // 数组排重 31 | function getFilterArray (array) { 32 | const res = []; 33 | const json = {}; 34 | for (let i = 0; i < array.length; i++){ 35 | const _self = array[i]; 36 | if(!json[_self]){ 37 | res.push(_self); 38 | json[_self] = 1; 39 | } 40 | } 41 | return res; 42 | } 43 | 44 | const store = new Vuex.Store({ 45 | state: { 46 | productList: [], 47 | cartList: [] 48 | }, 49 | getters: { 50 | brands: state => { 51 | const brands = state.productList.map(item => item.brand); 52 | return getFilterArray(brands); 53 | }, 54 | colors: state => { 55 | const colors = state.productList.map(item => item.color); 56 | return getFilterArray(colors); 57 | } 58 | }, 59 | mutations: { 60 | // 添加商品列表 61 | setProductList (state, data) { 62 | state.productList = data; 63 | }, 64 | // 添加到购物车 65 | addCart (state, id) { 66 | // 先判断购物车是否已有,如果有,数量+1 67 | const isAdded = state.cartList.find(item => item.id === id); 68 | if (isAdded) { 69 | isAdded.count ++; 70 | } else { 71 | state.cartList.push({ 72 | id: id, 73 | count: 1 74 | }) 75 | } 76 | }, 77 | // 修改商品数量 78 | editCartCount (state, payload) { 79 | const product = state.cartList.find(item => item.id === payload.id); 80 | product.count += payload.count; 81 | }, 82 | // 删除商品 findIndex返回数组中满足提供的测试函数的第一个元素的索引 83 | deleteCart (state, id) { 84 | const index = state.cartList.findIndex(item => item.id === id); 85 | state.cartList.splice(index, 1); 86 | }, 87 | // 清空购物车 88 | emptyCart (state) { 89 | state.cartList = []; 90 | } 91 | }, 92 | actions: { 93 | // 请求商品列表 94 | getProductList (context) { 95 | // 真实环境通过 ajax 获取,这里用异步模拟 96 | setTimeout(() => { 97 | context.commit('setProductList', product_data); 98 | }, 500); 99 | }, 100 | // 购买 101 | buy (context) { 102 | // 真实环境应通过 ajax 提交购买请求后再清空购物列表 103 | return new Promise(resolve=> { 104 | setTimeout(() => { 105 | context.commit('emptyCart'); 106 | resolve(); 107 | }, 500) 108 | }); 109 | } 110 | } 111 | }); 112 | 113 | new Vue({ 114 | el: '#app', 115 | router: router, 116 | store: store, 117 | render: h => { 118 | return h(App) 119 | } 120 | }); -------------------------------------------------------------------------------- /vue13/README13.md: -------------------------------------------------------------------------------- 1 | # 实战:知乎日报项目开发 2 | 3 | 日报项目以单页面呈现,基本覆盖了vue和webpack的核心功能,包括: 4 | + vue的单文件组件用法 5 | + vue的基本指令,自定义指令 6 | + 数据的获取,整理,可视化 7 | + prop,事件,子组件索引 8 | + es6模块 9 | 10 | *注意:写vue的时候a标签里不要再有href了,不然会出现意想不到的问题。* 11 | 12 | 跨域问题: 13 | 使用基于nodejs的request库来做代理 14 | 15 | `npm install request --save-dev` 16 | 17 | request 是一个用来简化 HTTP 请求操作的模块 18 | daily目录下新建proxy.js内容: 19 | 20 | ``` 21 | const http = require('http'); 22 | const request = require('request'); 23 | 24 | const hostname = '192.168.10.122'; 25 | const port = 8010; 26 | const imgPort = 8011; 27 | 28 | // 创建一个API 代理服务器 29 | const apiServer = http.createServer((req, res) => { 30 | const url = 'http://news-at.zhihu.com/api/4' + req.url; 31 | const options = { 32 | url: url 33 | }; 34 | 35 | function callback (error, response, body) { 36 | if (!error && response.statusCode === 200) { 37 | // 设置编码类型,否则中文会显示为乱码 38 | res.setHeader('Content-Type', 'text/plain;charset=UTF-8'); 39 | // 设置所有域允许跨域 40 | res.setHeader('Access-Control-Allow-Origin', '*'); 41 | // 返回代理后的内容 42 | res.end(body); 43 | } 44 | } 45 | request.get(options, callback); 46 | }); 47 | 48 | // 监听8010端口 49 | apiServer.listen(port, hostname, () => { 50 | console.log(`接口代理运行在 http://${hostname}:${port}/`); 51 | }); 52 | 53 | // 创建一个图片代理服务 54 | const imgServer = http.createServer((req, res) => { 55 | const url = req.url.split('/img/')[1]; 56 | const options = { 57 | url: url, 58 | encoding: null 59 | }; 60 | 61 | function callback (error, response, body) { 62 | if (!error && response.statusCode === 200) { 63 | const contentType = response.headers['content-type']; 64 | res.setHeader('Content-Type', contentType); 65 | res.setHeader('Access-Control-Allow-Origin', '*'); 66 | res.end(body); 67 | } 68 | } 69 | request.get(options, callback); 70 | }); 71 | 72 | // 监听8011端口 73 | imgServer.listen(imgPort,hostname,()=>{ 74 | console.log(`图片代理运行在http://${hostname}:${imgPort}/`); 75 | }) 76 | ``` 77 | 78 | Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。 79 | 80 | `npm install axios --save` 81 | 82 | daily\src\libs下新建util.js内容: 83 | 84 | ``` 85 | import axios from 'axios'; 86 | // 基本配置 87 | const Util = { 88 | imgPath:'http://192.168.10.122:8011/img/'; 89 | apiPath:'http://192.168.10.122:8010/' 90 | } 91 | 92 | // ajax通用配置 93 | Util.ajax = axios.create({ //自定义配置新建一个 axios 实例 94 | baseURL:Util.apiPath 95 | }) 96 | 97 | // 添加响应拦截器 在响应被 then 或 catch 处理前拦截它们。 98 | Util.ajax.interceptors.response.use(res=>{ 99 | return res.data; 100 | }); 101 | 102 | export default Util; 103 | ``` 104 | 比如在daily\src\app.vue中使用: 105 | ``` 106 | import $ from './libs/util'; 107 | 108 | methods:{ 109 | getThemes(){ 110 | //axios发起get请求 111 | $.ajax.get('themes').then(res =>{ 112 | this.themes = res.others; 113 | }) 114 | } 115 | } 116 | ``` 117 | 118 | 使用concurrent 模块实现同时监听执行两条命令 119 | 120 | `npm install concurrently --save-dev` 121 | 122 | 然后在package.json里面的 "script" 里面的 "start"写入同时执行语句 123 | 124 | ``` 125 | "scripts": { 126 | "dev": "webpack-dev-server --mode development --open --config webpack.config.js", 127 | "build": "webpack --progress --mode production --hide-modules --config webpack.prod.config.js", 128 | "start": "concurrently \"npm run dev\" \"node proxy.js\"" 129 | }, 130 | ``` 131 | 132 | 133 | -------------------------------------------------------------------------------- /vue13/daily/src/app.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 121 | -------------------------------------------------------------------------------- /vue09/sort_form/table.js: -------------------------------------------------------------------------------- 1 | Vue.component('vTable',{ 2 | props:{ 3 | columns:{ //描述每列的信息,并渲染在表头内 4 | type:Array, 5 | default:function(){ 6 | return [] 7 | } 8 | }, 9 | data:{ //每一行的数据,由columns决定每一行里的各列排序。 10 | type:Array, 11 | default:function(){ 12 | return [] 13 | } 14 | } 15 | }, 16 | // 为了排序后不影响原始数组,data里添加两个对应数据,组件操作在对应数据。不对原始数据做处理 17 | data:function(){ 18 | return { 19 | currentColumns:[], 20 | currentData:[] 21 | } 22 | }, 23 | // 用render构造虚拟DOM 24 | // 表格最外层元素,里面包含表头和表格主体。 25 | // thead是一行多列(一个tr多个th)。 tbody是多行多列(多个tr多个td) 26 | render:function(h){ //h就是createElement,只是换了个名称 27 | var _this = this; 28 | var ths = []; 29 | this.currentColumns.forEach(function(col,index){ 30 | if( col.sortable ){ 31 | ths.push(h('th',[ 32 | h('span',col.title), 33 | // 升序 34 | h('a',{ 35 | class:{ 36 | on:col._sortType === 'asc' 37 | }, 38 | on:{ 39 | click:function(){ 40 | _this.handleSortByAsc(index) 41 | } 42 | } 43 | },'↑'), 44 | // 降序 45 | h('a',{ 46 | class:{ 47 | on:col._sortType === 'desc' 48 | }, 49 | on:{ 50 | click:function(){ 51 | _this.handleSortByDesc(index) 52 | } 53 | } 54 | },'↓') 55 | ])) 56 | }else{ 57 | ths.push(h('th',col.title)) 58 | } 59 | }); 60 | 61 | var trs = []; 62 | // 先遍历所有行,然后在每一行内再遍历各列 63 | this.currentData.forEach(function(row){ 64 | var tds = []; 65 | _this.currentColumns.forEach(function(cell){ 66 | tds.push(h('td',row[cell.key])); 67 | }); 68 | trs.push(h('tr',tds)); 69 | }); 70 | 71 | return h('table',[ 72 | h('thead',[ 73 | h('tr',ths) 74 | ]), 75 | h('tbody',trs) 76 | ]) 77 | }, 78 | methods:{ 79 | // 把columns赋值给currentColumns 80 | makeColumns:function(){ 81 | this.currentColumns = this.columns.map(function( col,index ){ 82 | // 添加一个字段标识当前列排序的状态,赋值normal表示默认排序,就是不排序。 83 | col._sortType = 'normal'; 84 | // 添加一个字段标识当前列在数组中的索引 85 | col._index = index; 86 | return col; 87 | }) 88 | }, 89 | // 把data赋值给currentData 90 | makeData:function(){ 91 | this.currentData = this.data.map(function( row,index ){ 92 | // 添加一个字段标识当前行在数组中的索引 93 | row._index = index; 94 | return row; 95 | }) 96 | }, 97 | // 升序操作 由小到大 98 | handleSortByAsc:function(index){ 99 | var key = this.currentColumns[index].key; 100 | //排序前先将所有列的排序状态重置为normal 101 | this.currentColumns.forEach(function(col){ 102 | col._sortType = 'normal'; 103 | }); 104 | // 设置当前列的排序状态为asc,对应到元素的class名称on 105 | this.currentColumns[index]._sortType = 'asc'; 106 | this.currentData.sort(function(a,b){ 107 | return a[key] > b[key] ? 1 : -1; 108 | // return a[key] - b[key] 109 | }); 110 | }, 111 | // 降序操作 由大到小 112 | handleSortByDesc:function(index){ 113 | var key = this.currentColumns[index].key; 114 | this.currentColumns.forEach(function(col){ 115 | col._sortType = 'normal'; 116 | }); 117 | this.currentColumns[index]._sortType = 'desc'; 118 | this.currentData.sort(function(a,b){ 119 | return a[key] < b[key] ? 1 : -1; 120 | // return b[key] - a[key] 121 | }); 122 | } 123 | }, 124 | //渲染完表格后,父级修改了data数据,比如增加,v-table的currentData也应该更新 125 | //如果某列已存在排序,应该直接处理一次排序。 126 | watch:{ 127 | data:function(){ 128 | this.makeData(); 129 | var sortedColumn = this.currentColumns.filter(function(col){ 130 | return col._sortType !== 'normal'; //返回排序的数组 131 | }); 132 | if( sortedColumn.length ){ //如果有进行过排序 133 | if( sortedColumn[0]._sortType === 'asc' ){ 134 | this.handleSortByAsc(sortedColumn[0]._index); 135 | }else{ 136 | this.handleSortByDesc(sortedColumn[0]._index); 137 | } 138 | } 139 | } 140 | }, 141 | mounted(){ 142 | //v-table初始化时调用 143 | this.makeColumns(); 144 | this.makeData(); 145 | } 146 | }) --------------------------------------------------------------------------------