Webpack 入门教程:http://www.runoob.com/w3cnote/webpack-tutorial.html
官方文档:http://vuejs.org/v2/guide/syntax.html
https://vuejs.org/v2/api/
中文文档: https://cn.vuejs.org/v2/guide/syntax.html
https://cn.vuejs.org/v2/api/
image.png

  1. # 全局安装 vue-cli
  2. $ cnpm install --global vue-cli
  3. # 创建一个基于 webpack 模板的新项目
  4. $ vue init webpack my-project
  5. # 这里需要进行一些配置,默认回车即可
  6. $ cd my-project
  7. $ cnpm install
  8. $ cnpm run dev
  9. DONE Compiled successfully in 4388ms
  10. > Listening at http://localhost:8080

image.png

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
  6. <script src="https://unpkg.com/vue/dist/vue.js"></script>
  7. </head>
  8. <body>
  9. <div id="app">
  10. <p>{{ message }}</p>
  11. </div>
  12. <script>
  13. new Vue({
  14. el: '#app',
  15. data: {
  16. message: 'Hello Vue.js!'
  17. }
  18. })
  19. </script>
  20. </body>
  21. </html>

Vue.js 目录结构

上一章节中我们使用了 npm 安装项目,我们在 IDE(Eclipse、Atom等) 中打开该目录,结构如下所示:
Vue 起步一 - 图3

目录解析

目录/文件 说明
build 项目构建(webpack)相关代码
config 配置目录,包括端口号等。我们初学可以
使用默认的。
node_modules npm 加载的项目依赖模块
src 这里是我们要开发的目录,基本上要做的事情
都在这个目录里。里面包含了几个目录及文件:
- assets: 放置一些图片,如logo等。
- components: 目录里面放了一个组件文件

,可以不用。
- App.vue: 项目入口文件,我们也可以
直接将组件写这里,而不使用 components
目录。
- main.js: 项目的核心文件。
| | static | 静态资源目录,如图片、字体等。 | | test | 初始测试目录,可删除 | | .xxxx文件 | 这些是一些配置文件,包括语法配置,
git配置等。 | | index.html | 首页入口文件,你可以添加一些 meta
信息或统计代码啥的。 | | package.json | 项目配置文件。 | | README.md | 项目的说明文档,markdown 格式 |

