本文为拉勾网大前端高薪训练营第一期笔记
Vue.js基础
本文大部分Vuejs介绍来自Vuejs官方文档
Vue生命周期图示
单文件页面建议提前编译template,优化性能
Vue.js语法和概念
建议https://cn.vuejs.org/v2/guide/查看官方文档
- 插值表达式
<span>Message: {{ msg }}</span>
- 指令
指令 (Directives) 是带有 v- 前缀的特殊 attribute
跟angular的ng-if很接近
<p v-if="seen">现在你看到我了</p>
//这里,v-if 指令将根据表达式 seen 的值的真假来插入/移除 <p> 元素。
//v-bind 指令可以用于响应式地更新 HTML attribute
<a v-bind:href="url">...</a>
//Vue 为 v-bind 和 v-on 这两个最常用的指令,提供了特定简写
//<!-- 完整语法 -->
<a v-bind:href="url">...</a>
//<!-- 缩写 -->
<a :href="url">...</a>
//<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
//<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
//<!-- 缩写 -->
<a @click="doSomething">...</a>
//<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
- 计算属性和侦听器
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:
计算属性
//不使用计算属性
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
//使用计算属性
<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('')
}
}
})
//需要注意的是前者是计算属性是基于它们的响应式依赖进行缓存的。
//只在相关响应式依赖发生改变时它们才会重新求值。
//这就意味着只要 message 还没有发生改变,
//多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
//简单来说就是前面的做法有缓存,下面的做法没有,不想要缓存可以用下面的()方法调用式
<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在组件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
侦听器
和angularjs一样,根据数据变化来进行操作,能用计算属性的时候更推荐计算属性
<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
}
}
})
//更推荐这样
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]
}
}
}
- Class和Style绑定
//Class绑定
<div v-bind:class="{ active: isActive }"></div>
//还有很多种语法,比如数组语法,和计算属性结合使用,请看官方文档
//Style绑定
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
//直接绑定到一个样式对象通常更好,这会让模板更清晰:
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
- 条件渲染/列表渲染
条件渲染
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
//甚至还有 v-else-if
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
//Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key attribute 即可
//简单来说用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>
//v-show
<h1 v-show="ok">Hello!</h1>
//不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。
//v-show 只是简单地切换元素的 CSS property display。
//v-if vs v-show
//一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
//因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
列表渲染
<ul id="example-1">
<li v-for="item in items" :key="item.message">
{{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
//注意我们不推荐在同一元素上使用 v-if 和 v-for
//如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或 <template>) 上。如:
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
//2.2.0+ 的版本里,当在组件上使用 v-for 时,key 现在是必须的。
- 组件
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
<div id="components-demo">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
- 插槽
<navigation-link url="/profile">
Your Profile
</navigation-link>
//然后你在 <navigation-link> 的模板中可能会写为:
<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>
//当组件渲染的时候,<slot></slot> 将会被替换为“Your Profile”。
//可以理解为react里的props.children会在slot处渲染
//如果 <navigation-link> 的 template 中没有包含一个 <slot> 元素,
//则该组件起始标签和结束标签之间的任何内容都会被抛弃。
- 插件
插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制——一般有下面几种:
- 添加全局方法或者 property。如:vue-custom-element
- 添加全局资源:指令/过滤器/过渡等。如 vue-touch
- 通过全局混入来添加一些组件选项。如 vue-router
- 添加 Vue 实例方法,通过把它们添加到
Vue.prototype
上实现。 - 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router
- 混入mixin
// 定义一个混入对象
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// 定义一个使用混入对象的组件
var Component = Vue.extend({
mixins: [myMixin]
})
var component = new Component() // => "hello from mixin!"
//我的理解是组件的基类
- 深入响应式原理
现在是时候深入一下了!Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。这使得状态管理非常简单直接,不过理解其工作原理同样重要,这样你可以避开一些常见的问题。
建议安装 vue-devtools 来获取对检查数据更加友好的用户界面
- 不同构件版本的Vue
https://cn.vuejs.org/v2/guide/installation.html#对不同构建版本的解释
- 完整版
- 只包含运行时版
- 完整版 (生产环境)
- 只包含运行时版 (生产环境)
React和Vue性能对比
在 React 应用中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树。
如要避免不必要的子组件的重渲染,你需要在所有可能的地方使用 PureComponent
,或是手动实现 shouldComponentUpdate
方法。同时你可能会需要使用不可变的数据结构来使得你的组件更容易被优化。
然而,使用 PureComponent
和 shouldComponentUpdate
时,需要保证该组件的整个子树的渲染输出都是由该组件的 props 所决定的。如果不符合这个情况,那么此类优化就会导致难以察觉的渲染结果不一致。这使得 React 中的组件优化伴随着相当的心智负担。
在 Vue 应用中,组件的依赖是在渲染过程中自动追踪的,所以系统能精确知晓哪个组件确实需要被重渲染。你可以理解为每一个组件都已经自动获得了 shouldComponentUpdate
,并且没有上述的子树问题限制。
Vue 的这个特点使得开发者不再需要考虑此类优化,从而能够更好地专注于应用本身。