与JQuery相比,Vue可以方便的进行组件开发。Vue组件相当于扩展的html元素,使用十分方便。
stringify()
将之转化为stringkey
属性指定唯一值可以取消这种行为。v-bind
不使用指令参数,且值为对象,会将对象属性绑定到元素(组件上)vue指令以v-
开始,用于渲染DOM或绑定数据,定义在元素或组件上。
{{message}}
:绑定vue实例数据data
到文本上。(非指令,占位符)v-bind
:将vue实例数据绑定到元素属性上。v-if
:vue实例数据为true
则显示该元素。v-for
:遍历数组,产生多个该属性对应的html元素(及其子元素)。v-on
:绑定vue实例方法到html元素事件上。v-model
:实现input的value属性与vue实例数据的双向绑定,即value属性值改变也会影响vue实例数据。使用v-bind
只能单向绑定inptu的value属性。指令详细见第四章。注意,指令的值一般可以是表达式。
el
),根组件只能使用new
创建。html元素:在html,则将组件名当作新的html标签,然后创建该元素。但这种实例方式不能作为根组件,需要放入额外一个Vue实例下。
注意,组件作为
的子元素实例化会出现问题,因此需使用
is
,如:
<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>
is
指定组件,实例化后该组件会取代li
元素。
Vue实例:在javascript中,与new Vue({...})
类似,new
一个组件,并传入选项对象,绑定到一个html元素上(使用el
选项)。此时被绑定的元素会被模板template
替代。
Vue子类实例:Vue实例只能用于根组件,而Vue子类实例可以用于其他组件。Vue.extend()
中传入选项对象,返回一个Vue子类。然后实例化,并用$mount
挂载到DOM上。如下所示:
<div id="mount-point">div>
// create constructor
var Profile = Vue.extend({
template: '{{firstName}} {{lastName}} aka {{alias}}',
data: function () {
return {
firstName: 'Walter',
lastName: 'White',
alias: 'Heisenberg'
}
}
})
// create an instance of Profile and mount it on an element
new Profile().$mount('#mount-point')
注意data为函数。
如果想手动销毁实例,则使用$destroy
生命周期方法,但DOM元素仍未去除。
//定义一个叫todo-item的组件,成为新的html元素。还传入了一个选项对象。
Vue.component('todo-item', {
//该组件作为html元素可以接收的属性。
props: ['todo'],
//组件使用的html模板
template: '- {{ todo.text }}
'
})
现在可以将组件名作为html元素使用:<ol>
<todo-item>todo-item>
ol>
props
通信data
对象的属性添加到vue实例上和响应式系统中,即这些属性改变,视图也会改变。而之后vue实例添加的属性不会存在于响应式系统中。data
,methods
,vue实例也有一些有用的属性和方法,以$
为开头。部分如下:
$data
:选项对象中的data$el
:挂载在DOM中的html元素
vue允许在vue实例生命周期的某个阶段(如红色方框所示)上挂载用户自定义的函数,称为hook,如:
new Vue({
data: {
a: 1
},
created: function () {
// `this` points to the vm instance
console.log('a is: ' + this.a)
}
})
// => "a is: 1"
即将vue实例的数据插入到模板中,也称为数据绑定。
数据被双花括号围绕{{data}}
。如
<span>Message: {{ msg }}span>
这里的数据msg,来自选项对象中的data
和??谁?每当msg改变,view会被更新。
当使用v-once
指令时,该元素只会插值一次:
<span>Message: {{ msg }}span>
插入生的html,不被vue解析。如
<span v-html="rawHtml">span>
此时span
的innerHTML
使用属性rawHtml替换。
使用指令v-bind
,在需要插入数据的html属性上加上该指令。
前面都是绑定一些简单的属性值,也可以绑定表达式。表达式可以使用一些vue规定的全局变量如Math
、Date
,不能是自定义的全局变量。
指定是特殊的属性,以v-
开头。指令属性值期待一个js表达式(除了for)。指令的作用是当表达式值改变时,运用这些副作用(DOM的改变)到DOM中。
指令是有参数的,指令与参数冒号分隔,如
<a v-bind:href="url"> ... a>
v-bind
指令的参数是href
,即将url
绑定到href
属性上。
指定的参数可以是动态给出的,以[]
为标识,js表达式给出参数值,如:
<a v-bind:[attributeName]="url"> ... a>
这里的attributeName
是js表达式,表达式值必须为string,null表示删除绑定。
限制:[]
内不能存在spaces, quotes, <, >, / or =
modifiers是指令的特殊后缀,以.
表示,指示指令绑定的一些行为。如:
<form v-on:submit.prevent="onSubmit"> ... form>
表示触发事件时也执行event.preventDefault()
貌似可以叠加多个Modifiers
有的指令有缩写,如
v-bind
的缩写::
v-on
的缩写:@
v-slot
的缩写:#
此时不需要冒号分隔指令与参数。
computed
中的属性是data
中属性进过计算后得到的属性。
computed
中属性是一个get
方法,也可以额外设置set
方法。computed
中属性会放入vue实例中。var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.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]
}
}
}
// …
```
watch
:监听vue实例属性,改变时调用回调函数。data
中一些属性的改变是基于其他属性的,可在watch
中配置,如: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
}
}
})
上面配置了firstName和lastName改变时如何影响fullName改变。html的class和style都是属性,因此可以使用v-bind
来绑定vue属性,并且不仅string、还可以绑定object or array到html属性上。
<div v-bind:class="activeClass">div>
这里的activeClass为vue实例属性。<div v-bind:class="{ active: isActive }">div>
对象的key为class名,对象的vlue为boolean值,true则class存在。这里的value值是vue对应的属性值。注意指令的值是表达式,可以计算的。
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
>div>
<div v-bind:class="classObject">div>
<div v-bind:class="[activeClass, errorClass]">div>
数组中元素都是vue实例属性,class属性值;想要类不存在,修改属性为""
即可:<div v-bind:class="[isActive ? activeClass : '', errorClass]">div>
<div v-bind:class="[{ active: isActive }, errorClass]">div>
<my-component v-bind:class="{ active: isActive }">my-component>
这里绑定的是父组件的实例属性。并且该class会被添加到组件模板的根元素上。<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">div>
对象的key是样式名,使用驼峰命令法;value是vue实例属性。<div v-bind:style="[baseStyles, overridingStyles]">div>
v-if
指令的元素,只有在属性值为true时才会被渲染。v-if
指令条件渲染多个html元素,可使用template
包裹起来:<template v-if="ok">
<h1>Titleh1>
<p>Paragraph 1p>
<p>Paragraph 2p>
template>
v-else
,v-else-if
key
属性阻止这里行为:<template v-if="loginType === 'username'">
<label>Usernamelabel>
<input placeholder="Enter your username" key="username-input">
template>
<template v-else>
<label>Emaillabel>
<input placeholder="Enter your email address" key="email-input">
template>
但label还是会被复用含v-show
的元素还是会被渲染到dom中,但会条件性的选择是否显示它,使用了css的display
属性。因此隐藏或显示后,事件监听器还是存在的。
使用方式如下
v-for
可以将数组映射为Elements,最基本形式如下: <li v-for="item in items">
{{ item.message }}
li>
items为vue实例的数组属性,也可以是一个表达式;item为数组中的一项。然后可以使用{{data}}
进行文本插值。 <li v-for="(item, index) in items">
{{ index }} - {{ item.message }}
li>
of
,而不是in
<div v-for="item of items">div>
<li v-for="value in object">
{{ value }}
li>
会遍历object的所有可遍历属性,value表示对象的属性。<div v-for="(value, key) in object">
{{ key }}: {{ value }}
div>
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
div>
<div>
<span v-for="n in 10">{{ n }} span>
div>
这里再次强调一下,虚拟DOM应用到DOM时会patch/reuse元素,达到对DOM的最少操作。元素(如input)或组件的内部状态可能会被保存,使用key
属性可以将防止这种优化,如:
<div v-for="item in items" :key="item.id">
div>
对下面的话,做个总结:简而言之,vue检测不到
data
中数组属性中元素的修改,需要其他手段。对于对象也是同样的道理
我们知道,选项对象的data
中的属性会被添加到响应式系统,这些属性的改变会造成视图的重新渲染。但如果data
中存在数组属性,对数组元素的修改不会造成数据本身引用地址的改变(参考c++引用),因此vue不能通过数组属性检查数组元素是否改变。检测方法如下:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
替换数组属性不会造成视图全部更新,有优化的~Vue.set()
来设置属性(索引)值Vue.set(vm.items, indexOfItem, newValue)
vue实例也有该方法
vm.$set()
splice()
vm.items.splice(indexOfItem, 1, newValue)
它在删除元素的同时也在对应位置添加了newValue
理由同上,解决方法
set
方法v-for
也可以使用
元素聚合html元素块。v-for
与v-if
一起作用到同一个元素中,v-for
优先级高v-for
与组件搭配使用时,key
属性必须加上,保证组件的更改随视图更新而更新。组件之间的数据作用域是隔开的,如果父组件想将v-for
的索引值传入子组件,需绑定子组件的属性,子组件的属性由选项对象的props
设置。v-on
绑定的事件在虚拟DOM删除(real-DOM中reuse),事件也会被清除。
v-on
指令监听DOM事件,事件触发时执行js代码。
<button v-on:click="counter += 1">Add 1button>
指令值的可用$event
表示DOM原生事件,如:
之前说了,一些指令拥有modifier,v-on
也有。
参考:Event modifiers
当只监听某个键值时,可以使用key modifiers。如:
<input v-on:keyup.enter="submit">
PageDown
写成page-down
。.enter
keyCode
,如监听回车事件:<input v-on:keyup.13="submit">
v-model
用于对表单元素进行双向绑定,略!但记住:
<input v-model="searchText">
等于
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
如果是组件,则等于:
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
>custom-input>
这里的$event
是组件发出自定义事件时传的参数。与v-on
的$event
不同。
el
data
选项必须是一个函数,以致于每个组件实例都有自己的数据拷贝。Vue.component()
注册。全局组件可以作为根组件props
是组件的自定义属性,组件实例后会作为实例的属性而存在子组件中使用vm.$emit( eventName, […args] )
自定义事件并发出,arg是伴随事件的额外数组参数。
<button v-on:click="$emit('enlarge-text', 0.1)">
Enlarge text
button>
父组件可以监听该事件
<blog-post
v-on:enlarge-text="postFontSize += $event"
>blog-post>
这里的$event
代表$emit()
方法的参数数组中的第一个参数。
或者使用事件监听器:
<blog-post
v-on:enlarge-text="onEnlargeText"
>blog-post>
methods: {
onEnlargeText: function (enlargeAmount) {
this.postFontSize += enlargeAmount
}
}
事件处理器的参数可以有多个,与$emit()
方法的参数一一对应。
上面谈到过
<customer-input v-model="searchText">customer-input>
等于
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
>custom-input>
因此若子组件想要实现v-model
的数据双向绑定,可进行如下设计:
Vue.component('custom-input', {
props: ['value'],
template: `
`
})
如果想实现组件其他属性的双向绑定,需要model
选项更改v-model
绑定的属性和事件,如:
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
`
})
现在可以使用v-model
绑定到组件的checked属性上
<base-checkbox v-model="lovingVue">base-checkbox>
html中,组件中含有内容时,组件可通过
获取。如:
<alert-box>
Something bad happened.
alert-box>
Vue.component('alert-box', {
template: `
Error!
`
})
动态切换组件,使用is
属性,如:
<div id="app">
<component v-bind:is="which">component >
<select name="" id="" v-model="which">
<option>my-content1option>
<option>my-content2option>
<option>my-content3option>
select>
div>
let vm=new Vue({
el:"#app",
data:{
which:"my-content1"
},
components:{
"my-content1":{
template:`content1`
},
"my-content2":{
template:`content2`
},
"my-content3":{
template:`content3`
}
}
})
每次切换时,vue会重新生成组件实例,那么之前的状态不会被保存,需要使用
内置组件包裹它,使模板缓存起来:
<keep-alive>
<component v-bind:is="currentTabComponent">component>
keep-alive>
在html元素中,ul
,ol
,table
,select
规定了什么元素能够存在,如li
,tr
,option
。解决办法是使用is
属性。
但在其他模板中无这种问题:
template:'....'
.vue
Vue.component('my-component-name', { /* ... */ })
第一个参数为组件名,第二个参数为选项对象。全局注册的组件,可以直接在其他组件中使用。
创建Vue实例时,可将组件传给选项对象的components数组,如:
//选项对象
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
并且该组件只能在注册的父组件中使用。
my-component-name
,可以在html和模板中直接使用。MyComponentName
,此时在html中只能使用对应的kebab-case命令,但在模板中两则都可使用。(即存在自动转换过程)注意,html中元素和属性名都大小写不敏感。
props选项属性定义组件作为html元素收到的属性。属性的命令规则同上。
属性可以为数组或对象。对象可以额外设置属性类型、默认值、是否必须、验证函数。
属性值常与v-bind
一起使用。
如果在组件上使用props未定义的属性,那么属性会被添加到组件的根元素上。如果根元素已定义该属性,则被覆盖;style
,class
属性除外,它会被合并在一起。
inheritAttrs: false
会阻止未定义属性作用在组件根元素上的行为,而$attrs
接收未定义属性的赋值,因此此时可以将它手动绑定到组件中的一个元素上,如:
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
template: `
`
})
注意,都不会影响
class
和style
属性。
参考:props;
略
元素可以获取内容。
元素中可有默认内容,组件元素中可覆盖这些内容。
元素时,使用元素的name
属性来区分,允许其中一个
无name
值,则默认default
;那么组件元素的内容中需要使用
围绕部分内容,v-slot
指令指定对应slot
元素。如:<div class="container">
<header>
<slot name="header">slot>
header>
<main>
<slot>slot>
main>
<footer>
<slot name="footer">slot>
footer>
div>
父组件模板<base-layout>
<template v-slot:header>
<h1>Here might be a page titleh1>
template>
<template v-slot:default>
<p>A paragraph for the main content.p>
<p>And another one.p>
template>
<template v-slot:footer>
<p>Here's some contact infop>
template>
base-layout>
同样允许无
元素围绕的部分存在,对应default slot<base-layout>
<template v-slot:header>
<h1>Here might be a page titleh1>
template>
<p>A paragraph for the main content.p>
<p>And another one.p>
<template v-slot:footer>
<p>Here's some contact infop>
template>
base-layout>
元素中的属性会被绑定到一个对象中,组件元素中v-slot
可以获取该对象,实现了父组件中的组件元素使用组件内的数据。如:
<span>
<slot v-bind:user="user">
{{ user.lastName }}
slot>
span>
父组件模板中<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
template>
current-user>
当只有一个slot元素时,可缩写成:<current-user v-slot:default="slotProps">
{{ slotProps.user.firstName }}
current-user>
也可省略default<current-user v-slot="slotProps">
{{ slotProps.user.firstName }}
current-user>
上面传入的slotProps对象含有slot元素的属性值,可以使用es5的解构语法获得单个属性:<current-user v-slot="{ user }">
{{ user.firstName }}
current-user>
v-slot
的参数可以是动态的,如v-slot:[dynamicSlotName]
v-slot:
的缩写为#
,使用时后面必须存在参数。<div id="app-5">
<p>{{ message }}p>
<button v-on:click="reverseMessage">Reverse Messagebutton>
div>
//创建vue实例时,需要传入选项对象
var app5 = new Vue({
//绑定的element
el: '#app-5',
//data里的属性最终成为vue实例的属性
data: {
message: 'Hello Vue.js!'
},
//methods中的属性最终成为vue实例的方法,因此this指向vue实例
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})
$root
:访问组件的根实例$parent
:访问子组件的父组件$refs
:子元素或子组件上添加ref
属性,指定引用id,可通过$refs
来获取该DOM元素或组件实例。$el
:组件的根DOM元素用于双向绑定属性的,与v-model
类似。
如父组件绑定到字组件的title
属性上,当子组件发出update:title
事件时:
this.$emit('update:title', newTitle)
父组件更新title
值:
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
>text-document>
可简写为:
<text-document v-bind:title.sync="doc.title">text-document>
可以发现,
.sync
与v-model
监督的事件不同,.sync
监听的事件前有update:
前缀,v-model
默认监听input
事件。