在前面我们打开 APP.vue 文件,代码如下(解释在注释中):

  1. <!-- 展示模板 -->
  2. <template>
  3. <div id="app">
  4. <img src="./assets/logo.png">
  5. <hello></hello>
  6. <div>
  7. <h1 class="class1" v-bind:class="{ 'class2': use }">site : {{site}}</h1>
  8. <div v-bind:class="[ 'class1' ,use ? 'class2' : '']"></div>
  9. <div v-bind:class="classObject"></div>
  10. <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">style</div>
  11. <div v-bind:style="[baseStyles, overridingStyles]">style</div>
  12. <h1>url : {{url}}</h1>
  13. <h1>{{details()}}</h1>
  14. </div>
  15. <div v-html="message"></div>
  16. <br />
  17. {{5+5}}<br />
  18. {{ ok ? 'YES' : 'NO' }}<br />
  19. {{ msg.split('').reverse().join('') }}
  20. <div v-bind:id="'list-' + id">菜鸟教程</div>
  21. <p v-if="seen">现在你看到我了</p>
  22. <pre>
  23. <a v-bind:href="url">菜鸟教程</a>
  24. <a :href="url">v-bind可以缩写,菜鸟教程</a>
  25. </pre>
  26. <form v-on:submit.prevent="onSubmit">
  27. <p>{{ msg }}</p>
  28. <input v-model="msg">
  29. <button v-on:click="doSomething">绑定click事件</button>
  30. <button @click="doSomething">v-on:可以缩写,绑定click事件</button>
  31. <button type="submit">提交</button>
  32. </form>
  33. <br />
  34. <br />
  35. <!-- 在两个大括号中 -->
  36. {{ msg | capitalize | capitalize2 | capitalize3('arg1') }}
  37. <!-- 在 v-bind 指令中 -->
  38. <div v-bind:id="msg | capitalize | capitalize2 | capitalize3('arg1')">绑定id</div>
  39. <div v-if="type === 'A'">
  40. A
  41. </div>
  42. <div v-else-if="type === 'B'">
  43. B
  44. </div>
  45. <div v-else-if="type === 'C'">
  46. C
  47. </div>
  48. <div v-else>
  49. Not A/B/C
  50. </div>
  51. <h1 v-show="ok">Hello!</h1>
  52. <ul>
  53. <li v-for="site in sites">
  54. {{ site.name }}
  55. </li>
  56. <li v-for="value in object">
  57. {{ value }}
  58. </li>
  59. <li v-for="(value, key, index) in object">
  60. {{ value }}
  61. </li>
  62. <li v-for="n in 10">
  63. {{ n }}
  64. </li>
  65. </ul>
  66. <p>原始字符串: {{ msg }}</p>
  67. <p>计算后反转字符串: {{ reversedMessage }}</p>
  68. </div>
  69. </template>
  70. <script>
  71. // 导入组件
  72. import Hello from './components/Hello'
  73. export default {
  74. name: 'app',
  75. el: '#app',
  76. watch : {
  77. kilometers:function(val) {
  78. this.kilometers = val;
  79. this.meters = this.kilometers * 1000
  80. },
  81. meters : function (val) {
  82. this.kilometers = val/ 1000;
  83. this.meters = val;
  84. }
  85. },
  86. computed: {
  87. classObject: function () {
  88. return {
  89. class1: true,
  90. class2: this.use,
  91. }
  92. },
  93. // 计算属性的 getter
  94. reversedMessage: function () {
  95. // `this` 指向 vm 实例
  96. return this.msg.split('').reverse().join('')
  97. },
  98. siteComputed: { // computed 属性默认只有 getter ,不过在需要时你也可以提供一个 setter :
  99. // getter
  100. get: function () {
  101. return this.object.name + ' ' + this.object.url
  102. },
  103. // setter
  104. set: function (newValue) {
  105. var names = newValue.split(' ');
  106. this.object.name = names[0];
  107. this.object.url = names[names.length - 1];
  108. }
  109. }
  110. },
  111. filters: { // 过滤器
  112. capitalize: function (value) {
  113. if (!value) return ''
  114. value = value.toString()
  115. return value.charAt(0).toUpperCase() + value.slice(1)
  116. },
  117. capitalize2: function (value) { // 过滤器可以串联
  118. if (!value) return ''
  119. value = value.toString();
  120. return value.slice(0, value.length - 1) + value.charAt(value.length - 1).toUpperCase()
  121. },
  122. // 过滤器是 JavaScript 函数,因此可以接受参数:
  123. capitalize3: function (aa, value) {
  124. if (!value) return ''
  125. value = value.toString()
  126. return value + aa;
  127. },
  128. },
  129. components: {
  130. Hello, // 这里是一个子组件
  131. },
  132. data: {
  133. baseStyles: { color: 'red' },
  134. overridingStyles: { fontSize: '14px' },
  135. activeColor: 'red',
  136. fontSize: 14,
  137. kilometers: 0,
  138. meters: 0,
  139. type: 'A',
  140. id: 'id',
  141. msg: 'msg message',
  142. sites: [{ name: 'a' }, { name: 'b' }],
  143. object: {
  144. name: '菜鸟教程',
  145. url: 'http://www.runoob.com',
  146. slogan: '学的不仅是技术,更是梦想!'
  147. },
  148. site: "菜鸟教程",
  149. url: "www.runoob.com", // 绑定响应式更新元素 v-bind:href="url"
  150. alexa: "10000",
  151. use: false, // 绑定class v-bind当use为true时显示class1
  152. ok: true, // 三元表达式控制显示内容,操作字符串或表达式
  153. seen: true,// v-if的语法,操作组件或html元素
  154. message: '<h1>双括号用于输出文本,v-html用于输出html</h1>',
  155. },
  156. methods: {
  157. submit: function() { // v-on:submit.prevent="onSubmit" .prevent是修饰符
  158. // .prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault():
  159. this.msg = '提交';
  160. },
  161. doSomething: function(e){
  162. this.msg = Date.now().toString();
  163. e.preventDefault();
  164. e.stopPropagation();
  165. },
  166. details: function() {
  167. return this.site + " - 学的不仅是技术,更是梦想!";
  168. }
  169. },
  170. }
  171. /*
  172. // $watch 是一个实例方法
  173. vm.$watch('kilometers', function (newValue, oldValue) {
  174. // 这个回调将在 vm.kilometers 改变后调用
  175. document.getElementById ("info").innerHTML = "修改前值为: " + oldValue + ",修改后值为: " + newValue;
  176. });
  177. */
  178. </script>
  179. <!-- 样式代码 -->
  180. <style>
  181. #app {
  182. font-family: 'Avenir', Helvetica, Arial, sans-serif;
  183. -webkit-font-smoothing: antialiased;
  184. -moz-osx-font-smoothing: grayscale;
  185. text-align: center;
  186. color: #2c3e50;
  187. margin-top: 60px;
  188. }
  189. </style>

