├── .gitignore ├── 01-Vue入门之概念及Helloworld.md ├── 02-Vue入门之数据绑定.md ├── 03-Vue入门之列表渲染.md ├── 04-Vue入门之事件绑定处理.md ├── 05-Vue入门之Vue实例与生命周期.md ├── 06-Vue入门之组件化.md ├── 07-Vue入门之路由.md ├── 08-Vue入门之综合项目实战.md ├── 09-Vue入门之Filter过滤器.md ├── 10-Vue入门之Vuex实战.md ├── README.md ├── a.html ├── a.md ├── a.pdf ├── demos ├── 01-vue-helloworld.html ├── 02-vue-bind.html ├── 03-vue-prop-bind.html ├── 04-vue-classbind.html ├── 05-vue-htmlraw.html ├── 06-vue-stylebind.html ├── 07-vue-calc-prop.html ├── 08-vue-double-databind.html ├── 09-Vue-listrenderdemo.html ├── 10-vue-event.html ├── 11-vue-watch.html ├── 12-vue-lifedemo.html ├── 13-vue-extend-demo.html ├── 14-vue-componentdemo.html ├── 15-vue-component-solt.html ├── 16-vue-routerdemo.html ├── 17ttl.zip ├── 17ttl │ ├── .babelrc │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── README.md │ ├── build │ │ ├── build.js │ │ ├── check-versions.js │ │ ├── dev-client.js │ │ ├── dev-server.js │ │ ├── utils.js │ │ ├── webpack.base.conf.js │ │ ├── webpack.dev.conf.js │ │ └── webpack.prod.conf.js │ ├── config │ │ ├── dev.env.js │ │ ├── index.js │ │ ├── prod.env.js │ │ └── test.env.js │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.vue │ │ ├── approuter.js │ │ ├── assets │ │ │ └── logo.png │ │ ├── components │ │ │ ├── Hello.vue │ │ │ ├── Home.vue │ │ │ ├── Product.vue │ │ │ └── User.vue │ │ ├── filters │ │ │ └── DateFilter.js │ │ └── main.js │ ├── static │ │ └── .gitkeep │ └── test │ │ ├── e2e │ │ ├── custom-assertions │ │ │ └── elementCount.js │ │ ├── nightwatch.conf.js │ │ ├── runner.js │ │ └── specs │ │ │ └── test.js │ │ └── unit │ │ ├── .eslintrc │ │ ├── index.js │ │ ├── karma.conf.js │ │ └── specs │ │ └── Hello.spec.js ├── 18-vue-router-params.html ├── 19-vue-filterdemo.html ├── 20-vue-event-bus-demo.html ├── 21-vue-parent-child-event.html ├── 22-vue-vuex-bind.html └── 22-vue-vuex │ └── vuexdemo │ ├── .babelrc │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── README.md │ ├── build │ ├── build.js │ ├── check-versions.js │ ├── dev-client.js │ ├── dev-server.js │ ├── utils.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js │ ├── config │ ├── dev.env.js │ ├── index.js │ ├── prod.env.js │ └── test.env.js │ ├── index.html │ ├── package.json │ ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ ├── Demo.vue │ │ ├── Hello.vue │ │ └── TestMutation.vue │ ├── main.js │ └── store │ │ ├── actions.js │ │ ├── getters.js │ │ ├── index.js │ │ └── mutations.js │ ├── static │ └── .gitkeep │ └── test │ ├── e2e │ ├── custom-assertions │ │ └── elementCount.js │ ├── nightwatch.conf.js │ ├── runner.js │ └── specs │ │ └── test.js │ └── unit │ ├── .eslintrc │ ├── index.js │ ├── karma.conf.js │ └── specs │ └── Hello.spec.js ├── imgs ├── 01vue-helloworld.png ├── 02vue双向绑定.jpg ├── 03vue响应.png ├── 04vuex模型.png ├── 05vue.png ├── 06vue.png ├── 07eventbus.png ├── lifecycle-标注版本.png └── 父子容器数据传递.png ├── index.html └── preview ├── .DS_Store ├── 01-Vue入门之概念及Helloworld.html ├── 02-Vue入门之数据绑定.html ├── 03-Vue入门之列表渲染.html ├── 04-Vue事件绑定处理.html ├── 04-Vue入门之事件绑定处理.html ├── 05-Vue入门之Vue实例与生命周期.html ├── 06-Vue入门之组件化.html ├── 07-Vue入门之路由.html ├── 08-Vue入门之综合项目实战.html ├── 09-Vue入门之Filter过滤器.html ├── 10-Vue入门之Vuex实战.html ├── README.html ├── all.html ├── imgs ├── 01vue-helloworld.png ├── 02vue双向绑定.jpg ├── 03vue响应.png ├── 04vuex模型.png ├── 05vue.png ├── 06vue.png ├── 07eventbus.png ├── lifecycle-标注版本.png └── 父子容器数据传递.png ├── toc ├── css │ ├── demo.css │ └── zTreeStyle │ │ ├── img │ │ ├── diy │ │ │ ├── 1_close.png │ │ │ ├── 1_open.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ ├── 8.png │ │ │ └── 9.png │ │ ├── line_conn.gif │ │ ├── loading.gif │ │ ├── zTreeStandard.gif │ │ └── zTreeStandard.png │ │ └── zTreeStyle.css ├── js │ ├── jquery-1.4.4.min.js │ ├── jquery.ztree.all-3.5.min.js │ ├── ztree_toc.js │ └── ztree_toc.min.js └── style │ ├── Clearness Dark.css │ ├── Clearness.css │ ├── GitHub.css │ ├── GitHub2.css │ ├── github-bf51422f4bb36427d391e4b75a1daa083c2d840e.css │ ├── github2-d731afd4f624c99a4b19ad69f3083cd6d02b81d5.css │ └── makedownpad.css └── toc_conf.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Mac OS desktop services store 2 | .DS_Store 3 | ._* 4 | 5 | # Ignore Windows desktop setting file 6 | desktop.ini 7 | 8 | *.log 9 | 10 | .idea 11 | 12 | # Ignore vscode debug json 13 | .vscode 14 | src/.vscode 15 | -------------------------------------------------------------------------------- /01-Vue入门之概念及Helloworld.md: -------------------------------------------------------------------------------- 1 | # Vue 入门之概念及 Helloworld 2 | 3 | ## Vue 简介 4 | 5 | `Vue`是一个前端的双向绑定类的框架,发音[读音 /vjuː/, 类似于 [view]。新的 Vue 版本参考了 React 的部分设计,当然也有自己独特的地方,比如 Vue 的单文件组件开发方式都很有创新,另外 Vue 自身的一些绑定的语法、用法等都非常精炼,很容易上手,而且第三方的插件都非常丰富,社区非常活跃,最新的文档都有中文版本。而且 Vue 配合官方的和第三方的库可以实现单文件的组件化开发、SPA 等现代化前端开发。 6 | 详情请参考[Vue 官网](https://cn.vuejs.org/) 7 | 8 | ## Vue 的入门 demo 9 | 10 | `Vue` 可以直接把它当做一个 js 库使用,所以它可以很容易的接入到你的项目或者单个页面中。甚至你可以只使用它的双向绑定功能。所以它很容易上手。 11 | 12 | 比如:我们有一个需求,一个网页上一个 Div 标签,我们有一个 json 对象存储数据,把 json 对象上的数据放到 Div 上去。 13 | 14 | 接下来是步骤: 15 | 16 | ``` 17 | 第一步: 创建一个文件夹并创建一个html文件 比如:index.html. 18 | 当如你可以选择你自己的编辑器,我就用VSCode。 19 | 20 | 第二步:引入Vue库 21 | 22 | 当然了你可以直接下载Vue的js文件,推荐你直接用上面的cdn即可。 23 | 24 | 第三步:创建一个Div,给它一个id,比如:app 25 | 26 | 第四步:创建Vue的对象,并把数据绑定到上面创建好的div上去。 27 | ``` 28 | 29 | 最终的代码如下: 30 | 31 | ```html 32 | 33 | 34 | 35 | 36 | Vue入门之Helloworld 37 | 38 | 39 | 40 | 41 | 42 |
43 | 44 | {{ message }} 45 |
46 | 47 | 48 | 56 | 57 | 58 | ``` 59 | 60 | 最终的结果就是: 61 | 62 | ```html 63 | Hello Vue! 64 | ``` 65 | 66 | --- 67 | 68 | ## Vue 的 Helloworld 总结 69 | 70 | - Vue 构造函数的:选项 el 属性,就是 element 缩写,当前 Vue 对象挂载到哪个标签上的语法,支持 CSS 选择器或者 dom 对象,一般用 id 选择器选择当前页面的标签。 71 | - Vue 的选项:data 属性是自定义数据。这里我们只是演示了一个 message 属性,vue 会把自定义的数据可以与 html 的模板数据进行绑定。 72 | - Vue 数据绑定的方式就是用 `{{}}`,类似于 handlebars. 73 | - 上面这个 demo 就是演示了 Vue 的绑定数据的基本模型。注意点,标签先创建好了之后,再创建 Vue 对象,具体你应该懂吧。 74 | 75 | ![helloworld](imgs/01vue-helloworld.png) 76 | -------------------------------------------------------------------------------- /03-Vue入门之列表渲染.md: -------------------------------------------------------------------------------- 1 | # Vue 列表渲染及条件渲染实战 2 | 3 | ## 条件渲染 4 | 5 | 有时候我们要根据数据的情况,决定标签是否进行显示或者有其他动作。最常见的就是,表格渲染的时候,如果表格没有数据,就显示无数据。如果有数据就显示表格数据。 6 | Vue 帮我们提供了一个`v-if`的指令,帮助我们完成判断的模板处理。 7 | 8 | ```html 9 |
10 |

Yes

11 |

No

12 |
13 | 14 | 15 | 23 | ``` 24 | 25 | `v-if`指令可以根据数据绑定的情况进行插入标签或者移除标签。 26 | 当然,如果熟悉 js 的都清楚,有 if,肯定会有 else。 Vue 提供的是 `v-else`指令。 27 | 28 | ## 列表渲染 29 | 30 | ### 基本 v-for 循环渲染标签 31 | 32 | 模板引擎都会提供循环的支持。Vue 也不例外,Vue 是提供了一个`v-for`指令。基本的用法类似于 foreach 的用法。还是看例子最直接,上代码: 33 | 34 | ```html 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
姓名年龄地址
{{ item.name }}{{ item.age }}{{ item.address }}
53 |
54 | 66 | ``` 67 | 68 | ### Template 循环渲染多标签 69 | 70 | 上面的例子,我们演示的是 每次循环输出一个 tr 标签。如果我们希望每次循环生成两个 tr 标签呢?如果还有生成其他的标签呢? 71 | 72 | Vue 给我们提供了 template 标签,供我们用于 v-for 循环中进行处理。 73 | 74 | 上代码喽: 75 | 76 | ```html 77 | 84 | ``` 85 | 86 | ### 关于 v-for 对应的数组的更新 87 | 88 | 由于 Vue 的机制就是检测数据的变化,自动跟新 HTML。数组的变化,Vue 之检测部分函数,检测的函数执行时才会触发视图更新。这些方法如下: 89 | 90 | - push() 91 | - pop() 92 | - shift() 93 | - unshift() 94 | - splice() 95 | - sort() 96 | - reverse() 97 | 98 | ## 表格显示的综合案例 99 | 100 | 下面是一个综合的案例,每秒钟往表格中添加一条数据。 101 | 本案例综合使用了 v-if 和 v-for 循环综合案例。 102 | 103 | ```html 104 | 105 | 106 | 107 | 108 | Vue入门之动态显示表格 109 | 110 | 111 | 112 |
113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 |
姓名年龄地址
{{ item.name }}{{ item.age }}{{ item.address }}
没有数据奥!
133 |
134 | 147 | 148 | 149 | ``` 150 | 151 | ## 总结列表和条件绑定 152 | 153 | 列表的使用其实本质还是 js 的衍生使用,对于有 js 开发基础的没有什么难度。关键是多写几个案例就会详细通了。 154 | -------------------------------------------------------------------------------- /04-Vue入门之事件绑定处理.md: -------------------------------------------------------------------------------- 1 | # Vue 事件处理 2 | 3 | ## 监听事件的 Vue 处理 4 | 5 | Vue 提供了协助我们为标签绑定时间的方法,当然我们可以直接用 dom 原生的方式去绑定事件。Vue 提供的指令进行绑定也是非常方便,而且能让 ViewModel 更简洁,逻辑更彻底。所以还是推荐大家使用的。 6 | 7 | Vue 提供了`v-on`指令帮助我们进行事件的绑定。 8 | 基本的内联事件处理方法[官方 demo]: 9 | 10 | ```html 11 |
12 | 13 | 14 |

这个按钮被点击了 {{ counter }} 次。

15 |
16 | 24 | ``` 25 | 26 | ## 事件处理方法集成到 Vue 对象 27 | 28 | 内联的方式绑定的事件,只能处理简单的事件的处理逻辑。复杂的情况还是封装到 js 中最方便,也不容易出错。 29 | Vue 对象中可以添加 methods 属性,开发者可以把事件处理函数的逻辑放到 methods 中。 30 | 31 | ```html 32 | 33 | 34 | 35 | 36 | Vue入门之动态显示表格 37 | 38 | 39 | 40 |
41 |

{{ number }}

