1. 安装node,直接官网下载安卓即可,会自动安装上npm。
网址:https://nodejs.org
2. 检测node是否安装成功,在终端输入:node -v 以及 npm -v,若有版本信息,则安装成功。
若报错:‘npm’ 不是内部或外部命令,也不是可运行的程序
检查是否配置环境变量。计算机属性 --> 高级系统设置 --> 环境变量 --> 系统变量 --> Path,查看是否有node的路径,若没有,将node的安装路径添加在Path后面,注意路径之前用英文分号";"分割。
3. 全局安装cli3
npm install -g @vue/cli
vue -V(大写) 查看vue版本信息,若有信息则安装成功。
若报错:‘vue’ 不是内部或外部命令,也不是可运行的程序
电脑下全局搜索"vue.cmd",将其路径添加在系统环境变量Path里。
4. cd到工作目录,使用vue ui可视化创建项目。开始新建项目。
5. 安装完成后,我们在刚刚创建的项目根目录添加一个文件:vue.config.js
里面的代码为:
module.exports = {
baseUrl: './',
filenameHashing: false
}
执行 npm run build 之后的 dist 目录的静态资源的文件名多会追加上 hash 值,如果不要 hash ,只需要配置 vue.config.js 文件中的 filenameHashing为false; baseUrl配置跟路径。
6. 完成后在可视化界面添加插件
7. 任务 --> serve --> 运行,开启项目,localhost:8080查看项目
8. cdn
开发环境cdn: <script src="https://cdn.jsdelivr.net/npm/vue"></script>
生产环境cdn: <script src="https://cdn.jsdelivr.net/npm/vue"></script>
Vue学习
介绍
指令v-
绑定:v-bind: 将元素节点特性与Vue实例属性保持一致;
条件:v-if= true显示,false隐藏;
循环:v-for= 绑定数组的数据来渲染一个项目列表;
<div id="app">
<ul>
<li v-for="todo in todos">
{
{ todo.name }}
</li>
</ul>
</div>
var app = new Vue({
el: '#app',
data: {
message: '0',
name: 'biu',
todos: [
{name: 'biu',},
{name: 'cindy',},
{name: 'becky',},
{name: 'davina',},
]
}
})
apiready = function() {
app.todos.push({name: 'Emily'});
}
事件:v-on: 添加一个事件监听器,通过它调用在Vue实例中定义的方法;
<div id="app">
<p>{
{ message }}</p>
<button @click="reverseMsg">乾坤大挪移</button>
</div>
var app = new Vue({
el: '#app',
data: {
message: 'What a handsome boy !'
},
methods: {
reverseMsg: function() {
this.message = this.message.split('').reverse().join('').toUpperCase()
}
}
});
双向绑定:v-model= 实现表单输入和应用状态之间的双向绑定
<div id="app">
<input type="text" v-model="message" onfocus="this.select()">
<p>{
{ message }}</p>
</div>
var app = new Vue({
el: '#app',
data: {
message: 'write what you wanna'
},
});
组件化应用构建
允许使用小型、独立和通常可复用的组件构建大型应用。
在Vue里,一个组件本质上是一个拥有预定义选项的一个Vue实例。
在Vue中注册组件:
<!--定义名为todo-item的新组件-->
Vue.component('todo-item', {
template: '<li>Waiting for using</li>'
})
<!--用以上组件构建另一个组件模板-->
<ol>
<todo-item></todo-item>
</ol>
注意点:需要在实例化之前注册组件
<!--定义能够接受prop的组件-->
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{
{ todo.text }}</li>'
})
然后,可以使用v-bind指令将待办项传到循环输出的每个组件中:
<div id="app">
<ol>
<user-item v-for="item in users" v-bind:user="item" v-bind:key="item.id"></user-item>
</ol>
</div>
Vue.component('user-item', {
props: ['user'],
template: '<li>{
{ user.name }}</li>'
})
var app = new Vue({
el: '#app',
data: {
users: [
{id: 0, name: 'biu'},
{id: 1, name: 'cindy'},
{id: 2, name: 'becky'},
{id: 3, name: 'davina'}
]
},
})
v-bind绑定的属性名与props的接受参数名必须相同
Vue实例
创建一个Vue实例
每个Vue应用都是通过用Vue函数创建一个新的Vue实例开始的:
var vm = new Vue({
//选项
})
变量名vm(ViewModel)表示Vue的实例。
一个Vue应用由一个通过new Vue创建的根Vue实例,以及可选的嵌套的、可复用的组件树组成。
所有的Vue组件都是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 == 'hello'
那么对b的改动将不会触发任何视图的更新。若果知道后续会需要某个属性,可以创建实例时为它设置一些初始值。
Object.freeze(),会阻止修改现有的属性,意味着响应式系统无法再追踪变化。
var obj = {
foo: 'bar'
}
Object.freeze(obj)
new Vue({
el: '#app',
data: obj
})
除了数据属性,Vue实例还暴露了一些有用的实例属性与方法。它们都有前缀$,以便与用户定义的属性区分开来。
var data = {a: 1}
var vm = new Vue({
el: '#app',
data: data
})
vm.$data === data // => true
vm.$el === document.getElementById('app') // => true
// $watch 是一个实例方法
vm.$watch('a', function(newValue, oldValue) {
//这个回调将在`vm.a`改变后调用
})
实例生命周期钩子
每个Vue实例在被创建时都要经过一系列的初始化过程,例如,需要设置数据监听、编译模板、将实例挂载到DOM并在数据变化时更新DOM等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
比如created钩子可以用来在一个实例被创建之后执行代码。也有一些其他的钩子,在实例生命周期的不同阶段被调用,如mounted、updated和destroyed。
生命周期钩子的this上下文指向调用它的Vue实例。
不要在选项属性或回调上使用箭头函数,比如
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 之类的错误。
模板语法
Vue.js使用了基于HTML的模板语法,允许开发者声明式地将DOM绑定至底层Vue实例的数据。所有Vue.js的模板都是合法的HTML,所以能被遵循规范的浏览器和HTML解析器解析。
在底层的实现上,Vue将模板编译成虚拟DOM渲染函数。结合相应系统,Vue能够智能地计算出最少需要重新渲染多少组件,并把DOM操作次数减到最少。
插值
数据绑定最常见的形式就是使用“Mustache”语法(双大括号)的文本插值:
<span>Message: {
{ msg }}</span>
Mustache标签将会被替代为对应数据对象上msg属性的值。无论何时,绑定的数据对象上msg属性发生了改变,插值处的内容都会更新。
通过使用v-once指令,能执行一次性地插值,当数据改变时,插值处的内容不会更新。但这会影响到该节点上的其它数据绑定:
<div id="app">
<span v-once>the value won't change: {
{ msg }}</span>
<input type="text" v-model="msg">
<p>未使用v-once,会跟着变化: {
{ msg }}</p>
</div>
var app = new Vue({
el: '#app',
data: {
msg: 'biu'
},
})
原始HTML
双大括号会将数据解释为普通文本,而非HTML代码。为了输出真正的HTML,需要使用v-html指令:
<span>you'll see red words: <span v-html="msg"></span></span>
var app = new Vue({
el: '#app',
data: {
msg: '<span style="color:red">red words</span>'
},
})
特性
Mustache语法不能作用在HTML特性上,遇到这种情况应该使用v-bind指令。
对于布尔特性(它们只要存在就意味着值为true,否则为false,即绑定的属性值为:非字符串类型的null,undefined,false时是false):
<button v-bind:disabled="isDisabled">Button</button>
如果isDisabled的值是null、undefined或false,则disabled特性甚至不会被包含在渲染出来的元素中。
<button v-bind:disabled="isDisabled" @click="popalert">Button</button>
var app = new Vue({
el: '#app',
data: {
isDisabled: null
//null,undefined,false为false
//"null","undefined","false"为true
},
methods: {
popalert() {
alert(1)
}
}
})
使用JavaScript表达式
对于所有的数据绑定,Vue.js提供了完全的JavaScript表达式支持。
{
{ number + 1 }}
{
{ ok ? 'YES' : 'No' }}
{
{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>
这些表达式会在所属Vue实例的数据作用域下作为JavaScript被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。
<!--这是语句,不是表达式-->
{
{ var a = 1 }}
<!--流控制也不会生效,可以使用三元表达式代替-->
{
{ if(ok) {return message} }}
模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如Math和Data。不应该在模板表达式中试图访问用户定义的全局变量。
指令
指令(Directives)是带有v-前缀的特殊特性。指令的职责是,当表达式的值改变时,将其产生的连带影响,相应式地作用于DOM。
参数
一些指令能够接收一个“参数”,在指令名称之后以冒号表示。
动态参数
用方括号括起来的JavaScript表达式作为一个指令的参数:
<a v-bind:[attributeName] = "url"> ... </a>
这里的attributeName会被作为一个JavaScript表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果Vue实例有一个data属性attributeName,其值为’href’,那么这个绑定等价于v-bind:href。
同样地,可以使用动态参数为一个动态的事件名绑定处理函数:
<a v-on:[eventName] = 'doSomething'> ... </a>
对动态参数的值的约束
动态参数预期会求出一个字符串,异常情况下值为null。这个特殊的null值可以被显性地用于移除绑定。任何其它非字符串类型的值都将会触发一个警告。
对动态参数表达式的约束
动态参数表达式有一些语法约束,因为某些字符,例如空格和引号,放在HTML特性名里是无效的。同样,在DOM中使用模板时,需要回避大写键名。
<!--下面代码是无效的,会触发一个编译警告-->
<a v-bind:['foo' + bar]="value"> .. </a>
变通的办法是使用没有空格或引号的表达式,或用计算属性替代这种复杂表达式。
如果在DOM中使用模板(直接在一个HTML文件里撰写模板),需要留意浏览器会把特性名全部强制转为小写:
<!--在DOM中使用模板时以下代码会被转换为v-bind:[someattr]-->
<a v-bind:[someAttr]="value"> ... </a>
修饰符
修饰符(modifier)是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。如.prevent修饰符告诉v-on指令对于触发的事件调用event.preventDefault():
<form v-on:submit.prevent="onSubmit"> ... </form>
缩写
v-前缀作为一种视觉提示,用来识别模板中Vue特定的特性。
v-bind缩写为冒号(:)
v-on缩写为@
计算属性和侦听器
计算属性
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。对于任何复杂逻辑,应当使用计算属性。
div id="app">
{
{ message }}<br>
{
{ newmsg }}
</div>
var vm = new Vue({
el: '#app',
data: {
message: 'biu'
},
computed: {
newmsg: function() {
<!--this指向vm实例-->
return this.message.split('').reverse().join(' ')
}
}
})
可以像绑定普通属性一样在模板中绑定计算属性。
计算属性缓存vs方法
可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要message还没有发生改变,多次访问newmsg计算属性会立即返回之前的计算结果,而不必再次执行函数。
相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。
计算属性vs侦听属性
Vue提供了一种更通用的方式来观察和响应Vue实例上的数据变动:侦听属性。
<div id="app">
{
{ fullName }}
<br>
<input type="text" v-model="firstName">
<input type="text" v-model="lastName">
</div>
var vm = new Vue({
el: '#app',
data: {
firstName: 'biu',
lastName: 'huang',
fullName: 'biu haung'
},
watch: {
firstName: function(val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function(val) {
this.fullName = this.firstName + ' ' + val
}
}
})
上面代码是命令式且重复的。用计算属性将简便的多。
var vm = new Vue({
el: '#app',
data: {
firstName: 'biu',
lastName: 'huang'
},
computed: {
fullName: function() {
return this.firstName + ' ' + this.lastName
}
}
})
侦听器watch
当需要在数据变化时执行异步或开销较大的操作时,watch方式是最有用的。
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{
{ answer }}</p>
</div>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer: function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
}
}
})
Class与Style绑定
v-bind可以绑定表达式,表达式结果的类型可以是字符串,对象或数组。
绑定HTML Class
对象语法
我们可以传给v-bind:class一个对象,以动态地切换class:
<div v-bind:class="{active: isActive}"></div>
上面的语法表示active这个class村子与否将取决于数据属性isActive的truthiness(真或假)。
v-bind:class指令也可以与普通的class属性共存。
<div class="static" v-bind:class="{active: isActive, 'text-danger': hasError}"></div>
data: {
isActive: true,
hasError: false
}
结果为:
<div class="static active"></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'
}
}
}
数组语法
我们可以把一个数组传给v-bind:class,以应用一个class列表:
<div v-bind:class="[activeClass, errotClass]"></div>
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
渲染为:
<div class="active text-danger"></div>
如果想根据条件切换列表中的class,可以使用三元表达式:
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
数组语法中也可以使用对象语法:
<div v-bind:class="[{active: isActive}, errorClass]"></div>
用在组件上
当在一个自定义组件上使用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>
对于带数据绑定class也同样适用:
<my-component v-bind:class="{active: isActive}"></my-component>
绑定内联样式
对象语法
v-bind:style的对象语法十分直观–看着非常像CSS,但其实是一个JavaScript对象。CSS属性名可以用驼峰式或短横线分隔(需要用引号括起来)来命名:
<div v-bind:style="{color: activeColor, fontSize: fontSize + 'px'}"></div>
data: {
activeColor: 'red',
fontSize: 30
}
直接绑定到一个样式对象通常更好,这会让模板更清晰:
<div v-bind:style="styleObeject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
数组语法
v-bind:style的数组语法可以将多个样式对象应用到同一个元素上:
<div v-bind:style="[baseStyles, overridingStyles]"></div>
自动添加前缀
当v-bind:style使用需要添加浏览器引擎前缀的CSS属性时,如transform,Vue.js会自动侦测并添加相应的前缀。
多重值
可以为style绑定中的属性提供一个包含多个值的数组,常用于提供多个带前缀的值,如:
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex']}"></div>
这样写只会渲染数组中最后一个被浏览器支持的值。
条件渲染
v-if
v-if指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回truthy值的时候被渲染。
也可以用v-else添加一个’else’块:
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no</h1>
在元素上使用v-if条件渲染分组
因为v-if是一个指令,所有必须将它添加到一个元素上。如果想切换多个元素,可以把一个元素当作不可见的包裹元素,并在上面使用v-if。最终的渲染结果将不包含元素。
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
v-else
可以使用v-else指令来表示v-if的’else’块。
v-else元素必须紧跟在带v-if或者v-else-if的元素的后面,否则它将不会被识别。
v-else-if
充当v-if的’else-if’块,可以连续使用。
类似于v-else,v-else-if也必须紧跟在带v-if或者v-else-if的元素之后。
用key管理可复用的元素
表示某个元素是完全独立的,不能被复用。可以添加一个具有唯一值的key属性。
<input type="text" key="text1">
v-show
根据条件展示元素。
带有v-show的元素始终会被渲染并保留在DOM中。v-show只是简单地切换元素的CSS属性display。
v-show不支持元素,也不支持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指令基于一个数组来渲染一个列表。v-for指令需要使用item in items形式的特殊语法,其中items是源数据数组,而item则是被迭代的数组元素的别名。
在v-for块中,可以访问所有父作用域的属性。v-for还支持一个可选的第二个参数,即当前项的索引。
<ul id="example">
<li v-for="(item, index) in items">
{
{ parentMessage }} - {
{ index }} - {
{ item.message }}
<li>
</ul>
var vm = new Vue({
el: '#example',
data: {
parentMessage: 'Parent',
items: [
{message: 'Foo'},
{message: 'Bar'}
]
}
})
也可以使用of替代in作为分隔符,因为它更接近JavaScript迭代器的语法:
<div v-for="item of items"></div>
在v-for里使用对象
可以用v-for来遍历一个对象的属性。
也可以提供第二个的参数为property名称(键名)。
还可以用第三个参数作为索引。
<div v-for="(value, name, index) in object">
{
{ index }}. {
{ name }}: {
{ value }}
</div>
在遍历对象时,会按Object.keys()的结果遍历,但是不能保证它的结果在不同的JavaScript引擎下都一致。
维护状态
当Vue正在更新使用v-for渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时DOM状态(如:表单输入值)的列表渲染输出。
为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,需要为每项提供一个唯一key属性:
<div v-for="item in items" v-bind:key="item.id">
<!--内容-->
</div>
建议尽可能在使用v-for时提供key attribute,除非遍历输出的DOM内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
不要使用对象或数组之类的非基本类型值作为v-for的key。需要用字符串或数值类型的值。
数组更新检测
变异方法
Vue将被侦听的数组的变异方法进行了包裹,所以它们也将会触发视图更新。这些被包裹的方法包括:
push()
pop()
shift()
unshift()
splice()
reverser()
替换数组
变异方法,会改变调用了这些方法的原始数组。相比之下,也有非变异方法,例如:filter(), concat()和slice()。它们不会改变原始数组,而总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组:
example.items = example.items.filter(function(item) {
return item.message.match(/foo/)
})
注意事项
由于JavaScript的限制,Vue不能检测以下数组的变动:
- 当利用索引直接设置一个数组项时,例如:vm.items[index] = newValue
- 当修改数组的长度时,例如:vm.items.length = newLength
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
为了解决第一类问题,以下两种方式都可以实现和vm.items[index] = newValue相同的效果,同时也将在响应式系统内触发状态更新。
<!--Vue.set-->
Vue.set(vm.items, index, newValue)
<!--Array.prototype.splice-->
vm.items.splice(index, 1, newValue)
也可以使用vm.$set实例方法,该方法是全局方法Vue.set的一个别名:
vm.$set(vm.items, index, newValue)
为了解决第二类问题,可以使用splice:
vm.items.splice(newLength)
对象变更检测注意事项
由于JavaScript的限制,Vue不能检测对象属性的添加或删除:
var vm = new Vue({
data: {
a: 1
}
})
// vm.a 现在是响应式的
vm.b = 2
// vm.b 不是响应式的
对于已经创建的实例,Vue不允许动态添加根级别的响应式属性。但是,可以使用Vue.set(object, propertyName, value)方法向嵌套对象添加响应式属性。
var vm = new Vue({
data: {
userProfile: {
name: 'biu'
}
}
})
可以添加一个新的age属性到嵌套的userProfile对象:
Vue.set(vm.userProfile, 'age', 18)
还可以使用vm.$set实例方法,它是全局Vue.set的别名。
vm.$set(vm.userProfile, 'age', 18)
有时可能需要为已有对象赋值多个新属性,比如使用Object.assign()或_.extend()。这种情况下,应该用两个对象的属性创建一个新的对象。
Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
错误使用方式:
Object.assign(vm.userProgile, {
age: 18,
favoriteColor: 'yellow'
})
正确使用方式:
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 18,
favoriteColor: 'yellow'
})
显示过滤/排序后的结果
有时,我们想要显示一个数组经过过滤或排序后的版本,而不实际改变或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数组。
<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
})
}
}
在计算属性不适用的情况下(例如:在嵌套v-for循环中),可以使用一个方法:
<li v-for="n in even(numbers)">{
{ n }}</li>
data: {
numbers: [1, 2, 3, 4, 5]
},
methods: {
even: function(numbers) {
return numbers.filter(function(number) {
return number % 2 === 0
})
}
}
在v-for里使用值范围
v-for也可以接受整数。在这种情况下,它会把模板重复对应次数。
<div>
<span v-for="n in 10">{
{ n }}</span>
</div>
结果:
1 2 3 4 5 6 7 8 9 10
在上使用v-for
类似于v-if,也可以利用带有v-for的来循环渲染一段包含多个元素的内容。
<ul>
<template v-for="item in items">
<li>{
{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
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-for
在自定义组件上,可以像在任何普通元素上一样使用v-for。
<my-component v-for="item in items" :key="item.id"></my-component>
然而,任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,需要使用prop:
<my-component v-for="(item, index) in item" :item="item" :index="index" :key="item.id"></my-component>
不自动将item注入到组件里的原因是,这会使用组件与v-for的运作紧密耦合。明确组件数据的来源能够使组件在其他场合重复使用。
<div id="todo-list-example">
<form v-on:submit.prevent="addNewTodo">
<label for="new-todo">Add a todo</label>
<input
v-model="newTodoText"
id="new-todo"
placeholder="E.g. Feed the cat"
>
<button>Add</button>
</form>
<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>
</div>
Vue.component('todo-item', {
template: '\
<li>\
{
{ title }}\
<button v-on:click="$emit(\'remove\')">Remove</button>\
</li>\
',
props: ['title']
})
new Vue({
el: '#todo-list-example',
data: {
newTodoText: '',
todos: [
{
id: 1,
title: 'Do the dishes',
},
{
id: 2,
title: 'Take out the trash',
},
{
id: 3,
title: 'Mow the lawn'
}
],
nextTodoId: 4
},
methods: {
addNewTodo: function () {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
}
})
事件处理
监听事件
可以用v-on指令监听DOM事件,并在触发时运行一些JavaScript代码。
事件处理方法
v-on可以接收一个需要调用的方法名称。
内联处理器中的方法
除了直接绑定到一个方法,也可以在内联JavaScript语句中调用方法。
有时也需要在内联语句处理器中访问原始的DOM事件。可以用特殊变量$event把它传入方法:
<button v-on:click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
methods: {
warn: function(message, event) {
if(event) event.preventDefault()
alert(message)
}
}
事件修饰符
修饰符是由点开头的指令后缀来表示的。
.stop //阻止单击事件继续传播
.prevent //提交事件不再重载页面
//修饰符可以串联
<a v-on:click.stop.prevent="doThat"></a>
//只有修饰符
<form v-on:submit.prevent></form>
.capture //添加事件监听器时使用事件捕获模式,即元素自身触发的事件先在此处理,然后才交由内部元素进行处理
.self //只当在event.target是当前元素自身时触发处理函数
.once //点击事件将只会触发一次
.passive //滚动事件的默认行为(即滚动行为)将会立即触发,而不会等待onScroll完成,这其中包含event.preventDefault()的情况。
<div v-on:scroll.passive="onScroll">...</div>
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用v-on:click.prevent.self会阻止所有的点击,而v-on:click.self.prevent只会阻止对元素自身的点击。
不要把.passive和.prevent一起使用,因为.prevent将会被忽略,同时浏览器可能会展示一个警告。.passive会告诉浏览器你不想阻止事件的默认行为。
按键修饰符
//只有在key是Enter时调用vm.submit()
<input v-on:keyup.enter="submit">
可以直接将KeyboardEvent.key暴露的任意有效按键名转换为kebab-case来作为修饰符。
<input v-on:keyup.page-down="onPageDown">
按键码
keyCode的事件用法已经被废弃了并可能不会被最新的浏览器支持。
<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
系统修饰键
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
.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 @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
注意修饰键与常规按键不同,在和keyup事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 ctrl 的情况下释放其它按键,才能触发 keyup.ctrl。而单单释放 ctrl 也不会触发事件。如果你想要这样的行为,请为 ctrl 换用 keyCode:keyup.17。
.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
这些修饰符会限制处理函数仅相应特定的鼠标按钮。
为什么在HTML中监听事件
你可能注意到这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。但不必担心,因为所有的Vue.js事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用 v-on 有几个好处:
扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
因为你无须在JavaScript里手动绑定事件,你的ViewModel代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。
表单输入绑定
基础用法
可以用v-model指令在表单、及元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。
v-model会忽略所有表单元素的value、checked、selected特性的初始值而总是将Vue实例的数据作为数据来源。应该通过JavaScript在组件的data选项中声明初始值。
v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件:
text和textarea元素使用value属性和input事件;
checkbox和radio使用checked属性和change事件;
select字段将value作为prop并将change作为事件。
多行文本
<span>Multiline message is: </span>
<p style="white-space:pre-line;">{
{ message }}</p>
<br>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
pre-line: 合并空白符序列,但是保留换行符。
复选框
单个复选框,绑定到布尔值:
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{
{ checked }}</label>
多个复选框,绑定到同一个数组:
<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: []
}
})
单选按钮
<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: ''
}
})
选择框
单选时:
<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: ''
}
})
如果 v-model 表达式的初始值未能匹配任何选项&