Vue是一种遵循MVVM模型理念的框架。

一、基础

1.Vue实例

首先,通过 new Vue 创建一个根Vue实例,并且当实例被创建时,可以将 data 中的属性加入到Vue的响应式系统
(响应式系统:即当属性的值发生改变时,视图也会跟着响应,更新为新的值)
// 我们的数据对象
var data = { a: 1 }

// 该对象被加入到一个 Vue 实例中
var vm = new Vue({
  data: data
})

// 获得这个实例上的属性
// 返回源数据中对应的字段
vm.a == data.a // => true

// 设置属性也会影响到原始数据
vm.a = 2
data.a // => 2

// ……反之亦然
data.a = 3
vm.a // => 3
但是,只有当实例被创建时就存在于 data 中的属性才能被响应
如果通过 vm.b 添加一个新的属性,则不会触发响应,如果想要对后续增加的属性进行响应,则需要一些初始值:
data: {
  newTodoText: '',
  visitCount: 0,
  hideCompletedTodos: false,
  todos: [],
  error: null
}
另一个重要知识点是生命周期钩子
生命周期钩子就是在各个时间点自动运行的函数,如下图所示:

2.模板语法

所有 Vue.js 的模板都是合法的 HTML,在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。

A.插值

文本{{ msg }}
原始HTML:为了输出真正的HTML 需要 v-html 
Attribute:Mustache 语法不能作用在 HTML attribute 上,遇到这种情况应该使用 v-bind
<div v-bind:id="dynamicId"></div>
若v-bind绑定的属性值为 nullundefined 或 false 则该属性不会被渲染
JavaScript 表达式对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。但每个绑定只能包含单个表达式

B.指令

就是指带有 v- 前缀的特殊 attribute,其参数为 JS表达式 当表达式的值发生改变时,响应的作用于DOM
参数一些指令能够接收一个“参数”,在指令名称之后以冒号表示。如
<a v-bind:href="url">...</a>
href 是参数 告知 v-bind 指令将该元素的 href attribute 与表达式 url 的值绑定。
动态参数可以用方括号括起来的 JavaScript 表达式作为一个指令的参数
<a v-bind:[attributeName]="url"> ... </a>
 attributeName 会被作为一个 JS表达式进行动态求值,将其值作为参数。
例如,如果你的 Vue 实例有一个 data 属性 attributeName,其值为 "href",那么这个绑定将等价于 v-bind:href。
修饰符:修饰符 (modifier) 是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault()

C.缩写

v-bind    ====   :
v-on ==== @

3.计算属性和侦听器

A.计算属性

对于复杂属性,可以使用计算属性。
<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
  
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})  
虽然计算属性很类似于方法,但是计算属性可以进行缓存。只有当相关响应式依赖发生改变时才重新求值
计算属性默认只有 getter  不过也可以定义setter
// ...
computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
// ...

B.侦听器

用以监听变量的改变 和计算属性类似 也含有缓存当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
如:
  watch: {
    // 如果 `question` 发生改变,这个函数就会运行
    question: function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.debouncedGetAnswer()
    }
  }