42 | 43 | 44 |
45 | 59 | 60 | 61 | ``` 62 | 63 | ## 事件修饰符 64 | 65 | 官网上写的非常好,这块就直接用管网的吧。在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在 methods 中轻松实现这点,但更好的方式是:methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。 66 | 为了解决这个问题, Vue.js 为 v-on 提供了 事件修饰符。通过由点(.)表示的指令后缀来调用修饰符。 67 | 68 | - .stop 69 | - .prevent 70 | - .capture 71 | - .self 72 | - .once 73 | 74 | ```html 75 | 76 | 77 | 78 |
79 | 80 | 81 | 82 |
83 | 84 |
...
85 | 86 |
...
87 | 88 | 89 | ``` 90 | 91 | ## 按键修饰符 92 | 93 | 在监听键盘事件时,我们经常需要监测常见的键值。 Vue 允许为 v-on 在监听键盘事件时添加按键修饰符: 94 | 95 | ```html 96 | 97 | 98 | 记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名: 99 | 100 | 101 | 102 | 103 | ``` 104 | 105 | 全部的按键别名: 106 | 107 | - .enter 108 | - .tab 109 | - .delete (捕获 “删除” 和 “退格” 键) 110 | - .esc 111 | - .space 112 | - .up 113 | - .down 114 | - .left 115 | - .right 116 | - .ctrl 117 | - .alt 118 | - .shift 119 | - .meta 120 | 121 | ## 事件绑定的简写 122 | 123 | Vue 中属性的绑定的简写直接是`:` === 'v-bind:' 124 | 而事件的缩写是直接变成`@`. 也就是说: `v-on:` === `@` 125 | 看下面的例子: 126 | 127 | ```html 128 | 129 | 130 | 131 | 132 | ``` 133 | 134 | ## 事件绑定总结 135 | 136 | Vue 为了方便大家进行开发,提供了事件的相关的封装,可以让我们方便我们用 Vue 对事件进行开发,尤其是 v-on 指令的非常方便的跟 Vue 对象中 methods 进行配合进行复杂的事件处理,非常方便。另外事件的事件修饰符和按键修饰符也可以让 Vue 事件这块锦上添花。 137 | -------------------------------------------------------------------------------- /08-Vue入门之综合项目实战.md: -------------------------------------------------------------------------------- 1 | # Vue 综合实战项目 2 | 3 | ## 前置知识学习 4 | 5 | - npm 学习 6 | - [官方文档](https://docs.npmjs.com/) 7 | - 推荐资料 8 | - [npm 入门](http://www.cnblogs.com/kelsen/p/4947859.html) 9 | - [npm 介绍](http://www.nodeclass.com/articles/810142) 10 | - 需要了解的知识点 11 | - `package.json` 文件相关配置选项 12 | - npm 本地安装、全局安装、本地开发安装等区别及相关命令 13 | - npm script 脚步的基本编写能力 14 | 15 | > 有时间专门写一个这样的专题,如果需要可以邮件我。malun666@126.com 16 | 17 | - webpack 基础学习 18 | - [官方文档](https://webpack.js.org/) 19 | - Webpack 了解的知识点: 20 | 21 | - webpack 的基本配置 22 | - 了解 webpack 常用的 loader: less-loader、sass-loader、 vue-loader、style-loader、css-loader、eslint-loader、babel-loader 等 23 | - 熟悉 Webpack 的 webpack-dev-server 的基本配置和使用,会配置热更新 24 | - es6 语法学习 25 | - 阮一峰老师的大作[《ECMAScript 6 入门》](http://es6.ruanyifeng.com/) 26 | - 需要学习的知识点 27 | - es6 的模块机制 28 | - 各种最新语法糖,简写、geter、setter、箭头函数 29 | - 类、继承的心机制 30 | ... 31 | - nodejs 基础知识 32 | 33 | - 知识点学习: 34 | - 文件操作 35 | - http 服务 36 | - express 37 | 38 | - 组件化开发思想 39 | 40 | ## Vue 脚手架工具:`vue-cli`构建实战项目 41 | 42 | 其实如果编写 Vue 的前端项目,直接使用 vue 的官方 vue-cli 构建工具最好用,一个命令就可以直接生成项目的结构和目录。 43 | 而且官方需要依赖的包也可以自动配置好,只需要 npm instal 一下,然后就可以开发测试了。 44 | 45 | ### `vue-cli`安装 46 | 47 | ```shell 48 | # 安装vue-cli。 安装之前首先确保你已经安装好了nodejs 而且打开命令行 49 | $ npm install -g vue-cli 50 | 51 | # 校验一下是否安装成功 52 | $ vue -V 53 | 54 | #=> 2.5.1 我当前的版本是这个,你的可能比这个新 55 | ``` 56 | 57 | ### 使用`vue-cli`初始化项目 58 | 59 | 通过以下命令的方式可以创建一个项目文件夹,并初始化对应的文件。 60 | 61 | ```shell 62 | $ vue init 63 | ``` 64 | 65 | 其中 template-name 可以取以下值,每个值对应不同的项目构建的模板。 66 | 67 | - [webpack](https://github.com/vuejs-templates/webpack)--全功能的 Webpack + vueify,包括热加载,静态检测,单元测试 68 | - [webpack](https://github.com/vuejs-templates/webpack-simple)-simple--一个简易的 Webpack + vueify,以便于快速开始。 69 | - [browserify](https://github.com/vuejs-templates/browserify)--全功能的 Browserify + vueify,包括热加载,静态检测,单元测试 70 | - [browserify](https://github.com/vuejs-templates/browserify-simple)-simple--一个简易的 Browserify + vueify,以便于快速开始。 71 | 72 | 安装和开发控制台的命令: 73 | 74 | ```shell 75 | # 如果已经安装,请省略 76 | $ npm install -g vue-cli 77 | 78 | # 初始化一个webpack全功能包的vue项目,请您把my-project换成你自己的项目名。 79 | $ vue init webpack my-project 80 | 81 | # 用命令行进入当前项目目录 82 | $ cd my-project 83 | 84 | # npm安装所有的依赖的包 85 | $ npm install 86 | 87 | # 运行测试的首页 88 | $ npm run dev 89 | ``` 90 | 91 | ### 综合实例开发记录 92 | 93 | 1. 通过 vue-cli 构建工具初始化项目目录 94 | 95 | > 安装过程,控制台会问你项目名称是什么?项目描述?项目作者,是否使用 eslint 校验,是否使用单元测试等.... 96 | 97 | 我的安装过程如下请参考: 98 | 99 | ```shell 100 | $ vue init webpack ttl # => 安装webpack模板的项目 ttl(项目名可以随便取) 101 | 102 | A newer version of vue-cli is available. 103 | 104 | latest: 2.6.0 105 | installed: 2.5.1 106 | 107 | This will install Vue 2.x version of template. 108 | 109 | For Vue 1.x use: vue init webpack#1.0 ttl 110 | 111 | ? Project name mydemovue # => 项目名称 112 | ? Project description A Vue.js project # => 项目描述 113 | ? Author malun # => 作者 114 | ? Vue build standalone # => 是否支持单文件组件 115 | ? Use ESLint to lint your code? Yes # => 是否支持ESLint代码校验 116 | ? Pick an ESLint preset Standard # => 校验的标准是什么? 117 | ? Setup unit tests with Karma + Mocha? Yes # => 是否使用单元测试 118 | ? Setup e2e tests with Nightwatch? Yes # => 是否使用e2e测试 119 | 120 | vue-cli · Generated "ttl". 121 | 122 | To get started: 123 | 124 | cd ttl 125 | npm install 126 | npm run dev 127 | 128 | Documentation can be found at https://vuejs-templates.github.io/webpack 129 | ``` 130 | 131 | 通过上面一系列的命令后,我们就会创建一个 webpack 配置好的项目包。目录结构如下: 132 | 133 | ```shell 134 | ttl 135 | |--.babelrc #=> babel的配置文件,主要用于转换es6等最新的js语法。 136 | |--.editorconfig #=> 编辑器配置 137 | |--.eslintignore #=> eslint的忽略校验的配置文件 138 | |--.eslintrc.js #=> eslint的配置校验js是否规范的配置文件 139 | |--.gitignore #=> 设置git忽略的管理的文件 140 | |--README.md #=> readme说明文件 141 | |--build/ #=> 自动构建存放的文件地方 142 | |--config/ #=> 当前开发、测试等配置的文件,需要懂点nodejs了啊。 143 | |--index.html #=> 项目的主入口的模板 144 | |--package.json #=> npm的配置文件 145 | |--src/ #=> 源码目录 146 | |--static/ #=> 静态资源存放的目录 147 | |--test/ #=> 测试相关目录 148 | ``` 149 | 150 | 2. 初始化依赖包 151 | 152 | ```shell 153 | $ cd ttl #=> 进入上面创建好的项目目录 154 | $ npm install #=> 安装所有的依赖包。 安装过程可能非常长,网络也可能有问题,请耐心等待。 155 | 156 | # 安装完成后,可以直接运行测试,如果自动打开浏览器,并跳转到http://localhost:8080/ 说明一切都ok了。 157 | $ npm run dev 158 | ``` 159 | 160 | > npm 安装的时候经常网会断开,国内的网(哎,说多了都是泪)你懂的。最好能科学上网,或者是用淘宝的 npm 的镜像 161 | 162 | 3. 安装`vue-router`组件 163 | 164 | ```shell 165 | $ npm i -S vue-router 166 | ``` 167 | 168 | 4. 到项目的 `/src/components/` 目录下创建三个组件文件。 169 | 170 | 分别是: 171 | 172 | - 首页组件 173 | 174 | 175 | ```html 176 | 181 | 182 | 192 | 193 | 198 | ``` 199 | 200 | - 用户首页组件 201 | 202 | 203 | ```html 204 | 209 | 210 | 220 | 221 | 226 | ``` 227 | 228 | - 产品组件 229 | 230 | 231 | ```html 232 | 237 | 238 | 248 | 249 | 254 | ``` 255 | 256 | 项目的目录结构为: 257 | 258 | ``` 259 | ttl 260 | |-- src 261 | |--|-- Hello.vue 262 | |--|-- Home.vue 263 | |--|-- Product.vue 264 | |--|-- User.vue 265 | ``` 266 | 267 | 5. 创建 router 对象及配置路由 268 | 269 | 在`src`目录下创建`approuter.js`文件。 270 | 然后添加如下代码: 271 | 272 | ```js 273 | import VueRouter from 'vue-router'; // 导入路由模块 274 | import Home from './components/Home.vue'; // 导入Home组件 275 | import User from './components/User.vue'; 276 | import Product from './components/Product.vue'; 277 | 278 | export default new VueRouter({ 279 | // 定义路由规则对象 280 | routes: [ 281 | { path: '/home', component: Home }, 282 | { path: '/user/:id', component: User }, 283 | { path: '/product/:id', component: Product } 284 | ] 285 | }); 286 | ``` 287 | 288 | 6. 修改 main.js 文件 289 | 找到`src/`目录下的 main.js 文件, 290 | 共修改 4 处,添加路由引用、添加路由规则对象导入、启用路由、将路由键入到 Vue 中。 291 | 修改此文件为: 292 | 293 | ```js 294 | // The Vue build version to load with the `import` command 295 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 296 | import Vue from 'vue'; 297 | import App from './App'; 298 | import VueRouter from 'vue-router'; // +++1、导入路由组件 299 | import router from './approuter'; // +++2、导入我们自己写的路由配置文件 300 | 301 | // +++ 3、使用路由组件 302 | Vue.use(VueRouter); 303 | 304 | /* eslint-disable no-new */ 305 | new Vue({ 306 | el: '#app', 307 | template: '', 308 | components: { App }, 309 | router: router // +++4、添加路由对象 310 | }); 311 | ``` 312 | 313 | 7. 在 app.vue 中添加路由导航 314 | 315 | 最终代码如下: 316 | 317 | ```html 318 | 333 | 334 | 348 | 349 | 364 | ``` 365 | 366 | 刷新一下浏览器,你将会看到最终的运行结果。 367 | 368 | # 总结 369 | 370 | Vue 的入门系列基本都写完了,大部分内容是参考了官网的文档。 371 | 372 | 还有很多内容没有整理到这个系列中。比如:vue 的过渡动画,vue 的异步刷新队列,vue 的过滤器等,我相信你通过本文档就能 373 | 实现 vue 的入门了,那些琐碎的知识点只要看一下官方的文档应该很容入门。 374 | 375 | 这一次整理过程,让我对 Vue 有了更深入的认识,之前不熟悉的东西,强迫自己把 376 | 文档写一遍后,认识比以前更清晰了。Vue 确实带来很多的惊喜。希望这个文档对你有用。 377 | -------------------------------------------------------------------------------- /09-Vue入门之Filter过滤器.md: -------------------------------------------------------------------------------- 1 | # Vue 入门之 Filter 过滤器 2 | -------------------------------------------------------------------------------- /10-Vue入门之Vuex实战.md: -------------------------------------------------------------------------------- 1 | # Vue 入门之 Vuex 实战 2 | 3 | ## 引言 4 | 5 | Vue 组件化做的确实非常彻底,它独有的 vue 单文件组件也是做的非常有特色。组件化的同时带来的是:组件之间的数据共享和通信的难题。 6 | 尤其 Vue 组件设计的就是,父组件通过子组件的 prop 进行传递数据,而且数据传递是`单向`的。也就是说:父组件可以把数据传递给子组件,但是 7 | 反之则不同。如下图所示: 8 | 9 | ![vue父子传递](imgs/05vue.png) 10 | 11 | ## 单向数据流动 12 | 13 | 单方向的数据流动带来了非常简洁和清晰的数据流,纯展示性或者独立性较强的模块的开发确实非常方便和省事。 14 | 但是复杂的页面逻辑,组件之间的数据共享处理就会需要通过事件总线的方式解决或者使用 Vue 的 Vuex 框架了。 15 | 16 | ## 子组件通知父组件数据更新:事件方式的实现 17 | 18 | 子组件可以在子组件内触发事件,然后在父容器中添加子组件时绑定父容器的方法为事件响应方法的方式.如下图所示: 19 | 20 | ![vue父子传递](imgs/06vue.png) 21 | 22 | - 使用 v-on 绑定自定义事件 23 | 24 | ``` 25 | 每个 Vue 实例都实现了事件接口(Events interface),即: 26 | 使用 $on(eventName) 监听事件 27 | 使用 $emit(eventName) 触发事件 28 | ``` 29 | 30 | 参考代码案例: 31 | 32 | ```html 33 | 34 | 35 | 36 | 37 | 38 | Vue入门之event message 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
57 |

推荐次数:{{ voteCount }}

58 |
59 | 60 | 61 |
62 |
    63 |
  • {{o}}
  • 64 |
65 |
66 | 109 | 110 | 111 | 112 | ``` 113 | 114 | ## 事件总线方式解决非父子组件数据同步 115 | 116 | 如果非父子组件怎么通过事件进行同步数据,或者同步消息呢?Vue 中的事件触发和监听都是跟一个具体的 Vue 实例挂钩。 117 | 所以在不同的 Vue 实例中想进行事件的统一跟踪和触发,那就需要一个公共的 Vue 实例,这个实例就是公共的事件对象。 118 | 119 | ![](imgs/07eventbus.png) 120 | 121 | 参考下面做的一个购物车的案例的代码: 122 | 123 | ```html 124 | 125 | 126 | 127 | 128 | 129 | Vue入门之event message 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 |
148 | 149 |
150 | 151 |
152 | 264 | 265 | 266 | ``` 267 | 268 | ## Vuex 解决复杂单页面应用 269 | 270 | 上面的方式只能解决一些简单的页面中的组件的通信问题,但是如果是复杂的单页面应用就需要使用更强大的 Vuex 来帮我们进行状态的统一管理和同步。 271 | 272 | 当第一次接触 Vuex 的时候,眼前一亮,之前经过 Redux 之后,被它繁琐的使用令我痛苦不已,虽然思路很清晰,其实完全可以设计的更简单和高效。 273 | 当我接触到 Vuex 之后,发现这就是我想要的。的确简洁就是一种艺术。 274 | 275 | 其实本质上,Vuex 就是一个大的 EventBus 对象的升级版本,相当于一个特定的仓库,所有数据都在统一的仓库中,进行统一的管理。 276 | 277 | 几个核心的概念: 278 | 279 | - State: Vuex 仓库中的数据。 280 | - Getter: 类似于 Vue 实例中的计算属性,Getter 就是普通的获取 state 包装函数。 281 | - Mutations: Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutations 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。 282 | - Action: action 可以触发 Mutations,不能直接改变 state。 283 | 284 | 看下面一张图了解一下 Vuex 整体的数据流动: 285 | 286 | ![](imgs/04vuex模型.png) 287 | 288 | ## Vuex 实例 demo 289 | 290 | 可能前面的图和概念都太多了,先看一个例子,简单了解一下 Vuex 中的仓库的数据 怎么整合到 Vue 的实例中去。 291 | 292 | 创建 Vuexdemo 的项目 293 | 294 | ```shell 295 | # 通过vue-cli创建vuexdemo的项目,注意首先cd到你的存放项目代码的目录 296 | vue init webpack vuexdemo 297 | 298 | # 过程中,会有几个选项你可以选择输入Y或者n来开启或者关闭某些选项。 299 | 300 | # 创建完成后,就可以通过以下命令,进行初始化和安装相关的依赖项了。 301 | cd vuexdemo 302 | npm install 303 | npm run dev 304 | 305 | # 然后安装 vuex 306 | npm i vuex -S 307 | ``` 308 | -------------------------------------------------------------------------------- /a.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之event message 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |
21 | 22 |
23 | 135 | 136 | -------------------------------------------------------------------------------- /a.md: -------------------------------------------------------------------------------- 1 | ```html 2 | 3 | 4 | 5 | 6 | Vue入门之event message 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 |
22 | 23 |
24 | 136 | 137 | 138 | ``` 139 | -------------------------------------------------------------------------------- /a.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/a.pdf -------------------------------------------------------------------------------- /demos/01-vue-helloworld.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之Helloworld 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | {{ message }} 14 |
15 | 16 | 17 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /demos/02-vue-bind.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之数据绑定 6 | 7 | 8 | 9 |
10 | {{ msg + ' - ' + name }} 11 |

12 | {{ isOk ? '123' : '456' }} 13 |

14 |

我的年龄是: {{ age *2 }}

15 |
16 | 17 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /demos/03-vue-prop-bind.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之属性绑定 6 | 7 | 8 | 9 |
10 |
11 | 首页 12 | 产品 13 | 服务 14 | 关于 15 |
16 |
17 | 18 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /demos/04-vue-classbind.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之绑定样式类 6 | 7 | 12 | 13 | 14 |
15 |
16 | 绑定颜色类 17 |
18 |
19 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /demos/05-vue-htmlraw.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之htmlraw 6 | 7 | 8 | 9 |
10 |
11 |
12 |
13 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /demos/06-vue-stylebind.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之htmlraw 6 | 7 | 8 | 9 |
10 |
11 | vue 入门系列教程 12 |
13 |
14 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /demos/07-vue-calc-prop.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之htmlraw 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
生日{{ getBirthday }}
年龄{{ age }}
地址{{ address }}
22 |
23 | 24 | 25 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /demos/08-vue-double-databind.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之htmlraw 6 | 7 | 8 | 9 |
10 | 11 |

您输入的信息是:{{ msg }}

12 |
13 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /demos/09-Vue-listrenderdemo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之动态显示表格 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
姓名年龄地址
{{ item.name }}{{ item.age }}{{ item.address }}
没有数据奥!
29 |
30 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /demos/10-vue-event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之数据监控 6 | 7 | 8 | 9 |
10 |

{{ number }}

11 | 12 | 13 |
14 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /demos/11-vue-watch.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之数据监控 6 | 7 | 8 | 9 |
10 |

{{ number }}

11 | 12 |
13 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /demos/12-vue-lifedemo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之生命周期 6 | 7 | 8 | 9 |
10 |

{{ number }}

11 | 12 |
13 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /demos/13-vue-extend-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之extend全局方法 6 | 7 | 8 | 9 |
10 |
11 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /demos/14-vue-componentdemo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之extend全局方法 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 |
16 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /demos/15-vue-component-solt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之extend全局方法 6 | 7 | 8 | 9 |
10 | 11 | 12 |

这里是父容器写入的

13 |
14 | 15 | 16 | {{ email }} 17 | 18 | 19 | 20 |
21 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /demos/16-vue-routerdemo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之extend全局方法 6 | 7 | 8 | 14 | 15 | 16 |
17 | 18 |
19 |

email to: {{ email }}