数组操作

vm.$set( target, propertyName/index, value )

  • 参数
    • {Object | Array} target
    • {string | number} propertyName/index
    • {any} value
  1. <!-- 完整语法 -->
  2. <a v-bind:href="url">...</a>
  3. <!-- 缩写 -->
  4. <a :href="url">...</a>
  5. <!-- 动态参数的缩写 (2.6.0+) -->
  6. <a :[key]="url"> ... </a>
  7. // ====================================
  8. <!-- 缩写 -->
  9. <a @click="doSomething">...</a>
  10. <!-- 动态参数的缩写 (2.6.0+) -->
  11. <a @[event]="doSomething"> ... </a>
  12. // =======================================
  13. <h1 v-if="awesome">if</h1>
  14. <h1 v-else-if="type === 'C'">
  15. </h1>
  16. <h1 v-else>else</h1>
  17. // ===============================
  18. <ul id="example-1">
  19. <li
  20. v-for="(item, index) in items"
  21. v-for="item in items"
  22. v-for="item of items"
  23. v-for="(value, name, index) in object"
  24. ref="p" // this.$refs.p = [vt, vt, vt, ...] 如果这样写会变成这样的
  25. :key="item.message">
  26. {{ item.message }}
  27. </li>
  28. </ul>

过滤器 filters

Vue.js 允许你自定义过滤器,被用作一些常见的文本格式化。由”管道符”指示。可以通过过滤器对值进行加工处理

  1. {{ message | capitalize }}
  2. <!-- v-bind 指令中 -->
  3. <div v-bind:id="rawId | formatId"></div>

计算属性 computed

computed vs methods

我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。

监听属性 watch

我们将为大家介绍 Vue.js 监听属性 watch,我们可以通过 watch 来响应数据的变化。

  1. vm.$watch('kilometers', function (newValue, oldValue) {
  2. // ... newValue 表示新值, oldValue 表示老值
  3. });

修饰符

事件修饰符

Vue.js 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或 event.stopPropagation()。
Vue.js通过由点(.)表示的指令后缀来调用修饰符。

  • .stop
  • .prevent
  • .capture
  • .self
  • .once














按键修饰符

Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:


记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:




