携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情
vue组件中参数传递有很多种:
props/$emitEventBusvuex$attrs/$listenersprovide/inject
其实我们对前3种传递方式已经很熟悉了,这里就不做赘述,但是$attrs/$listeners和provide/inject这两对还是需要重点熟悉一下。
$attrs/$listeners
用于当祖先组件想传递属性或者方法到孙子组件时,路过子组件,在子组件中用
v-bind="$attrs"(传递属性)或v-on="$listeners"(传递事件),不需要在路过的子组件中多写一遍emit和props来接收和传递
例子如下:
index.vue
<template>
<div class="box">
<h3>祖先页面</h3>
<son :name="name" :color="color" @getData="getData" @setData="setData"></son>
</div>
</template>
<script>
import Son from './son.vue'
export default {
components: { Son },
data () {
return {
name: 'myTest',
color: '#cdcdcd'
}
},
methods: {
getData () {
console.log('getData', this.name)
},
setData (v) {
this.name = v
}
}
}
</script>
son.vue
<template>
<div class="box">
<h3>父页面</h3>
<grand-son v-bind="$attrs" v-on="$listeners"></grand-son>
</div>
</template>
<script>
import GrandSon from './grandson.vue'
export default {
components: { GrandSon }
}
</script>
grandson.vue
<template>
<div class="box">
<h3>子页面</h3>
color: {{color}}
<input v-model="data"/>
<button @click="setData">设置</button>
<button @click="getData">{{name}}</button>
</div>
</template>
<script>
export default {
data () {
return {
data: '888'
}
},
props: {
name: String,
color: String
},
methods: {
getData () {
this.$emit('getData')
},
setData () {
this.$emit('setData', this.data)
}
}
}
</script>
这样就可以在grandson.vue中使用祖先里的属性和方法了。
provide/inject
这一对的用法是,祖先组件向后代注入依赖,注入后可以在后代组件中任意使用祖先组件中的方法或事件,中间不需要传递
注意到这个用法是因为做项目时,遇到了vue单页面需要刷新页面的场景,这种场景下,为了不让整个页面白屏刷新,其实直接在app.vue中<router-view>的地方用v-if渲染,此时如果在组件里需要刷新页面,就要调用祖先组件里的reload方法,就需要用到provide和inject
app.vue
<template>
<router-view v-if="isRenderRouterView"></router-view>
</template>
<script>
export default {
name: 'app',
data () {
return {
isRenderRouterView: true
}
},
methods: {
reload () {
this.isRenderRouterView = false
this.$nextTick(() => {
this.isRenderRouterView = true
})
}
},
provide () {
return {
reload: this.reload
}
},
</script>
component.vue
<template>
<div class="box">
<h3>组件</h3>
<button @click="refresh">刷新</button>
</div>
</template>
<script>
export default {
inject: ['reload'],
methods: {
refresh () {
this.reload()
}
}
}
</script>
需要注意的是:provide/inject 破坏了vue单向数据流原则。如果多个组件同时依赖一个祖先组件中的数据状态,只要一个组件修改这个状态,所有组件都会受到影响,而且无法追溯到底是哪个组件修改了。因此,用provide/inject来做和vuex一样的状态管理是很危险的。他更适合用在组件的开发中。例如element-ui。