20 |
21 | 22 | 23 |
24 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /demos/17ttl.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/demos/17ttl.zip -------------------------------------------------------------------------------- /demos/17ttl/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"], 4 | "comments": false 5 | } 6 | -------------------------------------------------------------------------------- /demos/17ttl/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /demos/17ttl/.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | -------------------------------------------------------------------------------- /demos/17ttl/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module' 6 | }, 7 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 8 | extends: 'standard', 9 | // required to lint *.vue files 10 | plugins: [ 11 | 'html' 12 | ], 13 | // add your custom rules here 14 | 'rules': { 15 | // allow paren-less arrow functions 16 | 'arrow-parens': 0, 17 | // allow async-await 18 | 'generator-star-spacing': 0, 19 | // allow debugger during development 20 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /demos/17ttl/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | test/unit/coverage 6 | test/e2e/reports 7 | selenium-debug.log 8 | -------------------------------------------------------------------------------- /demos/17ttl/README.md: -------------------------------------------------------------------------------- 1 | # mydemovue 2 | 3 | > A Vue.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # run unit tests 18 | npm run unit 19 | 20 | # run e2e tests 21 | npm run e2e 22 | 23 | # run all tests 24 | npm test 25 | ``` 26 | 27 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 28 | -------------------------------------------------------------------------------- /demos/17ttl/build/build.js: -------------------------------------------------------------------------------- 1 | // https://github.com/shelljs/shelljs 2 | require('./check-versions')() 3 | require('shelljs/global') 4 | env.NODE_ENV = 'production' 5 | 6 | var path = require('path') 7 | var config = require('../config') 8 | var ora = require('ora') 9 | var webpack = require('webpack') 10 | var webpackConfig = require('./webpack.prod.conf') 11 | 12 | console.log( 13 | ' Tip:\n' + 14 | ' Built files are meant to be served over an HTTP server.\n' + 15 | ' Opening index.html over file:// won\'t work.\n' 16 | ) 17 | 18 | var spinner = ora('building for production...') 19 | spinner.start() 20 | 21 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) 22 | rm('-rf', assetsPath) 23 | mkdir('-p', assetsPath) 24 | cp('-R', 'static/*', assetsPath) 25 | 26 | webpack(webpackConfig, function (err, stats) { 27 | spinner.stop() 28 | if (err) throw err 29 | process.stdout.write(stats.toString({ 30 | colors: true, 31 | modules: false, 32 | children: false, 33 | chunks: false, 34 | chunkModules: false 35 | }) + '\n') 36 | }) 37 | -------------------------------------------------------------------------------- /demos/17ttl/build/check-versions.js: -------------------------------------------------------------------------------- 1 | var semver = require('semver') 2 | var chalk = require('chalk') 3 | var packageConfig = require('../package.json') 4 | var exec = function (cmd) { 5 | return require('child_process') 6 | .execSync(cmd).toString().trim() 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: 'node', 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | }, 15 | { 16 | name: 'npm', 17 | currentVersion: exec('npm --version'), 18 | versionRequirement: packageConfig.engines.npm 19 | } 20 | ] 21 | 22 | module.exports = function () { 23 | var warnings = [] 24 | for (var i = 0; i < versionRequirements.length; i++) { 25 | var mod = versionRequirements[i] 26 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 27 | warnings.push(mod.name + ': ' + 28 | chalk.red(mod.currentVersion) + ' should be ' + 29 | chalk.green(mod.versionRequirement) 30 | ) 31 | } 32 | } 33 | 34 | if (warnings.length) { 35 | console.log('') 36 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 37 | console.log() 38 | for (var i = 0; i < warnings.length; i++) { 39 | var warning = warnings[i] 40 | console.log(' ' + warning) 41 | } 42 | console.log() 43 | process.exit(1) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /demos/17ttl/build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /demos/17ttl/build/dev-server.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | var config = require('../config') 3 | if (!process.env.NODE_ENV) process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 4 | var path = require('path') 5 | var express = require('express') 6 | var webpack = require('webpack') 7 | var opn = require('opn') 8 | var proxyMiddleware = require('http-proxy-middleware') 9 | var webpackConfig = process.env.NODE_ENV === 'testing' 10 | ? require('./webpack.prod.conf') 11 | : require('./webpack.dev.conf') 12 | 13 | // default port where dev server listens for incoming traffic 14 | var port = process.env.PORT || config.dev.port 15 | // Define HTTP proxies to your custom API backend 16 | // https://github.com/chimurai/http-proxy-middleware 17 | var proxyTable = config.dev.proxyTable 18 | 19 | var app = express() 20 | var compiler = webpack(webpackConfig) 21 | 22 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 23 | publicPath: webpackConfig.output.publicPath, 24 | stats: { 25 | colors: true, 26 | chunks: false 27 | } 28 | }) 29 | 30 | var hotMiddleware = require('webpack-hot-middleware')(compiler) 31 | // force page reload when html-webpack-plugin template changes 32 | compiler.plugin('compilation', function (compilation) { 33 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 34 | hotMiddleware.publish({ action: 'reload' }) 35 | cb() 36 | }) 37 | }) 38 | 39 | // proxy api requests 40 | Object.keys(proxyTable).forEach(function (context) { 41 | var options = proxyTable[context] 42 | if (typeof options === 'string') { 43 | options = { target: options } 44 | } 45 | app.use(proxyMiddleware(context, options)) 46 | }) 47 | 48 | // handle fallback for HTML5 history API 49 | app.use(require('connect-history-api-fallback')()) 50 | 51 | // serve webpack bundle output 52 | app.use(devMiddleware) 53 | 54 | // enable hot-reload and state-preserving 55 | // compilation error display 56 | app.use(hotMiddleware) 57 | 58 | // serve pure static assets 59 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 60 | app.use(staticPath, express.static('./static')) 61 | 62 | module.exports = app.listen(port, function (err) { 63 | if (err) { 64 | console.log(err) 65 | return 66 | } 67 | var uri = 'http://localhost:' + port 68 | console.log('Listening at ' + uri + '\n') 69 | 70 | // when env is testing, don't need open it 71 | if (process.env.NODE_ENV !== 'testing') { 72 | opn(uri) 73 | } 74 | }) 75 | -------------------------------------------------------------------------------- /demos/17ttl/build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 7 | ? config.build.assetsSubDirectory 8 | : config.dev.assetsSubDirectory 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function (options) { 13 | options = options || {} 14 | // generate loader string to be used with extract text plugin 15 | function generateLoaders (loaders) { 16 | var sourceLoader = loaders.map(function (loader) { 17 | var extraParamChar 18 | if (/\?/.test(loader)) { 19 | loader = loader.replace(/\?/, '-loader?') 20 | extraParamChar = '&' 21 | } else { 22 | loader = loader + '-loader' 23 | extraParamChar = '?' 24 | } 25 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 26 | }).join('!') 27 | 28 | // Extract CSS when that option is specified 29 | // (which is the case during production build) 30 | if (options.extract) { 31 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 32 | } else { 33 | return ['vue-style-loader', sourceLoader].join('!') 34 | } 35 | } 36 | 37 | // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html 38 | return { 39 | css: generateLoaders(['css']), 40 | postcss: generateLoaders(['css']), 41 | less: generateLoaders(['css', 'less']), 42 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 43 | scss: generateLoaders(['css', 'sass']), 44 | stylus: generateLoaders(['css', 'stylus']), 45 | styl: generateLoaders(['css', 'stylus']) 46 | } 47 | } 48 | 49 | // Generate loaders for standalone style files (outside of .vue) 50 | exports.styleLoaders = function (options) { 51 | var output = [] 52 | var loaders = exports.cssLoaders(options) 53 | for (var extension in loaders) { 54 | var loader = loaders[extension] 55 | output.push({ 56 | test: new RegExp('\\.' + extension + '$'), 57 | loader: loader 58 | }) 59 | } 60 | return output 61 | } 62 | -------------------------------------------------------------------------------- /demos/17ttl/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var projectRoot = path.resolve(__dirname, '../') 5 | 6 | var env = process.env.NODE_ENV 7 | // check env & config/index.js to decide whether to enable CSS source maps for the 8 | // various preprocessor loaders added to vue-loader at the end of this file 9 | var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap) 10 | var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap) 11 | var useCssSourceMap = cssSourceMapDev || cssSourceMapProd 12 | 13 | module.exports = { 14 | entry: { 15 | app: './src/main.js' 16 | }, 17 | output: { 18 | path: config.build.assetsRoot, 19 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, 20 | filename: '[name].js' 21 | }, 22 | resolve: { 23 | extensions: ['', '.js', '.vue', '.json'], 24 | fallback: [path.join(__dirname, '../node_modules')], 25 | alias: { 26 | 'vue$': 'vue/dist/vue.common.js', 27 | 'src': path.resolve(__dirname, '../src'), 28 | 'assets': path.resolve(__dirname, '../src/assets'), 29 | 'components': path.resolve(__dirname, '../src/components') 30 | } 31 | }, 32 | resolveLoader: { 33 | fallback: [path.join(__dirname, '../node_modules')] 34 | }, 35 | module: { 36 | preLoaders: [ 37 | { 38 | test: /\.vue$/, 39 | loader: 'eslint', 40 | include: projectRoot, 41 | exclude: /node_modules/ 42 | }, 43 | { 44 | test: /\.js$/, 45 | loader: 'eslint', 46 | include: projectRoot, 47 | exclude: /node_modules/ 48 | } 49 | ], 50 | loaders: [ 51 | { 52 | test: /\.vue$/, 53 | loader: 'vue' 54 | }, 55 | { 56 | test: /\.js$/, 57 | loader: 'babel', 58 | include: projectRoot, 59 | exclude: /node_modules/ 60 | }, 61 | { 62 | test: /\.json$/, 63 | loader: 'json' 64 | }, 65 | { 66 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 67 | loader: 'url', 68 | query: { 69 | limit: 10000, 70 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 71 | } 72 | }, 73 | { 74 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 75 | loader: 'url', 76 | query: { 77 | limit: 10000, 78 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 79 | } 80 | } 81 | ] 82 | }, 83 | eslint: { 84 | formatter: require('eslint-friendly-formatter') 85 | }, 86 | vue: { 87 | loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }), 88 | postcss: [ 89 | require('autoprefixer')({ 90 | browsers: ['last 2 versions'] 91 | }) 92 | ] 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /demos/17ttl/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var config = require('../config') 2 | var webpack = require('webpack') 3 | var merge = require('webpack-merge') 4 | var utils = require('./utils') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | 8 | // add hot-reload related code to entry chunks 9 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 10 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 11 | }) 12 | 13 | module.exports = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 16 | }, 17 | // eval-source-map is faster for development 18 | devtool: '#eval-source-map', 19 | plugins: [ 20 | new webpack.DefinePlugin({ 21 | 'process.env': config.dev.env 22 | }), 23 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 24 | new webpack.optimize.OccurrenceOrderPlugin(), 25 | new webpack.HotModuleReplacementPlugin(), 26 | new webpack.NoErrorsPlugin(), 27 | // https://github.com/ampedandwired/html-webpack-plugin 28 | new HtmlWebpackPlugin({ 29 | filename: 'index.html', 30 | template: 'index.html', 31 | inject: true 32 | }) 33 | ] 34 | }) 35 | -------------------------------------------------------------------------------- /demos/17ttl/build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var env = process.env.NODE_ENV === 'testing' 10 | ? require('../config/test.env') 11 | : config.build.env 12 | 13 | var webpackConfig = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) 16 | }, 17 | devtool: config.build.productionSourceMap ? '#source-map' : false, 18 | output: { 19 | path: config.build.assetsRoot, 20 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 21 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 22 | }, 23 | vue: { 24 | loaders: utils.cssLoaders({ 25 | sourceMap: config.build.productionSourceMap, 26 | extract: true 27 | }) 28 | }, 29 | plugins: [ 30 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 31 | new webpack.DefinePlugin({ 32 | 'process.env': env 33 | }), 34 | new webpack.optimize.UglifyJsPlugin({ 35 | compress: { 36 | warnings: false 37 | } 38 | }), 39 | new webpack.optimize.OccurrenceOrderPlugin(), 40 | // extract css into its own file 41 | new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), 42 | // generate dist index.html with correct asset hash for caching. 43 | // you can customize output by editing /index.html 44 | // see https://github.com/ampedandwired/html-webpack-plugin 45 | new HtmlWebpackPlugin({ 46 | filename: process.env.NODE_ENV === 'testing' 47 | ? 'index.html' 48 | : config.build.index, 49 | template: 'index.html', 50 | inject: true, 51 | minify: { 52 | removeComments: true, 53 | collapseWhitespace: true, 54 | removeAttributeQuotes: true 55 | // more options: 56 | // https://github.com/kangax/html-minifier#options-quick-reference 57 | }, 58 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 59 | chunksSortMode: 'dependency' 60 | }), 61 | // split vendor js into its own file 62 | new webpack.optimize.CommonsChunkPlugin({ 63 | name: 'vendor', 64 | minChunks: function (module, count) { 65 | // any required modules inside node_modules are extracted to vendor 66 | return ( 67 | module.resource && 68 | /\.js$/.test(module.resource) && 69 | module.resource.indexOf( 70 | path.join(__dirname, '../node_modules') 71 | ) === 0 72 | ) 73 | } 74 | }), 75 | // extract webpack runtime and module manifest to its own file in order to 76 | // prevent vendor hash from being updated whenever app bundle is updated 77 | new webpack.optimize.CommonsChunkPlugin({ 78 | name: 'manifest', 79 | chunks: ['vendor'] 80 | }) 81 | ] 82 | }) 83 | 84 | if (config.build.productionGzip) { 85 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 86 | 87 | webpackConfig.plugins.push( 88 | new CompressionWebpackPlugin({ 89 | asset: '[path].gz[query]', 90 | algorithm: 'gzip', 91 | test: new RegExp( 92 | '\\.(' + 93 | config.build.productionGzipExtensions.join('|') + 94 | ')$' 95 | ), 96 | threshold: 10240, 97 | minRatio: 0.8 98 | }) 99 | ) 100 | } 101 | 102 | module.exports = webpackConfig 103 | -------------------------------------------------------------------------------- /demos/17ttl/config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /demos/17ttl/config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: '/', 11 | productionSourceMap: true, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'] 18 | }, 19 | dev: { 20 | env: require('./dev.env'), 21 | port: 8080, 22 | assetsSubDirectory: 'static', 23 | assetsPublicPath: '/', 24 | proxyTable: {}, 25 | // CSS Sourcemaps off by default because relative paths are "buggy" 26 | // with this option, according to the CSS-Loader README 27 | // (https://github.com/webpack/css-loader#sourcemaps) 28 | // In our experience, they generally work as expected, 29 | // just be aware of this issue when enabling this option. 30 | cssSourceMap: false 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /demos/17ttl/config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /demos/17ttl/config/test.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var devEnv = require('./dev.env') 3 | 4 | module.exports = merge(devEnv, { 5 | NODE_ENV: '"testing"' 6 | }) 7 | -------------------------------------------------------------------------------- /demos/17ttl/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | mydemovue 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /demos/17ttl/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mydemovue", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "malun ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "build": "node build/build.js", 10 | "unit": "karma start test/unit/karma.conf.js --single-run", 11 | "e2e": "node test/e2e/runner.js", 12 | "test": "npm run unit && npm run e2e", 13 | "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs" 14 | }, 15 | "dependencies": { 16 | "vue": "^2.1.0", 17 | "vue-router": "^2.1.1" 18 | }, 19 | "devDependencies": { 20 | "autoprefixer": "^6.4.0", 21 | "babel-core": "^6.0.0", 22 | "babel-eslint": "^7.0.0", 23 | "babel-loader": "^6.0.0", 24 | "babel-plugin-transform-runtime": "^6.0.0", 25 | "babel-preset-es2015": "^6.0.0", 26 | "babel-preset-stage-2": "^6.0.0", 27 | "babel-register": "^6.0.0", 28 | "chalk": "^1.1.3", 29 | "connect-history-api-fallback": "^1.1.0", 30 | "css-loader": "^0.25.0", 31 | "eslint": "^3.7.1", 32 | "eslint-friendly-formatter": "^2.0.5", 33 | "eslint-loader": "^1.5.0", 34 | "eslint-plugin-html": "^1.3.0", 35 | "eslint-config-standard": "^6.1.0", 36 | "eslint-plugin-promise": "^3.4.0", 37 | "eslint-plugin-standard": "^2.0.1", 38 | "eventsource-polyfill": "^0.9.6", 39 | "express": "^4.13.3", 40 | "extract-text-webpack-plugin": "^1.0.1", 41 | "file-loader": "^0.9.0", 42 | "function-bind": "^1.0.2", 43 | "html-webpack-plugin": "^2.8.1", 44 | "http-proxy-middleware": "^0.17.2", 45 | "json-loader": "^0.5.4", 46 | "karma": "^1.3.0", 47 | "karma-coverage": "^1.1.1", 48 | "karma-mocha": "^1.2.0", 49 | "karma-phantomjs-launcher": "^1.0.0", 50 | "karma-sinon-chai": "^1.2.0", 51 | "karma-sourcemap-loader": "^0.3.7", 52 | "karma-spec-reporter": "0.0.26", 53 | "karma-webpack": "^1.7.0", 54 | "lolex": "^1.4.0", 55 | "mocha": "^3.1.0", 56 | "chai": "^3.5.0", 57 | "sinon": "^1.17.3", 58 | "sinon-chai": "^2.8.0", 59 | "inject-loader": "^2.0.1", 60 | "isparta-loader": "^2.0.0", 61 | "phantomjs-prebuilt": "^2.1.3", 62 | "chromedriver": "^2.21.2", 63 | "cross-spawn": "^4.0.2", 64 | "nightwatch": "^0.9.8", 65 | "selenium-server": "2.53.1", 66 | "semver": "^5.3.0", 67 | "opn": "^4.0.2", 68 | "ora": "^0.3.0", 69 | "shelljs": "^0.7.4", 70 | "url-loader": "^0.5.7", 71 | "vue-loader": "^10.0.0", 72 | "vue-style-loader": "^1.0.0", 73 | "vue-template-compiler": "^2.1.0", 74 | "webpack": "^1.13.2", 75 | "webpack-dev-middleware": "^1.8.3", 76 | "webpack-hot-middleware": "^2.12.2", 77 | "webpack-merge": "^0.14.1" 78 | }, 79 | "engines": { 80 | "node": ">= 4.0.0", 81 | "npm": ">= 3.0.0" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /demos/17ttl/src/App.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 45 | 46 | 62 | -------------------------------------------------------------------------------- /demos/17ttl/src/approuter.js: -------------------------------------------------------------------------------- 1 | import VueRouter from 'vue-router' 2 | import Home from './components/Home.vue' 3 | import User from './components/User.vue' 4 | import Product from './components/Product.vue' 5 | 6 | export default new VueRouter({ 7 | routes: [ 8 | {path: '/home', component: Home}, 9 | {path: '/user/:id', component: User}, 10 | {path: '/product/:id', component: Product} 11 | ] 12 | }) 13 | -------------------------------------------------------------------------------- /demos/17ttl/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/demos/17ttl/src/assets/logo.png -------------------------------------------------------------------------------- /demos/17ttl/src/components/Hello.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 33 | 34 | 35 | 54 | -------------------------------------------------------------------------------- /demos/17ttl/src/components/Home.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 23 | -------------------------------------------------------------------------------- /demos/17ttl/src/components/Product.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 23 | -------------------------------------------------------------------------------- /demos/17ttl/src/components/User.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 23 | -------------------------------------------------------------------------------- /demos/17ttl/src/filters/DateFilter.js: -------------------------------------------------------------------------------- 1 | export default { 2 | chineseFormatFilter (val) { 3 | console.log('...') 4 | if (!val) return '' 5 | var dt = new Date(val.toString()) 6 | return dt.getFullYear() + '年' + dt.getMonth() + '月' + dt.getDay() + '日' 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /demos/17ttl/src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | import VueRouter from 'vue-router' // 导入路由组件 6 | import router from './approuter' 7 | // 使用路由组件 8 | Vue.use(VueRouter) 9 | 10 | /* eslint-disable no-new */ 11 | new Vue({ 12 | el: '#app', 13 | template: '', 14 | components: { App }, 15 | router: router 16 | }) 17 | -------------------------------------------------------------------------------- /demos/17ttl/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/demos/17ttl/static/.gitkeep -------------------------------------------------------------------------------- /demos/17ttl/test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // the name of the method is the filename. 3 | // can be used in tests like this: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // for how to write custom assertions see 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | exports.assertion = function (selector, count) { 10 | this.message = 'Testing if element <' + selector + '> has count: ' + count 11 | this.expected = count 12 | this.pass = function (val) { 13 | return val === this.expected 14 | } 15 | this.value = function (res) { 16 | return res.value 17 | } 18 | this.command = function (cb) { 19 | var self = this 20 | return this.api.execute(function (selector) { 21 | return document.querySelectorAll(selector).length 22 | }, [selector], function (res) { 23 | cb.call(self, res) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demos/17ttl/test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | var config = require('../../config') 3 | 4 | // http://nightwatchjs.org/guide#settings-file 5 | module.exports = { 6 | src_folders: ['test/e2e/specs'], 7 | output_folder: 'test/e2e/reports', 8 | custom_assertions_path: ['test/e2e/custom-assertions'], 9 | 10 | selenium: { 11 | start_process: true, 12 | server_path: 'node_modules/selenium-server/lib/runner/selenium-server-standalone-2.53.1.jar', 13 | host: '127.0.0.1', 14 | port: 4444, 15 | cli_args: { 16 | 'webdriver.chrome.driver': require('chromedriver').path 17 | } 18 | }, 19 | 20 | test_settings: { 21 | default: { 22 | selenium_port: 4444, 23 | selenium_host: 'localhost', 24 | silent: true, 25 | globals: { 26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port) 27 | } 28 | }, 29 | 30 | chrome: { 31 | desiredCapabilities: { 32 | browserName: 'chrome', 33 | javascriptEnabled: true, 34 | acceptSslCerts: true 35 | } 36 | }, 37 | 38 | firefox: { 39 | desiredCapabilities: { 40 | browserName: 'firefox', 41 | javascriptEnabled: true, 42 | acceptSslCerts: true 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /demos/17ttl/test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server using production config 2 | process.env.NODE_ENV = 'testing' 3 | var server = require('../../build/dev-server.js') 4 | 5 | // 2. run the nightwatch test suite against it 6 | // to run in additional browsers: 7 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" 8 | // 2. add it to the --env flag below 9 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` 10 | // For more information on Nightwatch's config file, see 11 | // http://nightwatchjs.org/guide#settings-file 12 | var opts = process.argv.slice(2) 13 | if (opts.indexOf('--config') === -1) { 14 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) 15 | } 16 | if (opts.indexOf('--env') === -1) { 17 | opts = opts.concat(['--env', 'chrome']) 18 | } 19 | 20 | var spawn = require('cross-spawn') 21 | var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) 22 | 23 | runner.on('exit', function (code) { 24 | server.close() 25 | process.exit(code) 26 | }) 27 | 28 | runner.on('error', function (err) { 29 | server.close() 30 | throw err 31 | }) 32 | -------------------------------------------------------------------------------- /demos/17ttl/test/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': function (browser) { 6 | // automatically uses dev Server port from /config.index.js 7 | // default: http://localhost:8080 8 | // see nightwatch.conf.js 9 | const devServer = browser.globals.devServerURL 10 | 11 | browser 12 | .url(devServer) 13 | .waitForElementVisible('#app', 5000) 14 | .assert.elementPresent('.hello') 15 | .assert.containsText('h1', 'Welcome to Your Vue.js App') 16 | .assert.elementCount('img', 1) 17 | .end() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /demos/17ttl/test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /demos/17ttl/test/unit/index.js: -------------------------------------------------------------------------------- 1 | // Polyfill fn.bind() for PhantomJS 2 | /* eslint-disable no-extend-native */ 3 | Function.prototype.bind = require('function-bind') 4 | 5 | // require all test files (files that ends with .spec.js) 6 | const testsContext = require.context('./specs', true, /\.spec$/) 7 | testsContext.keys().forEach(testsContext) 8 | 9 | // require all src files except main.js for coverage. 10 | // you can also change this to match only the subset of files that 11 | // you want coverage for. 12 | const srcContext = require.context('src', true, /^\.\/(?!main(\.js)?$)/) 13 | srcContext.keys().forEach(srcContext) 14 | -------------------------------------------------------------------------------- /demos/17ttl/test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var path = require('path') 7 | var merge = require('webpack-merge') 8 | var baseConfig = require('../../build/webpack.base.conf') 9 | var utils = require('../../build/utils') 10 | var webpack = require('webpack') 11 | var projectRoot = path.resolve(__dirname, '../../') 12 | 13 | var webpackConfig = merge(baseConfig, { 14 | // use inline sourcemap for karma-sourcemap-loader 15 | module: { 16 | loaders: utils.styleLoaders() 17 | }, 18 | devtool: '#inline-source-map', 19 | vue: { 20 | loaders: { 21 | js: 'isparta' 22 | } 23 | }, 24 | plugins: [ 25 | new webpack.DefinePlugin({ 26 | 'process.env': require('../../config/test.env') 27 | }) 28 | ] 29 | }) 30 | 31 | // no need for app entry during tests 32 | delete webpackConfig.entry 33 | 34 | // make sure isparta loader is applied before eslint 35 | webpackConfig.module.preLoaders = webpackConfig.module.preLoaders || [] 36 | webpackConfig.module.preLoaders.unshift({ 37 | test: /\.js$/, 38 | loader: 'isparta', 39 | include: path.resolve(projectRoot, 'src') 40 | }) 41 | 42 | // only apply babel for test files when using isparta 43 | webpackConfig.module.loaders.some(function (loader, i) { 44 | if (loader.loader === 'babel') { 45 | loader.include = path.resolve(projectRoot, 'test/unit') 46 | return true 47 | } 48 | }) 49 | 50 | module.exports = function (config) { 51 | config.set({ 52 | // to run in additional browsers: 53 | // 1. install corresponding karma launcher 54 | // http://karma-runner.github.io/0.13/config/browsers.html 55 | // 2. add it to the `browsers` array below. 56 | browsers: ['PhantomJS'], 57 | frameworks: ['mocha', 'sinon-chai'], 58 | reporters: ['spec', 'coverage'], 59 | files: ['./index.js'], 60 | preprocessors: { 61 | './index.js': ['webpack', 'sourcemap'] 62 | }, 63 | webpack: webpackConfig, 64 | webpackMiddleware: { 65 | noInfo: true 66 | }, 67 | coverageReporter: { 68 | dir: './coverage', 69 | reporters: [ 70 | { type: 'lcov', subdir: '.' }, 71 | { type: 'text-summary' } 72 | ] 73 | } 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /demos/17ttl/test/unit/specs/Hello.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Hello from 'src/components/Hello' 3 | 4 | describe('Hello.vue', () => { 5 | it('should render correct contents', () => { 6 | const vm = new Vue({ 7 | el: document.createElement('div'), 8 | render: (h) => h(Hello) 9 | }) 10 | expect(vm.$el.querySelector('.hello h1').textContent) 11 | .to.equal('Welcome to Your Vue.js App') 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /demos/18-vue-router-params.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vue入门之extend全局方法 7 | 8 | 9 | 10 | 11 | 12 |
13 | 18 | 19 |
20 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /demos/19-vue-filterdemo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vue入门之filter 7 | 8 | 9 | 10 | 11 | 12 |
13 |

