简介
组件(component)是vue.js最强大的功能之一。组件的作用就是封装可重用的代码,通常一个组件就是一个功能体,便于在多个地方都能够调用这个功能体。 每个组件都是Vue的实例对象。 我们实例化的Vue对象就是一个组件,而且是所有组件的根组件
创建组件
//简写
//my-componen.vue
<template>
<div>
</div>
</template>
<script>
export default {
};
</script>
//1. 注册组件,传入一个扩展过的构造器
Vue.component('my-component', Vue.extend({ /* ... */ }))
//使用Vue.extend去创建组件
var Profile = Vue.extend({
template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
data: function () {
return {
firstName: 'Walter',
lastName: 'White',
alias: 'Heisenberg'
}
}
})
//2. 注册组件,传入一个选项对象 (自动调用 Vue.extend)
Vue.component('my-component', {})
同步引入组件
var ComponentA = { /* ... */ }
异步引入组件
//简写:
const AsyncComponent = () => ({
component: import(’./MyComponent.vue’)
})
//完整写法:
//异步加载,就会存在加载过程(正在加载中)、以及加载失败等异常情况。高级用法提供了加载、失败、timeout、加载组件四种状态
const AsyncComponent = () => ({
// 需要加载的组件 (应该是一个 Promise 对象)
component: import(’./my-componen.vue’),
// 异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时时间且组件加载也超时了,
// 则使用加载失败时使用的组件。默认值是:Infinity
timeout: 3000
}
组件注册
1.全局注册
//这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue)
//的模板中。比如:
Vue.component('component-a', ComponentA)
new Vue({ el: '#app' })
局部注册
var ComponentA = { /* ... */ }
var ComponentB = {
components: {
'component-a': ComponentA
},
}
组件缓存
<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。
内子组件component中的is attribute 来切换不同的组件:
普通组件
export default {
name: 'currentTabComponent',
data () {
return {
}
}
}
include 字符串,数组或正则表达式。只有名称匹配的组件会被缓存。
exclude 字符串,数组或正则表达式。任何名称匹配的组件都不会缓存。
max 数字。最多可以缓存多少组件实例。
- 动态组件
<component v-bind:is="currentTabComponent"></component>
//动态组件缓存判断
<keep-alive include="test-keep-alive">
<!-- 将缓存name为test-keep-alive的组件 -->
<component :is="currentTabComponent"></component>
</keep-alive>
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>
<keep-alive include="a,b">
//将缓存name为a或者b的组件,结合动态组件使用
<component :is="view"></component>
</keep-alive>
//使用正则表达式,需使用v-bind
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
路由缓存
//缓存判断 ---同上
<keep-alive :include="includedComponents">
<router-view></router-view>
</keep-alive>
<keep-alive :include="['Home', 'User']">
<router-view />
</keep-alive>
<keep-alive include="Home,User">
<router-view />
</keep-alive>
<keep-alive :include="/a|b/">
<router-view />
</keep-alive>
//将不缓存name为test-keep-alive的组件--同上
<keep-alive exclude="test-keep-alive">
<router-view />
</keep-alive>
组件间通信
父传子
父: <children prop=‘prop’/>
子:export default {
//简写
props:['myMessage','mm'],
// 完整写法
props: {
myMessage: {
type: Array,
default: [5, 6, 7] //指定默认的值
}
},
}
//子传父
子:this.$emit("getData",data)
父:<children @getData='getdata'/>
method:{
getData(data){
console.log(data)
}
}
//兄弟间
//发数据的兄弟:
this.$eventBus.$emit("getData",data)
//在main.js中添加第三者:vue实例用于中转;
import eventBus from './eventBus'
Vue.prototype.$eventBus=eventBus
//接收数据的兄弟:
this.$eventBus.$on("getData",data)
//爷孙间
爷:<father prop=‘prop’ />
父:<children v-bind='$atter' v-on='$event'/>
孙:export default {
props:['prop']
}
//祖与后代-注意该方法不能反向通信
//祖:
export default {
provide () {
return {
demo: 'foo'
}
}
}
//后代:
export default {
inject: ['demo'],
data(){
return {
str: 'foo'
}
}
}
}
组件的生命周期
- beforeCreate
在实例初始化之后,数据观测和事件配置之前被调用,此时组件的选项对象还未创建,el 和 data 并未初始化,因此无法访问methods, data, computed等上的方法和数据。
- created
实例已经创建完成之后被调用,在这一步,实例已完成以下配置:数据观测、属性和方法的运算,watch/event事件回调,完成了data 数据的初始化,el没有。 然而,挂在阶段还没有开始, $el属性目前不可见,这是一个常用的生命周期,因为你可以调用methods中的方法,改变data中的数据,并且修改可以通过vue的响应式绑定体现在页面上,,获取computed中的计算属性等等,通常我们可以在这里对实例进行预处理;
有一些童鞋喜欢在这里发ajax请求,值得注意的是,这个周期中是没有什么方法来对实例化过程进行拦截的,因此假如有某些数据必须获取才允许进入页面的话,并不适合在这个方法发请求,建议在组件路由钩子beforeRouteEnter中完成
- beforeMount
挂在开始之前被调用,相关的render函数首次被调用(虚拟DOM),实例已完成以下的配置: 编译模板,把data里面的数据和模板生成html,完成了el和data 初始化,注意此时还没有挂在html到页面上。
- mounted
挂在完成,也就是模板中的HTML渲染到HTML页面中,此时一般可以做一些ajax操作,mounted只会执行一次。
- beforeUpdate
在数据更新之前被调用,发生在虚拟DOM重新渲染和打补丁之前,可以在该钩子中进一步地更改状态,不会触发附加地重渲染过程
- updated
在由于数据更改导致地虚拟DOM重新渲染和打补丁只会调用,调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作,然后在大多是情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环,该钩子在服务器端渲染期间不被调用
- activated
被 keep-alive 缓存的组件激活时调用。
- deactivated
被 keep-alive 缓存的组件失活时调用。
- beforeDestroy
在实例销毁之前调用,实例仍然完全可用,
这一步还可以用this来获取实例,
一般在这一步做一些重置的操作,比如清除掉组件中的定时器 和 监听的dom事件
- destroyed
在实例销毁之后调用,调用后,所以的事件监听器会被移出,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用
- 插槽
插槽(Slot)是 vue 为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的。
普通插槽
//定义: navigation
<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>
//使用组件
<navigation-link url="/profile">
Your Profile
</navigation-link>
具名插槽
//定义:
<template id="myButton">
<div>
<slot name="header"></slot>
</div>
</template>
//使用:
<my-button>
<template v-slot:header><h3>This is header</h3></template>
<my-button>
//跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 //#。例如 v-slot:header 可以被重写为 #header:
<my-button>
<template #header>
<h1>Here might be a page title</h1>
</template
</my-button>
作用域插槽
有时让插槽内容能够访问子组件中才有的数据是很有用的。例如,设想一个带有如下模板的
//定义默认作用域插槽:
<span>
<slot :user="user">
{{ user.lastName }}
</slot>
</span>
//使用
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
//简写:
<current-user #default="{ user }">
{{ user.firstName }}
</current-user>
//定义有名作用域插槽:
<span>
<slot name="todo" :user="user">
<!-- 后备内容 -->
{{ user.age }}
</slot>
</span>
//使用:
<current-user>
<template v-slot:todo="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
//简写:
<current-user>
<template #todo="{ user }">
{{ user.firstName }}
</template>
</current-user>
//注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确:
组件库
H5+ mui:利用H5的API以及mui的一些组件及方法实现接近原生的移动端的项目搭建;
vonic:利用原生开发的移动端ui组件库,文档我认为做的很是垃圾所以没看明白;
muse-UI:类似于bootstrup的UI组件适合于做pc端的网页开发(动画效果很nice);
element-UI:适合于做后台管理系统的pc端开发;
mint-UI:适用于在不使用uniapp开发基于vue的移动端开发但是vue缺少了对移动端的硬件设备的调用方法;
uview-UI:适用于在使用uniapp但是对内置和扩展的组件库不满时使用;
vant-UI:适用于小程序开发的第三方组件库;
---个人的理解。