组件的创建
使用对象描述
let myComponent = {
template:'<div>component</div>',
props:{},
data:() => {}
}
使用渲染函数描述
let myComponent = {
render(h){
return h('div', {
style:{},
onClick:() => {}
}, '')
}
}
使用defineComponent
defineComponent是一个辅助函数,可以提供类型推导,与使用对象创建类似
import {defineComponent} from 'vue'
let myComponent = {
template:'<div>component</div>',
props:{},
data:() => {}
}
const myComponent = defineComponet(myComponent);
组件注册
注册为全局组件
import {createApp} from 'vue'
import App from 'app.vue'
createApp(App).component('myComponent', myComponent);
注册为局部组件
<script setup>
import MyComponent from '@/component/MyComponent.vue'
</script>
异步组件
以异步的方式来渲染页面,可以灵活地指定部分组件异步加载
<script setup>
import { defineAsyncComponent} from 'vue'
const myComponentAsync = defineAsyncComponent(() => import('@/components/MyComponent.vue'))
</script>
在声明路由规则的时候使用 import() 引入的组件也是异步组件,这种情况下整个页面都是异步加载
const routes = [{
path:'/',
component:() => import('@/views/Home.vue')
}]
函数式组件
一个函数式组件本质上就是一个普通函数,该函数的返回值是虚拟 DOM,函数式组件没有自身状态
<script setup>
function MyComponent(props){
return {
type:'h1',
children:[props.title]
}
}
MyComponent.props = {
title:'component'
}
</script>
组件的属性
组件包含 props data emits components directives methods computed watch 生命周期钩子等属性
props
定义组件接收外部传递的状态,vue会用它区分绑定在组件上的数据哪些属于props,哪些属于attrs vue允许定义组件接受外部的状态的类型、默认值、类型校验
如果传递的props属性是基础数据类型,直接使用基础类型的默认值,如果是引用类型,需要通过一个函数返回默认值,该函数接收一个传递的原生的props。
如果一个属性的类型是函数,default函数会被作为默认值
import {defineProps} from 'vue'
defineProps({
formData:{
type:Object,
default:(rawProps) => {
return {}
},
required:true
}
})
data
存储组件内部的状态 在组合式API中暴露在setup中的变量都会被作为组件的状态,都可以在模板中使用
emits
定义组件自定义事件,通过事件与父组件进行通信
import {defineEmits} from 'vue'
const emit = defineEmits(['submit'])
function submit(){
emit('submit');
}
components
注册组件局部组件 在组合式API中暴露在setup中的组件会被作为局部组件直接使用不需要显示通过components注册
<script setup>
import myComponent from '@/components/myComponent.vue'
</script>
在选项API中需要通过components注册
import myComponent from '@/components/myComponent.vue'
export default {
components:{
myComponent
}
}
directives
注册组件局部指令 在组合式API中以v开头的变量都会被作为一个自定义指令
<script setup>
import {directives} from 'vue'
let vMydirect = {
mounted(){}
}
</script>
在选项API中需要通过directives注册
directives:{
vFocus:{
mounted(){}
}
}
methods
定义组件中使用到的函数
在组合式API中通过setup暴露的函数会被作为组建的方法
<script setup>
function submit(){
}
</script>
在选项API中需要挂载在methods中
methods:{
submit(){}
}
computed
计算属性,当依赖数据变化时会触发回调函数
import {ref} from 'vue'
const count = ref(1);
let countIncre = computed({
get(){
return count + 1;
},
set(){
count+1;
}
});
watch
监听组件中的数据,当数据发生变化时触发回调
import {watch,ref} from 'vue'
const count = ref(1);
watch(count, () => {
console.log('count changed');
})
生命周期钩子
onBeforeMount
在组件挂载之前调用,在服务器端渲染期间不会被调用
onMounted
在组件挂载后触发,在这个阶段可以操作模板中的DOM,在服务器端渲染期间不会被调用
onBeforeUpdate
在组件DOM更新前触发,在服务器端渲染期间不会被调用
onUpdated
在组件DOM更新后触发,子组件的更新钩子调用后才调用父组件的更新钩子
onBeforeUnmount
在组件卸载前触发,在服务端渲染期间不会被调用
onUnmount
在组件卸载后触发,可以在这个函数中处理没有被清除的数据
组件的实现原理
组件被编译为一个虚拟DOM,虚拟DOM中的props存储组件绑定的所有属性,在渲染时遍历虚拟DOM中的props数据判断数据是否是在选项对象中props被定义,如果定义了就存储在props中,否则就视为attrs存储在atts中。
组件绑定的事件被编译成on+事件名的形式,并存储在props中,当调用emit函数时根据事件名从props中找到对应的事件处理函数执行即可
组件的插槽会被编译成为函数,在渲染时调用对应的函数,并渲染函数返回的结果
组件在注册生命周期时,会通过一个全局变量保存当前组件实例,然后当调用注册生命周期的函数时,将函数注册到当前实例上,实例上的对应事件使用数组存储事件处理函数,当触发对应的事件,遍历执行该事件存储的处理函数
|