{{ stu.birthday | dateYmDMSFilter }}

14 |
15 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /demos/20-vue-event-bus-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vue入门之event message 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 |
27 | 28 |
29 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /demos/21-vue-parent-child-event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vue入门之event message 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 |

推荐次数:{{ voteCount }}

26 |
27 | 28 |
29 |
    30 |
  • {{o}}
  • 31 |
32 |
33 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /demos/22-vue-vuex-bind.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue入门之extend全局方法 6 | 7 | 8 | 9 | 10 |
11 |

推荐次数:{{ vote }}

12 | 13 | 14 |
15 |
    16 |
  • 17 | {{ item }} 18 |
  • 19 |
20 |
21 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"], 4 | "comments": false, 5 | "env": { 6 | "test": { 7 | "plugins": [ "istanbul" ] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module' 6 | }, 7 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 8 | extends: 'standard', 9 | // required to lint *.vue files 10 | plugins: [ 11 | 'html' 12 | ], 13 | // add your custom rules here 14 | 'rules': { 15 | // allow paren-less arrow functions 16 | 'arrow-parens': 0, 17 | // allow async-await 18 | 'generator-star-spacing': 0, 19 | // allow debugger during development 20 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | test/unit/coverage 6 | test/e2e/reports 7 | selenium-debug.log 8 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/README.md: -------------------------------------------------------------------------------- 1 | # vuexdemo 2 | 3 | > A Vue.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # run unit tests 18 | npm run unit 19 | 20 | # run e2e tests 21 | npm run e2e 22 | 23 | # run all tests 24 | npm test 25 | ``` 26 | 27 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 28 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/build/build.js: -------------------------------------------------------------------------------- 1 | // https://github.com/shelljs/shelljs 2 | require('./check-versions')() 3 | require('shelljs/global') 4 | env.NODE_ENV = 'production' 5 | 6 | var path = require('path') 7 | var config = require('../config') 8 | var ora = require('ora') 9 | var webpack = require('webpack') 10 | var webpackConfig = require('./webpack.prod.conf') 11 | 12 | console.log( 13 | ' Tip:\n' + 14 | ' Built files are meant to be served over an HTTP server.\n' + 15 | ' Opening index.html over file:// won\'t work.\n' 16 | ) 17 | 18 | var spinner = ora('building for production...') 19 | spinner.start() 20 | 21 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) 22 | rm('-rf', assetsPath) 23 | mkdir('-p', assetsPath) 24 | cp('-R', 'static/*', assetsPath) 25 | 26 | webpack(webpackConfig, function (err, stats) { 27 | spinner.stop() 28 | if (err) throw err 29 | process.stdout.write(stats.toString({ 30 | colors: true, 31 | modules: false, 32 | children: false, 33 | chunks: false, 34 | chunkModules: false 35 | }) + '\n') 36 | }) 37 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/build/check-versions.js: -------------------------------------------------------------------------------- 1 | var semver = require('semver') 2 | var chalk = require('chalk') 3 | var packageConfig = require('../package.json') 4 | var exec = function (cmd) { 5 | return require('child_process') 6 | .execSync(cmd).toString().trim() 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: 'node', 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | }, 15 | { 16 | name: 'npm', 17 | currentVersion: exec('npm --version'), 18 | versionRequirement: packageConfig.engines.npm 19 | } 20 | ] 21 | 22 | module.exports = function () { 23 | var warnings = [] 24 | for (var i = 0; i < versionRequirements.length; i++) { 25 | var mod = versionRequirements[i] 26 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 27 | warnings.push(mod.name + ': ' + 28 | chalk.red(mod.currentVersion) + ' should be ' + 29 | chalk.green(mod.versionRequirement) 30 | ) 31 | } 32 | } 33 | 34 | if (warnings.length) { 35 | console.log('') 36 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 37 | console.log() 38 | for (var i = 0; i < warnings.length; i++) { 39 | var warning = warnings[i] 40 | console.log(' ' + warning) 41 | } 42 | console.log() 43 | process.exit(1) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/build/dev-server.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | var config = require('../config') 3 | if (!process.env.NODE_ENV) process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 4 | var path = require('path') 5 | var express = require('express') 6 | var webpack = require('webpack') 7 | var opn = require('opn') 8 | var proxyMiddleware = require('http-proxy-middleware') 9 | var webpackConfig = process.env.NODE_ENV === 'testing' 10 | ? require('./webpack.prod.conf') 11 | : require('./webpack.dev.conf') 12 | 13 | // default port where dev server listens for incoming traffic 14 | var port = process.env.PORT || config.dev.port 15 | // Define HTTP proxies to your custom API backend 16 | // https://github.com/chimurai/http-proxy-middleware 17 | var proxyTable = config.dev.proxyTable 18 | 19 | var app = express() 20 | var compiler = webpack(webpackConfig) 21 | 22 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 23 | publicPath: webpackConfig.output.publicPath, 24 | quiet: true 25 | }) 26 | 27 | var hotMiddleware = require('webpack-hot-middleware')(compiler, { 28 | log: () => {} 29 | }) 30 | // force page reload when html-webpack-plugin template changes 31 | compiler.plugin('compilation', function (compilation) { 32 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 33 | hotMiddleware.publish({ action: 'reload' }) 34 | cb() 35 | }) 36 | }) 37 | 38 | // proxy api requests 39 | Object.keys(proxyTable).forEach(function (context) { 40 | var options = proxyTable[context] 41 | if (typeof options === 'string') { 42 | options = { target: options } 43 | } 44 | app.use(proxyMiddleware(context, options)) 45 | }) 46 | 47 | // handle fallback for HTML5 history API 48 | app.use(require('connect-history-api-fallback')()) 49 | 50 | // serve webpack bundle output 51 | app.use(devMiddleware) 52 | 53 | // enable hot-reload and state-preserving 54 | // compilation error display 55 | app.use(hotMiddleware) 56 | 57 | // serve pure static assets 58 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 59 | app.use(staticPath, express.static('./static')) 60 | 61 | var uri = 'http://localhost:' + port 62 | 63 | devMiddleware.waitUntilValid(function () { 64 | console.log('> Listening at ' + uri + '\n') 65 | }) 66 | 67 | module.exports = app.listen(port, function (err) { 68 | if (err) { 69 | console.log(err) 70 | return 71 | } 72 | 73 | // when env is testing, don't need open it 74 | if (process.env.NODE_ENV !== 'testing') { 75 | opn(uri) 76 | } 77 | }) 78 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 7 | ? config.build.assetsSubDirectory 8 | : config.dev.assetsSubDirectory 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function (options) { 13 | options = options || {} 14 | // generate loader string to be used with extract text plugin 15 | function generateLoaders (loaders) { 16 | var sourceLoader = loaders.map(function (loader) { 17 | var extraParamChar 18 | if (/\?/.test(loader)) { 19 | loader = loader.replace(/\?/, '-loader?') 20 | extraParamChar = '&' 21 | } else { 22 | loader = loader + '-loader' 23 | extraParamChar = '?' 24 | } 25 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 26 | }).join('!') 27 | 28 | // Extract CSS when that option is specified 29 | // (which is the case during production build) 30 | if (options.extract) { 31 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 32 | } else { 33 | return ['vue-style-loader', sourceLoader].join('!') 34 | } 35 | } 36 | 37 | // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html 38 | return { 39 | css: generateLoaders(['css']), 40 | postcss: generateLoaders(['css']), 41 | less: generateLoaders(['css', 'less']), 42 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 43 | scss: generateLoaders(['css', 'sass']), 44 | stylus: generateLoaders(['css', 'stylus']), 45 | styl: generateLoaders(['css', 'stylus']) 46 | } 47 | } 48 | 49 | // Generate loaders for standalone style files (outside of .vue) 50 | exports.styleLoaders = function (options) { 51 | var output = [] 52 | var loaders = exports.cssLoaders(options) 53 | for (var extension in loaders) { 54 | var loader = loaders[extension] 55 | output.push({ 56 | test: new RegExp('\\.' + extension + '$'), 57 | loader: loader 58 | }) 59 | } 60 | return output 61 | } 62 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var projectRoot = path.resolve(__dirname, '../') 5 | 6 | var env = process.env.NODE_ENV 7 | // check env & config/index.js to decide whether to enable CSS source maps for the 8 | // various preprocessor loaders added to vue-loader at the end of this file 9 | var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap) 10 | var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap) 11 | var useCssSourceMap = cssSourceMapDev || cssSourceMapProd 12 | 13 | module.exports = { 14 | entry: { 15 | app: './src/main.js' 16 | }, 17 | output: { 18 | path: config.build.assetsRoot, 19 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, 20 | filename: '[name].js' 21 | }, 22 | resolve: { 23 | extensions: ['', '.js', '.vue', '.json'], 24 | fallback: [path.join(__dirname, '../node_modules')], 25 | alias: { 26 | 'vue$': 'vue/dist/vue.common.js', 27 | 'src': path.resolve(__dirname, '../src'), 28 | 'assets': path.resolve(__dirname, '../src/assets'), 29 | 'components': path.resolve(__dirname, '../src/components') 30 | } 31 | }, 32 | resolveLoader: { 33 | fallback: [path.join(__dirname, '../node_modules')] 34 | }, 35 | module: { 36 | preLoaders: [ 37 | { 38 | test: /\.vue$/, 39 | loader: 'eslint', 40 | include: [ 41 | path.join(projectRoot, 'src') 42 | ], 43 | exclude: /node_modules/ 44 | }, 45 | { 46 | test: /\.js$/, 47 | loader: 'eslint', 48 | include: [ 49 | path.join(projectRoot, 'src') 50 | ], 51 | exclude: /node_modules/ 52 | } 53 | ], 54 | loaders: [ 55 | { 56 | test: /\.vue$/, 57 | loader: 'vue' 58 | }, 59 | { 60 | test: /\.js$/, 61 | loader: 'babel', 62 | include: [ 63 | path.join(projectRoot, 'src') 64 | ], 65 | exclude: /node_modules/ 66 | }, 67 | { 68 | test: /\.json$/, 69 | loader: 'json' 70 | }, 71 | { 72 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 73 | loader: 'url', 74 | query: { 75 | limit: 10000, 76 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 77 | } 78 | }, 79 | { 80 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 81 | loader: 'url', 82 | query: { 83 | limit: 10000, 84 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 85 | } 86 | } 87 | ] 88 | }, 89 | eslint: { 90 | formatter: require('eslint-friendly-formatter') 91 | }, 92 | vue: { 93 | loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }), 94 | postcss: [ 95 | require('autoprefixer')({ 96 | browsers: ['last 2 versions'] 97 | }) 98 | ] 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var config = require('../config') 2 | var webpack = require('webpack') 3 | var merge = require('webpack-merge') 4 | var utils = require('./utils') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var FriendlyErrors = require('friendly-errors-webpack-plugin') 8 | 9 | // add hot-reload related code to entry chunks 10 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 11 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 12 | }) 13 | 14 | module.exports = merge(baseWebpackConfig, { 15 | module: { 16 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 17 | }, 18 | // eval-source-map is faster for development 19 | devtool: '#eval-source-map', 20 | plugins: [ 21 | new webpack.DefinePlugin({ 22 | 'process.env': config.dev.env 23 | }), 24 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 25 | new webpack.optimize.OccurrenceOrderPlugin(), 26 | new webpack.HotModuleReplacementPlugin(), 27 | new webpack.NoErrorsPlugin(), 28 | // https://github.com/ampedandwired/html-webpack-plugin 29 | new HtmlWebpackPlugin({ 30 | filename: 'index.html', 31 | template: 'index.html', 32 | inject: true 33 | }), 34 | new FriendlyErrors() 35 | ] 36 | }) 37 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var env = process.env.NODE_ENV === 'testing' 10 | ? require('../config/test.env') 11 | : config.build.env 12 | 13 | var webpackConfig = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) 16 | }, 17 | devtool: config.build.productionSourceMap ? '#source-map' : false, 18 | output: { 19 | path: config.build.assetsRoot, 20 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 21 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 22 | }, 23 | vue: { 24 | loaders: utils.cssLoaders({ 25 | sourceMap: config.build.productionSourceMap, 26 | extract: true 27 | }) 28 | }, 29 | plugins: [ 30 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 31 | new webpack.DefinePlugin({ 32 | 'process.env': env 33 | }), 34 | new webpack.optimize.UglifyJsPlugin({ 35 | compress: { 36 | warnings: false 37 | } 38 | }), 39 | new webpack.optimize.OccurrenceOrderPlugin(), 40 | // extract css into its own file 41 | new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), 42 | // generate dist index.html with correct asset hash for caching. 43 | // you can customize output by editing /index.html 44 | // see https://github.com/ampedandwired/html-webpack-plugin 45 | new HtmlWebpackPlugin({ 46 | filename: process.env.NODE_ENV === 'testing' 47 | ? 'index.html' 48 | : config.build.index, 49 | template: 'index.html', 50 | inject: true, 51 | minify: { 52 | removeComments: true, 53 | collapseWhitespace: true, 54 | removeAttributeQuotes: true 55 | // more options: 56 | // https://github.com/kangax/html-minifier#options-quick-reference 57 | }, 58 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 59 | chunksSortMode: 'dependency' 60 | }), 61 | // split vendor js into its own file 62 | new webpack.optimize.CommonsChunkPlugin({ 63 | name: 'vendor', 64 | minChunks: function (module, count) { 65 | // any required modules inside node_modules are extracted to vendor 66 | return ( 67 | module.resource && 68 | /\.js$/.test(module.resource) && 69 | module.resource.indexOf( 70 | path.join(__dirname, '../node_modules') 71 | ) === 0 72 | ) 73 | } 74 | }), 75 | // extract webpack runtime and module manifest to its own file in order to 76 | // prevent vendor hash from being updated whenever app bundle is updated 77 | new webpack.optimize.CommonsChunkPlugin({ 78 | name: 'manifest', 79 | chunks: ['vendor'] 80 | }) 81 | ] 82 | }) 83 | 84 | if (config.build.productionGzip) { 85 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 86 | 87 | webpackConfig.plugins.push( 88 | new CompressionWebpackPlugin({ 89 | asset: '[path].gz[query]', 90 | algorithm: 'gzip', 91 | test: new RegExp( 92 | '\\.(' + 93 | config.build.productionGzipExtensions.join('|') + 94 | ')$' 95 | ), 96 | threshold: 10240, 97 | minRatio: 0.8 98 | }) 99 | ) 100 | } 101 | 102 | module.exports = webpackConfig 103 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: '/', 11 | productionSourceMap: true, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'] 18 | }, 19 | dev: { 20 | env: require('./dev.env'), 21 | port: 8095, 22 | assetsSubDirectory: 'static', 23 | assetsPublicPath: '/', 24 | proxyTable: {}, 25 | // CSS Sourcemaps off by default because relative paths are "buggy" 26 | // with this option, according to the CSS-Loader README 27 | // (https://github.com/webpack/css-loader#sourcemaps) 28 | // In our experience, they generally work as expected, 29 | // just be aware of this issue when enabling this option. 30 | cssSourceMap: false 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/config/test.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var devEnv = require('./dev.env') 3 | 4 | module.exports = merge(devEnv, { 5 | NODE_ENV: '"testing"' 6 | }) 7 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vuexdemo 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuexdemo", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "malun ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "build": "node build/build.js", 10 | "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run", 11 | "e2e": "node test/e2e/runner.js", 12 | "test": "npm run unit && npm run e2e", 13 | "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs" 14 | }, 15 | "dependencies": { 16 | "vue": "^2.1.0", 17 | "vuex": "^2.1.1" 18 | }, 19 | "devDependencies": { 20 | "autoprefixer": "^6.4.0", 21 | "babel-core": "^6.0.0", 22 | "babel-eslint": "^7.0.0", 23 | "babel-loader": "^6.0.0", 24 | "babel-plugin-transform-runtime": "^6.0.0", 25 | "babel-preset-es2015": "^6.0.0", 26 | "babel-preset-stage-2": "^6.0.0", 27 | "babel-register": "^6.0.0", 28 | "chalk": "^1.1.3", 29 | "connect-history-api-fallback": "^1.1.0", 30 | "css-loader": "^0.25.0", 31 | "eslint": "^3.7.1", 32 | "eslint-friendly-formatter": "^2.0.5", 33 | "eslint-loader": "^1.5.0", 34 | "eslint-plugin-html": "^1.3.0", 35 | "eslint-config-standard": "^6.1.0", 36 | "eslint-plugin-promise": "^3.4.0", 37 | "eslint-plugin-standard": "^2.0.1", 38 | "eventsource-polyfill": "^0.9.6", 39 | "express": "^4.13.3", 40 | "extract-text-webpack-plugin": "^1.0.1", 41 | "file-loader": "^0.9.0", 42 | "friendly-errors-webpack-plugin": "^1.1.2", 43 | "function-bind": "^1.0.2", 44 | "html-webpack-plugin": "^2.8.1", 45 | "http-proxy-middleware": "^0.17.2", 46 | "json-loader": "^0.5.4", 47 | "cross-env": "^3.1.3", 48 | "karma": "^1.3.0", 49 | "karma-coverage": "^1.1.1", 50 | "karma-mocha": "^1.2.0", 51 | "karma-phantomjs-launcher": "^1.0.0", 52 | "karma-sinon-chai": "^1.2.0", 53 | "karma-sourcemap-loader": "^0.3.7", 54 | "karma-spec-reporter": "0.0.26", 55 | "karma-webpack": "^1.7.0", 56 | "lolex": "^1.4.0", 57 | "mocha": "^3.1.0", 58 | "chai": "^3.5.0", 59 | "sinon": "^1.17.3", 60 | "sinon-chai": "^2.8.0", 61 | "inject-loader": "^2.0.1", 62 | "babel-plugin-istanbul": "^3.0.0", 63 | "phantomjs-prebuilt": "^2.1.3", 64 | "chromedriver": "^2.21.2", 65 | "cross-spawn": "^4.0.2", 66 | "nightwatch": "^0.9.8", 67 | "selenium-server": "2.53.1", 68 | "semver": "^5.3.0", 69 | "opn": "^4.0.2", 70 | "ora": "^0.3.0", 71 | "shelljs": "^0.7.4", 72 | "url-loader": "^0.5.7", 73 | "vue-loader": "^10.0.0", 74 | "vue-style-loader": "^1.0.0", 75 | "vue-template-compiler": "^2.1.0", 76 | "webpack": "^1.13.2", 77 | "webpack-dev-middleware": "^1.8.3", 78 | "webpack-hot-middleware": "^2.12.2", 79 | "webpack-merge": "^0.14.1" 80 | }, 81 | "engines": { 82 | "node": ">= 4.0.0", 83 | "npm": ">= 3.0.0" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 25 | 26 | 36 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/demos/22-vue-vuex/vuexdemo/src/assets/logo.png -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/src/components/Demo.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 41 | 42 | 45 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/src/components/Hello.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 33 | 34 | 35 | 54 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/src/components/TestMutation.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 42 | 43 | 46 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | import store from './store/index' 6 | 7 | /* eslint-disable no-new */ 8 | new Vue({ 9 | el: '#app', 10 | template: '', 11 | components: { App }, 12 | store: store 13 | }) 14 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/src/store/actions.js: -------------------------------------------------------------------------------- 1 | export default { 2 | addApple: function (context, count) { 3 | context.commit('addCount', count) 4 | }, 5 | removeApple: function (context, count) { 6 | context.commit('removeCount', count) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/src/store/getters.js: -------------------------------------------------------------------------------- 1 | export default { 2 | getCount (state) { 3 | return state.appleCount 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import getters from './getters' 4 | import actions from './actions' 5 | import mutations from './mutations' 6 | 7 | Vue.use(Vuex) 8 | 9 | export default new Vuex.Store({ 10 | state: { 11 | appleCount: 2 12 | }, 13 | actions, 14 | getters, 15 | mutations 16 | }) 17 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/src/store/mutations.js: -------------------------------------------------------------------------------- 1 | export default { 2 | addCount: function (state, n) { 3 | if (!isNaN(n)) { 4 | state.appleCount += n 5 | } 6 | }, 7 | removeCount: function (state, n) { 8 | if (isNaN(n)) { 9 | return 10 | } 11 | state.appleCount -= n 12 | } 13 | } 14 | 15 | //echo "UUID=7854D26A-3F53-4E2A-A3F7-4E3F8122768D none ntfs rw,auto,nobrowse" | sudo tee -a /etc/fstab 16 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/demos/22-vue-vuex/vuexdemo/static/.gitkeep -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // the name of the method is the filename. 3 | // can be used in tests like this: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // for how to write custom assertions see 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | exports.assertion = function (selector, count) { 10 | this.message = 'Testing if element <' + selector + '> has count: ' + count 11 | this.expected = count 12 | this.pass = function (val) { 13 | return val === this.expected 14 | } 15 | this.value = function (res) { 16 | return res.value 17 | } 18 | this.command = function (cb) { 19 | var self = this 20 | return this.api.execute(function (selector) { 21 | return document.querySelectorAll(selector).length 22 | }, [selector], function (res) { 23 | cb.call(self, res) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | var config = require('../../config') 3 | 4 | // http://nightwatchjs.org/guide#settings-file 5 | module.exports = { 6 | src_folders: ['test/e2e/specs'], 7 | output_folder: 'test/e2e/reports', 8 | custom_assertions_path: ['test/e2e/custom-assertions'], 9 | 10 | selenium: { 11 | start_process: true, 12 | server_path: 'node_modules/selenium-server/lib/runner/selenium-server-standalone-2.53.1.jar', 13 | host: '127.0.0.1', 14 | port: 4444, 15 | cli_args: { 16 | 'webdriver.chrome.driver': require('chromedriver').path 17 | } 18 | }, 19 | 20 | test_settings: { 21 | default: { 22 | selenium_port: 4444, 23 | selenium_host: 'localhost', 24 | silent: true, 25 | globals: { 26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port) 27 | } 28 | }, 29 | 30 | chrome: { 31 | desiredCapabilities: { 32 | browserName: 'chrome', 33 | javascriptEnabled: true, 34 | acceptSslCerts: true 35 | } 36 | }, 37 | 38 | firefox: { 39 | desiredCapabilities: { 40 | browserName: 'firefox', 41 | javascriptEnabled: true, 42 | acceptSslCerts: true 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server using production config 2 | process.env.NODE_ENV = 'testing' 3 | var server = require('../../build/dev-server.js') 4 | 5 | // 2. run the nightwatch test suite against it 6 | // to run in additional browsers: 7 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" 8 | // 2. add it to the --env flag below 9 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` 10 | // For more information on Nightwatch's config file, see 11 | // http://nightwatchjs.org/guide#settings-file 12 | var opts = process.argv.slice(2) 13 | if (opts.indexOf('--config') === -1) { 14 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) 15 | } 16 | if (opts.indexOf('--env') === -1) { 17 | opts = opts.concat(['--env', 'chrome']) 18 | } 19 | 20 | var spawn = require('cross-spawn') 21 | var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) 22 | 23 | runner.on('exit', function (code) { 24 | server.close() 25 | process.exit(code) 26 | }) 27 | 28 | runner.on('error', function (err) { 29 | server.close() 30 | throw err 31 | }) 32 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/test/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': function (browser) { 6 | // automatically uses dev Server port from /config.index.js 7 | // default: http://localhost:8080 8 | // see nightwatch.conf.js 9 | const devServer = browser.globals.devServerURL 10 | 11 | browser 12 | .url(devServer) 13 | .waitForElementVisible('#app', 5000) 14 | .assert.elementPresent('.hello') 15 | .assert.containsText('h1', 'Welcome to Your Vue.js App') 16 | .assert.elementCount('img', 1) 17 | .end() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/test/unit/index.js: -------------------------------------------------------------------------------- 1 | // Polyfill fn.bind() for PhantomJS 2 | /* eslint-disable no-extend-native */ 3 | Function.prototype.bind = require('function-bind') 4 | 5 | // require all test files (files that ends with .spec.js) 6 | const testsContext = require.context('./specs', true, /\.spec$/) 7 | testsContext.keys().forEach(testsContext) 8 | 9 | // require all src files except main.js for coverage. 10 | // you can also change this to match only the subset of files that 11 | // you want coverage for. 12 | const srcContext = require.context('src', true, /^\.\/(?!main(\.js)?$)/) 13 | srcContext.keys().forEach(srcContext) 14 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var path = require('path') 7 | var merge = require('webpack-merge') 8 | var baseConfig = require('../../build/webpack.base.conf') 9 | var utils = require('../../build/utils') 10 | var webpack = require('webpack') 11 | var projectRoot = path.resolve(__dirname, '../../') 12 | 13 | var webpackConfig = merge(baseConfig, { 14 | // use inline sourcemap for karma-sourcemap-loader 15 | module: { 16 | loaders: utils.styleLoaders() 17 | }, 18 | devtool: '#inline-source-map', 19 | vue: { 20 | loaders: { 21 | js: 'babel-loader' 22 | } 23 | }, 24 | plugins: [ 25 | new webpack.DefinePlugin({ 26 | 'process.env': require('../../config/test.env') 27 | }) 28 | ] 29 | }) 30 | 31 | // no need for app entry during tests 32 | delete webpackConfig.entry 33 | 34 | // Use babel for test files too 35 | webpackConfig.module.loaders.some(function (loader, i) { 36 | if (/^babel(-loader)?$/.test(loader.loader)) { 37 | loader.include.push(path.resolve(projectRoot, 'test/unit')) 38 | return true 39 | } 40 | }) 41 | 42 | module.exports = function (config) { 43 | config.set({ 44 | // to run in additional browsers: 45 | // 1. install corresponding karma launcher 46 | // http://karma-runner.github.io/0.13/config/browsers.html 47 | // 2. add it to the `browsers` array below. 48 | browsers: ['PhantomJS'], 49 | frameworks: ['mocha', 'sinon-chai'], 50 | reporters: ['spec', 'coverage'], 51 | files: ['./index.js'], 52 | preprocessors: { 53 | './index.js': ['webpack', 'sourcemap'] 54 | }, 55 | webpack: webpackConfig, 56 | webpackMiddleware: { 57 | noInfo: true 58 | }, 59 | coverageReporter: { 60 | dir: './coverage', 61 | reporters: [ 62 | { type: 'lcov', subdir: '.' }, 63 | { type: 'text-summary' } 64 | ] 65 | } 66 | }) 67 | } 68 | -------------------------------------------------------------------------------- /demos/22-vue-vuex/vuexdemo/test/unit/specs/Hello.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Hello from 'src/components/Hello' 3 | 4 | describe('Hello.vue', () => { 5 | it('should render correct contents', () => { 6 | const vm = new Vue({ 7 | el: document.createElement('div'), 8 | render: (h) => h(Hello) 9 | }) 10 | expect(vm.$el.querySelector('.hello h1').textContent) 11 | .to.equal('Welcome to Your Vue.js App') 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /imgs/01vue-helloworld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/imgs/01vue-helloworld.png -------------------------------------------------------------------------------- /imgs/02vue双向绑定.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/imgs/02vue双向绑定.jpg -------------------------------------------------------------------------------- /imgs/03vue响应.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/imgs/03vue响应.png -------------------------------------------------------------------------------- /imgs/04vuex模型.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/imgs/04vuex模型.png -------------------------------------------------------------------------------- /imgs/05vue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/imgs/05vue.png -------------------------------------------------------------------------------- /imgs/06vue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/imgs/06vue.png -------------------------------------------------------------------------------- /imgs/07eventbus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/imgs/07eventbus.png -------------------------------------------------------------------------------- /imgs/lifecycle-标注版本.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/imgs/lifecycle-标注版本.png -------------------------------------------------------------------------------- /imgs/父子容器数据传递.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/imgs/父子容器数据传递.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /preview/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/.DS_Store -------------------------------------------------------------------------------- /preview/01-Vue入门之概念及Helloworld.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | itcastmark:01-Vue入门之概念及Helloworld 6 | 7 | 9 | 10 | 105 | 106 | 107 | 108 |
109 | 115 |
116 |

