一、组件化
组件:实现应用中局部功能代码和资源的集合。
1.1. 组件定义
Vue中使用组件的三大步骤:
- 定义组件(创建组件)
- 使用
Vue.extend(options)
创建,其中options
和new Vue(options)
里面传入的options
几乎一样,但也有区别el
不要写。因为最终所有的组件都要经过同一个vm
的管理,由vm
中的el
决定服务哪个容器。data
必须写成函数。因为对象在内存中只存在一份,为了避免组件被复用时数据存在引用关系,只能写成函数(每次都返回新的对象)。
- 使用
template
可以配置组件的HTML结构。 - 简写:
const school = Vue.extend(options)
可简写为const school = options
- 使用
- 注册组件
- 局部注册:
new Vue
传入components
选项 - 全局注册:
Vue.component('组件名', 组件)
- 局部注册:
- 使用组件(写组件标签)
- 例:
<school></school>
- 不使用脚手架时,
<school/>
写法会导致后续组件不能渲染
- 例:
1 | <body> |
1.2. 组件名
- 一个单词
- 首字母小写:
school
- 首字母大写:
School
- 首字母小写:
- 多个单词
- kebab-case:
my-school
- 驼峰:
MySchool
(需要Vue脚手架支持)
- kebab-case:
组件名尽可能回避HTML中已有的元素名称,例如:h2
、H2
都不行。
可以使用name
配置项指定组件在开发者工具中显示的名字。例:const school = Vue.extend({name:'Custom-School'})
。如果没有配置name
,默认会读取注册组件的名字。
1.3. VueComponent
school
组件本质是一个名为VueComponent
的构造函数,且不是程序员定义的,是Vue.extend
生成的。- 我们只需要写
<school/>
或<school></school>
,Vue解析时会帮我们创建school
组件的实例对象,即Vue帮我们执行了new VueComponent(options)
。 - 特别注意:每次调用
Vue.extend
返回的都是一个全新的VueComponent - 关于
this
指向问题:- 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数,它们的
this
都是VueComponent实例对象 new Vue()
配置中:data函数、methods中的函数、watch中的函数、computed中的函数,它们的this
都是Vue实例对象
- 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数,它们的
- VueComponent的实例对象,简称vc,也可称为组件实例对象。
- Vue的实例对象:简称vm。
Vue与VueComponent的关系:
为什么会有这个关系(VueComponent.prototype.__proto__ === Vue.prototype
)?目的是让组件实例对象(vc)可以访问到Vue原型上的属性和方法(Vue框架代码的复用)。
二、单文件组件
2.1. 格式
1 | <!-- 1. 模板 --> |
2.2. 脚手架
全局安装
1
2
3
4
5
6
7
8
9安装
npm install -g @vue/cli
OR
yarn global add @vue/cli
升级
npm update -g @vue/cli
OR
yarn global upgrade --latest @vue/cli切换到要创建项目的目录,使用CLI命令创建项目
1
vue create xxx
启动项目
1
2
3npm run serve
OR
yarn serve
2.3. render
vue.js
与vue.runtime.xxx.js
的区别:
vue.js
是完整版的Vue,包含核心功能和模板解析器vue.runtime.xxx.js
是运行版的Vue,只包含核心功能,没有模板解析器。
主要目的是为了减少包体积,而且项目上线后是不需要模板解析器的,因为最终都是HTML+CSS+JS。
因为vue.runtime.xxx.js
没有模板解析器,所以不能使用template配置项,需要使用render
函数接收到的createElement
函数去指定具体内容。
三、增强
3.1. ref
被用来给元素或子组件注册引用信息(id的替代者)
应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
使用方式:
1 | <!-- 打标识 --> |
3.2. props
组件传值。
1 | <!-- 传值,注意如果是非字符串类型(例如:age),需要使用v-bind形式 --> |
default
和required
是互斥的,不能同时存在。- 外部传入的
props
在组件内部尽量不要直接修改(直接修改Vue会发出警告),如果需要修改,可以在data中定义一个新的属性,属性值是props
中的属性值,最终通过修改data中的属性达到目的,如下代码。
1 | <script> |
补充:props不仅局限于String和Number,还可以传函数。
3.3. mixin
混入可以把多个组件共用的配置提取成一个混入对象(不影响原有逻辑)。
- 如果组件中的data数据和mixin中的data有相同的属性,优先使用组件中的data数据。
- 组件中的生命周期函数和mixin中的生命周期都是独立的,互相没有影响。mixin中的生命周期函数优先执行。
混入方式:局部混入和全局混入。
1 | <!-- Student.vue --> |
全局混入:Vue.mixin(testRun)
。如果有更多的混入项,多次进行配置即可。
3.4. plugins
插件的功能是为了增强Vue。本质上是一个包含install
方法的对象,install
的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据(可选)。
定义插件:
1 | export default { |
使用插件(必须在实例化Vue之前使用):
1 | Vue.use(xxx) |
3.5. scoped
Vue中所有编写的组件style最终都会合并到一个css文件中,所以style很大可能会有冲突覆盖问题。
只需要给style标签加上scoped关键词就可以让每个组件的样式互相隔离,只在组件内部生效。
1 | <style scoped> |
本质上是Vue给组件最外层标签加了一个随机属性(<div data-v-33gfsgb class="demo"></div>
),并用属性选择器.demo[data-v-33gfsgb]{background-color: red}
为其添加样式。
如果指定style的lang
为less
,需要额外添加less-loader
,但是需要注意webpack和less-loader
的版本兼容问题,例如:less-loader
的7.x对应webpack的4.x,安装时需要先查看脚手架中webpack的版本,然后再去安装指定版本的less-loader
:npm i less-loader@7
。
3.6. 自定义事件
使用场景:A是父组件,B是组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。
子给父传递数据:
- 父组件给子组件传递函数类型的props实现(可能会套娃)
- 父组件给子组件绑定一个自定义事件实现(
@事件名
或ref
)
3.6.1. emit
1 | <!-- App.vue --> |
3.6.2. on
绑定原则:谁绑定(on
)事件,谁触发(emit
)事件。
1 | <!-- App.vue --> |
如果通过on
监听事件的方式,并且只需要触发一次事件时,需要把$on
替换为$once
。
如果是通过@事件名
方式,自定义事件也可以使用事件修饰符(如:@stuevent.once="xxx"
)。
3.6.3. off
使用$off
可以把解绑自定义事件。
解绑原则:谁触发(emit
)事件,谁解绑(off
)事件。
1 | <!-- Student.vue --> |
注意:Vue销毁后,销毁的事件就是类似上面的自定义事件(包含Vue内置事件,但原生事件不受影响)。
组件上也可以绑定原生DOM事件,如<Student @click="xxx">
这样使用,其实绑定的是自定义click事件,如果需要原生事件响应,需要使用native
修饰符,<Student @click.native="xxx">
。
通过this.$refs.xxx.$on('stuevent', 回调)
绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,普通函数this
指向会出问题(绑定的是哪个组件,this
指向的就是这个组件)。
3.7. 全局事件总线
自定义事件适用于子组件给父组件传递数据,而全局事件总线适用于任意组件间通信。
安装全局事件总线
1
2
3
4
5
6
7
8<script>
new Vue({
//...
beforeCreate() {
Vue.prototype.$bus = this // $bus就是当前应用的vm
}
})
</script>把
$bus
绑定到Vue原型对象上,VueComponent实例对象也可以访问。使用事件总线
A组件想接收数据,则在A组件中给
$bus
绑定自定义事件,事件的回调留在A组件自身。1
2
3
4
5
6
7
8
9
10<script>
methods() {
demo(data){
......
}
}
mounted() {
this.$bus.$on('xxx', this.demo)
}
</script>提供数据:
this.$bus.$emit('xxx', 数据)
。解绑事件
最好在
beforeDestory
钩子中,用$off
去解绑当前组件所用到的事件。1
2
3beforeDestory() {
this.$bus.$off('xxx')
}
事件总线是程序员总结的经验成果,并不是Vue官方的API。
3.8. 消息订阅与发布
一种组件间通信的方式,适用于任意组件间通信。
- 安装第三方库:
npm i pubsub.js
- 引入:
import pubsub from 'pubsub.js'
- 订阅(接收数据):
this.pubId = pubsub.subscribe('hello', function(msgName, data) {})
- 发布(提供数据):
pubsub.publish('hello', '你好')
- 取消订阅:
pubsub.unsubscribe(pubId)
1 | <script> |
建议使用全局事件总线,因为是官方提供的套路。并且消息订阅与发布在使用上和全局事件总线也类似,开发者工具看不到pubsub的订阅发布事件,因此没有更多必要使用第三方库。
3.9. nextTick
作用:在下一次DOM更新结束后执行其指定的回调。
使用场景:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
1 | <template> |
3.10. 动画
作用:插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名。
准备好样式
- 元素进入的样式
v-enter
:进入的起点v-enter-active
:进入过程中v-enter-to
:进入的终点
- 元素离开的样式
v-leave
:离开的起点v-leave-active
:离开过程中v-leave-to
:离开的终点
- 元素进入的样式
使用
<transition>
包裹要过渡的元素,并配置name
属性1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<!-- appear为true时可以让页面进入时直接执行动画 -->
<transition name="hello" appear>
<h1 v-show="isShow">你好</h1>
</transition>
<style>
.hello-enter-active {
animation: testAnimate 0.5s linear;
}
.hello-leave-active {
animation: testAnimate 0.5s linear reverse;
}
@keyframes testAnimate {
from {
transform: translateX(100%);
}
to {
transform: translateX(0px);
}
}
</style>若多个元素需要过渡,则需要使用
<transition-group>
,且每个元素都要指定key
值。
使用第三方库:
- 安装:
npm install animate.css | yarn add animate.css
- 引入:
import 'animate.css'
- 使用:
<transition name="animate__animated animate__bounce" enter-active-class="" leave-active-class="">
,具体可以参考官方文档
3.11. 插槽
3.11.1. 默认插槽
1 | <!-- 父组件中使用子组件 --> |
3.11.2. 具名插槽
1 | <!-- 父组件中使用子组件 --> |
3.11.3. 作用域插槽
场景:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
1 | <!-- 父组件中使用子组件 --> |
四、axios
网络请求框架:
- xhr(XMLHttpRequest):太麻烦
- jQuery:封装了xhr请求,但是体量太大(核心代码是为了操作DOM,只有少部分代码是网络请求)
- fetch:和xhr平级的,比较难用(返回的数据有两层Promise,IE浏览器不能使用)
- axios:轻量,并且Vue官方推荐
4.1. 跨域
jsonp解决跨域:需要前后端配合,并且只能解决GET请求的跨域。
Vue官方使用代理解决跨域问题:
方法一:在vue.config.js
中进行如下配置
1 | module.exports = { |
方法二:在vue.config.js
中配置代理规则
1 | module.exports = { |
上面方法二的优点是可以配置多个代理,且可以灵活的控制请求是否走代理。缺点是配置略微繁琐,请求资源时必须加前缀。
4.2. vue-resource
Vue的插件库,在vue1.x使用的很广泛,使用流程和axios基本类似,只需要安装vue-resource,然后引用插件,最终this.$http.get().then()
使用就可以了。
目前官方已经不再维护(交给其他团队了)。