一. vue.js教程总结
1. Object.freeze()
阻止 数据改变时,视图会进行重渲染的现象。
2. vue暴露了一些有用的实例属性与方法,加上前缀 $
vm.$data === data // => true
vm.$el === document.getElementById('example') // => true
// $watch 是一个实例方法
vm.$watch('a', function (newValue, oldValue) {
// 这个回调将在 `vm.a` 改变后调用
})
注意 :
不要在选项属性或回调上使用 箭头函数
比如 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 之类的错误。
4. v-once
当数据改变时,插值处的内容不会更新
5. v-html
输出真正HTML
注意:
你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。
6. 动态参数 (2.6.0 新增)
<a v-bind:[attributeName]="url"> ... </a>
// Vue 实例有一个 data 属性 attributeName,其值为 "href" 等价于 v-bind:href
// 不能使用 空格或者引号的表达式
7. v-bind 缩写
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
8. v-on 缩写
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
9. 计算属性
<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('')
}
}
})
10. 计算属性和方法的区别
计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。
相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。
11. 计算属性的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]
}
}
}
// 现在再运行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstName 和 vm.lastName 也会相应地被更新。
12. watch 侦听器
可以监视 data 中指定数据的变化,然后触发这个 watch 中对应的 function 处理函数
该方法可以不用绑定事件
<body>
<div id="app">
<input type="text" v-model="firstname">+
<input type="text" v-model="lastname">=
<input type="text" v-model="fullname">
</div>
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
firstname: '',
lastname: '',
fullname: ''
},
methods: {},
watch: {
'firstname': function(oldVal,newVal){
this.fullname = newVal + '-' + this.lastname
},
'lastname': function(oldVal,newVal){
this.fullname = this.firstname + '-' + newVal
}
// 监听的是对象或者数组需要加上 deep: true;
}
});
</script>
</body>
13. watch、computed和methods之间的对比
computed 属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;
methods 方法表示一个具体的操作,主要书写业务逻辑;
watch 一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是computed和methods的结合体;
14. Class 与 Style 绑定
14.1 绑定 HTML Class
14.1.1 对象语法
data: {
isActive: true,
hasError: false
}
<div v-bind:class="{ active: isActive }"></div>
<div class="active"></div>
// active 这个 class 存在与否将取决于数据属性 isActive 是否为true
// 可以在对象中传入更多属性来动态切换多个 class
// 与普通的 class 属性共存
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
// 渲染结果
<div class="static active"></div>
// 绑定的数据对象不必内联定义在模板里
<div v-bind:class="classObject"></div>
// 也可以绑定一个返回对象的计算属性
<div v-bind:class="classObject"></div>
data: {
classObject: {
active: true,
'text-danger': false
}
}
// 计算属性
data: {
isActive: true,
error: null
},
computed: {
classObject: function () {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
14.1.2 数组语法
<div v-bind:class="[activeClass, errorClass]"></div>
// 渲染结果
<div class="active text-danger"></div>
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
根据条件切换可以选择三元表达式
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
// 这样写始终添加 errorClass,但是只有在 isActive 是 truthy[1] 时才添activeClass
// 多个条件是还可以这样写
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
14.1.3 用在组件上
当在一个自定义组件上使用 class 属性时,这些 class 将被添加到该组件的根元素上面。这个元素上已经存在的 class 不会被覆盖。
// 声明一个组件之后
Vue.component('my-component', {
template: '<p class="foo bar">Hi</p>'
})
// 在使用该组件的时候再加一些class
<my-component class="baz boo"></my-component>
// 将会渲染成这样
<p class="foo bar baz boo">Hi</p>
14.2 绑定内联样式
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red',
fontSize: 30
}
如果样式多可以绑定在一个对象上 而且看起来模板更加清晰
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
数组语法可以将多个对象应用到同一个元素上
<div v-bind:style="[baseStyles, overridingStyles]"></div>
14.2.1 多重值
可以用于提供多个前缀的值
// 用于适配
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
15. 条件渲染 v-if, v-else, v-else-if
15.1 在 元素上使用 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-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
15.2 用 key 管理可复用的元素
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染
// 当这两个元素是完全独立的,不要复用它们时 只需添加一个具有唯一值的 key 属性即可
<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>
15.3 v-show
不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display。
15.4 v-show 和 v-if 区别
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-show 就是简单的css样式的切换
需要非常频繁地切换,则使用 v-show 较好;
如果在运行时条件很少改变,则使用 ==v-if ==较好。
15.5 v-if 和 v-for 一起使用
当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级
16. 列表渲染
16.1 在v-for使用对象
可以提供第二个的参数为 property 名称 (也就是键名):
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
<div v-for="(value, name) in object">
{{ name }}: {{ value }}
</div>
显示为:
title: How to do lists in Vue
author: Jane Doe
publishedAt: 2016-04-10
还可以用第三个参数作为索引:
<div v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</div>
16.2 维护状态(绑定 :key)
为什么添加key属性?
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
16.3 数组的更新检测
变异方法
会改变原始数组
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
非变异方法
不会改变原始数组,而总是返回一个新数组
filter()、concat() 和 slice()
16.4 显示过滤/排序后的结果
可以创建一个计算属性,来返回过滤或排序后的数组。
<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循环中
<ul v-for="set in sets">
<li v-for="n in even(set)">{{ n }}</li>
</ul>
data: {
sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
v-for 与 v-if 一同使用
v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。当你只想为部分项渲染节点时,这种优先级的机制会十分有用
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
如果是想有条件的跳过循环,可以将v-if至于外层
16.5 在组件上使用 v-for
2.2.0+ 的版本里,当在组件上使用 v-for 时,key 现在是必须的。
任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数
<my-component v-for="item in items" :key="item.id"></my-component>
// 据传递到组件里,我们要使用prop
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>
注意
is=“todo-item” 这种做法在使用 DOM 模板时是十分必要的,因为在
- 元素内只有
- 元素会被看作有效内容。这样做实现的效果与 相同,但是可以避开一些潜在的浏览器解析错误
17. 事件处理 v-on
17.1 内联处理器的方法
有时也需要在内联语句处理器中访问原始的 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)
}
}
17.2 修饰符
17.2.1 事件修饰符
.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>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
// 这个 .passive 修饰符尤其能够提升移动端的性能
<div v-on:scroll.passive="onScroll">...</div>
多个修饰符的顺序是自前往后
17.2.2 按键修饰符
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
<input v-on:keyup.page-down="onPageDown">
<!--处理函数只会在 $event.key 等于 PageDown 时被调用。-->
<!--使用 keyCode attribute 也是允许的:-->
<input v-on:keyup.13="submit">
为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
17.2.3 系统修饰符
.ctrl
.alt
.shift
.meta
.ctrl
.alt
.shift
.meta
.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button v-on:click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button v-on:click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button v-on:click.exact="onClick">A</button>
17.2.4 鼠标修饰符
.left
.right
.middle
使用v-on的好处
- 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
- 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试
- 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。
18. 表单输入
18.1 修饰符
.lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">
.number
转为数字类型
<input v-model.number="age" type="number">
19. 组件基础
19.1 data必须是一个函数
一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝
20. 插槽
20.1 具名插槽(新语法)
一个带有如下模板的 子组件
对于这样的情况, 元素有一个特殊的 attribute:name。这个 attribute 可以用来定义额外的插槽
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
一个不带 name 的 出口会带有隐含的名字“default”。
在向具名插槽提供内容的时候,我们可以在一个 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称:
父子件中
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<!--任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容。-->
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<!--希望更明确点仍然可以在一个 <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 info</p>
</template>
</base-layout>
任何一种写法子组件中都会渲染出:
<div class="container">
<header>
<h1>Here might be a page title</h1>
</header>
<main>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</main>
<footer>
<p>Here's some contact info</p>
</footer>
</div>
20.2 作用域插槽(新语法)
子组件模板如下
<span>
<slot v-bind:user="user">
{{ user.lastName }}
</slot>
</span>
在父组件中:
绑定在 元素上的 attribute 被称为插槽 prop
<!-- slotProps 可以使任意的名字 -->
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
简化版
<!--当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用-->
<current-user v-slot="slotProps">
{{ slotProps.user.firstName }}
</current-user>
出现多个插槽,请始终为所有的插槽使用完整的基于 的语法:
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
<template v-slot:other="otherSlotProps">
...
</template>
</current-user>
解构插槽 Prop
v-slot 的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式,可以使用 ES2015 解构来传入具体的插槽 prop
<current-user v-slot="{ user }">
{{ user.firstName }}
</current-user>
将 user 重命名为 person
<current-user v-slot="{ user: person }">
{{ person.firstName }}
</current-user>
你甚至可以定义后备内容,用于插槽 prop 是 undefined 的情形
<current-user v-slot="{ user = { firstName: 'Guest' } }">
{{ user.firstName }}
</current-user>
20.3 具名插槽的缩写
v-slot: 替换为字符== #== 例如 v-slot:header 可以被重写为 #header
然而,和其它指令一样,该缩写只在其有参数的时候才可用。这意味着以下语法是无效的
<!-- 这样会触发一个警告 -->
<current-user #="{ user }">
{{ user.firstName }}
</current-user>
必须始终以明确插槽名
<current-user #default="{ user }">
{{ user.firstName }}
</current-user>