生命在于分享,技术源于生命

117 |

学无止境,谦虚慎行,三人行必有我师.

118 |
119 |
120 | 121 |
122 |
123 |
    124 | 125 |
126 |
127 |
128 |
129 |

Vue入门之概念及Helloworld

130 |

Vue简介

131 |

Vue是一个前端的双向绑定类的框架,发音[读音 /vjuː/, 类似于 view]。新的Vue版本参考了React的部分设计,当然也有自己独特的地方,比如Vue的单文件组件开发方式都很有创新,另外Vue自身的一些绑定的语法、用法等都非常精炼,很容易上手,而且第三方的插件都非常丰富,社区非常活跃,最新的文档都有中文版本。而且Vue配合官方的和第三方的库可以实现单文件的组件化开发、SPA等现代化前端开发。
详情请参考Vue官网

132 |

Vue的入门demo

133 |

Vue 可以直接把它当做一个js库使用,所以它可以很容易的接入到你的项目或者单个页面中。甚至你可以只使用它的双向绑定功能。所以它很容易上手。

134 |

比如:我们有一个需求,一个网页上一个Div标签,我们有一个json对象存储数据,把json对象上的数据放到Div上去。

135 |

接下来是步骤:

136 |
第一步: 创建一个文件夹并创建一个html文件 比如:index.html.
137 | 当如你可以选择你自己的编辑器,我就用VSCode。
138 | 
139 | 第二步:引入Vue库
140 | <script src="https://unpkg.com/vue/dist/vue.js"></script>
141 | 当然了你可以直接下载Vue的js文件,推荐你直接用上面的cdn即可。
142 | 
143 | 第三步:创建一个Div,给它一个id,比如:app
144 | 
145 | 第四步:创建Vue的对象,并把数据绑定到上面创建好的div上去。
146 | 

最终的代码如下:

147 |
<!DOCTYPE html> <!--第一步:创建文件夹及html文件-->
148 | <html lang="en">
149 | <head>
150 |   <meta charset="UTF-8">
151 |   <title>Vue入门之Helloworld</title>
152 |   <!--第二步:引入Vue库-->
153 |   <script src="https://unpkg.com/vue/dist/vue.js"></script>
154 | </head>
155 | <body>
156 |   <!--第三步:创建一个Div-->
157 |   <div id="app">
158 |     <!--Vue的模板的绑定数据的方法, 类似于很多其他前端的模板,可以用两对花括号进行绑定Vue中的数据对象的属性 -->
159 |     {{ message }}
160 |   </div>
161 | 
162 |   <!--第四步:创建Vue的对象,并把数据绑定到上面创建好的div上去。-->
163 |   <script>
164 |     var app = new Vue({         // 创建Vue对象。Vue的核心对象。
165 |       el: '#app',               // el属性:把当前Vue对象挂载到 div标签上,#app是id选择器
166 |       data: {                   // data: 是Vue对象中绑定的数据
167 |         message: 'Hello Vue!'   // message 自定义的数据
168 |       }
169 |     });
170 |   </script>
171 | </body>
172 | </html>
173 | 
174 |

最终的结果就是:

175 |
Hello Vue!
176 | 

177 |

Vue的Helloworld总结

178 |
    179 |
  • Vue构造函数的:选项el属性,就是element缩写,当前Vue对象挂载到哪个标签上的语法,支持CSS选择器或者dom对象,一般用id选择器选择当前页面的标签。
  • 180 |
  • Vue的选项:data属性是自定义数据。这里我们只是演示了一个message属性,vue会把自定义的数据可以与html的模板数据进行绑定。
  • 181 |
  • Vue 数据绑定的方式就是用 {{}},类似于handlebars.
  • 182 |
  • 上面这个demo就是演示了Vue的绑定数据的基本模型。注意点,标签先创建好了之后,再创建Vue对象,具体你应该懂吧。
  • 183 |
184 |

helloworld

185 | 186 |
187 |
188 |
189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 208 | -------------------------------------------------------------------------------- /preview/03-Vue入门之列表渲染.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | itcastmark:03-Vue入门之列表渲染 6 | 7 | 9 | 10 | 105 | 106 | 107 | 108 |
109 | 115 |
116 |

生命在于分享,技术源于生命

117 |

学无止境,谦虚慎行,三人行必有我师.

118 |
119 |
120 | 121 |
122 |
123 |
    124 | 125 |
126 |
127 |
128 |
129 |

Vue列表渲染及条件渲染实战

130 |

条件渲染

131 |

有时候我们要根据数据的情况,决定标签是否进行显示或者有其他动作。最常见的就是,表格渲染的时候,如果表格没有数据,就显示无数据。如果有数据就显示表格数据。 132 | Vue帮我们提供了一个v-if的指令,帮助我们完成判断的模板处理。

133 |
<div id="app">
134 |   <h1 v-if="ok">Yes</h1>
135 |   <h1 v-else>No</h1>  
136 | </div>
137 | <!-- 当ok为true的时候,输出: Yes, 否则输出: No -->
138 | 
139 | <script>
140 |   var app = new Vue({         
141 |     el: '#app',               
142 |     data: {    
143 |       ok: true      // true,返回:Yes,   false=> No               
144 |     }
145 |   });
146 | </script>
147 | 
148 |

v-if指令可以根据数据绑定的情况进行插入标签或者移除标签。 149 | 当然,如果熟悉js的都清楚,有if,肯定会有else。 Vue提供的是 v-else指令。

150 |

列表渲染

151 |

基本v-for循环渲染标签

152 |

模板引擎都会提供循环的支持。Vue也不例外,Vue是提供了一个v-for指令。基本的用法类似于foreach的用法。还是看例子最直接,上代码:

