引入Scrimba 上的系列教程
当一个 Vue 实例被创建时,它向 Vue 的响应式系统中加入了其 data 对象中能找到的所有的属性。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
// 我们的数据对象
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
使用 Object.freeze(),会阻止修改现有的属性,也意味着响应系统无法再追踪变化。
v-once 表示指令一次性插值
<span>Message: {{ msg }}span>
<span v-once>这个将不会改变: {{ msg }}span>
<span v-html="rawHtml">span>
你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。
XSS 是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。
<div v-bind:id="dynamicId">div>
对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id">div>
指令 (Directives) 是带有 v- 前缀的特殊特性。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。
<p v-if="seen">现在你看到我了p>
一些指令能够接收一个“参数”,在指令名称之后以冒号表示。例如,v-bind 指令可以用于响应式地更新 HTML 特性:
<a v-bind:href="url">...a>
v-on 指令,它用于监听 DOM 事件。
<a v-on:click="doSomething">...a>
修饰符 (Modifiers) 是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。
例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault():
<form v-on:submit.prevent="onSubmit">...form>
<a v-bind:href="url">...a>
<a :href="url">...a>
<a v-on:click="doSomething">...a>
<a @click="doSomething">...a>
对于任何复杂逻辑,你都应当使用计算属性。
<div id="example">
<p>Original message: "{{ message }}"p>
<p>Computed reversed message: "{{ reversedMessage }}"p>
div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
// 在组件中
methods: {
reversedMessage: function () {
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
}
}
})
计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter :
// ...
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]
}
}
}
// ...
可以传给 v-bind:class
一个对象,以动态地切换 class。
可以在对象中传入更多属性来动态切换多个 class。
v-bind:class
指令也可以与普通的 class 属性共存。
可以绑定一个返回对象的计算属性。这是一个常用且强大的模式
<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'
}
}
}
//数据对象
data: {
classObject: {
active: true,
'text-danger': false
}
}
可以把一个数组传给 v-bind:class
,以应用一个 class 列表:
<div v-bind:class="[activeClass, errorClass]">div>
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
当在一个自定义组件上使用 class 属性时,这些类将被添加到该组件的根元素上面。这个元素上已经存在的类不会被覆盖。
v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) 来命名:
<div v-bind:style="styleObject">div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
<div v-bind:style="[baseStyles, overridingStyles]">div>
用于选择渲染的元素。
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。
Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key 属性即可(不添加key,元素会被复用,如input的输入状态不会被清除)。
另一个用于根据条件展示元素的选项是 v-show
指令。
<h1 v-show="ok">Hello!h1>
不同的是带有 v-show
的元素始终会被渲染并保留在 DOM 中。v-show
只是简单地切换元素的 CSS 属性 display
。
一般来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
当 v-if
与 v-for
一起使用时,v-for
具有比 v-if
更高的优先级。
//下面代码只返回未完成的todo
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
li>
v-for 指令根据一组数组的选项列表进行渲染。v-for 指令需要使用 item in items 形式的特殊语法,items 是源数据数组并且 item 是数组元素迭代的别名。
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
li>
ul>
var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
<ul id="v-for-object" class="demo">
<li v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
li>
ul>
new Vue({
el: '#v-for-object',
data: {
object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
})
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性(否则列表顺序改变时,vue只是简单的复用元素)。理想的 key 值是每项都有的且唯一的 id。
建议尽可能在使用 v-for 时提供 key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
Vue 包含一组观察数组的变异方法,它们会触发视图更新。
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
非变异方法,例如:filter(), concat() 和 slice() 。这些不会改变原始数组,但总是返回一个新数组。
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
由于 JavaScript 的限制,Vue 不能检测以下变动的数组(1/2)及对象(3):
vm.items[indexOfItem] = newValue
vm.items.length = newLength
解决方法:
//1.
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
//2.
vm.items.splice(newLength)
//3.
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
//添加一个新的 age 属性到嵌套的 userProfile 对象
Vue.set(vm.userProfile, 'age', 27)
vm.$set(vm.userProfile, 'age', 27)
//使用Object.assign()为已有对象赋予多个新属性
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
有时,我们想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。在这种情况下,可以创建返回过滤或排序数组的计算属性。
<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
})
}
}
<div id="todo-list-example">
<form v-on:submit.prevent="addNewTodo">
<label for="new-todo">Add a todolabel>
<input
v-model="newTodoText"
id="new-todo"
placeholder="E.g. Feed the cat"
>
<button>Addbutton>
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: '\
\
{{ title }}\
\
\
',
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 代码。
<div id="example-3">
<button v-on:click="say('hi')">Say hibutton>
<button v-on:click="say('what')">Say whatbutton>
div>
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>
// ...
methods: {
warn: function (message, event) {
// 现在我们可以访问原生事件对象
if (event) event.preventDefault()
alert(message)
}
}
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>
<div v-on:click.self="doThat">...div>
<a v-on:click.once="doThis">a>
<div v-on:scroll.passive="onScroll">...div>
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
Vue 允许为 v-on
在监听键盘事件时添加按键修饰符。
按键别名:
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
<input v-on:keyup.enter="submit">
<input @keyup.enter="submit">
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
.ctrl
.alt
.shift
.meta
<input @keyup.alt.67="clear">
<div @click.ctrl="doSomething">Do somethingdiv>
<button @click.ctrl="onClick">Abutton>
<button @click.ctrl.exact="onCtrlClick">Abutton>
<button @click.exact="onClick">Abutton>
.left
.right
.middle
v-on
有几个好处:你可以用 v-model
指令在表单 及
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。
v-model
会忽略所有表单元素的 value
、checked
、selected
特性的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data
选项中声明初始值。
详细:https://cn.vuejs.org/v2/guide/forms.html
new Vue
接收相同的选项,例如 data
、computed
、watch
、methods
以及生命周期钩子等。仅有的例外是像 el
这样根实例特有的选项。// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', { //通过 Vue.component 全局注册
data: function () {
return {
count: 0
}
},
template: ''
})
我们可以在一个通过 new Vue
创建的 Vue 根实例中,把这个组件作为自定义元素来使用:
<div id="components-demo"> <button-counter>button-counter>div>
new Vue({ el: '#components-demo' })
Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。
Vue.component('blog-post', {
props: ['title'],
template: '{{ title }}
'
})
<blog-post title="My journey with Vue">blog-post>