1.组件概述
组件可以拓展HTML元素,内部封装了可复用的HTML、CSS、JS代码片段。
组件类似于vue实例,组件内部有template属性,用于指定模板,
vue实例内部有el属性,用于指定模板。
2.组件定义
let component = {
data() {
return {
// 返回对象值的唯一拷贝,保证复用的组件内部数据不会相互影响
msg: '我是组件的数据'
}
},
template: `
<div>
<p>我是组件</p>
<h1>{{msg}}</h1>
</div>
`
}
3.组件注册
全局注册的组件,可以在任意vue实例或者组件内部使用
局部注册的组件,只能在当前注册的实例或者组件内部使用
类似于js中的全局变量、局部变量
1)全局注册
Vue.component('my-com', component);
如果一个组件被多个其他组件调用,用全局注册较好
2)局部注册
如果一个组件在一个实例或者组件内部被多次调用,用局部注册较好
new Vue({
el: '#app',
data: {},
components: {
'my-com': component
}
})
4.组件交互
1)父组件向子组件传参
父组件使用prop属性,向子组件传参
<div id="app">"
<my-com :title="title" msg="hello"></my-com>
</div>
动态传参
没有:传递的常量字符串
有: 传递boolean、number、对象、数组、变量
子组件接受参数
let component = {
props: ['title','msg'],
}
props校验
let component = {
props: {
title: {
type: String, // 验证数据类型
required: true, // 该参数必需传递的参数
// 基本数据类型直接写在default后面
default: '你好', // 当前参数的默认值
// 引用数据类型,使用工厂函数的形式返回一个对象或者数组
default() {
return { }
}
validator(val) { // 自定义的验证器
return val.length > 3
}
}
},
}
2)子组件向父组件传参
<div id="app">"
<my-com @son-handler="fatherHandler" msg="hello"></my-com>
</div>
let component = {
data() {
return {
comMsg: '我是子组件数据'
}
},
template:`
<div>
<button @click='clickHandler'>发送事件</button>
</div>
`,
methods: {
clickHandler() {
this.$emit('son-handler', this.comMsg)
}
}
}
new Vue({
el:'#app',
data: {
fatherDate: ''
},
methods: {
fatherHandler(val) {
// val就是子组件发送事件时,携带的参数this.comMsg
this.fatherDate = val
}
},
components: {
myCom: component
}
})
3)单向数据流
父级的prop数据的更新,会向下流动到子组件中,反过来不行。
父组件能够修改子组件中的数据,而子组件不能直接修改父组件中的数据。
作用:
防止子组件意外变更状态,会影响父组件中的状态或者数据。
5.插槽
1)普通插槽
<my-com>hello vue</my-com>
let com = {
template: `
<div>
<slot></slot> // 默认插槽
</div>
`
}
2)具名插槽
<my-com>
<template v-slot:header> 简写 #header
我是头部内容
</template>
<template v-slot:default>
<p>hello component</p>
<h3>你好组件插槽</h3>
</template>
<template v-slot:footer>
我是脚部内容
</template>
</my-com>
let com = {
template: `
<div>
<header>
<slot name="header"></slot> // 具名插槽
</header>
<main>
<slot name="default"></slot> // 匿名插槽
</main>
<footer>
<slot name="footer"></slot> // 具名插槽
</footer>
</div>
`
}
3)作用域插槽
<my-com>
<template v-slot:header="scope">
{{scope.msg}} // scope是作用域对象,内部封装了子组件传递上来的msg数据,可以使用对象的解构
我是头部内容
</template>
<template v-slot:default>
<p>hello component</p>
<h3>你好组件插槽</h3>
</template>
<template v-slot:footer>
我是脚部内容
</template>
</my-com>
let com = {
data() {
return {
msg: '我是组件数据'
}
}
template: `
<div>
<header>
<slot name="header" :msg="msg"></slot> // 具名插槽
</header>
<main>
<slot name="default"></slot> // 匿名插槽
</main>
<footer>
<slot name="footer"></slot> // 具名插槽
</footer>
</div>
`
}
6.动态组件
<component is="my-com1"></component> // 静态组件
<component :is="current"></component> // 动态组件
7.混入
混入规则:
1)数据模型中的数据,会进行递归合并,出现同名属性,以组件中的数据为准
2)同名的构造函数会合并成数组,其中的函数都会调用,混入的钩子执行在前,组件的钩子执行在后
3)内部对象的合并,类似于components、methods回合并为一个对象,发生冲突时,以组件中的为准
全局混入
Vue.mixin({})
局部混入
mixins: [mixin]
8.自定义指令
指令内部有5个钩子函数
bind(){}
inserted(){}
update(){}
componentUpdated(){}
unbind(){}
每个钩子函数内部都有4个形参
el 当前指令绑定的dom对象
binding 当值绑定指令的详细信息
vNode Vue编译生成的虚拟dom节点
oldNode 上一个虚拟dom节点,只有在update和componentUpdated这两个钩子触发时,该参数才有实参。
9.过滤器
使用场景
{{timestamp | fmtDate}}
v-bind="msg | fmtText"
全局注册
Vue.filter('fmtDate', (val) => {
return ...val
})
局部注册
filters: {
fmtDate(val) {
return ...val
}
}
10.render函数
render(createElement) {
return createElement(nodeName,props,childVnode)
}
createElement函数内部参数说明
nodeName: 标签名
props: 该元素的配置信息
‘class’、style、attrs、props、domProps、On、nativeOn
childVnode: 子虚拟节点,一般为数组,表示其子元素有多个
11.plugin插件
plugin插件需要提供一个install方法
在vue实例构建之前去调用该插件
保证创建出来的vue实例能够访问插件中的全局方法或属性
Vue.user(MyPlugin)
let vm = new Vue({})