Vue.js 要点
关于 Vue
Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
下面是渐进式(自底向上)的图示:
看看 Vue 作者的描述:
Vue从设计角度来讲,虽然能够涵盖这张图上所有的东西,但是你并不需要一上手就把所有东西全用上,因为没有必要。无论从学习角度,还是实际情况,这都是可选的。声明式渲染和组建系统是Vue的核心库所包含内容,而客户端路由、状态管理、构建工具都有专门解决方案。这些解决方案相互独立,你可以在核心的基础上任意选用其他的部件,不一定要全部整合在一起。
响应式原理
-
在响应式原理中是如何追踪变化的呢?
原理是把一个对象传给 data 选项,Vue 将遍历此对象所有的属性,并使用
Object.defineProperty
把这些属性全部转为 getter/setter。这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。 -
每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
响应式原理的图示:
生命周期
生命周期是指每个 Vue 实例在被创建时都要经过一系列的初始化过程。这个过程中会运行一些叫做生命周期钩子的函数,给用户在不同阶段添加自己的代码。
下面是生命周期图示,其中红色字就是生命周期钩子:
缓存
我们为什么需要缓存?
假设我们有一个性能开销比较大的的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A。如果没有缓存,我们将不可避免的多次执行 A 的 getter。如果你不希望有缓存,请用 methods 来替代。
计算属性
-
模板内的表达式可以对 data 做额外操作,但是设计它的初衷是用于简单运算的,所以对于任何复杂逻辑,应当使用 computed。
除了 computed 还可以用一个 methods 实现复杂逻辑,两种方式的最终结果确实是完全相同的。不同的是 computed 是基于它们的依赖进行缓存的。
-
computed 取值操作时,getter 会被调用,运行赋值语句时,setter 会被调用。
data
当一个组件(.vue)被定义,data 必须声明为返回一个函数,因为组件可能被用来创建多个实例。如果返回一个对象,则所有实例将共享同一个对象。
侦听器
Vue 有个选项叫 watch,它和 computed 看起来很像,其实是有区别的。
当需要在数据变化时执行异步或开销较大的操作时,watch 选项是最有用的。它允许我们执行异步操作,限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性 computed 无法做到的。
条件渲染
看个例子:
<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-if 放在不可见元素(如 template)
- v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面。
- 添加一个具有唯一值的 key 属性,使得两个元素是完全独立的。
除了 v-if,有时会看到用 v-show 判断,区别是 v-if 的开销比 v-show 大,所以:
- 如果需要非常频繁地切换,使用 v-show 较好。
- 如果在运行时条件很少改变,使用 v-if 较好。
关于循环和判断的优先关系,当 v-for 和 v-if 处于同一节点,for 的优先级比 if 高,即循环判断。
列表渲染
- 列表渲染时加不加 key 看起来没有差别,不加 key 是高效的,不过只适用于不依赖子组件状态或临时 DOM 状态(?)的列表渲染。
-
列表渲染一般是操作数组,关于操作数组时是否会触发视图更新的条件如下:
能改变原数组的就会触发视图更新:
push()
、pop()
、shift()
、unshift()
、splice()
、sort()
、reverse()
不能改变原数组的不会触发视图更新:
filter()
、concat()
、slice()
用索引赋值不会触发视图更新:
item[index] = newValue
用 set 赋值会触发视图更新:
vm.$set(item, index, newValue)
或者Vue.set(item, index, newValue)
-
列表渲染时不能检测对象属性的添加或删除:
let vm = new Vue({ el: '#list', data: { obj: { a: 1 } } }); vm.obj.b = 4; // 不响应
-
列表渲染时不能动态添加根级别的响应式属性:
let vm = new Vue({ el: '#list', data: { a: 1 } }); vm.$set(vm, 'b', 4); // 报错
但是通过 set 可以给嵌套对象添加响应式属性:
let vm = new Vue({ el: '#list', data: { obj: { a: 1 } } }); vm.$set(vm.obj, 'b', 4);
-
在自定义组件使用列表渲染时,我们要用 props 把数据传给组件,而不是注入组件,因为组件有自己的作用域。使用 props 使得组件可以在其它场合利用,用法如下:
<todo-item v-for="todo in todos" :title="todo.title"></todo-item>
这里的 title 是在父组件中定义的,然后在注册组件时传入:
Vue.component('todo-item', { template: ``, props: ['title'] });
事件处理
在实际业务中,常常会使用 event.preventDefault()
或 event.stopPropagation()
,但 Vue 建议方法中只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。可以使用事件修饰符来代替它们:.stop
、.prevent
。
此外还有其它修饰符 .capture
、.self
、.once
、.passive
。
表单输入绑定
-
Vue 用 v-model 来绑定表单输入,v-model 本质上不过是语法糖:
<input v-model="searchText">
等价于:
<input v-bind:value="searchText" v-on:input="searchText = $event.target.value">
-
对于单选按钮,复选框及选择框的选项,v-model 绑定的值通常是静态字符串 (对于复选框也可以是布尔值)。
组件
组件 (Component) 是 Vue.js 最强大的功能之一。
组件是自定义元素,也可以表现为用 is 特性进行了扩展的原生 HTML 元素。
关于组件的父子关系:
- 组件设计初衷就是要配合使用的,最常见的就是形成父子组件的关系:组件 A 在它的模板中使用了组件 B。它们之间必然需要相互通信:父组件可能要给子组件下发数据,子组件则可能要将它内部发生的事情告知父组件。然而,通过一个良好定义的接口来尽可能将父子组件解耦也是很重要的。这保证了每个组件的代码可以在相对隔离的环境中书写和理解,从而提高了其可维护性和复用性。
- 关于父子组件通信可以参考:vue2.0 子组件和父组件之间的传值
- 父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。
关于 prop:
- 父子组件的关系可以总结为 prop 向下传递,事件向上传递。
- prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解。
- prop 会在组件实例创建之前进行校验,所以在 default 或 validator 函数里,诸如 data、computed 或 methods 等实例属性还无法使用。
- 所谓非 prop 特性,就是指它可以直接传入组件,而不需要定义相应的 prop。
- 在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。
关于事件:
自定义事件可以用来创建自定义的表单输入组件,使用 v-model 来进行数据双向绑定。
异步更新队列
- 只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。
- Vue 在内部尝试对异步队列使用原生的 Promise.then 和 MessageChannel,如果执行环境不支持,会采用
setTimeout(fn, 0)
代替。
vue-router
Vue Router 是路由管理器。
- 导航守卫用来解决 URL 不合规范的问题
- Redirect 用来解决默认路由的问题
AJAX
在 Vue 中如何使用 axios 跨域访问数据
axios 请求问题
学习 Vue 的心得
没使用过框架的人读文档可能会感觉吃力,看完文档再看看风格指南会更明白为什么要按某种格式写代码。
Leave a comment