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
JavaScript 表达式:对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。但每个绑定只能包含单个表达式
<div v-bind:id="dynamicId"></div>若v-bind绑定的属性值为 null、undefined 或 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()
修饰符:修饰符 (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-else,v-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其他使用
在整数上使用:把模板重复对应次数
当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。
可是实现为部分节点进行渲染,如:
在组件上使用:
在组件上使用v-for,必须设定key值,但是数据不会被自动传到组件里,需要使用prop
<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>