渐进式 JavaScript 框架 Vue 2 开发速查手册的快速参考列表,包含常用 API 和示例。
Vue 是一套用于构建用户界面的渐进式框架
注意:Vue 2.x 版本对应 Vue Router 3.x 路由版本
npx @vue/cli create hello-world
参考: Vue CLI 创建一个项目
<div id="example">
<p>原始信息: "{{ message }}"</p>
<p>
计算的反向信息: "{{ reversedMessage }}"
</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('')
.reverse().join('')
}
}
})
结果
原始信息: "Hello"
计算的反向信息: "olleH"
<li v-for="value in object">
{{ value }}
</li>
如下 data
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
渲染结果
How to do lists in Vue
Jane Doe
2016-04-10
提供第二个的参数为 property 名称 (也就是键名)
<div v-for="(value, name) in object">
{{ name }}: {{ value }}
</div>
还可以用第三个参数作为索引
<div v-for="(value,name,index) in object">
{{ index }}. {{ name }}: {{ value }}
</div>
<li
v-for="todo in todos"
v-if="!todo.isComplete"
>
{{ todo }}
</li>
只渲染未完成的 todo,下面加上 v-else 示例
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
注意: v-for 和 v-if 不推荐一起使用参考官方文档
<div id="example-2">
<!-- `greet` 是在下面定义的方法名 -->
<button v-on:click="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)
}
}
}
})
也可以用 JavaScript 直接调用方法
example2.greet() // => 'Hello Vue.js!'
<div id="example-3">
<button v-on:click="say('hi')">
弹出 hi
</button>
<button v-on:click="say('what')">
弹出 what
</button>
</div>
new Vue({
el: '#example-3',
methods: {
say: function (message) {
alert(message)
}
}
})
访问原始的 DOM 事件,用特殊变量 $event
<button v-on:click="say('what', $event)">
提交
</button>
methods: {
say: function (message, event) {
// 现在我们可以访问原生事件对象
if (event) {
event.preventDefault()
}
alert(message)
}
}
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="submit"></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() 的情况 -->
<p v-on:scroll.passive="onScroll">
...
</p>
这个 .passive 修饰符尤其能够提升移动端的性能。
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>
计算的反向消息: "{{ reversedMessage }}"
</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('')
.reverse().join('')
}
}
})
<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
}
}
})
上面代码是命令式且重复的。将它与计算属性的版本进行比较:
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName
+ ' ' + this.lastName
}
}
})
<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>
如下 data
new Vue({
el: '...',
data: {
checkedNames: []
}
})
<select v-model="selected">
<option
v-for="option in options"
v-bind:value="option.value"
>
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
new Vue({
el: '...',
data: {
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
}
})
将 HTML/CSS/JS 三部分存放到一个 Hello.vue 文件中
<template>
<p>{{ title }} World!</p>
</template>
<script>
export default {
name: 'Hello',
props: {
title: {
type: String,
default: 'Hello'
}
},
data: function() {
return {
greeting: "Hello"
};
}
};
</script>
<style scoped>
p {
font-size: 2em;
text-align: center;
}
</style>
使用 Hello.vue 组件
<script>
import Vue from "vue";
import Hello from "./Hello";
export default {
components: { Hello }
}
</script>
<template>
<div>
<Hello :title="'aaaa'"></Hello>
</div>
</template>
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: `
<button v-on:click="count++">
你点击了我 {{ count }} 次
</button>
`
})
组件是可复用的 Vue 实例
<div id="components-demo">
<button-counter></button-counter>
</div>
new Vue({
el: '#components-demo'
})
组件的复用
<div id="components-demo">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<button
v-on:click="$emit('enlarge-txt')"
>放大文字
</button>
<div v-html="post.content"></div>
</div>
`
})
<blog-post
...
v-on:enlarge-text="postFontSize += 0.1"
></blog-post>
可以使用 $emit 的第二个参数来提供这个值
<button
v-on:click="$emit('enlarge-text', 0.1)"
>
Enlarge text
</button>
通过 $event 访问到被抛出的这个值
<blog-post
...
v-on:enlarge-text="postFontSize += $event"
></blog-post>
如果这个事件处理函数是一个方法
<blog-post
...
v-on:enlarge-text="onEnlargeText"
></blog-post>
那么这个值将会作为第一个参数传入这个方法
methods: {
onEnlargeText: function(enlargeAmount) {
this.postFontSize += enlargeAmount
}
}
自定义事件也可以用于创建支持 v-model 的自定义输入组件。
<input v-model="searchText">
等价于
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
当用在组件上时,v-model 则会这样:
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
为了让它正常工作,这个组件内的 <input> 必须:
value attribute 绑定到一个名叫 value 的 prop 上input 事件被触发时,将新的值通过自定义的 input 事件抛出Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
现在 v-model 就应该可以在这个组件上完美地工作起来了
<custom-input
v-model="searchText"
>
</custom-input>
<div id="dynamic-component-demo" class="demo">
<button
v-for="tab in tabs"
v-bind:key="tab"
v-bind:class="['tab-button', { active: currentTab === tab }]"
v-on:click="currentTab = tab"
>
{{ tab }}
</button>
<component v-bind:is="currentTabComponent" class="tab"></component>
</div>
<script>
Vue.component("tab-home", {
template: "<div>Home component</div>"
});
Vue.component("tab-posts", {
template: "<div>Posts component</div>"
});
Vue.component("tab-archive", {
template: "<div>Archive component</div>"
});
new Vue({
el: "#dynamic-component-demo",
data: {
currentTab: "Home",
tabs: ["Home", "Posts", "Archive"]
},
computed: {
currentTabComponent: function() {
return "tab-" + this.currentTab.toLowerCase();
}
}
});
</script>
有些 HTML 元素,诸如 <ul>、<ol>、<table> 和 <select>,对于哪些元素可以出现在其内部是有严格限制的。有些元素,诸如 <li>、<tr> 和 <option>,只能出现在其它某些特定的元素内部
<table>
<blog-post-row></blog-post-row>
</table>
<blog-post-row> 会被作为无效的内容提升到外部
如果我们从以下来源使用模板的话,这条限制是不存在的
template: '...').vue)<script type="text/x-template"><template>
<button v-on:click="show = !show">
切换
</button>
<transition name="fade">
<p v-if="show">切换内容</p>
</transition>
</template>
<script>
export default {
data: function() {
return {
show: true
};
}
};
</script>
<style scoped>
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
/* .fade-leave-active 低于 2.1.8 版本 */
.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>
<template>
<button @click="show = !show">
切换渲染
</button>
<transition name="slide-fade">
<p v-if="show">切换内容</p>
</transition>
</template>
<script>
export default {
data: function() {
return {
show: true
};
}
};
</script>
<style scoped>
/* 可以设置不同的进入和离开动画 */
/* 设置持续时间和动画函数 */
.slide-fade-enter-active {
transition: all .3s ease;
}
.slide-fade-leave-active {
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
/* .slide-fade-leave-active 用于 2.1.8 以下版本 */
.slide-fade-enter, .slide-fade-leave-to {
transform: translateX(10px);
opacity: 0;
}
</style>
<template>
<button @click="show = !show">切换展示</button>
<transition name="bounce">
<p v-if="show">切换内容</p>
</transition>
</template>
<script>
export default {
data: function() {
return {
show: true
};
}
};
</script>
<style scoped>
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
</style>
| :- | :- |
|---|---|
v-enter | 定义进入过渡的开始状态 # |
v-enter-active | 定义进入过渡生效时的状态 # |
v-enter-to (2.1.8) | 定义进入过渡的结束状态 # |
v-leave | 定义离开过渡的开始状态 # |
v-leave-active | 定义离开过渡生效时的状态 # |
v-leave-to (2.1.8) | 定义离开过渡的结束状态 # |
如果你使用了 <transition name="my-tran">,那么 v-enter 会替换为 my-tran-enter。
| :- | :- |
|---|---|
enter-class | # |
enter-active-class | # |
enter-to-class (2.1.8+) | # |
leave-class | # |
leave-active-class | # |
leave-to-class (2.1.8+) | # |
<transition
name="custom-classes-transition"
enter-active-class="animated tada"
leave-active-class="animated bounceOutRight"
>
<p v-if="show">hello</p>
</transition>
可以通过 appear attribute 设置节点在初始渲染的过渡
<transition appear>
<!-- ... -->
</transition>
这里默认和进入/离开过渡一样,同样也可以自定义 CSS 类名
<transition
appear
appear-class="custom-appear-class"
appear-to-class="custom-appear-to-class"
appear-active-class="custom-appear-active-class"
>
<!-- ... -->
</transition>
自定义 JavaScript 钩子:
<transition
appear
v-on:before-appear="customBeforeAppearHook"
v-on:appear="customAppearHook"
v-on:after-appear="customAfterAppearHook"
v-on:appear-cancelled="customAppearCancelledHook"
>
<!-- ... -->
</transition>
无论是 appear attribute 还是 v-on:appear 钩子都会生成初始渲染过渡
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
<!-- ... -->
</transition>
钩子函数可以结合 CSS transitions/animations 使用,也可以单独使用
<template>
<button v-on:click="add">添加</button>
<button v-on:click="remove">删除</button>
<transition-group name="list" tag="p">
<span v-for="item in items" v-bind:key="item" class="list-item">
{{ item }}
</span>
</transition-group>
</template>
<script>
export default {
data: function() {
return {
items: [1,2,3,4,5,6,7,8,9],
nextNum: 10
};
},
methods: {
randomIndex: function () {
return Math.floor(Math.random() * this.items.length)
},
add: function () {
this.items.splice(this.randomIndex(), 0, this.nextNum++)
},
remove: function () {
this.items.splice(this.randomIndex(), 1)
},
}
};
</script>
<style scoped>
.list-item {
display: inline-block;
margin-right: 10px;
}
.list-enter-active, .list-leave-active {
transition: all 1s;
}
/* .list-leave-active 适用于 2.1.8 以下版本 */
.list-enter, .list-leave-to {
opacity: 0;
transform: translateY(30px);
}
</style>
| :- | :- |
|---|---|
vm.$data | 观察的数据对象 # |
vm.$props (2.2.0) | 组件接收的 props 对象 # |
vm.$el | 实例使用的根 DOM 元素 # |
vm.$options | 实例的初始化选项 # |
vm.$parent | 父实例 # |
vm.$root | 当前组件树的根实例 # |
vm.$children | 当前实例的直接子组件 # |
vm.$slots | 访问被插槽分发的内容 # |
vm.$scopedSlots (2.1.0) | 访问作用域插槽 # |
vm.$refs | DOM 元素和组件实例 # |
vm.$isServer | 是否运行于服务器 # |
vm.$attrs (2.4.0) | 包含父作用域中不作为 prop 被识别的属性绑定 ( # |
vm.$listeners (2.4.0) | 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器 # |
| :- | :- |
|---|---|
v-on:click.stop # | 调用 event.stopPropagation()。 |
v-on:click.prevent # | 调用 event.preventDefault()。 |
v-on:click.capture # | 添加事件侦听器时使用 capture 模式。 |
v-on:click.self # | 只当事件是从侦听器绑定的元素本身触发时才触发回调。 |
v-on:click.{keyCode|keyAlias} # | 只当事件是从特定键触发时才触发回调。 |
v-on:click.native # | 监听组件根元素的原生事件。 |
v-on:click.once # | 只触发一次回调。 |
v-on:click.passive (2.3.0) # | 以 { passive: true } 模式添加侦听器 |