Vue.js 学习笔记
Vue.js 通常简称 Vue,是一个介于 Angular 和 Reactjs 之间的前端开发框架和库。
- 官方文档:英文 中文
- 官方索引:awesome-vue
- 项目源代码:vuejs/vue
- 开发工具:
- 脚手架工具 vue-cli (面向组件开放的项目都建议使用这个官方工具初始化)
- Webpack 插件 vue-loader (官方推荐)
- Browserify 插件 vueify (webpack 明显是一个更优选择)
- Chrome 开发插件 vue-devtools
- xhr
- vue-resource (文档和代码都比较简单)
- UI 库:
- vue-antd 蚂蚁金服 ant design 的 Vue 实现(不够完善,但是看起来比 vue-strap 好看些。
- vue-spectre
- 路由
- vue-router(官方 router)
- vuex-router-sync(Vuex 和 Vue-Router 的绑定)
- 单项数据流
- VueX 相当于 React-Redux + Redux
Vue 2.0 更新
高级部分
模板渲染不再依赖于 DOM,也就是说 <script type="text/x-template">
以及单文件组件用户由于不需要手动设置 el
选项将不再会受 1.0 时代的渲染限制。
由于 Vue 2.0 已经将编译器和运行时环境解耦,因此提供了两种不同的构建:
- 独立版本。和 1.x 类似,包含编译器和运行时环境两者。
- 仅包含运行时。并不包含编译器,你可以选择自己预编译模板,或者手动编写渲染函数。npm 上默认是该版本,因此你需要配合 Browserify 或者 Webpack 进行预编译处理。
config 设置
新增配置
silent
optionMergeStrategies
devtools
errorHandler
keyCodes
: configure custom key aliases forv-on
反对配置:
debug
async
delemiters
:改为组件级设置unsafeDelimiters
:使用v-html
代替
全局 API
新增 Vue.compile
(仅针对独立版本)。
反对的 API 有:
- stagger:set and access data-index on el instead
- Vue.elementDirective:使用组件代替
- Vue.partial:使用组件函数代替
选项
反对项:
- props.coerce:请使用 computed 代替修改 prop
- prop 绑定模式:v-model 支持组件
- replace:组件必须且只能有一个根元素
新增:
- propsData:instantiation only
- render
生命周期
init
改为 beforeCreate
新增:
- beforeMount
- mounted
- beforeUpdate
- updated
- activated
- deactivated
反对:
- ready:使用 mounted 代替
- active:改为在 vue-router 中进行管理
- beforeCompile:使用 created 代替
- compiled:使用 mounted 代替
- attached:请在其它 hook 中检查是否存在于 DOM
- detached:同上
Assets
partials 和 elementDirectives 已反对。
其它
不再支持 events。
新增:
- delimiters:代替之前的全局设置,仅支持独立模式。
- functional:将组件设置为无状态、无实例。(仅仅是一个返回虚拟节点的渲染函数)
实例属性
vm.$refs 和 vm.$els 合并为前者。
实例方法
data 中已反对项:
- $get
- $set:使用 Vue.set 代替
- $delete:使用 Vue.delete 代替
- $eval
- $interpolate
- $log:使用 devtools 插件代替
事件中反对:
- $dispatch:使用全局事件或者 Vuex。
- $broadcast:同上。
DOM 相关
反对项:
- vm.$appendTo
- vm.$before
- vm.$after
- vm.$remove
基本上都可以用原生 DOM API 代替。
指令变化
- 反对使用
\{\{\{\}\}\}
- 反对 v-for 中使用
$index
和$key
,使用(value, index) in arr
或者(value, key, index) in obj
代替。 - 反对 debounce,使用第三方 debounce 函数配合v-on:input 来代替。
- v-ref:改为属性
ref
- v-el:已合并进
ref
属性
渲染相关
提供 renderToString
、renderToStream
和客户端渲染。
详细:https://github.com/vuejs/vue/issues/2873
常见更新问题
不支持过滤器怎么办?
建议使用 computed 属性代替。
debounce 和 v-model 怎么解决?
debounce 是用来限制 Ajax 等耗时时间的出发频率的,Vue 的 debounce 属性使得 v-model 的控制变得容易,但它只能用于延迟状态的更新而不是复杂操作本身,这是它的限制之处。
比如说你在设计一个搜索提示功能,使用 debounce 意味着用户必须停止输入一段时间之后才会发送搜索请求,而你真正需要的应该是搜索频率的限制。
基本概念
入前面所说,Vue 的定位介于 Angular 和 Reactjs,既可以手动绑定 DOM 元素,也可以定义组件进行模块化开发。
双向绑定
Vue 作为一个 MVVM 框架,双向绑定是其最基本的特性。
数据的绑定、类/状态的绑定、样式绑定
动态数据的绑定(computed
)
组件(核心)
template 标签
插槽 slot
对于一个灵活的组件来说,可替换的组件非常重要。Vue 中提供了一个叫做 slot 的概念,使用 slot
标签作为内容插槽的占位符。
定义:
<template>
<div class="modal">
<div class="modal-header">
<slot name="header"></slot>
</div>
<div class="modal-content">
<slot name="content"></slot>
</div>
<div class="modal-footer">
<slot name="footer"></slot>
</div>
</div>
</template>
使用:
<modal>
<template slot="header"><!-- 声明替换 template 中的 header 槽 -->
<h2>This is header</h2>
</template>
<div slot="body"><!-- template 标签不是必须的,可以指定槽元素 -->
<p>Content body.</p>
</div>
<template slot="footer">
<div>Footer</div>
</template>
</modal>
片段实例()
下面几种情况会让实例变成一个片断实例:
- 模板包含多个顶级元素。
- 模板只包含普通文本。
- 模板只包含其它组件(其它组件可能是一个片段实例)。
- 模板只包含一个元素指令,如 或 vue-router 的 。
- 模板根节点有一个流程控制指令,如 v-if 或 v-for。
片段实例的问题在于,可能无法找到唯一对应的顶级元素,因此无法正常绑定 $el
。
大多数情况下不建议使用片段实例。
递归组件
和函数的递归类似,需要组件名和跳出条件避免死循环。
异步组件
可以理解为 templateUrl 的替代品。
指令
指令的作用和组件类似,相当于轻量级的组件。
MixIn
跟 Python 等语言的 MixIn 很像。
事件与组件的生命周期
过渡动画
CSS 过渡和 JS 过渡
CSS 过渡
CSS 动画的原理是在触发创建和销毁事件时修改元素的类名,浏览器察觉样式变换后执行 CSS3 动画。
<div v-if="show" transition="expand">hello</div>
<style>
/* 必需 */
.expand-transition {
transition: all .3s ease;
height: 30px;
padding: 10px;
background-color: #eee;
overflow: hidden;
}
/* .expand-enter 定义进入的开始状态 */
/* .expand-leave 定义离开的结束状态 */
.expand-enter, .expand-leave {
height: 0;
padding: 0 10px;
opacity: 0;
}
</style>
过渡类名:
类名的添加和切换取决于 transition 特性的值。比如 transition="fade",会有三个 CSS 类名:
- .fade-transition 始终保留在元素上。
- .fade-enter 定义进入过渡的开始状态。只应用一帧然后立即删除。
- .fade-leave 定义离开过渡的结束状态。在离开过渡开始时生效,在它结束后删除。
transition 特性没有值时默认类名是 .v-transition, .v-enter 和 .v-leave。
配合 Animate.css 使用
引入 Animate.css 后注册 bounce 效果:
Vue.transition('bounce', {
enterClass: 'bounceInLeft',
leaveClass: 'bounceOutRight'
})
就可以像上面那样使用了。
JS 过渡
过滤器
对数据进行额外的处理,使用管道符 |
分隔数据和过滤器,可以同时使用多个过滤器。
自定义过滤器
过滤器通常是单参数函数,可以使用 Vue.filter(filterName, filterFunc)
方法全局注册。
双向过滤器
自定义开发
自定义指令
插件开发
增强代码的可复用性
规范的命名约定
Vue 默认会自动转换 camelCase 和 PascalCase 的组件名为 kebab-case,以支持 HTML tag。
组件
组件应当定义好清晰的公开接口,允许外部环境通过 props 传递数据给组件,允许组件触发外部事件,使用 slot 提供可插拔的替换内容。
默认事件
- init 组件实例初始化完毕,并未开始设置数据监控和事件、监控
- created 数据监控、计算熟悉、方法、事件监控已就绪,DOM 未就绪,$el 尚不存在
- beforeCompile 即将开始构建
- compiled 构建已完成,指令已链接,$el 和 DOM 尚未就绪
- ready $el 插入文档
- attached
- detached
- beforeDestroy Vue 实例即将销毁
- destroyed Vue 实例销毁完成
事件派发
常见问题
Vue.js 和其它框架对比如何?该如何选择框架?
官方文档中《对比其它框架》已经讲得很清楚了,也挺客观。
Vue 项目应当怎样组织文件结构?
可以使用 vue-cli 工具自动生成:
├── src
│ ├── App.vue
│ ├── assets
│ │ └── favicon.ico
│ ├── components
│ │ └── HelloWorld.vue
│ ├── libs
│ │ └── xxx.coffee
│ ├── entry.js
│ ├── styles
│ │ └── base.scss
│ └── views
│ └── Hello.vue
├── test
│ └── unit
│ ├── Hello.spec.js
│ └── index.js
├── webpack.base.conf.js
├── webpack.dev.conf.js
├── webpack.prod.conf.js
├── package.json
├── index.html
├── README.md
├── dist
├── 构建结果
是否会提供类似 templateURL 的支持?
不过 Vue 提供了另一个相似的功能,也就是异步加载组件。
用做 SPA 的时候如何不重复渲染被隐藏的组件?
可以考虑使用 v-show
指令来代替 v-if
,可以使用 keep-alive
指令。 较新版本的 vue-loader 也提供了 keep-alive
的支持。
组件中数据同步问题?
虽然 Vue 提供了 :data.sync='obj'
这样的组件间数据双向绑定的写法,但对于复杂关联的数据,推荐使用 $dispatch()
向上派发和 $broadcast()
向下广播事件。
父子组件间数据交换的最佳实践?
$root
消息 props slot
webpack 常见问题
引入未发布在 npm 中的第三方库
webpack 提供了 [expose-loader]:
require('expose?本地名!../vendors/第三方库.js')
由于第三方库通常是以 JS 全局变量的形式进行注册,而 webpack 默认禁止这种行为,因此引入后需要注册才能使用。