概述:一套用于构建用户界面的渐进式框架。
vue被设计为可以自底向上逐层应用,vue的核心库只关注视图层,易于上手且便于与第三方库或已有项目进行整合。
VUE基础概述
环境
想要使用vue有两种方式:
-
直接在html文件的
<script>
中引入xur.js可以直接下载,或者使用CDN。
<!-- 带有帮助信息的开发环境版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <!-- 优化大小速度的生产环境版本 --> <script src="https://cdn.jsdelivr.net/npm/vue"></script>
使用命令行工具:
vue-cli
基本操作
首先,vue其实就是一个js框架。
其精妙之处在于虚拟化了一个DOM对象,并在未加载html时就对该对象进行虚拟操作,等到加载后,该虚拟对象与真实的htmlDOM对象进行了关联,此时操作就会由真实DOM呈现。
基础渲染
文本插值:
<div id="app">
{{ message }}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
</script>
绑定attribute
<div id="app-2">
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
<script>
var app2 = new Vue({
el: '#app-2',
data: {
message: '页面加载于 ' + new Date().toLocaleString()
}
})
</script>
条件与循环
v-if
<div id="app-3">
<p v-if="seen">现在你看到我了</p>
</div>
<script>
var app3 = new Vue({
el: '#app-3',
data: {
seen: true
}
})
</script>
继续在控制台输入 app3.seen = false
,你会发现之前显示的消息消失了。
v-for
<div id="app-4">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</div>
<script>
var app4 = new Vue({
el: '#app-4',
data: {
todos: [
{ text: '学习 JavaScript' },
{ text: '学习 Vue' },
{ text: '整个牛项目' }
]
}
})
</script>
在控制台里,输入 app4.todos.push({ text: '新项目' })
,你会发现列表最后添加了一个新项目。
事件监控器
v-on:***
<div id="app-5">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">反转消息</button>
</div>
<script>
var app5 = new Vue({
el: '#app-5',
data: {
message: 'Hello Vue.js!'
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})
</script>
console输出myapp5.btnDown = function(){this.btnMsg = '嘻嘻';}
,则按下按钮会变。
表单
Vue 还提供了 v-model
指令,它能轻松实现表单输入和应用状态之间的双向绑定。
双向绑定:修改message
会修改表单内内容,修改表单内内容,会修改massage
<div id="app-6">
<p>{{ message }}</p>
<input v-model="message">
</div>
<script>
var app6 = new Vue({
el: '#app-6',
data: {
message: 'Hello Vue!'
}
})
</script>
组件化应用构建
组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:
组件:拥有预定义选项的 Vue 实例。(类似于javaBean:可重用组件)
注册组件方式:
①<script>
中创建组件
几个要点:
-
props
:起着占位符的作用,里面是占位符数组。传值方式:
- 在html使用组件时,开始标签中使用
propName=""
来传递 - 在html使用组件时,开始标签中使用
v-bind:porpName=""
来传递。
- 在html使用组件时,开始标签中使用
template
:被调用时,显示的内容。其内容可以跟普通 html 标签完全一样data
:数据methods
:函数方法
<!-- 组件化应用 -->
<div id="app-7">
<ol>
<xixi v-for="fruit in fruits" v-bind:todo="fruit"></xixi>
<button-counter title="①"></button-counter>
<button-counter title="②"></button-counter>
</ol>
</div>
<script>
Vue.component('button-counter',{
props:['title'],
template:'<button v-on:click="count++">{{title}}点了我{{count}}次</button>',
data:function(){
return{
count: 0
}
},
})
Vue.component('xixi',{
props:['todo'],
template: '<li v-on:click="changeName()">{{todo.text}}</li>',
methods: {
changeName: function(){
this.todo.text = "荔枝";
},
}
})
</script>
实际模型概述
<div id="app">
<app-nav></app-nav>
<app-view>
<app-sidebar></app-sidebar>
<app-content></app-content>
</app-view>
</div>
VUE实例
创建一个Vue实例
规范:
- 一个根 Vue 实例
- 可选的嵌套的可重用组件(也是 Vue 实例)
根实例
└─ TodoList
├─ TodoItem
│ ├─ DeleteTodoButton
│ └─ EditTodoButton
└─ TodoListFooter
├─ ClearTodosButton
└─ TodoListStatistics
数据与方法
当一个Vue实例被创建时,会将data
对象的所有 property 加入到Vue 的响应式系统中;当某个属性发生变化时,该系统会产生响应,作用到视图上就是更新为新的值。(双向)
响应式:
当数据改变时,视图会进行冲渲染。注意:仅当存在于Vue实例的data
对象中的属性(数据)才是响应式的。
一些小知识:
-
初始值:(以后可能会用到该数据,先将其变成响应式数据)
data: { newTodoText: '', visitCount: 0, hideCompletedTodos: false, todos: [], error: null }
例外:Object.freeze(obj)
该语句会阻止对已有对象obj
的修改。所以该对象的属性的响应式功能会失效。
var obj = {
foo: 'bar'
}
Object.freeze(obj)
new Vue({
el: '#app',
data: obj
})
<div id="app">
<p>{{ foo }}</p>
<!-- 这里的 `foo` 不会更新! -->
<button v-on:click="foo = 'baz'">Change it</button>
</div>
Vue提供的实例
所有的new出来的Vue实例,都继承了Vue定义的property与方法;
语法:$属性
如:
var data = { a: 1 }
var vm = new Vue({
el: '#example',
data: data
})
vm.$data === data // => true
vm.$el === document.getElementById('example') // => true
// $watch 是一个Vue定义的实例方法
vm.$watch('a', function (newValue, oldValue) {
// 这个回调将在 `vm.a` 改变后调用
})
以后你可以在 API 参考中查阅到完整的实例 property 和方法的列表
Vue实例的生命周期钩子
创建:
每个Vue实例被创建时,都要经过一系列的初始化过程:
- 设置数据监听
- 编译模板
- 将实例挂载关联到DOM,并在数据变化时更新DOM
- ...
在这个过程中,同时会运行一些叫生命周期钩子的函数。
作用:用户可在不同阶段添加自己的代码。如:
created
会在Vue创建后,执行
new Vue({
data: {
a: 1
},
created: function () {
// `this` 指向 vm 实例
console.log('a is: ' + this.a)
}
})
// => "a is: 1"
生命周期钩子:
created
-
mounted
(已安装、已挂载) updated
destroyed
生命周期钩子的this
,指调用它的Vue实例。
注意:
不要在选项 property 或回调上使用箭头函数,比如
created: () => console.log(this.a) 或
vm.$watch('a', newValue => this.myMethod())。
因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致
Uncaught TypeError: Cannot read property of undefined 或
Uncaught TypeError: this.myMethod is not a function 之类的错误。
生命周期图示
模板语法
插值
文本
最常见格式:
-
{{}}
- "Mustache"(八字胡)语法,双大括号中插入变量名
如:
{{msg}}
,显示时会显示msg
这个属性的值,且具有响应式更新。 -
v-once
-
一次性的放置数据,之后数据改变时,该插值内容不会变。如:
<span v-once>这个将不会变:{{msg}}</span>
-
原始 HTML
说明:使用{{}}
,里面的数据将被解释为普通文本,而非 HTML 代码。
如:
<!--假定msg='<b>你好</b>'-->
<div id="example">
{{msg}} //显示的信息为:<b>你好</b>,而非粗体你好
</div>
指令:
-
v-html = "data"
<p> 使用双括号:{{rawHtml}} </p> <p> 使用v-html指令:<span v-html="rawHtml"></span> </p>
注意:
你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。
Attribute属性
说明:Mustache
语法不能作用在 HTML 标签属性上,如果需要,可以使用v-bind
指令
指令:
-
v-bind:AttributeName = "data"
<div v-bind:id="dynamicId"></div>
使用 JS 表达式
说明:插值不仅包含普通的属性键值,还可以支持完整的 JS 表达式。
{{ number + 1 }}
{{ ok? 'yes':'no' }}
{{ message.split('').reverse().join('.') }}
<div v-bind:id="'list-' + id"></div>
限制:
只能包含单个表单,所以下面的例子不会生效:
<!-- 这是语句不是表达式 -->
{{ var a = 1 }}
<!-- 流控制也不会生效,可以用三元表达式代替 -->
{{ if (ok) { return message } }}
注意:
模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如
Math
和Date
。你不应该在模板表达式中试图访问用户定义的全局变量。
指令
说明:指令(Directives)指标签元素中带有:v-
前缀的特殊属性。
职责:
预期职责:作为单个 JavaScript 表达式(v-for是例外情况),当指令改变时,会响应式地对整个标签起作用。如:
<p v-if="seen">现在看得见</p>
当seen
的值由true
变为false
时,该DOM会被重新渲染,直接移除。
参数
说明:一些指令能够接收一个"参数",在指令名称之后,以冒号表示。如:
<a v-bind:href="url">
本链接的地址是:{{url}}
</a>
其可以接收从 Vue 挂载对象的属性,已达到更复杂多样的变化。
动态参数
2.6.0新增
说明:
可以用方括号括起来的 JavaScript 表达式作为一个指令的参数:
<!--
注意,参数表达式的写法存在一些约束,如之后的“对动态参数表达式的约束”章节所述。
-->
<a v-bind:[attributeName]="url"> ... </a>
这里的 attributeName
会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果你的 Vue 实例有一个 data
property attributeName
,其值为 "href"
,那么这个绑定将等价于 v-bind:href
。
对动态参数的值的约束
动态参数预期会求出一个字符串,异常情况下值为 null
。这个特殊的 null
值可以被显性地用于移除绑定。任何其它非字符串类型的值都将会触发一个警告。
对动态参数表达式的约束
动态参数表达式有一些语法约束,因为某些字符,如空格和引号,放在 HTML attribute 名里是无效的。例如:
<!-- 这会触发一个编译警告 -->
<a v-bind:['foo' + bar]="value"> ... </a>
变通的办法是使用没有空格或引号的表达式,或用计算属性替代这种复杂表达式。
在 DOM 中使用模板时 (直接在一个 HTML 文件里撰写模板),还需要避免使用大写字符来命名键名,因为浏览器会把 attribute 名全部强制转为小写:
<!--
在 DOM 中使用模板时这段代码会被转换为 `v-bind:[someattr]`。
除非在实例中有一个名为“someattr”的 property,否则代码不会工作。
-->
<a v-bind:[someAttr]="value"> ... </a>
修饰符
修饰符 (modifier) 是以半角句号 .
指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent
修饰符告诉 v-on
指令对于触发的事件调用 event.preventDefault()
:
<form v-on:submit.prevent="onSubmit">...</form>
在接下来对 v-on
和 v-for
等功能的探索中,你会看到修饰符的其它例子。
缩写
v-
前缀作为一种视觉提示,用来识别模板中 Vue 特定的 attribute。当你在使用 Vue.js 为现有标签添加动态行为 (dynamic behavior) 时,v-
前缀很有帮助,然而,对于一些频繁用到的指令来说,就会感到使用繁琐。同时,在构建由 Vue 管理所有模板的单页面应用程序 (SPA - single page application) 时,v-
前缀也变得没那么重要了。因此,Vue 为 v-bind
和 v-on
这两个最常用的指令,提供了特定简写:
v-bind
缩写
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
v-on
缩写
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
注意:
它们看起来可能与普通的 HTML 略有不同,但
:
与@
对于 attribute 名来说都是合法字符,在所有支持 Vue 的浏览器都能被正确地解析。而且,它们不会出现在最终渲染的标记中。缩写语法是完全可选的,但随着你更深入地了解它们的作用,你会庆幸拥有它们。
计算属性和侦听器
计算属性
说明:对于模板内(html)的表达式,会提供很多遍历,但是其仅支持简单运算,如果逻辑太复杂会难以维护。
如:
<div id = "example">
{{ message.split(''). }}
</div>
基础例子
<div id="reverse1">
<p>消息:"{{msg}}"</p>
<p>消息:"{{msgReverse}}"</p>
</div>
<script>
var reverse1 = new Vue({
el: "#reverse1",
data:{
msg: "apple"
},
computed:{
msgReverse: function(){
return this.msg.split('').reverse().join('.');
}
}
})
</script>
结果:
Original message: "Hello"
Computed reversed message: "olleH"
说明:computed
相当于提供一个msgReverse的get()
函数,其也是响应式的:
控制台输出==> reverse1.msg = '西瓜'
html显示:
消息:"西瓜"
消息:"瓜.西"
调用方法也能完成一样的效果。
//组件中
methods: {
msgReverse: function(){
return this.msg.split('').reverse().join('.');
}
}
//调用:
<p>消息:"{{msgReverse()}}"</p>
methods和计算属性
最终结果相同
方法没缓存、计算属性有缓存。
-
依赖方式不同:
method中:每次重新渲染都需要执行函数。
-
计算属性中:基于响应式依赖进行缓存,只在相关响应式依赖发生改变时,才会重新求值,只要
msg
还没有改变,多次访问msgReverse
会立即返回之前的计算结果,而不必再次执行函数。注意:
此时,如果计算属性函数是:
time:funciton(){
return new Date.now()
}
其永远不会更新.
计算属性 vs 侦听属性
侦听属性:
定义:Vue提供的一种通用方式,来观察、响应Vue实例上的数据变动。
计算属性和监听属性都可以用于:随数据变动而改变的值。
但有时可能是计算属性更好用:
例子:
<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
}
}
})
计算属性的 setter
计算属性默认只有 getter,但在需要时可以提供 setter:
...//Vue声明中
computed: {
fullName:{
get: function () {
return this.firstName + ' ' + this.lastName
}
set: function(new value){
var names = newValue.split(' ');
this.firstName = names[0];
this.lastName = names[1];
}
}
}
...
现在再运行 vm.fullName = 'John Doe'
时,setter 会被调用,vm.firstName
和 vm.lastName
也会相应地被更新。
侦听器
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch
选项提供了一个更通用的方法,来响应数据的变化。
场景:
当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
class 与 style 绑定
条件渲染
v-if
作用:根据其值是否为true,来选择是否渲染该标签。
<p id="customP2" :style="myStyle" v-if="render">我是中国人</p>
v-else
作用:需要紧跟v-if
,且是相同元素标签,用于表达else语法。
<p id="customP2" :style="myStyle" v-if="render">我是中国人</p>
<p v-else>我是中国人</p>
v-else-if
作用:需要紧跟在v-if
、v-else-if
后面。
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else-if="Math.random() > 0.5">
else if
</div>
总说:
<div id="exam">
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else-if="Math.random() > 0.5">
else if
</div>
<div v-else>
Now you don't
</div>
</div>
<script>
var exam = new Vue({
el:"#exam"
})
</script>
用 key
管理可复用的元素
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
那么在上面的代码中切换 loginType
将不会清除用户已经输入的内容。因为两个模板使用了相同的元素.
<input>
不会被替换掉——仅仅是替换了它的placeholder
.
这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key
attribute 即可:
<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>
现在,每次切换时,输入框都将被重新渲染。
注意,
<label>
元素仍然会被高效地复用,因为它们没有添加key
attribute。
v-show
作用:根据value
真假,选择是否展示元素。
<h1 v-show="ok">ok真,就看得到,假,就看不到</h1>
与v-if
区别
v-show
所在元素,始终会被渲染并保留在 DOM 中。v-show
只是简单的切换元素的CSS样式style="display:true"
、style="display:false"
注意,
v-show
不支持<template>
元素,也不支持v-else
。
v-if
vs v-show
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。
使用场景总结:
-
v-show
:需要非常频繁地切换。 -
v-if
:如果在运行时条件很少改变。
v-if
与 v-for
一起使用
不推荐同时使用 v-if
和 v-for
。请查阅风格指南以获取更多信息。
当 v-if
与 v-for
一起使用时,v-for
具有比 v-if
更高的优先级。请查阅列表渲染指南以获取详细信息。
列表渲染
v-for
作用:用于遍历数组、对象。
语法:
v-for="item in items"
-
v-for="item of items"
:等同第一个,更切和JS
语法 -
v-for="(item, index) in items"
:items的index属性也可以访问 -
v-for="(item, name ) in items"
:对象属性的遍历,也可以用两个属性,分别获得键、值。 v-for="(item, name,index) in items"
item
参数:可以访问所有父作用域的 property 属性。
<div id="items">
<ul>
<label style="color:lightseagreen;font-size: x-large;">
具体犬类
</label>
<li style="font: bold;color: lightskyblue;" v-for="(item, index) in items">
{{item+':'+index}}
</li>
</ul>
<ul>
<label style="color:lightseagreen;font-size: x-large;">
犬类特征
</label>
<li style="font: bold;color: lightskyblue;" v-for="value of faces">{{value}}</li>
</ul>
</div>
var items = new Vue({
el: "#items",
data: {
items: [
"田园犬",
"泰迪",
"拉布拉多"
],
faces: {
type: "哺乳动物",
voice: "汪汪",
walkType: "爬行",
}
}
})
指定唯一key
对v-for
遍历,为方便 Vue 跟踪每个节点,而重新排序等,可以为每项提供给一个唯一key
:
只能是基础数据类型:int ,string 等等
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>
尽量在使用
v-for
时,指定唯一key
,除非遍历输出的的DOM内容非常简单,或是为获得性能刻意不指定。因为它是 Vue 识别节点的一个通用机制,
key
并不仅与v-for
特别关联。后面我们将在指南中看到,它还具有其它用途。
更多 key
attribute 的细节用法请移步至 key
的 API 文档。
数组更新检测
更新方法
数组的变更会触发 DOM 重渲染,方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
如之前的item
例子,Console==》items.items.push("西施")
,则 DOM 会对应重渲染
替换数组
变更方法,顾名思义,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如 filter()
、concat()
和 slice()
。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
注意事项
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。深入响应式原理中有相关的讨论。
v-for
里使用值范围
说明:即父标签或更上层标签中,放入v-for
语句,形成更大的循环范围。
v-for
与 v-if
一同使用
注意我们不推荐在同一元素上使用
v-if
和v-for
。更多细节可查阅风格指南。
当它们处于同一节点,v-for
的优先级比 v-if
更高,这意味着 v-if
将分别重复运行于每个 v-for
循环中。当你只想为部分项渲染节点时,这种优先级的机制会十分有用,如下:
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
上面的代码将只渲染未完成的 todo。
而如果你的目的是有条件地跳过循环的执行,那么可以将 v-if
置于外层元素 (或 `) 上。如:
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
v-on
事件处理
职责:用于监听 DOM 事件,并在触发时,运行一些 JS
代码。
基本格式:v-on:xxx
示例:
<div id="example-1">
<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
}
})
事件处理方法
说明:有些事件处理逻辑很复杂,直接写在v-on
不是个好办法,替换的是v-on
接收一个需要调用的方法名。
如下
<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)
}
}
}
})
// 也可以用 JavaScript 直接调用方法
example2.greet() // => 'Hello Vue.js!'
内联处理器中的方法
除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法:
<div id="example-3">
<button v-on:click="say('hi')">Say hi</button>
<button v-on:click="say('what')">Say what</button>
</div>
<script>
new Vue({
el: '#example-3',
methods: {
say: function (message) {
alert(message)
}
}
})
有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event
把它传入方法:
<button v-on:click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
// ...
<script>
methods: {
warn: function (message, event) {
// 现在我们可以访问原生事件对象
if (event) {
event.preventDefault()
}
alert(message)
}
}
事件修饰符
在事件处理程序中调用 event.preventDefault()
或 event.stopPropagation()
是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题,Vue.js 为 v-on
提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
.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>
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用
v-on:click.prevent.self
会阻止所有的点击,而v-on:click.self.prevent
只会阻止对元素自身的点击。
2.1.4 新增
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
不像其它只能对原生的 DOM 事件起作用的修饰符,.once
修饰符还能被用到自定义的组件事件上。如果你还没有阅读关于组件的文档,现在大可不必担心。
2.3.0 新增
Vue 还对应 addEventListener
中的 passive
选项提供了 .passive
修饰符。
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
这个 .passive
修饰符尤其能够提升移动端的性能。
不要把 .passive
和 .prevent
一起使用,因为 .prevent
将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive
会告诉浏览器你不想阻止事件的默认行为。
按键修饰符
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on
在监听键盘事件时添加按键修饰符:
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
你可以直接将 KeyboardEvent.key
暴露的任意有效按键名转换为 kebab-case 来作为修饰符。
<input v-on:keyup.page-down="onPageDown">
在上述示例中,处理函数只会在 $event.key
等于 PageDown
时被调用。
按键码
keyCode
的事件用法已经被废弃了并可能不会被最新的浏览器支持。
使用 keyCode
attribute 也是允许的:
<input v-on:keyup.13="submit">
为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
.enter
.tab
-
.delete
(捕获“删除”和“退格”键) .esc
.space
.up
.down
.left
.right
有一些按键 (.esc
以及所有的方向键) 在 IE9 中有不同的 key
值, 如果你想支持 IE9,这些内置的别名应该是首选。
你还可以通过全局 config.keyCodes
对象自定义按键修饰符别名:
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
系统修饰键
2.1.0 新增
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
.ctrl
.alt
.shift
.meta
注意:在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。在 Sun 操作系统键盘上,meta 对应实心宝石键 (◆)。在其他特定键盘上,尤其在 MIT 和 Lisp 机器的键盘、以及其后继产品,比如 Knight 键盘、space-cadet 键盘,meta 被标记为“META”。在 Symbolics 键盘上,meta 被标记为“META”或者“Meta”。
例如:
<!-- Alt + C -->
<input v-on:keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div v-on:click.ctrl="doSomething">Do something</div>
请注意修饰键与常规按键不同,在和
keyup
事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住ctrl
的情况下释放其它按键,才能触发keyup.ctrl
。而单单释放ctrl
也不会触发事件。如果你想要这样的行为,请为ctrl
换用keyCode
:keyup.17
。
表单输入绑定
v-model
作用:做为表单标签元素的属性,其值v-model="value"
。
value
会挂载:【表单元素的输入值】---- Vue 实例的【data
的属性】。
不同<input>
元素
**v-model
**为不同输入元素,使用不同 property ,并抛出不同的事件:
-
<text>
、<textarea>
元素:value
property 和input
事件; -
<checkbox>
和< radio>
:checked
property 和change
事件; -
<select>
字段:value
作为 prop 并将change
作为事件。
v-model
会忽略所有表单元素的value
、checked
、selected
attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的data
选项中声明初始值。
文本
说明:Vue
的响应式数据,使前端可以做到原来后端才能做的事。
message
:用作输入框内容和 Vue
实例绑定的数据,实现当输入时,会实时显示在<p>
中。
<div id="example-1">
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
</div>
<script>
new Vue({
el: '#example-1',
data: {
message: ''
}
})
</script>
多行文本
message
:用作输入框内容和 Vue
实例绑定的数据,实现当输入时,会实时显示在<p>
中。
<div id="exam2">
<span>Multiline message is:</span>
<p style="white-space:pre-line;">
{{message}}
</p>
<textarea v-model="message" placeholder="在这里输入"></textarea>
</div>
<script>
var exam2 = new Vue({
el: "#exam2",
data:{
message:""
}
})
</script>
在文本区域插值 (
{{text}}
) 并不会生效,应用v-model
来代替。
复选框
单个复选框
绑定到bool值:
<div id="exam3">
<input type="checkbox" id="checkbox" v-mode="checked">
<label for="checkbox">
{{checked}}
</label>
</div>
<script>
var exam3 = new Vue({
el: "#exam3",
data:{
checked: true
}
})
</script>
多个复选框
绑定到一个value数组,凡是勾选的框,其value就刷新为数组元素:
<div id="exam4">
<input type="checkbox" id="mrLi" value="mrLi" v-model="boxList">
<input type="checkbox" id="mrSun" value="mrSun" v-model="boxList">
<input type="checkbox" id="mrWang" value="mrWang" v-model="boxList">
<p>数组:</p>
<p>
{{boxlist}}
</p>
</div>
<script>
var exam4 = new Vue({
el: "#exam4",
data:{
boxList: ["首元素:nothing"]
}
})
</script>
单选按钮
<div id="exam5">
<input type="radio" v-model="radio" value="男">男
<br/>
<input type="radio" v-model="radio" value="女">女
<br/>
<p>radio:</p>
<p>{{radio}}</p>
</div>
<script>
var exam5 = new Vue({
el: "#exam5",
data:{
radio:""
}
})
</script>
选择框
单选时:
<div id="exam6">
<select v-modle="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>selected is : {{selected}}</span>
</div>
<script>
var exam6 = new Vue({
el: "#exam6",
data:{
selected:''
}
})
</script>
注意
如果
v-model
表达式的初始值未能匹配任何选项,<select>
元素将被渲染为“未选中”状态。 在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
多选时,绑定到一个数组:
<div id="exam7">
<select v-model="selectedList" multiple style="background-color:lightseagreen;width: 50px">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>selectedList is : {{selectedList}}</span>
</div>
<script>
var exam7 = new Vue({
el: "#exam7",
data:{
selectedList:[]
}
})
</script>
配合v-for
<div id="exam8">
<!-- 单选择框+v-for -->
<select v-model="selectedList" multiple style="background-color:lightseagreen;width: 50px">
<option v-for="op of options">{{op}}</option>
</select>
<span>selectedList is : {{selectedList}}</span>
<br/><hr/><br/>
<!-- 单选择框+v-for -->
<select v-model="selectedList" multiple style="background-color:lightseagreen;width: 50px">
<option v-for="op of options">{{op}}</option>
</select>
<span>selectedList is : {{selectedList}}</span>
</div>
<script>
var exam8 = new Vue({
el: "#exam8",
data:{
selectedList:[],
options:[
"甲木",
"丙火",
"戊土",
"庚金",
"壬水"
]
}
})
</script>
表单值绑定
说明:对于单选按钮,复选框及选择框的选项,v-model
绑定的值通常是静态字符串 (对于复选框也可以是布尔值):
但是有时我们可能想把值绑定到 Vue 实例的一个动态 property 上,这时可以用 v-bind
实现,并且这个 property 的值可以不是字符串。
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no"
>
// 当选中时
vm.toggle === 'yes'
// 当没有选中时
vm.toggle === 'no'
这里的
true-value
和false-value
attribute 并不会影响输入控件的value
attribute,因为浏览器在提交表单时并不会包含未被选中的复选框。如果要确保表单中这两个值中的一个能够被提交,(即“yes”或“no”),请换用单选按钮。
表单v-model
修饰符
.lazy
用法:修饰符用法,都是在v-model
后面直接连接就行。
职责:
在默认情况下,v-model
在每次 input
事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy
修饰符,从而转为在 change
事件之后进行同步:
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">
.number
职责:自动将用户输入的值,转换为整数类型。
这通常很有用,因为即使在 type="number"
时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat()
解析,则会返回原始的值。
.trim
(修剪)
职责:自动过滤用户输入的首尾空白字符。
组件基础
定义形如:
Vue.component('button-demo',{
template: "<p>这里是显示模板</p>",
data: function()[{
return{
count: 0
}
},
methods:{
....
}
})
说明:组件是可服用的 Vue 实例,且带有一个名字,如上<button-demo>
。
相同:含有
data
、computed
、watch
、methods
以及生命周期钩子等。区别:其不含有
el
这个根实例项。
使用:直接在html中使用即可
组件复用
说明:组件可以复用任意次数,每次使用一个组件时,就会创建一个新Vue实例,他们维护各自的数据。
data
必须是一个函数
说明:在组件中,data
并不是一个对象,而是等于一个函数的return
值的形式.
原因:为每个实例提供一份唯一的拷贝。若非这样,则对一个组件的操作,会影响相同的组件。
组件的组织
格式:通常以树状来组织。
如:导航栏、侧边栏、内容区等组件。
每个组件又包含了其他的像导航链接、博文之类的组件。
组件注册
要使用组件,首先得注册组件