Vue学习中常用的网站
vue-router官网 || API-Vue.js || Vue官网 || axios中文网
1.指令篇(vue的13个v指令)
1.1 v-on: 与事件处理有关。
基本用法:
- 绑定事件监听器。事件类型由参数指定。
- 表达式可以是一个方法的名字或一个内联语句,如果没有修饰符也可以省略。
- 用在普通元素上时,只能监听原生 DOM 事件。
- 用在自定义元素组件上时,也可以监听子组件触发的自定义事件。
- 在监听原生 DOM 事件时,方法以事件为唯一的参数。
- 如果使用内联语句,语句可以访问一个 $event property:v-on:click=“handle(‘ok’, $event)”。
- 从 2.4.0 开始,v-on 同样支持不带参数绑定一个事件/监听器键值对的对象。
- 注意当使用对象语法时,是不支持任何修饰器的。
监听事件:使用 v-on 指令来监听 DOM 事件,并在触发时运行一些 JavaScript 代码。例如操作data中的counter使其自增。
<div id="example-1"> <!--执行例子的代码,每点击一次按钮,使得counter值每次自增一 -->
<button v-on:click="counter += 1">Add 1</button>
<p>The button above has been clicked {{ counter }} times.</p>
</div>
var example1 = new Vue({
el: '#example-1',
data: {
counter: 0 //定义一个counter属性来存储点击的次数
}
})
监听自定义的事件处理方法,定义了一个greet方法:
点击按钮弹出两个消息,一个弹出 alert('Hello ’ + this.name + ‘!’) ,一个alert(event.target.tagName)触发事件的标签名
<div id="example-2">
<button v-on:click="greet">Greet</button> <!-- `greet` 是在下面定义的方法名 -->
</div>
var example2 = new Vue({
el: '#example-2',
data: {
name: 'Vue.js'
},
methods: { // 在 `methods` 对象中定义方法 `greet`
greet: function (event) {
alert('Hello ' + this.name + '!') // `this` 在方法里指向当前 Vue 实例 exampole2
if (event) { // `event` 是原生 DOM 事件
alert(event.target.tagName)
}
}
}
})
// 也可以用 JavaScript 直接调用方法
example2.greet() // => 'Hello Vue.js!'
内联处理器中的方法 所谓内联处理器就是带括号的()语句,为了访问原始DOM用特殊变量 $event把它传入方法.
<div id="example-3"> <!-- 点击两个按钮中的一个,提示出对应内容hi或者是what -->
<button v-on:click="say('hi')">Say hi</button>
<button v-on:click="say('hi',$event)">Say hi</button>
<button v-on:click="say('what')">Say what</button>
<button v-on:click="say('what',$event)">Say hi</button>
</div>
new Vue({
el: '#example-3',
methods: {
say: function (message) {
alert(message);
alert(event.target.tagName);
}
}
})
v-on的缩写形式@click=" "
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
<!-- 方法处理器 -->
<button v-on:click="doThis"></button>
<!-- 动态事件 (2.6.0+) -->
<button v-on:[event]="doThis"></button>
<!-- 内联语句 -->
<button v-on:click="doThat('hello', $event)"></button>
<!-- 缩写 -->
<button @click="doThis"></button>
<!-- 动态事件缩写 (2.6.0+) -->
<button @[event]="doThis"></button>
<!-- 停止冒泡 -->
<button @click.stop="doThis"></button>
<!-- 阻止默认行为 -->
<button @click.prevent="doThis"></button>
<!-- 阻止默认行为,没有表达式 -->
<form @submit.prevent></form>
<!-- 串联修饰符 -->
<button @click.stop.prevent="doThis"></button>
<!-- 键修饰符,键别名 -->
<input @keyup.enter="onEnter">
<!-- 键修饰符,键代码 -->
<input @keyup.13="onEnter">
<!-- 点击回调只会触发一次 -->
<button v-on:click.once="doThis"></button>
<!-- 对象语法 (2.4.0+) -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
v-on的事件修饰符和按键修饰符:
-
形如@click.once"xxx"
-
.stop - 调用 event.stopPropagation(),简单来说阻止冒泡。
-
.prevent - 调用 event.preventDefault(),简单来说阻止默认行为。
-
.capture - 添加事件侦听器时使用 capture 模式。
-
.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。简单来说仅仅绑定元素自身触发。
-
.once - 只触发一次回调。 简单来说绑定事件只会触发一次。
-
.passive - (2.3.0) 以 { passive: true } 模式添加侦听器,简单来说滚动事件的默认行为 (即滚动行为) 将会立即触发,不能和.prevent 一起使用
-
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。
-
因此,用 v-on:click.prevent.self 会阻止所有的点击,而=v-on:click.self.prevent 只会阻止对元素自身的点击。
-
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
-
.native - 监听组件根元素的原生事件。
-
.left - (2.2.0) 只当点击鼠标左键时触发。
-
.right - (2.2.0) 只当点击鼠标右键时触发。
-
.middle - (2.2.0) 只当点击鼠标中键时触发。
-
.passive - (2.3.0) 以 { passive: true } 模式添加侦听器,简单来说滚动事件的默认行为 (即滚动行为) 将会立即触发,不能和.prevent 一起使用
事件总结:
在methods中定义方法主要有两种方式:
- 无括号的方法相当于自带$event,可以访问原始DOM,查看target等操作。例如, 上面例子中的greet方法。
- 内联处理器中的方法相当于带括号的方法,如果不传参 $event则无法访问原始DOM,所以在传参时要写上 $event。
1.2 v-for: 列表渲染
- 指令可以将数组渲染成一个列表。指令基本语法 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 是被迭代的数组元素的别名。你也可以用 of 替代 in, 作为分隔符,因为它更接近 JavaScript 迭代器的语法:
<ul id="example-1">
<li v-for="item in items" :key="item.message">
{{ item.message }}
</li>
</ul>
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
<!-- 在数组items中循环item -->
<div v-for="item of items"></div>
<!-- -->
<ul id="v-for-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
</ul>
<!-- 带键名 -->
<div v-for="(value, name) in object">
{{ name }}: {{ value }}
</div>
<!-- 带键名和索引 -->
<div v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</div>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
//数组
var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
//对象
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
- 为了给 Vue 一个提示,为了跟踪每个节点的身份,从而重用和重新排序现有元素,需要为每项提供一个唯一 key attribute:,通过v-bind:key的形式,一般为item.id,可以简写为:key=’‘item.id’’
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>
- 建议在使用 v-for 时提供 key attribute,除非遍历出的 DOM内容非常简单,或者是刻意追求性能上的提升。它是 Vue 识别节点的一个通用机制,key 并不仅与 v-for 特别关联,它还具有其它用途。
- 不要使用对象或数组之类的非基本类型值作为 v-for 的 key。请用字符串或数值类型的值。
1.3 v-pre : 跳过这个元素和它的子元素的编译过程。
可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译,简单来说,忽略相应的指令。
<span v-pre>{{ this will not be compiled }}</span> 显示的是{{ this will not be compiled }}
<span v-pre>{{msg}}</span> 即使data里面定义了msg这里仍然是显示的{{msg}}
v-once: 场景:有些 template 中的静态 dom 没有改变,这时就只需要渲染一次,可以降低性能开销
<span v-once> 这时只需要加载一次的标签</span>
- v-once 和 v-pre 的区别: v-once只渲染一次;v-pre不编译,原样输出
1.4-1.7 条件渲染(v-if/v-show/v-else-if/v-else)
v-if: 根据表达式的值的真假来渲染元素.
- 当和 v-if 一起使用时,v-for 的优先级比 v-if 更高
- v-if指令会条件性地渲染一块内容,这块内容只会在指令的表达式返回 true值的时候被渲染。
<h1 v-if="awesome">Vue is awesome!</h1> //只有awesome为真才会显示后面的内容
v-else-if和v-else联合使用:
<div v-if="type === 'A'"> A
</div>
<div v-else-if="type === 'B'"> B
</div>
<div v-else-if="type === 'C'"> C
</div>
<div v-else> Not A/B/C
</div>```
v-if和v-show
<h1 v-show="tf">Hello!</h1>
<p v-if="tf">现在你看到我了</p>
- v-if 指令根据表达式 tf的值的真假来插入/移除 p元素里面的内容。v-if 是“真正”的条件渲染,它在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。v-if是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
- v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
- v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
- 需要非常频繁地切换,则使用 v-show 较好;
- 如果在运行时条件很少改变,则使用 v-if 较好。
1.8-1.10 v-once,v-html,其中v-bind(缩写为:)
数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:,下面统一简称双括号。
<span>Message: {{ msg }}</span>
- 双括号会被替代为对应数据对象上msg的值。
- 只要绑定的数据对象上msg的值发生了改变,双括号的内容都会更新,这就是双向绑定。
- 通过使用 v-once 指令,执行一次性地插值,当数据改变时,插值处的内容不会更新
<span v-once>这个将不会改变: {{ msg }}</span>
- 双括号将数据解释为普通文本,非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html指令。
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
v-bind基本用法:
修饰符:
- .prop - 作为一个 DOM property 绑定而不是作为 attribute 绑定。
- .camel - (2.1.0+) 将 kebab-case attribute 名转换为 camelCase。(从 2.1.0 开始支持)
- .sync (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器。
用法:
- 动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。
- 在绑定 class 或 style attribute 时,支持其它类型的值,如数组或对象。
- 在绑定 prop 时,prop 必须在子组件中声明。可以用修饰符指定不同的绑定类型。
- 没有参数时,可以绑定到一个包含键值对的对象。注意此时 class 和 style 绑定不支持数组和对象。
- 双括号语法不能作用在 HTML attribute 上(如绑定id、class、href等情况)这个时候应该使用 v-bind 指令
<div v-bind:id="dynamicId"></div>
对于布尔 attribute (它们只要存在就意味着值为 true),v-bind 工作起来略有不同,在这个例子中:
<button v-bind:disabled="isButtonDisabled">Button</button>
v-bind的缩写形式 :href=“url” ,:id="123"的形式。
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写为:href="url" -->
<a :href="url">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
<!-- 绑定一个 attribute -->
<img v-bind:src="imageSrc">
<!-- 动态 attribute 名 (2.6.0+) -->
<button v-bind:[key]="value"></button>
<!-- 缩写 -->
<img :src="imageSrc">
<!-- 动态 attribute 名缩写 (2.6.0+) -->
<button :[key]="value"></button>
<!-- 内联字符串拼接 -->
<img :src="'/path/to/images/' + fileName">
<!-- class 绑定 -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]">
<!-- style 绑定 -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>
<!--绑定一个全是 attribute 的对象 -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
<!-- 通过 prop 修饰符绑定 DOM attribute -->
<div v-bind:text-content.prop="text"></div>
<!-- prop 绑定。“prop”必须在 my-component 中声明。-->
<my-component :prop="someThing"></my-component>
<!-- 通过 $props 将父组件的 props 一起传给子组件 -->
<child-component v-bind="$props"></child-component>
<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>
1.11 v-model(给表单控件绑定属性,在表单控件或者组件上创建双向绑定。)
v-model 会 忽略所有表单元素的 value、checked、selected, attribute 的初始值,而是 将Vue 实例的数据作为数据来源 。 你应该在组件的data 选项中声明初始值。
v-model的修饰符(lazy失去焦点/number转化为数字/trim过滤空格)
<input v-model.lazy="msg"> <!--失去焦点时候触发 ,取代 input 监听 change 事件-->
<input v-model.number="age" type="number"> <!--自动将用户的输入值转为数值类型-->
<input v-model.trim="msg"> <!--过滤用户输入的首尾空白字符-->
计算属性:Computed
模板内的表达式非常便利,适合用于简单运算的。在模板中放入太多的逻辑会变得十分复杂。
<div id="example"> <!--将message 分割-> 翻转-> 拼接 -->
{{ message.split('').reverse().join('') }}
</div>
本例,模板不再是简单的声明式逻辑。是显示变量 message 的翻转字符串。
对于任何复杂逻辑,应当使用计算属性。
<div id="example">
<p>Original msg: "{{ msg}}"</p>
<p>Computed reversed msg: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
msg: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.msg.split('').reverse().join('')
}
}
})
结果: Original msg: "Hello" Computed reversed msg: "olleH"
- 声明了一个计算属性 reversedMessage。
vm.reversedMessage 的 getter 函数:
console.log(vm.reversedMessage) // => 'olleH'
vm.message = 'Goodbye'
console.log(vm.reversedMessage) // => 'eybdooG'
- f12打开控制台修改 vm,msg的值。计算属性vm.reversedMessage 的值始终取决 vm.msg的值。
计算属性computed缓存 和函数function()的比较
- 在表达式中调用方法reveredMessage()来达到同样的效果:
<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在组件中
methods: { //在methods中定义相关方法
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
- 同一函数定义为一个方法,两种方式的结果是相同的。
- 不同的是计算属性是基于它们的响应式依赖进行缓存的。
- 只在响应式依赖发生改变时才会重新求值。这就意味着只要 message 还没有发生改变,多次访问
reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。 - 每当触发重新渲染时,调用方法将总会再次执行函数。
为什么需要缓存 ? 假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A。如果没有缓存,我们将不可避免的多次执行 A 的 getter!
下面用一个实例进行展示效果。
计算属性 vs 侦听属性
Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。
- 适合场景:数据变化时执行异步或开销较大的操作。
当你有一些数据需要随着其它数据变动而变动时。更好的做法是计算属性不是命令式的 watch 回调。
侦听器watch和计算属性computed的对比实例:
<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
}
},
computed: { //计算属性时不需要提供fullname
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
计算属性默认形式为 getter,只能返回计算值,你也可以提供一个 setter。
运行 vm.fullName = ‘John Doe’ 时,setter 会被调用,vm.firstName 和 vm.lastName 会被更新。
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]
}
}
}
实例:侦听器监听firstName和lastName
实例2:模拟异步任务,监听uname的变化,并调用checkName方法实现模拟验证。
vm.$watch()
用法:
- 观察 Vue 实例上的一个表达式或者一个函数计算结果的变化。
- 回调函数得到的参数为新值和旧值。
- 表达式只接受简单的键路径。对于更复杂的表达式,用一个函数取代。
// 键路径
vm.$watch('a.b.c', function (newVal, oldVal) {
// 做点什么
})
// 函数
vm.$watch(
function () {
// 表达式 `this.a + this.b` 每次得出一个不同的结果时
// 处理函数都会被调用。
// 这就像监听一个未被定义的计算属性
return this.a + this.b
},
function (newVal, oldVal) {
// 做点什么
}
)
过滤器filter(处理文本格式化):
Vue.js 允许你自定义过滤器,用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示:
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
在一个组件的选项中定义本地的过滤器:
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
全局定义过滤器:
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
当全局过滤器和局部过滤器重名时,会采用局部过滤器。
过滤器函数总接收表达式的值 (之前的操作链的结果) 作为第一个参数。
在上述例子中,capitalize 过滤器函数将会收到 message 的值作为第一个参数。
过滤器的串联:
{{ message | filterA | filterB }}
本例中,filterA 被定义为接收单个参数的过滤器函数,表达式 message 的值将作为参数传入到函数
中。继续调用同样被定义为接收单个参数的过滤器函数 filterB,将 filterA 的结果传递到 filterB 中。
过滤器是 JavaScript 函数,因此可以接收参数:
{{ message | filterA('arg1', arg2) }}
filterA 被定义为接收三个参数的过滤器函数。其中 message 的值作为第一个参数,普通字符串 ‘arg1’
作为第二个参数,表达式 arg2 的值作为第三个参数。
实例:一个全局filter实例 upper和 lower来控制首字母大小写 ,和一个局部实例 upper
1.12 v-text(等价于{{msg}})
一般来说v-text指令等价于{{msg}},所以直接双大括号{{ }}取值即可。
<span v-text="msg"></span>
<!-- 和下面的一样 -->
<span>{{msg}}</span>
1.13 v-cloak(增强用户体验)
- 指令保持在元素上直到关联实例,结束编译的时候结束。
- CSS 代码[v-cloak] { display: none }加上标签,指令隐藏未编译的{{msg}}标签直到实例准备完毕。
- 简单来说:增强用户体验,在标签没加载完成之前不会显示。加载过程就是由{{msg}}到msg里面值显示的过程,在网卡的时候不会显示双括号。
css添加代码如下
[v-cloak] {
display: none;
}
标签中代码如下
<div v-cloak>
{{ message }}
</div>
1.14 v-slot(插槽起别名,v-slot:可简写为#)详细可见组件篇插槽
**作用:**提供具名插槽或需要接收 prop 的插槽。
限制: 1. :template标签, 2. 组件中 (对于一个单独的带 prop 的默认插槽)
<!-- 具名插槽 -->
<base-layout>
<template v-slot:header>
Header content
</template>
Default slot content
<template v-slot:footer>
Footer content
</template>
</base-layout>
<!-- 接收 prop 的具名插槽 -->
<infinite-scroll>
<template v-slot:item="slotProps">
<div class="item">
{{ slotProps.item.text }}
</div>
</template>
</infinite-scroll>
<!-- 接收 prop 的默认插槽,使用了解构 -->
<mouse-position v-slot="{ x, y }">
Mouse position: {{ x }}, {{ y }}
</mouse-position>
2. Vue的生命周期
2.1 beforeCreate
在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用
2.2 created
在实例创建完成后被立即调用。挂载阶段还没开始,$el property 目前尚不可用。
2.3 beforeMount
在挂载开始之前被调用:相关的 render 函数首次被调用。
2.4 mounted
实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了。
如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm.el 也在文档内。
注意 mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以
在 mounted 内部使用 vm.$nextTick:
2.5 beforeUpdate(数据更新时调用)
适用于更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
2.6 updated
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,之后会调用该钩子。
当这个钩子被调用时,组件 DOM 已经更新,你可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。
注意 updated 不会保证所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm.$nextTick:
2.7 activated
被 keep-alive 缓存的组件激活时调用。
2.8 deactivated
被 keep-alive 缓存的组件停用时调用。
2.9 beforeDestroy(实例销毁之前调用)
在这一步,实例仍然完全可用。
2.10 destroyed(实例销毁后调用)
调用后,对应 Vue 实例的所有指令都被解绑、事件监听器被移除、子实例也都被销毁。
2.11 errorCaptured
3 Vue Api介绍
3.1 el(挂载点)
类型:string | Element
限制:只在用 new 创建实例时生效。
提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。
在实例挂载之后,元素可以用 vm.$ el 访问。
如果在实例化时存在这个选项,实例将立即进入编译过程,否则,需要显式调用 vm.$mount() 手动开启编译。
提供的元素只能作为挂载点。不同于 Vue 1.x,所有的挂载元素会被 Vue 生成的 DOM 替换。因此不推荐挂载 root 实例到 或者 上。
如果 render 函数和 template property 都不存在,挂载 DOM 元素的 HTML 会被提取出来用作模板,此时,必须使用 Runtime + Compiler 构建的 Vue 库。
3.2 data(数据对象)
类型:Object | Function
限制:组件的定义只接受 function。
详细:
Vue 实例的数据对象。Vue 将会递归将 data 的 property 转换为 getter/setter,从而让 data 的 property 能够响应数据变化。对象必须是纯粹的对象 (含有零个或多个的 key/value 对):浏览器 API 创建的原生对象,原型上的 property 会被忽略。大概来说,data 应该只能是数据 - 不推荐观察拥有状态行为的对象。
一旦观察过,你就无法在根数据对象上添加响应式 property。因此推荐在创建实例之前,就声明所有的根级响应式 property。
实例创建之后,可以通过 vm.
d
a
t
a
访
问
原
始
数
据
对
象
。
V
u
e
实
例
也
代
理
了
d
a
t
a
对
象
上
所
有
的
p
r
o
p
e
r
t
y
,
因
此
访
问
v
m
.
a
等
价
于
访
问
v
m
.
data 访问原始数据对象。Vue 实例也代理了 data 对象上所有的 property,因此访问 vm.a 等价于访问 vm.
data访问原始数据对象。Vue实例也代理了data对象上所有的property,因此访问vm.a等价于访问vm.data.a。
以 _ 或 $ 开头的 property 不会被 Vue 实例代理,因为它们可能和 Vue 内置的 property、API 方法冲突。你可以使用例如 vm.
d
a
t
a
.
p
r
o
p
e
r
t
y
的
方
式
访
问
这
些
p
r
o
p
e
r
t
y
。
当
一
个
组
件
被
定
义
,
d
a
t
a
必
须
声
明
为
返
回
一
个
初
始
数
据
对
象
的
函
数
,
因
为
组
件
可
能
被
用
来
创
建
多
个
实
例
。
如
果
d
a
t
a
仍
然
是
一
个
纯
粹
的
对
象
,
则
所
有
的
实
例
将
共
享
引
用
同
一
个
数
据
对
象
!
通
过
提
供
d
a
t
a
函
数
,
每
次
创
建
一
个
新
实
例
后
,
我
们
能
够
调
用
d
a
t
a
函
数
,
从
而
返
回
初
始
数
据
的
一
个
全
新
副
本
数
据
对
象
。
如
果
需
要
,
可
以
通
过
将
v
m
.
data._property 的方式访问这些 property。 当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。 如果需要,可以通过将 vm.
data.property的方式访问这些property。当一个组件被定义,data必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果data仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供data函数,每次创建一个新实例后,我们能够调用data函数,从而返回初始数据的一个全新副本数据对象。如果需要,可以通过将vm.data 传入 JSON.parse(JSON.stringify(…)) 得到深拷贝的原始数据对象。
3.3 methods(方法函数)
类型:{ [key: string]: Function }
详细:
methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为 Vue 实例。
注意,不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined。
3.4 computed
类型:{ [key: string]: Function | { get: Function, set: Function } }
详细:
计算属性将被混入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。
注意如果你为一个计算属性使用了箭头函数,则 this 不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问。
计算属性的结果会被缓存,除非依赖的响应式 property 变化才会重新计算。注意,如果某个依赖 (比如非响应式 property) 在该实例范畴之外,则计算属性是不会被更新的。
3.5 watch
类型:{ [key: string]: string | Function | Object | Array }
详细:
一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个 property。
注意,不应该使用箭头函数来定义 watcher 函数 (例如 searchQuery: newValue => this.updateAutocomplete(newValue))。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.updateAutocomplete 将是 undefined。
3.6-3.17 11个生命周期函数都可以当做选项,具体见2.1-2.11
3.15实例 property
vm.$data
Vue 实例观察的数据对象。Vue 实例代理了对其 data 对象 property 的访问。
vm.$props
当前组件接收到的 props 对象。Vue 实例代理了对其 props 对象 property 的访问。
vm.$el
Vue 实例使用的根 DOM 元素。
vm.$options
用于当前 Vue 实例的初始化选项。需要在选项中包含自定义 property 时会有用处:
new Vue({
customOption: 'foo',
created: function () {
console.log(this.$options.customOption) // => 'foo'
}
})
vm.$parent
父实例,如果当前实例有的话。
vm.$root
当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。
vm.$children
当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的。如果你使用 $children 来进行数据绑定,使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为来源。
vm.$slots (访问被插槽分发的内容)
每个具名插槽有其相应的 property (例如:v-slot:foo 中的内容将会在 vm.$slots.foo 中被找到)。default property 包括了所有没有被包含在具名插槽中的节点,或 v-slot:default 的内容。
注意:v-slot:foo 在 2.6 以上的版本才支持。对于之前的版本,你可以使用废弃了的语法。
在使用渲染函数书写一个组件时,访问 vm.$slots 最有帮助。
示例:
<blog-post>
<template v-slot:header>
<h1>About Me</h1>
</template>
<p>Here's some page content, which will be included in vm.$slots.default, because it's not inside a named slot.</p>
<template v-slot:footer>
<p>Copyright 2016 Evan You</p>
</template>
<p>If I have some content down here, it will also be included in vm.$slots.default.</p>.
</blog-post>
Vue.component('blog-post', {
render: function (createElement) {
var header = this.$slots.header
var body = this.$slots.default
var footer = this.$slots.footer
return createElement('div', [
createElement('header', header),
createElement('main', body),
createElement('footer', footer)
])
}
})
vm.$scopedSlots (访问作用域插槽)
对于包括 默认 slot 在内的每一个插槽,该对象都包含一个返回相应 VNode 的函数。
vm.$scopedSlots 在使用渲染函数开发一个组件时特别有用。
注意:从 2.6.0 开始,这个 property 有两个变化:
作用域插槽函数现在保证返回一个 VNode 数组,除非在返回值无效的情况下返回 undefined。
所有的 $slots 现在都会作为函数暴露在 $scopedSlots 中。如果你在使用渲染函数,不论当前插槽是否带有作用域,我们都推荐始终通过 $scopedSlots 访问它们。这不仅仅使得在未来添加作用域变得简单,也可以让你最终轻松迁移到所有插槽都是函数的 Vue 3。
vm.$refs和ref attribute
- ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。
- 在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
- vm.$refs是一个对象,持有注册过 ref attribute 的所有 DOM 元素和组件实例。
第一行在子组件中起别名aaa,父组件可以直接访问button-counter,第二行普通标签p,则就是p标签
打印所有存在ref别名的元素或者组件实例。
注意:
- $refs 只会在组件渲染完成之后生效,并且它们不是响应式的。
- 这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs。
vm.$isServer
当前 Vue 实例是否运行于服务器。
vm.$attrs(class 和 style 除外)
- 父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 。
- 当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定,
- 并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。
- 父组件传给儿子组件书名book,没有content和price。
- 给孙子模板绑定v-bind="$attrs"指令来拿到父组件的数据。
效果图,第一个没有v-bind="$attrs",第二个绑定了。
vm.$listeners
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。
通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
3.16实例方法 / 数据(三个函数)
vm.$watch( expOrFn, callback, [options] )
见上面指令篇的watch侦听属性。
vm.$set( target, propertyName/index, value )
- 全局 Vue.set 的别名。
基本用法:
Vue.set(this.namelist,'name');//vue方法
Vue.set(vm.namelist,'name');//vm实例的对象,并设置name
Vue.set(vm.msglist,2);//vm实例的数组,并设置第二个元素
vm.$delete( target, propertyName/index )
- 全局 Vue.delete 的别名。
基本用法:
Vue.delete(this.namelist,'name');//vue方法
Vue.delete(vm.namelist,'name');//vm实例的对象,并删除name
Vue.delete(vm.msglist,2);//vm实例的数组,并删除第二个元素
3.17实例方法 / 事件(四个函数)
vm.$on( event, callback )监听当前实例上的自定义事件。
事件可以由 vm.$emit 触发。回调函数会接收所有传入事件触发函数的额外参数。
如本例,emit触发test事件传参hi, $on用msg接收参数hi并打印
vm.$on('test', function (msg) {
console.log(msg)
})
vm.$emit('test', 'hi')
// => "hi"
vm.$once( event, callback )
- 监听一个自定义事件,只触发一次。
- 一旦触发之后,监听器就会被移除。
vm.$off( [event, callback] ) 移除自定义事件监听器。
如果没有提供参数,则移除所有的事件监听器;
如果只提供了事件,则移除该事件所有的监听器;
如果同时提供了事件与回调,则只移除这个回调的监听器。
vm.$emit( eventName, […args] )详细见组件篇目说明
触发当前实例上的事件。附加参数都会传给监听器回调。
3.18 实例方法 / 生命周期(四个函数
vm.$ mount()
如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。
使用 vm.$mount() 手动地挂载一个未挂载的实例。
vm.$ forceUpdate()
迫使 Vue 实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
vm.$ nextTick( function(){} )
- 将回调延迟到下次 DOM 更新循环之后执行。
- 在修改数据之后立即使用它,然后等待 DOM 更新。
- 它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
vm.$destroy()
- 完全销毁一个实例。清理它与其它实例的连接,解绑它的全部指令及事件监听器。
- 触发 beforeDestroy 和 destroyed 的钩子。
4. 组件篇
- 组件是可复用的 Vue 实例,并带有一个名字:在本例中是 。在一个通过 new Vue 创建的 Vue 根实例中,把组件当自定义元素来使用。
- 一个组件的 data 选项必须是一个函数,确保每个实例可以维护一份唯一的数据。
- 通过 Prop 向(子组件)中传递数据。可以是字符、数字、布尔、数组和对象五种形式。
- 单个根元素:每个组件只有一个根元素,简单来说一个最外层元素、标签。
- 子组件可以调用 $emit 方法并传入事件名称来触发一个父组件的事件。
- 自定义事件可以用于创建,支持 v-model 的自定义输入组件。
- 通过标签slot来分发内容。
- 动态组件
Vue.component('button-counter', {// 定义一个名为 button-counter 的新组件
props: ['title'],
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
4.1: vm.$emit( eventName, […args] ) 子传父,子调父
函数作用:触发当前实例上的事件,附加参数都会传给监听器回调。
参数类型主要有六种类型,无参构造、有参构造两种、嵌套有无参构造下面给出示例。
- 步骤一:在模板定义相关点击事件函数,触发emit回调至父组件,可以简单传定值参数。
- 步骤二:在父组件监听事件并回调至methods执行相应方法,接收参数则需要$event。
- 步骤三:定义相关方法(函数)来进行相应的有无参数操作。
总结:
- 在模板中传参只能写成固定值例如123或者’hello world之类的定值,不能直接访问组件中的data例如本例中的num,如果访问则结果变为undefined。
- 如需调用还需使用内嵌形式,所谓内嵌就是在组件方法中调用emit。
- 在组件的方法中调用emit并this.num的形式传参,在父组件中使用$event来接收参数,并在父组件的methods方法中使用。
4.2 Prop介绍
- 这两个示例中,传值都是字符串类型的,实际上任何类型的值都可以传给一个 prop。
<blog-post title="My journey with Vue"></blog-post>
<!-- 动态赋予一个变量的值 -->
<blog-post v-bind:title="post.title"></blog-post>
<!-- 动态赋予一个复杂表达式的值 -->
<blog-post
v-bind:title="post.title + ' by ' + post.author.name">
</blog-post>
prop传数字、布尔、对象、数组的示例。
<blog-post v-bind:likes="42"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:likes="post.likes"></blog-post>
<!-- 包含该 prop 没有值的情况在内,都意味着 `true`。-->
<blog-post is-published></blog-post>
<blog-post v-bind:is-published="false"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:is-published="post.isPublished"></blog-post>
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:comment-ids="post.commentIds"></blog-post>
<blog-post
v-bind:author="{
name: 'Veronica',
company: 'Veridian Dynamics'
}"
></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:author="post.author"></blog-post>
传入一个对象的所有 property:
<blog-post v-bind="post"></blog-post>
等价于:
<blog-post
v-bind:id="post.id"
v-bind:title="post.title"
></blog-post>
单向数据流:简单来说:prop都是父组件对子组件的单向数据传输。
- prop 都使其父子 prop 形成了单向下行绑定:父级 prop 的更新会向下流动到子组件中,防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
- 当父级组件发生变更时,子组件中所有的 prop 都将刷新为最新的值。这代表你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
4.2.1两种常见的手段来操作 prop 的情形:
- prop 接收父组件的传值,子组件定义一个本地的数据counter来将"initialcounter" 用作其初始值。
props: ['initialCounter'], //接收父组件传递的initialcounter值
data: function () {
return {
counter: this.initialCounter //将initialcounter传给counter实现本地化。
}
}
- prop接收父组件传值size,子组件定义计算属性"normalizerSize"来返回size的表达式。
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
- 在 js 中对象和数组是通过引用传入的,对于数组或对象类型的 prop 来说,在子组件中改变对象或数组本身将会影响到父组件的状态。
4.2.2 Prop 验证(未完结待更新)
为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。
为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。
注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的 property (如 data、computed 等) 在 default 或 validator 函数中是不可用的。
类型检查
type 可以是下列原生构造函数中的一个:
String
Number
Boolean
Array
Object
Date
Function
Symbol
额外的,type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认。例如,给定下列现成的构造函数:
function Person (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
你可以使用:
Vue.component(‘blog-post’, {
props: {
author: Person
}
})
来验证 author prop 的值是否是通过 new Person 创建的。
非 Prop 的 Attribute
一个非 prop 的 attribute 是指传向一个组件,但是该组件并没有相应 prop 定义的 attribute。
因为显式定义的 prop 适用于向一个子组件传入信息,然而组件库的作者并不总能预见组件会被用于怎样的场景。这也是为什么组件可以接受任意的 attribute,而这些 attribute 会被添加到这个组件的根元素上。
例如,想象一下你通过一个 Bootstrap 插件使用了一个第三方的 组件,这个插件需要在其 上用到一个 data-date-picker attribute。我们可以将这个 attribute 添加到你的组件实例上:
然后这个 data-date-picker=“activated” attribute 就会自动添加到 的根元素上。
替换/合并已有的 Attribute
想象一下 的模板是这样的:
<bootstrap-date-input
data-date-picker=“activated”
class=“date-picker-theme-dark”
在这种情况下,我们定义了两个不同的 class 的值:
form-control,这是在组件的模板内设置好的
date-picker-theme-dark,这是从组件的父级传入的
对于绝大多数 attribute 来说,从外部提供给组件的值会替换掉组件内部设置好的值。所以如果传入 type=“text” 就会替换掉 type=“date” 并把它破坏!庆幸的是,class 和 style attribute 会稍微智能一些,即两边的值会被合并起来,从而得到最终的值:form-control date-picker-theme-dark。
禁用 Attribute 继承
如果你不希望组件的根元素继承 attribute,你可以在组件的选项中设置 inheritAttrs: false。例如:
Vue.component(‘my-component’, {
inheritAttrs: false,
// …
})
这尤其适合配合实例的 $attrs property 使用,该 property 包含了传递给一个组件的 attribute 名和 attribute 值,例如:
{
required: true,
placeholder: ‘Enter your username’
}
有了 inheritAttrs: false 和 $attrs,你就可以手动决定这些 attribute 会被赋予哪个元素。在撰写基础组件的时候是常会用到的:
Vue.component(‘base-input’, {
inheritAttrs: false,
props: [‘label’, ‘value’],
template: <label> {{ label }} <input v-bind="$attrs" v-bind:value="value" v-on:input="$emit('input', $event.target.value)" > </label>
})
注意 inheritAttrs: false 选项不会影响 style 和 class 的绑定。
这个模式允许你在使用基础组件的时候更像是使用原始的 HTML 元素,而不会担心哪个元素是真正的根元素:
<base-input
v-model=“username”
required
placeholder=“Enter your username”
4.3 自定义事件
4.4插槽
插槽内容: 1. 普通文本 2. 标签 3. 其他组件
编译作用域: 插槽跟模板的其它地方一样可以访问相同的实例 property (也就是相同的“作用域”)
规则:(简称父在父,子在子)
- 父级模板里的所有内容都是在父级作用域中编译的;
- 子模板里的所有内容都是在子作用域中编译的。
后备内容(或者叫默认内容)
标签中调用
输出结果:
具名插槽:(根据名字的标签分发内容) v-slot:header可以缩写#header的形式
主要有两种样式:
- 在template标签中使用v-slot:header起别名的形式,使用v-slot指令来取名,默认为default。
- 使用标签header、main、footer和模板中的一致。
模板中定义的内容:
作用域插槽:(使插槽内容能访问子组件中才有的数据)
插槽内容和插槽不一样要注意:
- 插槽内容实际上定义在父级作用域,相对于组件来说,无法直接访问子组件的相应数据。
- 绑定在slot元素上的attribute被称为插槽 prop,用v-bind:user='user’来绑定。
- 简写为:user=‘user’,为了将zujian3中的user传递给插槽,这样插槽内容通过插槽prop中就可以访问zujian3中的user数据。
在父级作用域中,使用带值的 v-slot 来定义插槽 prop的名字,v-slot:可以简写为#。
总结: 插槽是slot标签,而插槽内容是父级作用域中显示在插槽标签中的内容。
插槽内容的作用域是比模板高的,所以插槽标签在模板中可以直接访问组件中的data数据,而插槽内容不可以,所以通过作用域插槽来使得插槽内容访问组件中的数据。