153 |
<div id="app">
154 |   <table>
155 |     <thead>
156 |       <tr>
157 |         <th>姓名</th>
158 |         <th>年龄</th>
159 |         <th>地址</th>
160 |       </tr>
161 |     </thead>
162 |     <tbody> 
163 |       <!-- 每次for循环,都会创建一个tr标签。item是遍历的元素。 -->
164 |       <tr v-for="item in UserList" >
165 |         <td>{{ item.name }}</td>
166 |         <td>{{ item.age }}</td>
167 |         <td>{{ item.address }}</td>
168 |       </tr>
169 |     </tbody>
170 |   </table>
171 | </div>
172 | <script>
173 |   var app = new Vue({         
174 |     el: '#app',               
175 |     data: {                   
176 |      UserList: [
177 |       {'name': 'malun', 'age': 18, 'address': '北京黑地下室'},
178 |       {'name': 'flydragon', 'age': 22, 'address': '厦门的很多热的地方'},
179 |       {'name': 'temp', 'age': 25, 'address': '东北松花江上'}
180 |      ]
181 |     }
182 |   });
183 | </script>
184 | 
185 |

Template循环渲染多标签

186 |

上面的例子,我们演示的是 每次循环输出一个tr标签。如果我们希望每次循环生成两个tr标签呢?如果还有生成其他的标签呢?

187 |

Vue给我们提供了template标签,供我们用于v-for循环中进行处理。

188 |

上代码喽:

189 |
<ul>
190 |   <!-- 通过template标签,可以一次循环,输出两个li标签 -->
191 |   <template v-for="item in items">
192 |     <li>{{ item.msg }}</li>
193 |     <li class="divider"></li>
194 |   </template>
195 | </ul>
196 | 
197 |

关于v-for对应的数组的更新

198 |

由于Vue的机制就是检测数据的变化,自动跟新HTML。数组的变化,Vue之检测部分函数,检测的函数执行时才会触发视图更新。这些方法如下:

199 |
    200 |
  • push()
  • 201 |
  • pop()
  • 202 |
  • shift()
  • 203 |
  • unshift()
  • 204 |
  • splice()
  • 205 |
  • sort()
  • 206 |
  • reverse()
  • 207 |
208 |

表格显示的综合案例

209 |

下面是一个综合的案例,每秒钟往表格中添加一条数据。 210 | 本案例综合使用了v-if 和 v-for循环综合案例。

211 |
<!DOCTYPE html> 
212 | <html lang="en">
213 | <head>
214 |   <meta charset="UTF-8">
215 |   <title>Vue入门之动态显示表格</title>
216 |   <script src="https://unpkg.com/vue/dist/vue.js"></script>
217 | </head>
218 | <body>
219 |   <div id="app">
220 |     <table>
221 |       <thead>
222 |         <tr>
223 |           <th>姓名</th>
224 |           <th>年龄</th>
225 |           <th>地址</th>
226 |         </tr>
227 |       </thead>
228 |       <!-- 如果列表有数据,直接输出表格数据,没有数据提示用户没有数据 -->
229 |       <tbody v-if="UserList.length > 0"> 
230 |         <tr v-for="item in UserList" >
231 |           <td>{{ item.name }}</td>
232 |           <td>{{ item.age }}</td>
233 |           <td>{{ item.address }}</td>
234 |         </tr>
235 |       </tbody>
236 |       <tbody v-else>
237 |         <tr><td colspan="3">没有数据奥!</td></tr>
238 |       </tbody>
239 |     </table>
240 |   </div>
241 |   <script>
242 |     var app = new Vue({         
243 |       el: '#app',               
244 |       data: {                   
245 |        UserList: []
246 |       }
247 |     });
248 | 
249 |     // 每秒钟插入一条数据。
250 |     setInterval(function () {
251 |       app.UserList.push({'name': 'malun', 'age': 18, 'address': '北京黑地下室'});
252 |     }, 1000);
253 |   </script>
254 | </body>
255 | </html>
256 | 
257 |

总结列表和条件绑定

258 |

列表的使用其实本质还是js的衍生使用,对于有js开发基础的没有什么难度。关键是多写几个案例就会详细通了。

259 | 260 |
261 |
262 |
263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 282 | -------------------------------------------------------------------------------- /preview/04-Vue事件绑定处理.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | itcastmark:04-Vue事件绑定处理 6 | 7 | 9 | 10 | 105 | 106 | 107 | 108 |
109 | 115 |
116 |

生命在于分享,技术源于生命

117 |

学无止境,谦虚慎行,三人行必有我师.

118 |
119 |
120 | 121 |
122 |
123 |
    124 | 125 |
126 |
127 |
128 |
129 |

Vue事件处理

130 |

监听事件的Vue处理

131 |

Vue提供了协助我们为标签绑定时间的方法,当然我们可以直接用dom原生的方式去绑定事件。Vue提供的指令进行绑定也是非常方便,而且能让ViewModel更简洁,逻辑更彻底。所以还是推荐大家使用的。

132 |

Vue提供了v-on指令帮助我们进行事件的绑定。 133 | 基本的内联事件处理方法[官方demo]:

134 |
<div id="example-1">
135 |   <!-- 为按钮绑定点击事件,执行counter += 1的任务。 -->
136 |   <button v-on:click="counter += 1">增加 1</button>
137 |   <p>这个按钮被点击了 {{ counter }} 次。</p>
138 | </div>
139 | <script>
140 | var example1 = new Vue({
141 |   el: '#example-1',
142 |   data: {
143 |     counter: 0
144 |   }
145 | })
146 | </script>
147 | 
148 |

事件处理方法集成到Vue对象

149 |

内联的方式绑定的事件,只能处理简单的事件的处理逻辑。复杂的情况还是封装到js中最方便,也不容易出错。 150 | Vue对象中可以添加methods属性,开发者可以把事件处理函数的逻辑放到methods中。

151 |
<!DOCTYPE html> 
152 | <html lang="en">
153 | <head>
154 |   <meta charset="UTF-8">
155 |   <title>Vue入门之动态显示表格</title>
156 |   <script src="https://unpkg.com/vue/dist/vue.js"></script>
157 | </head>
158 | <body>
159 |   <div id="app">
160 |     <p>{{ number }}</p>
161 |     <input type="button" name="btnGetNumber" value="增加[绑定事件处理器]" v-on:click="getNumber">
162 |     <input type="button" name="btnGetNumber" value="增加[内联方法调用]" v-on:click="getNumber()">
163 |   </div>
164 |   <script>
165 |     var app = new Vue({         
166 |       el: '#app',               
167 |       data: {                   
168 |         number: 1
169 |       },
170 |       methods: {
171 |         // 事件响应方法的逻辑代码
172 |         getNumber: function (e) {
173 |           this.number += 1;   // 不管是内联方法调用,还是绑定事件处理器两种方式执行事件响应方法的时候 this都是指向 app
174 |         }
175 |       }
176 |     });
177 |   </script>
178 | </body>
179 | </html>
180 | 
181 |

事件修饰符

182 |

官网上写的非常好,这块就直接用管网的吧。在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在 methods 中轻松实现这点,但更好的方式是:methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。 183 | 为了解决这个问题, Vue.js 为 v-on 提供了 事件修饰符。通过由点(.)表示的指令后缀来调用修饰符。

184 |
    185 |
  • .stop
  • 186 |
  • .prevent
  • 187 |
  • .capture
  • 188 |
  • .self
  • 189 |
  • .once
    <!-- 阻止单击事件冒泡 -->
    190 | <a v-on:click.stop="doThis"></a>
    191 | <!-- 提交事件不再重载页面 -->
    192 | <form v-on:submit.prevent="onSubmit"></form>
    193 | <!-- 修饰符可以串联  -->
    194 | <a v-on:click.stop.prevent="doThat"></a>
    195 | <!-- 只有修饰符 -->
    196 | <form v-on:submit.prevent></form>
    197 | <!-- 添加事件侦听器时使用事件捕获模式 -->
    198 | <div v-on:click.capture="doThis">...</div>
    199 | <!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
    200 | <div v-on:click.self="doThat">...</div>
    201 | <!-- the click event will be triggered at most once -->
    202 | <a v-on:click.once="doThis"></a>
    203 | 
    204 |
  • 205 |
206 |

按键修饰符

207 |

在监听键盘事件时,我们经常需要监测常见的键值。 Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

208 |
<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
209 | <input v-on:keyup.13="submit">
210 | 记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:
211 | <!-- 同上 -->
212 | <input v-on:keyup.enter="submit">
213 | <!-- 缩写语法 -->
214 | <input @keyup.enter="submit">
215 | 
216 |

全部的按键别名:

217 |
    218 |
  • .enter
  • 219 |
  • .tab
  • 220 |
  • .delete (捕获 “删除” 和 “退格” 键)
  • 221 |
  • .esc
  • 222 |
  • .space
  • 223 |
  • .up
  • 224 |
  • .down
  • 225 |
  • .left
  • 226 |
  • .right
  • 227 |
  • .ctrl
  • 228 |
  • .alt
  • 229 |
  • .shift
  • 230 |
  • .meta
  • 231 |
232 |

事件绑定的简写

233 |

Vue中属性的绑定的简写直接是: === 'v-bind:'
而事件的缩写是直接变成@. 也就是说: v-on: === @ 234 | 看下面的例子:

235 |
<!-- 完整语法 -->
236 | <a v-on:click="doSomething"></a>
237 | <!-- 缩写 -->
238 | <a @click="doSomething"></a>
239 | 
240 |

事件绑定总结

241 |

Vue为了方便大家进行开发,提供了事件的相关的封装,可以让我们方便我们用Vue对事件进行开发,尤其是v-on指令的非常方便的跟Vue对象中methods进行配合进行复杂的事件处理,非常方便。另外事件的事件修饰符和按键修饰符也可以让Vue事件这块锦上添花。

242 | 243 |
244 |
245 |
246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 265 | -------------------------------------------------------------------------------- /preview/04-Vue入门之事件绑定处理.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | itcastmark:04-Vue入门之事件绑定处理 6 | 7 | 9 | 10 | 105 | 106 | 107 | 108 |
109 | 115 |
116 |

生命在于分享,技术源于生命

117 |

学无止境,谦虚慎行,三人行必有我师.

118 |
119 |
120 | 121 |
122 |
123 |
    124 | 125 |
126 |
127 |
128 |
129 |

Vue事件处理

130 |

监听事件的Vue处理

131 |

Vue提供了协助我们为标签绑定时间的方法,当然我们可以直接用dom原生的方式去绑定事件。Vue提供的指令进行绑定也是非常方便,而且能让ViewModel更简洁,逻辑更彻底。所以还是推荐大家使用的。

132 |

Vue提供了v-on指令帮助我们进行事件的绑定。 133 | 基本的内联事件处理方法[官方demo]:

134 |
<div id="example-1">
135 |   <!-- 为按钮绑定点击事件,执行counter += 1的任务。 -->
136 |   <button v-on:click="counter += 1">增加 1</button>
137 |   <p>这个按钮被点击了 {{ counter }} 次。</p>
138 | </div>
139 | <script>
140 | var example1 = new Vue({
141 |   el: '#example-1',
142 |   data: {
143 |     counter: 0
144 |   }
145 | })
146 | </script>
147 | 
148 |

事件处理方法集成到Vue对象

149 |

内联的方式绑定的事件,只能处理简单的事件的处理逻辑。复杂的情况还是封装到js中最方便,也不容易出错。 150 | Vue对象中可以添加methods属性,开发者可以把事件处理函数的逻辑放到methods中。

151 |
<!DOCTYPE html> 
152 | <html lang="en">
153 | <head>
154 |   <meta charset="UTF-8">
155 |   <title>Vue入门之动态显示表格</title>
156 |   <script src="https://unpkg.com/vue/dist/vue.js"></script>
157 | </head>
158 | <body>
159 |   <div id="app">
160 |     <p>{{ number }}</p>
161 |     <input type="button" name="btnGetNumber" value="增加[绑定事件处理器]" v-on:click="getNumber">
162 |     <input type="button" name="btnGetNumber" value="增加[内联方法调用]" v-on:click="getNumber()">
163 |   </div>
164 |   <script>
165 |     var app = new Vue({         
166 |       el: '#app',               
167 |       data: {                   
168 |         number: 1
169 |       },
170 |       methods: {
171 |         // 事件响应方法的逻辑代码
172 |         getNumber: function (e) {
173 |           this.number += 1;   // 不管是内联方法调用,还是绑定事件处理器两种方式执行事件响应方法的时候 this都是指向 app
174 |         }
175 |       }
176 |     });
177 |   </script>
178 | </body>
179 | </html>
180 | 
181 |

事件修饰符

182 |

官网上写的非常好,这块就直接用管网的吧。在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在 methods 中轻松实现这点,但更好的方式是:methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。 183 | 为了解决这个问题, Vue.js 为 v-on 提供了 事件修饰符。通过由点(.)表示的指令后缀来调用修饰符。

184 |
    185 |
  • .stop
  • 186 |
  • .prevent
  • 187 |
  • .capture
  • 188 |
  • .self
  • 189 |
  • .once
    <!-- 阻止单击事件冒泡 -->
    190 | <a v-on:click.stop="doThis"></a>
    191 | <!-- 提交事件不再重载页面 -->
    192 | <form v-on:submit.prevent="onSubmit"></form>
    193 | <!-- 修饰符可以串联  -->
    194 | <a v-on:click.stop.prevent="doThat"></a>
    195 | <!-- 只有修饰符 -->
    196 | <form v-on:submit.prevent></form>
    197 | <!-- 添加事件侦听器时使用事件捕获模式 -->
    198 | <div v-on:click.capture="doThis">...</div>
    199 | <!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
    200 | <div v-on:click.self="doThat">...</div>
    201 | <!-- the click event will be triggered at most once -->
    202 | <a v-on:click.once="doThis"></a>
    203 | 
    204 |
  • 205 |
206 |

按键修饰符

207 |

在监听键盘事件时,我们经常需要监测常见的键值。 Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

208 |
<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
209 | <input v-on:keyup.13="submit">
210 | 记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:
211 | <!-- 同上 -->
212 | <input v-on:keyup.enter="submit">
213 | <!-- 缩写语法 -->
214 | <input @keyup.enter="submit">
215 | 
216 |

全部的按键别名:

217 |
    218 |
  • .enter
  • 219 |
  • .tab
  • 220 |
  • .delete (捕获 “删除” 和 “退格” 键)
  • 221 |
  • .esc
  • 222 |
  • .space
  • 223 |
  • .up
  • 224 |
  • .down
  • 225 |
  • .left
  • 226 |
  • .right
  • 227 |
  • .ctrl
  • 228 |
  • .alt
  • 229 |
  • .shift
  • 230 |
  • .meta
  • 231 |
232 |

事件绑定的简写

233 |

Vue中属性的绑定的简写直接是: === 'v-bind:'
而事件的缩写是直接变成@. 也就是说: v-on: === @ 234 | 看下面的例子:

235 |
<!-- 完整语法 -->
236 | <a v-on:click="doSomething"></a>
237 | <!-- 缩写 -->
238 | <a @click="doSomething"></a>
239 | 
240 |

事件绑定总结

241 |

Vue为了方便大家进行开发,提供了事件的相关的封装,可以让我们方便我们用Vue对事件进行开发,尤其是v-on指令的非常方便的跟Vue对象中methods进行配合进行复杂的事件处理,非常方便。另外事件的事件修饰符和按键修饰符也可以让Vue事件这块锦上添花。

242 | 243 |
244 |
245 |
246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 265 | -------------------------------------------------------------------------------- /preview/09-Vue入门之Filter过滤器.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | itcastmark:09-Vue入门之Filter过滤器 6 | 7 | 9 | 10 | 105 | 106 | 107 | 108 |
109 | 115 |
116 |

生命在于分享,技术源于生命

117 |

学无止境,谦虚慎行,三人行必有我师.

118 |
119 |
120 | 121 |
122 |
123 |
    124 | 125 |
126 |
127 |
128 |
129 |

Vue入门之Filter过滤器

