本文主要参考了Vue的官方文档,还结合了其他的优秀博客内容,提炼出最常用的知识点,通过本文能快速地了解或者复习Vue的基础知识。
安装
Vue Devtools
浏览器插件,允许开发者在更友好的界面调试Vue应用
script标签引入
构建文件引入
1.最新版本
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
2.特定版本
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
3.兼容 ES Module
<script type="module">
import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.esm.browser.js'
</script>
4.更小构建
vue.js换成vue.min.js
开发版本和生产版本
开发版本包含完整的警告和调试模式
生产版本删除了警告,33.30KB min+gzip
NPM
构建大型Vue应用时推荐用npm,因为它能和打包器webpack配合使用
npm install vue
命令行工具CLI
命令行界面(英语:command-line interface,缩写:CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行。
命令行界面要较图形用户界面节约计算机系统的资源。在熟记命令的前提下,使用命令行界面往往要较使用图形用户界面的操作速度要快。
CLI (@vue/cli) 是一个全局安装的 npm 包,提供了终端里的 vue 命令。它可以通过 vue create 快速创建一个新项目的脚手架,或者直接通过 vue serve 构建新想法的原型。你也可以通过 vue ui 通过一套图形化界面管理你的所有项目。
介绍
核心概念
- javascript框架,网页越复杂,js文件越多,其连接了许多的html与css,缺乏正规的组织形式,这就需要js框架来组织这些文件
- 渐进式,如果已存在一个应用,可将Vue作为一小部分嵌入其中
- 组件化,将页面划分为一个个组件,每个组件都有自己的html、css、js,且组件可复用
- 响应式,数据改变,页面上所有用到该数据的地方都会随之更新
- 命令行工具,用于快速初始化大型项目
- 单文件组件,即.vue文件,本身就是一个单独的组件(与之对应的是在.html文件中的script标 签内new Vue({el:"xxx"})),拥有template、style、script,通过vue-loader对.vue进行解析,因为浏览器不认识.vue文件。
声明式渲染
模板语法{{ x }}
对属性 v-bind:属性名="x"
条件与循环
v-if="x"
v-for="x in arrays"
处理用户输入
v-on:click="func"
<input v-model="message">
组件化应用构建
注册组件
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
使用组件
<div id="app-7">
<ol>
<todo-item
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id"
></todo-item>
</ol>
</div>
组件和自定义元素的关系
相同点:实现Slot API和is特性
不同点:相比自定义元素,组件在所有支持的浏览器下表现一致(兼容性好),多了一些功能,如跨组件数据流、自定义事件通信以及构建工具集成
Vue实例
创建一个vue实例
var vm = new Vue({
// 选项对象
})
数据和方法
数据-响应式
var data = { a: 1 }
var vm = new Vue({
data: data
})
//只有当实例被创建时就已经存在于 data 中的属性才是响应式的
data.b = 'xx' // 非响应式
//响应系统无法再追踪变化
Object.freeze(data)
方法
都带有前缀$
vm.$data
vm.$el
vm.$watch('a', function (newValue, oldValue) {
// 这个回调将在 `vm.a` 改变后调用
})
...
生命周期钩子
本人提炼一下
beforeCreate
啥都不存在
created
Vue实例的data数据已存在,可更改
判断el是否存在
存在则继续生命周期,否则停止
页面渲染
优先级:render函数>template>html
beforeMount
<div>{{ x }}</div>
mounted
<div>内容</div>
beforeUpdate
$el和$data都改变,实际是data数据改变,但页面未渲染的阶段
updated
更新完毕
beforeDestroy
此阶段实例仍可使用,可做路由跳转
destroyed
vue 实例指示的所有东西都会解绑,所有的事件监听器会被移除,所有的子实例也会被销毁。

模板语法
基于HTML,将DOM与数据绑定,Vue在底层上将模板语法编译成虚拟DOM渲染函数,这样可智能计算出最少需要重新渲染多少组件,减少DOM操作。
也可不用模板,用渲染render函数,jsx语法。
插值
文本插值( {{ }} )
<span>Message: {{ msg }}</span>
一次性插值(v-once)
<span v-once>这个将不会改变: {{ msg }}</span>
原始HTML(v-html)
<span v-html="rawHtml"></span>
特性(v-bind)
<div v-bind:id="dynamicId"></div>
<button v-bind:disabled="isButtonDisabled">Button</button>
// 若disable为false,特性disabled不会被渲染在模板中
强调 :给属性添加变量时要加v-bind:(本人老是忘记)
js表达式
{{ }} 中可以放变量的算数操作,三元表达式,数组方法等,但不可放语句(if else var)
""引号中也可写js表达式(变量是响应的,也能识别布尔值true和false),
不过如果想要字符串的话,加''单引号,可用+连接js表达式和字符串
指令
参数
<a v-bind:href="url">...</a>
动态参数
<a v-bind:[attributeName]="url"> ... </a>
修饰符
<form v-on:submit.prevent="onSubmit">...</form>
缩写
v-bind
<a v-bind:href="url">...</a>
<a :href="url">...</a>
v-on
<a v-on:click="doSomething">...</a>
<a @click="doSomething">...</a>
计算属性和侦听属性
计算属性computed
语法格式如下:
<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('')
}
}
})
- reversedMessage为一个属性,不是一个方法,它和普通的变量使用方式一样。
- 无需在data中再声明一边,外面也可以和访问变量一样访问该属性(this.计算属性名)
- 给它设置的函数,为getter函数,当访问这个属性时就返回这个函数的返回值。
- 它依赖于message这个变量,但内部依赖变化,该计算属性也会响应式地变化。
- 也可以设置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]
}
}
}
// 使用setter函数
vm.fullName = "name1 name2"
计算属性和方法methods的区别
<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在组件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
从以上例子可以看出,利用methods访问同样可以实现computed的功能。
不同之处如下:
- computed放的是属性,和变量一样使用;methods放的是函数,使用时后面要加括号
- 计算属性基于响应式依赖进行缓存的,如果依赖没变,多次访问该属性,都是直接调用缓存的,不必再次执行函数;而methods下的方法,多次访问就要多次执行函数。
但也要注意,computed下用到Date()的话,计算属性不会更新的
侦听器watch
语法格式如下:
<div id="demo">{{ fullName }}</div>
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
watch下监听的都是在data中声明过的变量,若变量变化,则会执行回调函数。
最佳使用场景:在数据变化时执行异步或开销较大的操作。
不过一般情况下都建议用计算属性computed,往往代码更简单,在一些数据需要随着其它数据变动而变动时更为明显。
样式绑定——class和style
属性的绑定都用v-bind:属性名="js表达式+'字符串'+'js表达式'"
原本属性的赋值只能用字符串,由于Vue的增强,还可以用对象和数组,但是还是要包在""下
绑定class
对象语法
"{类名: 变量或布尔值, 类名:变量或布尔值, ...}"
变量也要是布尔值,作用是设置是否绑定对应的类样式
<div v-bind:class="{ active: isActive }"></div>
// 允许普通赋值和对象赋值同时
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
// 更加清晰的写法
<div v-bind:class="classObject"></div>
data: {
classObject: {
active: true,
'text-danger': false
}
}
// 结合计算属性功能更强大
<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'
}
}
}
数组语法
"[变量, 变量, ...]"
变量存放着类名,作用是绑定哪些类名,也可在[]中放三元表达式
本人觉得和直接字符串赋值一样,只是要绑定多个类名,字符串要用+' '+将它们隔开,数组语法直接逗号隔开
<div v-bind:class="[activeClass, errorClass]"></div>
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
// 三元表达式
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
// 数组语法和对象语法结合
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
用在组件上
语法和上面一样,注意的就是使用组件时加的类名不会覆盖原本定义组件时加的类名,两者共同存在。
绑定style
对象语法
"{css属性:变量,css属性:变量 + '单位',...}"
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red',
fontSize: 30
}
// 更直观的表示
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
// 也常和计算属性结合
数组语法
"[变量,变量,...]"
变量存放着样式,作用是将多个样式对象添加到同一个元素上
<div v-bind:style="[baseStyles, overridingStyles]"></div>
对于不同的浏览器,Vue会自动添加前缀
条件渲染——v-if/v-show
v-if
v-if = "变量/表达式"
为truthy则渲染对应的内容
v-else
要有v-if或v-else-if与之相对应
v-else-if
用法同v-if
用v-if渲染分组
可以把一个<template> 元素当做不可见的包裹元素,并在上面使用 v-if,最终的渲染结果将不包含 <template> 元素。
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
key
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染
<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>
// input的元素中不加key属性的话,即使用条件切换展示的元素后,之前在input的输入信息仍存在
// 因为Vue的高效渲染机制,不会替换<input>,而是改变它的placeholder属性值,其他不变
v-show
注意:作用相当于display: none
而不是visibility: hidden
带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display。
两者区别
- v-if会真正地销毁和重建元素
- v-if是惰性的,起初为false,则就不渲染了
- v-show必渲染,然后改变css而已
- 切换频繁的话用v-show,省资源;切换少的话用v-if,万一就不展示了呢!
列表渲染——v-for
v-for遍历数组
语法:
单参数:v-for="item in items"
双参数:v-for="(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' }
]
}
})
v-for遍历对象
语法:
单参数:v-for="value in object"
双参数:v-for="(value, name) in object"
三参数:v-for="(value, name, index) in object"
<ul id="v-for-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
</ul>
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
// 双参数
<div v-for="(value, name) in object">
{{ name }}: {{ value }}
</div>
// 三参数
<div v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</div>
状态维护——key
Vue比较懒,能不操作DOM就不操作DOM,对v-for
,当其数组变化时,Vue不会移动DOM的位置,而是重新渲染DOM使其与数组对应,这样的话虽然消耗少,但有问题(比如表单输入值还留在原位置)
建议使用v-for
的时候都加key
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>
数组更新检测
对v-for遍历的数组而言,其发生变化,视图应该要响应式地更新
能响应式更新视图的操作数组的方法
push() pop() shift() unshift() splice() sort() reverse()
需要进一步操作的
filter()、concat() 和 slice(),因为它们不改变原数组,而是返回新数组
操作方法:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
不能响应式更新视图
- 通过索引值改变数组元素
- 改变数组.length来改变数组
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
解决问题1:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
vm.$set(vm.items, indexOfItem, newValue)
解决问题2:
vm.items.splice(newLength)
对象更新检测
Vue 不能检测对象属性的添加或删除
响应式方法:
Vue.set(vm.userProfile, 'age', 27)
vm.$set(vm.userProfile, 'age', 27)
// 添加多个对象
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
其他
显示过滤/排序后的结果
将v-for
循环的数组放在计算属性中,该计算属性返回对原数组的操作后的一个新数组,这样既不会改变原数组的顺序,又能按自己的想法显示过滤或排序后的结果
v-for可以对数字循环
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
// 输出
1 2 3 4 5 6 7 8 9 10
可以在<template>
上使用v-for
v-for
与v-if
一同使用
v-for
的优先级大于v-if
,从而先循环出列表,再根据条件决定是否渲染单一元素
要想实现先条件再循环的效果,将v-if
放在v-for
的外层元素上即可
组件上也可使用v-for
但是组件内部是无法获取循环的元素的,还是要通过prop
注意,组件用v-for
的话key
是必须的
事件处理——v-on
v-on语法
v-on="JS代码"
<div id="example-1">
<button v-on:click="counter += 1">Add 1</button>
<p>The button above has been clicked {{ counter }} times.</p>
</div>
v-on="methods中定义的方法"
注意该方法的第一个参数 event 为原生 DOM 事件
<div id="example-2">
<!-- `greet` 是在下面定义的方法名 -->
<button v-on:click="greet">Greet</button>
</div>
var example2 = new Vue({
el: '#example-2',
data: {
name: 'Vue.js'
},
// 在 `methods` 对象中定义方法
methods: {
greet: function (event) {
// `this` 在方法里指向当前 Vue 实例
alert('Hello ' + this.name + '!')
// `event` 是原生 DOM 事件
if (event) {
alert(event.target.tagName)
}
}
}
})
v-on="methods方法(js语句)"
还可传入特殊变量 $event,表示DOM事件
<div id="example-3">
<button v-on:click="say('hi')">Say hi</button>
<button v-on:click="say('what', $event)">Say what</button>
</div>
new Vue({
el: '#example-3',
methods: {
say: function (message, event) {
alert(message)
}
}
})
事件修饰符
- .stop
- .prevent
- .capture
- .self
- .once
- .passive
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
按键修饰符
- .enter
- .tab
- .delete (捕获“删除”和“退格”键)
- .esc
- .space
- .up
- .down
- .left
- .right
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
按键码的方式(快被废弃了)
<input v-on:keyup.13="submit">
自定义按键修饰符
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
系统修饰键
- .ctrl
- .alt
- .shift
- .meta
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
- .exact
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>
鼠标修饰符
- .left
- .right
- .middle
表单绑定——v-model
在表单元素 <input>
、<textarea>
及 <select>
上创建双向数据绑定,根据控件类型自动选取正确的方法来更新元素。
本质是语法糖
基础用法
- text 和 textarea 元素使用 value 属性和 input 事件;
- checkbox 和 radio 使用 checked 属性和 change 事件;
- select 字段将 value 作为 prop 并将 change 作为事件。
文本text
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
多行文本textarea
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
复选框checkbox
<div id='example-3'>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>
new Vue({
el: '#example-3',
data: {
checkedNames: []
}
})
全选结果 checkedNames: ["Jack", "John", "Mike"]
// 单个的话,可以不用指定value,绑定的是一个布尔值
// 多个的话,为了区分要指定value,不然就是一起勾选,一起不选,绑定的是一个数组,元素为对应value
单选框radio
<div id="example-4">
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
</div>
new Vue({
el: '#example-4',
data: {
picked: ''
}
})
// 对于单选框,只有一个的话就没有意义,因为点了就无法取消
// 多个的话绑定的就是对应的value值
选择框
// 单选
<div id="example-5">
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
new Vue({
el: '...',
data: {
selected: ''
}
})
// 多选
在select头部加属性multiple
Vue实例中的selected定义为空数组
值绑定
把值绑定到 Vue 实例的一个动态属性上,这时可以用 v-bind 实现,并且这个属性的值可以不是字符串。
复选框
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no"
>
// 当选中时
vm.toggle === 'yes'
// 当没有选中时
vm.toggle === 'no'
单选框
<input type="radio" v-model="pick" v-bind:value="a">
// 当选中时
vm.pick === vm.a
选择框
<select v-model="selected">
<!-- 内联对象字面量 -->
<option v-bind:value="{ number: 123 }">123</option>
</select>
// 当选中时
typeof vm.selected // => 'object'
vm.selected.number // => 123
修饰符
.lazy
在“change”时而非“input”时更新
<input v-model.lazy="msg" >
.number
自动将用户的输入值转为数值类型
<input v-model.number="age" type="number">
.trim
<input v-model.trim="xxx">