关键词:
data/$data 数据依赖
props/$props 父组件传值通道
slot 分发
created Vue生命周期
$listeners 静态函数传递
$emit 事件传递
$on 事件绑定
watch 监听数据变化
provide 向父组件传递数据
inject 子组件接受接收
$attrs 静态数据传递
inheritAttrs 标签美化
中心思想
子组件拥有自身状态的同时,允许父组件对自身进行任何操作
生命周期
组件的进阶封装,需要对Vue生命周期有简单的了解
需要了解的小伙伴请查看我的另一篇博客:
本文以button
组件封装为例
基础组件
export const GlobelButton = {
template: `
<div>
<button type="button" :style="style">
{{title}}
</button>
</div>
`,
data () {
return {
style: {
backgroundColor: '#b50136',
fontSize: '12px',
color: '#fff'
},
title: 'title'
}
}
}
暴露出一个button组件,已经在子组件内部写好样式,父组件可以直接引用
允许父组件控制title属性
export const GlobelButton = {
template: `
<div>
<button type="button" :style="style">
{{title}}
</button>
</div>
`,
data () {
return {
style: {
backgroundColor: '#b50136',
fontSize: '12px',
color: '#fff'
}
####################
// title: 'title'
####################
}
},
####################
props: {
// innerHtml 文案
title: {
type: String,
default: function () { return '暂未定义title' }
}
}
#####################
}
允许父组件传入的title值覆盖子组件本身数据,并为子组件提供默认数据
#
区域为修改区域
为组件增加插槽
export const GlobelButton = {
template: `
<div>
###########
<slot name="first"></slot>
########
<button type="button" :style="style">
{{title}}
</button>
###########
<slot name="end"></slot>
#############
</div>
`,
data () {
return {
style: {
backgroundColor: '#b50136',
fontSize: '12px',
color: '#fff'
}
}
},
props: {
// innerHtml 文案
title: {
type: String,
default: function () { return '暂未定义title' }
}
}
}
插槽的添加很多程度上扩展了组件的灵活性,允许父组件任意的增加DOM
将样式控制交给父组件
export const GlobelButton = {
template: `
<div>
<slot name="first"></slot>
<button type="button" :style="style">
{{title}}
</button>
<slot name="end"></slot>
</div>
`,
######################
created () {
const styled = this.styled || {}
if (!styled) return
if (styled instanceof Object || JSON.stringify(styled) !== '{}') {
for (const key in styled) {
this.style[key] = styled[key]
}
}
},
#######################
data () {
return {
style: {
backgroundColor: '#b50136',
fontSize: '12px',
color: '#fff'
}
}
},
props: {
// innerHtml 文案
title: {
type: String,
default: function () { return '暂未定义title' }
},
########################
// 样式
styled: {
type: Object,
default: function () { return {} }
}
#######################
}
}
组件中的样式是通过对象style来控制的,如何才能做到让父组件动态控制style对象的值呢?在Vue——神秘的生命周期一文中我们知道,created生命周期中 data、 d a t a 、 props都已经准备完毕,那么我们就可以在这里做一些改变。
改变父组件状态
export const GlobelButton = {
template: `
<div>
<slot name="first"></slot>
################
<button type="button" :style="style" @click="changeBg">
#################
{{title}}
</button>
<slot name="end"></slot>
</div>
`,
created () {
const styled = this.styled || {}
if (!styled) return
if (styled instanceof Object || JSON.stringify(styled) !== '{}') {
for (const key in styled) {
this.style[key] = styled[key]
}
}
},
data () {
return {
style: {
backgroundColor: '#b50136',
fontSize: '12px',
color: '#fff'
}
}
},
########################
methods: {
changeBg () {
this.style.backgroundColor = 'green'
this.$emit('change-color', 'green')
}
},
########################
props: {
// innerHtml 文案
title: {
type: String,
default: function () { return '暂未定义title' }
},
// 样式
styled: {
type: Object,
default: function () { return {} }
}
}
}
我们经常会遇到需要同步改变子组件以及父组件状态的情况,如dialog的显示和隐藏状态的触发,然而Vue并不建议我们直接修改props的值,此时我们可以借助 emit触发this. e m i t 触 发 t h i s . listeners中由父组件$on绑定的方法,自然也可以配合watch使用,监听父组件的值并同步修改子组件状态
接受父组件公共状态
export const GlobelButton = {
template: `
<div>
<slot name="first"></slot>
<button type="button" :style="style" @click="changeBg">
{{title}}
</button>
#############
{{inject}}
#############
<slot name="end"></slot>
</div>
`,
created () {
const styled = this.styled || {}
if (!styled) return
if (styled instanceof Object || JSON.stringify(styled) !== '{}') {
for (const key in styled) {
this.style[key] = styled[key]
}
}
},
data () {
return {
style: {
backgroundColor: '#b50136',
fontSize: '12px',
color: '#fff'
}
}
},
#################
inject: ['inject'],
#################
methods: {
changeBg () {
this.style.backgroundColor = 'green'
this.$emit('change-color', 'green')
}
},
props: {
// innerHtml 文案
title: {
type: String,
default: function () { return '暂未定义title' }
},
// 样式
styled: {
type: Object,
default: function () { return {} }
}
}
}
对于某些情况下,一个父组件可能拥有多个子组件,此时父组件的功能状态可以通过provide: { inject: ‘test provide’ }传递,子组件中inject接受到的数据可以直接用this访问
静态属性的传递
export const GlobelButton = {
template: `
<div>
<slot name="first"></slot>
<button type="button" :style="style" @click="changeBg">
{{title}}
</button>
{{inject}}
<slot name="end"></slot>
</div>
`,
created () {
const styled = this.styled || {}
if (!styled) return
if (styled instanceof Object || JSON.stringify(styled) !== '{}') {
for (const key in styled) {
this.style[key] = styled[key]
}
}
},
data () {
return {
style: {
backgroundColor: '#b50136',
fontSize: '12px',
color: '#fff'
},
##############
attrs: this.$attrs
##############
}
},
#################
inheritAttrs: false
#################
inject: ['inject'],
methods: {
changeBg () {
this.style.backgroundColor = 'green'
this.$emit('change-color', 'green')
}
},
props: {
// innerHtml 文案
title: {
type: String,
default: function () { return '暂未定义title' }
},
// 样式
styled: {
type: Object,
default: function () { return {} }
}
}
}
在开发过程中经常会出现父组件向孙子组件传值,父组件向子组件传递多个
静态属性
,此时我们可以借助$attrs
来接受所有没有在props中定义,但是父组件调用子组件确绑定了的值,同时为了使绑定值不出现在DOM渲染中,从而保证DOM树的整洁,我们需要借助:inheritAttrs: false
需要注意的是
$attrs
在beforeCreate
中已经准备好了,并且不会进行响应式数据变化,所以传递的一定要是静态属性