130 | 131 |
132 |
133 |
134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 153 | -------------------------------------------------------------------------------- /preview/imgs/01vue-helloworld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/imgs/01vue-helloworld.png -------------------------------------------------------------------------------- /preview/imgs/02vue双向绑定.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/imgs/02vue双向绑定.jpg -------------------------------------------------------------------------------- /preview/imgs/03vue响应.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/imgs/03vue响应.png -------------------------------------------------------------------------------- /preview/imgs/04vuex模型.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/imgs/04vuex模型.png -------------------------------------------------------------------------------- /preview/imgs/05vue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/imgs/05vue.png -------------------------------------------------------------------------------- /preview/imgs/06vue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/imgs/06vue.png -------------------------------------------------------------------------------- /preview/imgs/07eventbus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/imgs/07eventbus.png -------------------------------------------------------------------------------- /preview/imgs/lifecycle-标注版本.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/imgs/lifecycle-标注版本.png -------------------------------------------------------------------------------- /preview/imgs/父子容器数据传递.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/imgs/父子容器数据传递.png -------------------------------------------------------------------------------- /preview/toc/css/demo.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { 2 | margin: 0;padding: 0;border: 0;outline: 0;font-weight: inherit;font-style: inherit;font-size: 100%;font-family: inherit;vertical-align: baseline;} 3 | body {color: #2f332a;font: 15px/21px Arial, Helvetica, simsun, sans-serif;background: #f0f6e4 \9;} 4 | h1, h2, h3, h4, h5, h6 {color: #2f332a;font-weight: bold;font-family: Helvetica, Arial, sans-serif;padding-bottom: 5px;} 5 | h1 {font-size: 24px;line-height: 34px;text-align: center;} 6 | h2 {font-size: 14px;line-height: 24px;padding-top: 5px;} 7 | h6 {font-weight: normal;font-size: 12px;letter-spacing: 1px;line-height: 24px;text-align: center;} 8 | a {color:#3C6E31;text-decoration: underline;} 9 | a:hover {background-color:#3C6E31;color:white;} 10 | input.radio {margin: 0 2px 0 8px;} 11 | input.radio.first {margin-left:0;} 12 | input.empty {color: lightgray;} 13 | code {color: #2f332a;} 14 | .highlight_red {color:#A60000;} 15 | .highlight_green {color:#A7F43D;} 16 | li {list-style: circle;font-size: 12px;} 17 | li.title {list-style: none;} 18 | ul.list {margin-left: 17px;} 19 | 20 | div.content_wrap {width: 600px;height:380px;} 21 | div.content_wrap div.left{float: left;width: 250px;} 22 | div.content_wrap div.right{float: right;width: 340px;} 23 | div.zTreeDemoBackground {width:250px;height:362px;text-align:left;} 24 | 25 | ul.ztree {margin-top: 10px;border: 1px solid #617775;background: #f0f6e4;width:220px;height:360px;overflow-y:scroll;overflow-x:auto;} 26 | ul.log {border: 1px solid #617775;background: #f0f6e4;width:300px;height:170px;overflow: hidden;} 27 | ul.log.small {height:45px;} 28 | ul.log li {color: #666666;list-style: none;padding-left: 10px;} 29 | ul.log li.dark {background-color: #E3E3E3;} 30 | 31 | /* ruler */ 32 | div.ruler {height:20px; width:220px; background-color:#f0f6e4;border: 1px solid #333; margin-bottom: 5px; cursor: pointer} 33 | div.ruler div.cursor {height:20px; width:30px; background-color:#3C6E31; color:white; text-align: right; padding-right: 5px; cursor: pointer} -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/diy/1_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/diy/1_close.png -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/diy/1_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/diy/1_open.png -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/diy/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/diy/2.png -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/diy/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/diy/3.png -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/diy/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/diy/4.png -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/diy/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/diy/5.png -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/diy/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/diy/6.png -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/diy/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/diy/7.png -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/diy/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/diy/8.png -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/diy/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/diy/9.png -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/line_conn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/line_conn.gif -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/loading.gif -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/zTreeStandard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/zTreeStandard.gif -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/img/zTreeStandard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malun666/vue-stepbystep/1ac8a1b7c768dbb8a40b55390f6f5aa86f0e3ba5/preview/toc/css/zTreeStyle/img/zTreeStandard.png -------------------------------------------------------------------------------- /preview/toc/css/zTreeStyle/zTreeStyle.css: -------------------------------------------------------------------------------- 1 | /*------------------------------------- 2 | zTree Style 3 | 4 | version: 3.4 5 | author: Hunter.z 6 | email: hunter.z@263.net 7 | website: http://code.google.com/p/jquerytree/ 8 | 9 | -------------------------------------*/ 10 | 11 | .ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif} 12 | .ztree {margin:0; padding:5px; color:#333} 13 | .ztree li{padding:0; margin:0; list-style:none; line-height:14px; text-align:left; white-space:nowrap; outline:0} 14 | .ztree li ul{ margin:0; padding:0 0 0 18px} 15 | .ztree li ul.line{ background:url(./img/line_conn.gif) 0 0 repeat-y;} 16 | 17 | .ztree li a {padding:1px 3px 0 0; margin:0; cursor:pointer; height:17px; color:#333; background-color: transparent; 18 | text-decoration:none; vertical-align:top; display: inline-block} 19 | .ztree li a:hover {text-decoration:underline} 20 | .ztree li a.curSelectedNode {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;} 21 | .ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;} 22 | .ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#316AC5; color:white; height:16px; border:1px #316AC5 solid; 23 | opacity:0.8; filter:alpha(opacity=80)} 24 | .ztree li a.tmpTargetNode_prev {} 25 | .ztree li a.tmpTargetNode_next {} 26 | .ztree li a input.rename {height:14px; width:80px; padding:0; margin:0; 27 | font-size:12px; border:1px #7EC4CC solid; *border:0px} 28 | .ztree li span {line-height:16px; margin-right:2px} 29 | .ztree li span.button {line-height:0; margin:0; width:16px; height:16px; display: inline-block; vertical-align:middle; 30 | border:0 none; cursor: pointer;outline:none; 31 | background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; 32 | background-image:url("./img/zTreeStandard.png"); *background-image:url("./img/zTreeStandard.gif")} 33 | 34 | .ztree li span.button.chk {width:13px; height:13px; margin:0 3px 0 0; cursor: auto} 35 | .ztree li span.button.chk.checkbox_false_full {background-position:0 0} 36 | .ztree li span.button.chk.checkbox_false_full_focus {background-position:0 -14px} 37 | .ztree li span.button.chk.checkbox_false_part {background-position:0 -28px} 38 | .ztree li span.button.chk.checkbox_false_part_focus {background-position:0 -42px} 39 | .ztree li span.button.chk.checkbox_false_disable {background-position:0 -56px} 40 | .ztree li span.button.chk.checkbox_true_full {background-position:-14px 0} 41 | .ztree li span.button.chk.checkbox_true_full_focus {background-position:-14px -14px} 42 | .ztree li span.button.chk.checkbox_true_part {background-position:-14px -28px} 43 | .ztree li span.button.chk.checkbox_true_part_focus {background-position:-14px -42px} 44 | .ztree li span.button.chk.checkbox_true_disable {background-position:-14px -56px} 45 | .ztree li span.button.chk.radio_false_full {background-position:-28px 0} 46 | .ztree li span.button.chk.radio_false_full_focus {background-position:-28px -14px} 47 | .ztree li span.button.chk.radio_false_part {background-position:-28px -28px} 48 | .ztree li span.button.chk.radio_false_part_focus {background-position:-28px -42px} 49 | .ztree li span.button.chk.radio_false_disable {background-position:-28px -56px} 50 | .ztree li span.button.chk.radio_true_full {background-position:-42px 0} 51 | .ztree li span.button.chk.radio_true_full_focus {background-position:-42px -14px} 52 | .ztree li span.button.chk.radio_true_part {background-position:-42px -28px} 53 | .ztree li span.button.chk.radio_true_part_focus {background-position:-42px -42px} 54 | .ztree li span.button.chk.radio_true_disable {background-position:-42px -56px} 55 | 56 | .ztree li span.button.switch {width:18px; height:18px} 57 | .ztree li span.button.root_open{background-position:-92px -54px} 58 | .ztree li span.button.root_close{background-position:-74px -54px} 59 | .ztree li span.button.roots_open{background-position:-92px 0} 60 | .ztree li span.button.roots_close{background-position:-74px 0} 61 | .ztree li span.button.center_open{background-position:-92px -18px} 62 | .ztree li span.button.center_close{background-position:-74px -18px} 63 | .ztree li span.button.bottom_open{background-position:-92px -36px} 64 | .ztree li span.button.bottom_close{background-position:-74px -36px} 65 | .ztree li span.button.noline_open{background-position:-92px -72px} 66 | .ztree li span.button.noline_close{background-position:-74px -72px} 67 | .ztree li span.button.root_docu{ background:none;} 68 | .ztree li span.button.roots_docu{background-position:-56px 0} 69 | .ztree li span.button.center_docu{background-position:-56px -18px} 70 | .ztree li span.button.bottom_docu{background-position:-56px -36px} 71 | .ztree li span.button.noline_docu{ background:none;} 72 | 73 | .ztree li span.button.ico_open{margin-right:2px; background-position:-110px -16px; vertical-align:top; *vertical-align:middle} 74 | .ztree li span.button.ico_close{margin-right:2px; background-position:-110px 0; vertical-align:top; *vertical-align:middle} 75 | .ztree li span.button.ico_docu{margin-right:2px; background-position:-110px -32px; vertical-align:top; *vertical-align:middle} 76 | .ztree li span.button.edit {margin-right:2px; background-position:-110px -48px; vertical-align:top; *vertical-align:middle} 77 | .ztree li span.button.remove {margin-right:2px; background-position:-110px -64px; vertical-align:top; *vertical-align:middle} 78 | 79 | .ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle} 80 | 81 | ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)} 82 | 83 | span.tmpzTreeMove_arrow {width:16px; height:16px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute; 84 | background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; 85 | background-position:-110px -80px; background-image:url("./img/zTreeStandard.png"); *background-image:url("./img/zTreeStandard.gif")} 86 | 87 | ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)} 88 | .zTreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute} 89 | 90 | /* level style*/ 91 | /*.ztree li span.button.level0 { 92 | display:none; 93 | } 94 | .ztree li ul.level0 { 95 | padding:0; 96 | background:none; 97 | }*/ -------------------------------------------------------------------------------- /preview/toc/js/ztree_toc.js: -------------------------------------------------------------------------------- 1 | /*! ztree_toc - v0.2.2 - 2014-02-08 2 | * https://github.com/i5ting/jQuery.zTree_Toc.js 3 | * Copyright (c) 2014 alfred.sang; Licensed MIT */ 4 | function encode_id_with_array(opts,arr) { 5 | var result = 0; 6 | for(var z = 0; z < arr.length; z++ ) { 7 | result += factor(opts, arr.length - z ,arr[z]); 8 | } 9 | 10 | return result; 11 | } 12 | 13 | 14 | /** 15 | * 1.1.1 = 1*100*100 + 1*100 + 1 16 | * 1.2.2 = 1*100*100 + 2*100 + 3 17 | * 18 | * 1 = 0*100 +1 19 | 20 | 1,1 = 100 21 | 22 | */ 23 | function get_parent_id_with_array(opts,arr) { 24 | var result_arr = []; 25 | 26 | for(var z = 0; z < arr.length; z++ ) { 27 | result_arr.push(arr[z]); 28 | } 29 | 30 | result_arr.pop(); 31 | 32 | var result = 0; 33 | for(var z = 0; z < result_arr.length; z++ ) { 34 | result += factor(opts,result_arr.length - z,result_arr[z]); 35 | } 36 | 37 | return result; 38 | } 39 | 40 | function factor(opts ,count,current) { 41 | if(1 == count) { 42 | return current; 43 | } 44 | 45 | var str = ''; 46 | for(var i = count - 1;i > 0; i-- ) { 47 | str += current * opts.step+'*'; 48 | } 49 | 50 | return eval( str + '1' ); 51 | } 52 | 53 | ;(function($) { 54 | /* 55 | * 根据header创建目录内容 56 | */ 57 | function create_toc(opts) { 58 | $(opts.documment_selector).find(':header').each(function() { 59 | var level = parseInt(this.nodeName.substring(1), 10); 60 | 61 | _rename_header_content(opts,this,level); 62 | 63 | _add_header_node(opts,$(this)); 64 | });//end each 65 | } 66 | 67 | /* 68 | * 渲染ztree 69 | */ 70 | function render_with_ztree(opts) { 71 | var t = $(opts._zTree); 72 | t = $.fn.zTree.init(t,opts.ztreeSetting,opts._header_nodes).expandAll(opts.is_expand_all); 73 | // alert(opts._headers * 88); 74 | // $(opts._zTree).height(opts._headers * 33 + 33); 75 | 76 | $(opts._zTree).css(opts.ztreeStyle); 77 | } 78 | 79 | /* 80 | * 将已有header编号,并重命名 81 | */ 82 | function _rename_header_content(opts ,header_obj ,level) { 83 | if(opts._headers.length == level) { 84 | opts._headers[level - 1]++; 85 | } else if(opts._headers.length > level) { 86 | opts._headers = opts._headers.slice(0, level); 87 | opts._headers[level - 1] ++; 88 | } else if(opts._headers.length < level) { 89 | for(var i = 0; i < (level - opts._headers.length); i++) { 90 | // console.log('push 1'); 91 | opts._headers.push(1); 92 | } 93 | } 94 | 95 | if(opts.is_auto_number == true) { 96 | //另存为的文件里会有编号,所以有编号的就不再重新替换 97 | if($(header_obj).text().indexOf( opts._headers.join('.') ) != -1){ 98 | 99 | }else{ 100 | $(header_obj).text(opts._headers.join('.') + '. ' + $(header_obj).text()); 101 | } 102 | } 103 | } 104 | 105 | /* 106 | * 给ztree用的header_nodes增加数据 107 | */ 108 | function _add_header_node(opts ,header_obj) { 109 | var id = encode_id_with_array(opts,opts._headers); 110 | var pid = get_parent_id_with_array(opts,opts._headers); 111 | 112 | // 设置锚点id 113 | $(header_obj).attr('id',id); 114 | 115 | log($(header_obj).text()); 116 | 117 | opts._header_offsets.push($(header_obj).offset().top - opts.highlight_offset); 118 | 119 | log('h offset ='+( $(header_obj).offset().top - opts.highlight_offset ) ); 120 | 121 | opts._header_nodes.push({ 122 | id:id, 123 | pId:pid , 124 | name:$(header_obj).text()||'null', 125 | open:true, 126 | url:'#'+ id, 127 | target:'_self' 128 | }); 129 | } 130 | 131 | /* 132 | * 根据滚动确定当前位置,并更新ztree 133 | */ 134 | function bind_scroll_event_and_update_postion(opts) { 135 | var timeout; 136 | var highlight_on_scroll = function(e) { 137 | if (timeout) { 138 | clearTimeout(timeout); 139 | } 140 | 141 | timeout = setTimeout(function() { 142 | var top = $(window).scrollTop(),highlighted; 143 | 144 | if(opts.debug) console.log('top='+top); 145 | 146 | for (var i = 0, c = opts._header_offsets.length; i < c; i++) { 147 | // fixed: top+5防止点击ztree的时候,出现向上抖动的情况 148 | if (opts._header_offsets[i] >= (top + 5) ) { 149 | console.log('opts._header_offsets['+ i +'] = '+opts._header_offsets[i]); 150 | $('a').removeClass('curSelectedNode'); 151 | 152 | // 由于有root节点,所以i应该从1开始 153 | var obj = $('#tree_' + (i+1) + '_a').addClass('curSelectedNode'); 154 | break; 155 | } 156 | } 157 | }, opts.refresh_scroll_time); 158 | }; 159 | 160 | if (opts.highlight_on_scroll) { 161 | $(window).bind('scroll', highlight_on_scroll); 162 | highlight_on_scroll(); 163 | } 164 | } 165 | 166 | /* 167 | * 初始化 168 | */ 169 | function init_with_config(opts) { 170 | opts.highlight_offset = $(opts.documment_selector).offset().top; 171 | } 172 | 173 | /* 174 | * 日志 175 | */ 176 | function log(str) { 177 | return; 178 | if($.fn.ztree_toc.defaults.debug == true) { 179 | console.log(str); 180 | } 181 | } 182 | 183 | $.fn.ztree_toc = function(options) { 184 | // 将defaults 和 options 参数合并到{} 185 | var opts = $.extend({},$.fn.ztree_toc.defaults,options); 186 | 187 | return this.each(function() { 188 | opts._zTree = $(this); 189 | 190 | // 初始化 191 | init_with_config(opts); 192 | 193 | // 创建目录导航,获取元数据_headers 194 | create_toc(opts); 195 | 196 | // 根据_headers生成ztree 197 | render_with_ztree(opts); 198 | 199 | // 根据滚动确定当前位置,并更新ztree 200 | bind_scroll_event_and_update_postion(opts); 201 | }); 202 | // each end 203 | } 204 | 205 | //定义默认 206 | $.fn.ztree_toc.defaults = { 207 | _zTree: null, 208 | _headers: [], 209 | _header_offsets: [], 210 | _header_nodes: [{ id:1, pId:0, name:"目录导航",open:true}], 211 | debug: true, 212 | highlight_offset: 0, 213 | highlight_on_scroll: true, 214 | /* 215 | * 计算滚动判断当前位置的时间,默认是50毫秒 216 | */ 217 | refresh_scroll_time: 50, 218 | documment_selector: 'body', 219 | is_posion_top: false, 220 | /* 221 | * 默认是否显示header编号 222 | */ 223 | is_auto_number: false, 224 | /* 225 | * 默认是否展开全部 226 | */ 227 | is_expand_all: true, 228 | /* 229 | * 是否对选中行,显示高亮效果 230 | */ 231 | is_highlight_selected_line: true, 232 | step: 100, 233 | ztreeStyle: { 234 | width:'260px', 235 | overflow: 'auto', 236 | position: 'fixed', 237 | 'z-index': 2147483647, 238 | border: '0px none', 239 | left: '0px', 240 | bottom: '0px', 241 | // height:'100px' 242 | }, 243 | ztreeSetting: { 244 | view: { 245 | dblClickExpand: false, 246 | showLine: true, 247 | showIcon: false, 248 | selectedMulti: false 249 | }, 250 | data: { 251 | simpleData: { 252 | enable: true, 253 | idKey : "id", 254 | pIdKey: "pId", 255 | // rootPId: "0" 256 | } 257 | }, 258 | callback: { 259 | beforeClick: function(treeId, treeNode) { 260 | $('a').removeClass('curSelectedNode'); 261 | if(treeNode.id == 1){ 262 | // TODO: when click root node 263 | console.log('click root 目录导航'); 264 | } 265 | if($.fn.ztree_toc.defaults.is_highlight_selected_line == true) { 266 | $('#' + treeNode.id).css('color' ,'red').fadeOut("slow" ,function() { 267 | // Animation complete. 268 | $(this).show().css('color','black'); 269 | }); 270 | } 271 | }, 272 | onRightClick: function(event, treeId, treeNode) { 273 | if(treeNode.id == 1){ 274 | // TODO: when right_click root node:table content 275 | console.log('right_click root 目录导航'); 276 | } 277 | } 278 | } 279 | } 280 | }; 281 | 282 | })(jQuery); -------------------------------------------------------------------------------- /preview/toc/js/ztree_toc.min.js: -------------------------------------------------------------------------------- 1 | /*! ztree_toc - v0.2.2 - 2014-02-08 2 | * https://github.com/i5ting/jQuery.zTree_Toc.js 3 | * Copyright (c) 2014 alfred.sang; Licensed MIT */ 4 | function encode_id_with_array(a,b){for(var c=0,d=0;d0;i--)str+=current*opts.step+"*";return eval(str+"1")}!function(a){function b(b){a(b.documment_selector).find(":header").each(function(){var c=parseInt(this.nodeName.substring(1),10);d(b,this,c),e(b,a(this))})}function c(b){var c=a(b._zTree);c=a.fn.zTree.init(c,b.ztreeSetting,b._header_nodes).expandAll(b.is_expand_all),a(b._zTree).css(b.ztreeStyle)}function d(b,c,d){if(b._headers.length==d)b._headers[d-1]++;else if(b._headers.length>d)b._headers=b._headers.slice(0,d),b._headers[d-1]++;else if(b._headers.lengthd;d++)if(b._header_offsets[d]>=c+5){console.log("opts._header_offsets["+d+"] = "+b._header_offsets[d]),a("a").removeClass("curSelectedNode"),a("#tree_"+(d+1)+"_a").addClass("curSelectedNode");break}},b.refresh_scroll_time)};b.highlight_on_scroll&&(a(window).bind("scroll",d),d())}function g(b){b.highlight_offset=a(b.documment_selector).offset().top}function h(a){}a.fn.ztree_toc=function(d){var e=a.extend({},a.fn.ztree_toc.defaults,d);return this.each(function(){e._zTree=a(this),g(e),b(e),c(e),f(e)})},a.fn.ztree_toc.defaults={_zTree:null,_headers:[],_header_offsets:[],_header_nodes:[{id:1,pId:0,name:"目录导航",open:!0}],debug:!0,highlight_offset:0,highlight_on_scroll:!0,refresh_scroll_time:50,documment_selector:"body",is_posion_top:!1,is_auto_number:!1,is_expand_all:!0,is_highlight_selected_line:!0,step:100,ztreeStyle:{width:"260px",overflow:"auto",position:"fixed","z-index":2147483647,border:"0px none",left:"0px",bottom:"0px"},ztreeSetting:{view:{dblClickExpand:!1,showLine:!0,showIcon:!1,selectedMulti:!1},data:{simpleData:{enable:!0,idKey:"id",pIdKey:"pId"}},callback:{beforeClick:function(b,c){a("a").removeClass("curSelectedNode"),1==c.id&&console.log("click root 目录导航"),1==a.fn.ztree_toc.defaults.is_highlight_selected_line&&a("#"+c.id).css("color","red").fadeOut("slow",function(){a(this).show().css("color","black")})},onRightClick:function(a,b,c){1==c.id&&console.log("right_click root 目录导航")}}}}}(jQuery); -------------------------------------------------------------------------------- /preview/toc/style/Clearness Dark.css: -------------------------------------------------------------------------------- 1 | h1, 2 | h2, 3 | h3, 4 | h4, 5 | h5, 6 | h6, 7 | p, 8 | blockquote { 9 | margin: 0; 10 | padding: 0; 11 | } 12 | body { 13 | font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif; 14 | font-size: 13px; 15 | line-height: 18px; 16 | color: #fff; 17 | background-color: #282a36; 18 | margin: 10px 13px 10px 13px; 19 | } 20 | table { 21 | margin: 10px 0 15px 0; 22 | border-collapse: collapse; 23 | } 24 | td,th { 25 | border: 1px solid #ddd; 26 | padding: 3px 10px; 27 | } 28 | th { 29 | padding: 5px 10px; 30 | } 31 | a { 32 | color: #59acf3; 33 | } 34 | a:hover { 35 | color: #a7d8ff; 36 | text-decoration: none; 37 | } 38 | a img { 39 | border: none; 40 | } 41 | p { 42 | margin-bottom: 9px; 43 | } 44 | h1, 45 | h2, 46 | h3, 47 | h4, 48 | h5, 49 | h6 { 50 | color: #fff; 51 | line-height: 36px; 52 | } 53 | h1 { 54 | margin-bottom: 18px; 55 | font-size: 30px; 56 | } 57 | h2 { 58 | font-size: 24px; 59 | } 60 | h3 { 61 | font-size: 18px; 62 | } 63 | h4 { 64 | font-size: 16px; 65 | } 66 | h5 { 67 | font-size: 14px; 68 | } 69 | h6 { 70 | font-size: 13px; 71 | } 72 | hr { 73 | margin: 0 0 19px; 74 | border: 0; 75 | border-bottom: 1px solid #ccc; 76 | } 77 | blockquote { 78 | padding: 13px 13px 21px 15px; 79 | margin-bottom: 18px; 80 | font-family:georgia,serif; 81 | font-style: italic; 82 | } 83 | blockquote:before { 84 | content:"\201C"; 85 | font-size:40px; 86 | margin-left:-10px; 87 | font-family:georgia,serif; 88 | color:#eee; 89 | } 90 | blockquote p { 91 | font-size: 14px; 92 | font-weight: 300; 93 | line-height: 18px; 94 | margin-bottom: 0; 95 | font-style: italic; 96 | } 97 | code, pre { 98 | font-family: Monaco, Andale Mono, Courier New, monospace; 99 | } 100 | code { 101 | color: #ff4a14; 102 | padding: 1px 3px; 103 | font-size: 12px; 104 | -webkit-border-radius: 3px; 105 | -moz-border-radius: 3px; 106 | border-radius: 3px; 107 | } 108 | pre { 109 | display: block; 110 | padding: 14px; 111 | margin: 0 0 18px; 112 | line-height: 16px; 113 | font-size: 11px; 114 | border: 1px solid #bf370f; 115 | white-space: pre; 116 | white-space: pre-wrap; 117 | word-wrap: break-word; 118 | } 119 | pre code { 120 | background-color: #282a36; 121 | color: #ff4a14; 122 | font-size: 11px; 123 | padding: 0; 124 | } 125 | sup { 126 | font-size: 0.83em; 127 | vertical-align: super; 128 | line-height: 0; 129 | } 130 | * { 131 | -webkit-print-color-adjust: exact; 132 | } 133 | @media screen and (min-width: 914px) { 134 | body { 135 | width: 854px; 136 | margin:10px auto; 137 | } 138 | } 139 | @media print { 140 | body,code,pre code,h1,h2,h3,h4,h5,h6 { 141 | color: black; 142 | } 143 | table, pre { 144 | page-break-inside: avoid; 145 | } 146 | } -------------------------------------------------------------------------------- /preview/toc/style/Clearness.css: -------------------------------------------------------------------------------- 1 | h1, 2 | h2, 3 | h3, 4 | h4, 5 | h5, 6 | h6, 7 | p, 8 | blockquote { 9 | margin: 0; 10 | padding: 0; 11 | } 12 | body { 13 | font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif; 14 | font-size: 13px; 15 | line-height: 18px; 16 | color: #737373; 17 | background-color: white; 18 | margin: 10px 13px 10px 13px; 19 | } 20 | table { 21 | margin: 10px 0 15px 0; 22 | border-collapse: collapse; 23 | } 24 | td,th { 25 | border: 1px solid #ddd; 26 | padding: 3px 10px; 27 | } 28 | th { 29 | padding: 5px 10px; 30 | } 31 | 32 | a { 33 | color: #0069d6; 34 | } 35 | a:hover { 36 | color: #0050a3; 37 | text-decoration: none; 38 | } 39 | a img { 40 | border: none; 41 | } 42 | p { 43 | margin-bottom: 9px; 44 | } 45 | h1, 46 | h2, 47 | h3, 48 | h4, 49 | h5, 50 | h6 { 51 | color: #404040; 52 | line-height: 36px; 53 | } 54 | h1 { 55 | margin-bottom: 18px; 56 | font-size: 30px; 57 | } 58 | h2 { 59 | font-size: 24px; 60 | } 61 | h3 { 62 | font-size: 18px; 63 | } 64 | h4 { 65 | font-size: 16px; 66 | } 67 | h5 { 68 | font-size: 14px; 69 | } 70 | h6 { 71 | font-size: 13px; 72 | } 73 | hr { 74 | margin: 0 0 19px; 75 | border: 0; 76 | border-bottom: 1px solid #ccc; 77 | } 78 | blockquote { 79 | padding: 13px 13px 21px 15px; 80 | margin-bottom: 18px; 81 | font-family:georgia,serif; 82 | font-style: italic; 83 | } 84 | blockquote:before { 85 | content:"\201C"; 86 | font-size:40px; 87 | margin-left:-10px; 88 | font-family:georgia,serif; 89 | color:#eee; 90 | } 91 | blockquote p { 92 | font-size: 14px; 93 | font-weight: 300; 94 | line-height: 18px; 95 | margin-bottom: 0; 96 | font-style: italic; 97 | } 98 | code, pre { 99 | font-family: Monaco, Andale Mono, Courier New, monospace; 100 | } 101 | code { 102 | background-color: #fee9cc; 103 | color: rgba(0, 0, 0, 0.75); 104 | padding: 1px 3px; 105 | font-size: 12px; 106 | -webkit-border-radius: 3px; 107 | -moz-border-radius: 3px; 108 | border-radius: 3px; 109 | } 110 | pre { 111 | display: block; 112 | padding: 14px; 113 | margin: 0 0 18px; 114 | line-height: 16px; 115 | font-size: 11px; 116 | border: 1px solid #d9d9d9; 117 | white-space: pre-wrap; 118 | word-wrap: break-word; 119 | } 120 | pre code { 121 | background-color: #fff; 122 | color:#737373; 123 | font-size: 11px; 124 | padding: 0; 125 | } 126 | sup { 127 | font-size: 0.83em; 128 | vertical-align: super; 129 | line-height: 0; 130 | } 131 | * { 132 | -webkit-print-color-adjust: exact; 133 | } 134 | @media screen and (min-width: 914px) { 135 | body { 136 | width: 854px; 137 | margin:10px auto; 138 | } 139 | } 140 | @media print { 141 | body,code,pre code,h1,h2,h3,h4,h5,h6 { 142 | color: black; 143 | } 144 | table, pre { 145 | page-break-inside: avoid; 146 | } 147 | } -------------------------------------------------------------------------------- /preview/toc/style/GitHub.css: -------------------------------------------------------------------------------- 1 | *{margin:0;padding:0;} 2 | body { 3 | font:13.34px helvetica,arial,freesans,clean,sans-serif; 4 | color:black; 5 | line-height:1.4em; 6 | background-color: #F8F8F8; 7 | padding: 0.7em; 8 | } 9 | p { 10 | margin:1em 0; 11 | line-height:1.5em; 12 | } 13 | table { 14 | font-size:inherit; 15 | font:100%; 16 | margin:1em; 17 | } 18 | table th{border-bottom:1px solid #bbb;padding:.2em 1em;} 19 | table td{border-bottom:1px solid #ddd;padding:.2em 1em;} 20 | input[type=text],input[type=password],input[type=image],textarea{font:99% helvetica,arial,freesans,sans-serif;} 21 | select,option{padding:0 .25em;} 22 | optgroup{margin-top:.5em;} 23 | pre,code{font:12px Monaco,"Courier New","DejaVu Sans Mono","Bitstream Vera Sans Mono",monospace;} 24 | pre { 25 | margin:1em 0; 26 | font-size:12px; 27 | background-color:#eee; 28 | border:1px solid #ddd; 29 | padding:5px; 30 | line-height:1.5em; 31 | color:#444; 32 | overflow:auto; 33 | -webkit-box-shadow:rgba(0,0,0,0.07) 0 1px 2px inset; 34 | -webkit-border-radius:3px; 35 | -moz-border-radius:3px;border-radius:3px; 36 | } 37 | pre code { 38 | padding:0; 39 | font-size:12px; 40 | background-color:#eee; 41 | border:none; 42 | } 43 | code { 44 | font-size:12px; 45 | background-color:#f8f8ff; 46 | color:#444; 47 | padding:0 .2em; 48 | border:1px solid #dedede; 49 | } 50 | img{border:0;max-width:100%;} 51 | abbr{border-bottom:none;} 52 | a{color:#4183c4;text-decoration:none;} 53 | a:hover{text-decoration:underline;} 54 | a code,a:link code,a:visited code{color:#4183c4;} 55 | h2,h3{margin:1em 0;} 56 | h1,h2,h3,h4,h5,h6{border:0;} 57 | h1{font-size:170%;border-top:4px solid #aaa;padding-top:.5em;margin-top:1.5em;} 58 | h1:first-child{margin-top:0;padding-top:.25em;border-top:none;} 59 | h2{font-size:150%;margin-top:1.5em;border-top:4px solid #e0e0e0;padding-top:.5em;} 60 | h3{margin-top:1em;} 61 | hr{border:1px solid #ddd;} 62 | ul{margin:1em 0 1em 2em;} 63 | ol{margin:1em 0 1em 2em;} 64 | ul li,ol li{margin-top:.5em;margin-bottom:.5em;} 65 | ul ul,ul ol,ol ol,ol ul{margin-top:0;margin-bottom:0;} 66 | blockquote{margin:1em 0;border-left:5px solid #ddd;padding-left:.6em;color:#555;} 67 | dt{font-weight:bold;margin-left:1em;} 68 | dd{margin-left:2em;margin-bottom:1em;} 69 | sup { 70 | font-size: 0.83em; 71 | vertical-align: super; 72 | line-height: 0; 73 | } 74 | * { 75 | -webkit-print-color-adjust: exact; 76 | } 77 | @media screen and (min-width: 914px) { 78 | body { 79 | width: 854px; 80 | margin:0 auto; 81 | } 82 | } 83 | @media print { 84 | table, pre { 85 | page-break-inside: avoid; 86 | } 87 | pre { 88 | word-wrap: break-word; 89 | } 90 | } -------------------------------------------------------------------------------- /preview/toc/style/makedownpad.css: -------------------------------------------------------------------------------- 1 | 2 | /* GitHub stylesheet for MarkdownPad (http://markdownpad.com) */ 3 | /* Author: Nicolas Hery - http://nicolashery.com */ 4 | /* Version: b13fe65ca28d2e568c6ed5d7f06581183df8f2ff */ 5 | /* Source: https://github.com/nicolahery/markdownpad-github */ 6 | 7 | /* RESET 8 | =============================================================================*/ 9 | 10 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { 11 | margin: 0; 12 | padding: 0; 13 | border: 0; 14 | } 15 | 16 | /* BODY 17 | =============================================================================*/ 18 | 19 | body { 20 | font-family: Helvetica, arial, freesans, clean, sans-serif; 21 | font-size: 14px; 22 | line-height: 1.6; 23 | color: #333; 24 | background-color: #fff; 25 | padding: 20px; 26 | max-width: 960px; 27 | margin: 0 auto; 28 | } 29 | 30 | body>*:first-child { 31 | margin-top: 0 !important; 32 | } 33 | 34 | body>*:last-child { 35 | margin-bottom: 0 !important; 36 | } 37 | 38 | /* BLOCKS 39 | =============================================================================*/ 40 | 41 | p, blockquote, ul, ol, dl, table, pre { 42 | margin: 15px 0; 43 | } 44 | 45 | /* HEADERS 46 | =============================================================================*/ 47 | 48 | h1, h2, h3, h4, h5, h6 { 49 | margin: 20px 0 10px; 50 | padding: 0; 51 | font-weight: bold; 52 | -webkit-font-smoothing: antialiased; 53 | } 54 | 55 | h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code { 56 | font-size: inherit; 57 | } 58 | 59 | h1 { 60 | font-size: 28px; 61 | color: #000; 62 | } 63 | 64 | h2 { 65 | font-size: 24px; 66 | border-bottom: 1px solid #ccc; 67 | color: #000; 68 | } 69 | 70 | h3 { 71 | font-size: 18px; 72 | } 73 | 74 | h4 { 75 | font-size: 16px; 76 | } 77 | 78 | h5 { 79 | font-size: 14px; 80 | } 81 | 82 | h6 { 83 | color: #777; 84 | font-size: 14px; 85 | } 86 | 87 | body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child { 88 | margin-top: 0; 89 | padding-top: 0; 90 | } 91 | 92 | a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 { 93 | margin-top: 0; 94 | padding-top: 0; 95 | } 96 | 97 | h1+p, h2+p, h3+p, h4+p, h5+p, h6+p { 98 | margin-top: 10px; 99 | } 100 | 101 | /* LINKS 102 | =============================================================================*/ 103 | 104 | a { 105 | color: #4183C4; 106 | text-decoration: none; 107 | } 108 | 109 | a:hover { 110 | text-decoration: underline; 111 | } 112 | 113 | /* LISTS 114 | =============================================================================*/ 115 | 116 | ul, ol { 117 | padding-left: 30px; 118 | } 119 | 120 | ul li > :first-child, 121 | ol li > :first-child, 122 | ul li ul:first-of-type, 123 | ol li ol:first-of-type, 124 | ul li ol:first-of-type, 125 | ol li ul:first-of-type { 126 | margin-top: 0px; 127 | } 128 | 129 | ul ul, ul ol, ol ol, ol ul { 130 | margin-bottom: 0; 131 | } 132 | 133 | dl { 134 | padding: 0; 135 | } 136 | 137 | dl dt { 138 | font-size: 14px; 139 | font-weight: bold; 140 | font-style: italic; 141 | padding: 0; 142 | margin: 15px 0 5px; 143 | } 144 | 145 | dl dt:first-child { 146 | padding: 0; 147 | } 148 | 149 | dl dt>:first-child { 150 | margin-top: 0px; 151 | } 152 | 153 | dl dt>:last-child { 154 | margin-bottom: 0px; 155 | } 156 | 157 | dl dd { 158 | margin: 0 0 15px; 159 | padding: 0 15px; 160 | } 161 | 162 | dl dd>:first-child { 163 | margin-top: 0px; 164 | } 165 | 166 | dl dd>:last-child { 167 | margin-bottom: 0px; 168 | } 169 | 170 | /* CODE 171 | =============================================================================*/ 172 | 173 | pre, code, tt { 174 | font-size: 12px; 175 | font-family: Consolas, "Liberation Mono", Courier, monospace; 176 | } 177 | 178 | code, tt { 179 | margin: 0 0px; 180 | padding: 0px 0px; 181 | white-space: nowrap; 182 | border: 1px solid #eaeaea; 183 | background-color: #f8f8f8; 184 | border-radius: 3px; 185 | } 186 | 187 | pre>code { 188 | margin: 0; 189 | padding: 0; 190 | white-space: pre; 191 | border: none; 192 | background: transparent; 193 | } 194 | 195 | pre { 196 | background-color: #f8f8f8; 197 | border: 1px solid #ccc; 198 | font-size: 13px; 199 | line-height: 19px; 200 | overflow: auto; 201 | padding: 6px 10px; 202 | border-radius: 3px; 203 | } 204 | 205 | pre code, pre tt { 206 | background-color: transparent; 207 | border: none; 208 | } 209 | 210 | kbd { 211 | -moz-border-bottom-colors: none; 212 | -moz-border-left-colors: none; 213 | -moz-border-right-colors: none; 214 | -moz-border-top-colors: none; 215 | background-color: #DDDDDD; 216 | background-image: linear-gradient(#F1F1F1, #DDDDDD); 217 | background-repeat: repeat-x; 218 | border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD; 219 | border-image: none; 220 | border-radius: 2px 2px 2px 2px; 221 | border-style: solid; 222 | border-width: 1px; 223 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; 224 | line-height: 10px; 225 | padding: 1px 4px; 226 | } 227 | 228 | /* QUOTES 229 | =============================================================================*/ 230 | 231 | blockquote { 232 | border-left: 4px solid #DDD; 233 | padding: 0 15px; 234 | color: #777; 235 | } 236 | 237 | blockquote>:first-child { 238 | margin-top: 0px; 239 | } 240 | 241 | blockquote>:last-child { 242 | margin-bottom: 0px; 243 | } 244 | 245 | /* HORIZONTAL RULES 246 | =============================================================================*/ 247 | 248 | hr { 249 | clear: both; 250 | margin: 15px 0; 251 | height: 0px; 252 | overflow: hidden; 253 | border: none; 254 | background: transparent; 255 | border-bottom: 4px solid #ddd; 256 | padding: 0; 257 | } 258 | 259 | /* TABLES 260 | =============================================================================*/ 261 | 262 | table th { 263 | font-weight: bold; 264 | } 265 | 266 | table th, table td { 267 | border: 1px solid #ccc; 268 | padding: 6px 13px; 269 | } 270 | 271 | table tr { 272 | border-top: 1px solid #ccc; 273 | background-color: #fff; 274 | } 275 | 276 | table tr:nth-child(2n) { 277 | background-color: #f8f8f8; 278 | } 279 | 280 | /* IMAGES 281 | =============================================================================*/ 282 | 283 | img { 284 | max-width: 100% 285 | } 286 | -------------------------------------------------------------------------------- /preview/toc_conf.js: -------------------------------------------------------------------------------- 1 | var jquery_ztree_toc_opts = { 2 | debug:false, 3 | is_auto_number:true, 4 | documment_selector:'.markdown-body', 5 | ztreeStyle: { 6 | width:'25%', 7 | overflow: 'auto', 8 | position: 'fixed', 9 | 'z-index': 2147483647, 10 | border: '0px none', 11 | left: '0px', 12 | top: '50px', 13 | // 'overflow-x': 'hidden', 14 | 'height': ($(window).height() -50) + 'px' 15 | } 16 | } 17 | var markdown_panel_style = { 18 | 'width':'70%', 19 | 'margin-left':'25%', 20 | 'margin-top': '20px' 21 | }; 22 | --------------------------------------------------------------------------------