当然,也可以使用Vue提供的  vm.$watch  API:
  • 参数

    • {string | Function} expOrFn:监听对象
    • {Function | Object} callback:回调函数
    • {Object} [options]:可设定属性
      • {boolean} deep: 为true时 可进行深度监听
      • {boolean} immediate:为true时 将立即以表达式的当前值触发回调
  • 返回值:{Function} unwatch

  • 用法

    var vm = new Vue({
      el: '#demo',
      data: {
        firstName: 'Foo',
        lastName: 'Bar',
        fullName: 'Foo Bar'
      }
    })
     
    vm.$watch('firstName', function (val) {
      this.fullName = val + ' ' + this.lastName
    })
     
    vm.$watch('lastName', function (val) {
      this.fullName = this.firstName + ' ' + val
    


4.Class 与 Style 绑定

样式绑定可以通过将 v-bind 用于 class 和 style 来进行,并且表达式结果的类型除了字符串之外,还可以是对象或数组。

A.HTML Class

对象语法:
通过给 v-bind:class 一个对象,以动态地切换 class  并在<style>语法里写相应class的样式。
也可以与计算属性结合使用:
<div v-bind:class="classObject"></div>

data: {
  isActive: true,
  error: null
},
computed: {
  classObject: function () {
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error && this.error.type === 'fatal'
    }
  }
}
数组语法:
可以把一个数组传给 v-bind:class,以应用一个 class 列表,并且可以在数组中应用对象
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
用在组件上:
当在一个自定义组件上使用 class 属性时,这些 class 将被添加到该组件的根元素上面。这个元素上已经存在的 class 不会被覆盖。
//声明一个组件
Vue.component('my-component', {
  template: '<p class="foo bar">Hi</p>'
})
//使用时添加class
<my-component class="baz boo"></my-component>
//HTML渲染为
<p class="foo bar baz boo">Hi</p>

B.Style绑定

对象语法:
可以直接绑定对象
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
也可以绑定到一个样式上
<div v-bind:style="styleObject"></div>

data: {
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}
数组语法:
<div v-bind:style="[baseStyles, overridingStyles]"></div>
数组里的每一个对象都是对象

5.条件渲染

A.v-if

v-if 是一个指令,必须将它添加到一个元素上
如:
<h1 v-if="awesome">Vue is awesome!</h1>
若想切换多个元素 则 利用 <template>  进行包裹 并且<template>不会渲染到页面上
<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>
v-elsev-else-if 必须紧跟在带 v-if 或者 v-else-if 的元素之后
但由于Vue会复用已有元素,而不是从头开始渲染,为了表示“两个同名称的元素完全独立,需要重新渲染”就添加 key 值 
如:
<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>

B.v-show

和v-if类似 
区别:1.v-show哪怕是false 该标签的dom也在页面上存在  2.v-show 不支持 <template> 元素

6.列表渲染 V-FOR

A.v-for 循环数组

v-for 指令需要使用 item in/of items 形式的特殊语法
并且有第二个可选参数,为当前项的索引 (item, index) in items
<ul id="example-2">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>
  
  var example2 = new Vue({
  el: '#example-2',
  data: {
    parentMessage: 'Parent',
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})

B.v-for循环对象

一共可以提供三个参数作为索引:
<div v-for="(value, name, index) in object">
  {{ index }}. {{ name }}: {{ value }}
</div>

new Vue({
  el: '#v-for-object',
  data: {
    object: {
      title: 'How to do lists in Vue',
      author: 'Jane Doe',
      publishedAt: '2016-04-10'
    }
  }
})

C.数组更新检测

找到一些方法,既又能改变数组,又能更新页面
变异方法:
使用这七种变异方法,可以实现页面更新效果:
  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()
替换数组:
通过改变引用,用新数组替代旧数组来实现效果:
example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})
Set方法:
通过使用全局方法Vue.set也可以实现响应更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
也可以使用实例方法vm.$set 
m.$set(vm.items, indexOfItem, newValue)

D.对象更新检测

对于已经创建的实例,Vue 不允许动态添加根级别的响应式属性。
但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式属性
var vm = new Vue({
  data: {
    userProfile: {
      name: 'Anika'
    }
  }
})

//全局方法:
Vue.set(vm.userProfile, 'age', 27)
//实例方法:
vm.$set(vm.userProfile, 'age', 27)

E.显示过滤/排序后的结果

可以创建一个计算属性,来返回过滤或排序后的数组:
<li v-for="n in evenNumbers">{{ n }}</li>

data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
  evenNumbers: function () {
    return this.numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

F.v-for其他使用

在整数上使用:把模板重复对应次数
<div>
  <span v-for="n in 10">{{ n }} </span>
</div>
<template>上使用:可以循环渲染一段包含多个元素的内容
<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>
与v-if一同使用:
当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。
可是实现为部分节点进行渲染,如:
<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo }}
</li>
上面的代码将只渲染未完成的 todo。
在组件上使用:
在组件上使用v-for,必须设定key值,但是数据不会被自动传到组件里,需要使用prop
//定义组件
Vue.component('todo-item', {
  template: '\
    <li>\
      {{ title }}\
      <button v-on:click="$emit(\'remove\')">Remove</button>\
    </li>\
  ',
  props: ['title']
})

//组件实例
<ul>
    <li
      is="todo-item"
      v-for="(todo, index) in todos"
      v-bind:key="todo.id"
      v-bind:title="todo.title"
      v-on:remove="todos.splice(index, 1)"
    ></li>
  </ul>