全部的按键别名:

  • .enter
  • .tab
  • .delete (捕获 “删除” 和 “退格” 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
  • .ctrl
  • .alt
  • .shift
  • .meta

实例




Do something

表单修饰符

.lazy

在默认情况下, v-model 在 input 事件中同步输入框的值与数据,但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步:

.number

如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 number 给 v-model 来处理输入值:

这通常很有用,因为在 type=”number” 时 HTML 中输入的值也总是会返回字符串类型。

.trim

如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入:

表单的双向绑定

  1. <div id="app">
  2. <p>单个复选框:</p>
  3. <input type="checkbox" id="checkbox" v-model="checked">
  4. <label for="checkbox">{{ checked }}</label>
  5. <p>多个复选框:</p>
  6. <input type="checkbox" id="runoob" value="Runoob" v-model="checkedNames">
  7. <label for="runoob">Runoob</label>
  8. <input type="checkbox" id="google" value="Google" v-model="checkedNames">
  9. <label for="google">Google</label>
  10. <input type="checkbox" id="taobao" value="Taobao" v-model="checkedNames">
  11. <label for="taobao">taobao</label>
  12. <br>
  13. <span>选择的值为: {{ checkedNames }}</span>
  14. </div>
  15. <script>
  16. new Vue({
  17. el: '#app',
  18. data: {
  19. checked : false,
  20. checkedNames: []
  21. }
  22. })
  23. </script>

VUE组件注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。

全局组件的注册方法

  1. <div id="app">
  2. <runoob></runoob>
  3. <child message="hello!"></child>
  4. <child v-bind:message="parentMsg"></child>
  5. <ol>
  6. <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
  7. </ol>
  8. </div>
  9. <script>
  10. // 注册
  11. Vue.component('runoob', {
  12. template: '<h1>自定义组件!</h1>'
  13. });
  14. Vue.component('child', {
  15. // 声明 props
  16. props: ['message'],
  17. // 同样也可以在 vm 实例中像 "this.message" 这样使用
  18. template: '<span>{{ message }}</span>'
  19. });
  20. Vue.component('todo-item', {
  21. props: ['todo'],
  22. template: '<li>{{ todo.text }}</li>'
  23. });
  24. // 创建根实例
  25. new Vue({
  26. el: '#app',
  27. data: {
  28. parentMsg: '父组件内容',
  29. sites: [
  30. { text: 'Runoob' },
  31. { text: 'Google' },
  32. { text: 'Taobao' }
  33. ],
  34. },
  35. });
  36. </script>

局部组件的组册方法

  1. <div id="app">
  2. <runoob></runoob>
  3. </div>
  4. <script>
  5. var Child = {
  6. template: '<h1>自定义组件!</h1>'
  7. }
  8. // 创建根实例
  9. new Vue({
  10. el: '#app',
  11. components: {
  12. // <runoob> 将只在父模板可用
  13. 'runoob': Child
  14. }
  15. })
  16. </script>

Prop 验证

组件可以为 props 指定验证要求。
prop 是一个对象而不是字符串数组时,它包含验证要求:

  1. Vue.component('example', {
  2. props: {
  3. // 基础类型检测 (`null` 意思是任何类型都可以)
  4. propA: Number,
  5. // 多种类型
  6. propB: [String, Number],
  7. // 必传且是字符串
  8. propC: {
  9. type: String,
  10. required: true
  11. },
  12. // 数字,有默认值
  13. propD: {
  14. type: Number,
  15. default: 100
  16. },
  17. // 数组/对象的默认值应当由一个工厂函数返回
  18. propE: {
  19. type: Object,
  20. default: function () {
  21. return { message: 'hello' }
  22. }
  23. },
  24. // 自定义验证函数
  25. propF: {
  26. validator: function (value) {
  27. return value > 10
  28. }
  29. }
  30. }
  31. })

type 可以是下面原生构造器:

  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array

type 也可以是一个自定义构造器,使用 instanceof 检测。

VUE组件自定义事件

父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:

  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件

另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。

  1. <div id="app">
  2. <div id="counter-event-example">
  3. <p>{{ total }}</p>
  4. <button-counter v-on:increment="incrementTotal"></button-counter>
  5. <button-counter v-on:increment="incrementTotal"></button-counter>
  6. </div>
  7. </div>
  8. <script>
  9. Vue.component('button-counter', {
  10. template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
  11. data: function () { // data 必须是一个函数,data 是一个对象则会影响到其他实例
  12. return {
  13. counter: 0
  14. }
  15. },
  16. methods: {
  17. incrementHandler: function () {
  18. this.counter += 1
  19. this.$emit('increment')
  20. }
  21. },
  22. })
  23. new Vue({
  24. el: '#counter-event-example',
  25. data: {
  26. total: 0
  27. },
  28. methods: {
  29. incrementTotal: function () {
  30. this.total += 1
  31. }
  32. }
  33. })
  34. </script>

如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:

  1. <my-component v-on:click.native="doTheThing"></my-component>

.sync

感觉这玩意违反单向数据流,数据流向自顶向下

  1. // 父组件
  2. <component value.sync="value" />
  3. // 子组件改变父组件的值
  4. this.$emit('update:title', newValue)

vue-router

  1. this.$router.push({
  2. path: "/urlpath",
  3. query: {
  4. a: 1,
  5. b: 2
  6. },
  7. params: {
  8. id: 1
  9. }
  10. })
  11. this.$route.params