前言
上一篇关于vue面试的文章 (面试时面试官想要听到什么答案) 中提到了多种组件传值方式,本文对几种传值方式如何使用具体说明一下。
props、$emit、eventbus、vuex、$parent / $children / ref、sessionStorage、localStorage、路由传参(也是传值) 这些传值方式都太常见了,而且每一个使用vue的人都不可能不知道,所以本文就不一一说明了,现在介绍几种平时不常见的传值方式。如果对以上几个有疑问的可以在评论中留言,感谢拨冗翻阅拙作,敬请斧正。
1. provide/ inject
父组件中通过provide来提供变量, 然后再子组件中通过inject来注入变量。
注意: 这里不论子组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据,而不局限于只能从当前父组件的props属性中回去数据
假设A为父组件B和C均为A的子组件,D为B的子组件,则在A组件中使用provide定义变量,在B、C、D组件中均可通过inject拿到传过来的值。(provide中定义的变量不可在父组件中 使用)
注:provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。(官方文档描述)
父组件
export default {
data () {
return {}
},
provide: {
index: '来自index的数据'
}
}
子 组件
export default {
data () {
return {}
},
inject: ['index'] // 直接可以在页面使用index或在js中进行赋值
}
2. $attrs
在父组件A中调用子组件three:<custom-three :custom="custom" :custon="custon" />
,子组件three使用props进行接收,未被子组件使用props接收的可以使用$attrs拿到传递的值,即three组件分为以下情况
- props: ['custom','custon] 时,$attrs = {};
- props: ['custom'] 时,$attrs = {custon: 'ton'};
- props: [] 时,$attrs = {custom: 'tom', custon: 'ton'};
此时,在three组件中引入four子组件,并使用v-bind将$attrs绑定在组件上<custom-four v-bind="$attrs" />
即可在four中使用props或$attrs接收,按此规律可一直传递。
并且未被组件使用的变量将显示在html结构中,例:
<div custon="ton">
<p>three---tom</p> >
<p>attr---{}</p>
</div>
在子组件中添加inheritAttrs可以将div标签的 custon="ton" 隐藏,inheritAttrs默认值为true,将其设为false即可隐藏。注意:将inheritAttrs设为false并不会影响$attrs的使用。
3.$listeners
2中讲述的是使用$attrs将父组件的值隔代传给子组件,本小节中的$listeners就是将方法从父组件隔代传给子组件,实现子组件调用时将子组件的值隔代传给父组件。
首先在父组件A中调用子组件three:<custom-three @customEvent="customEvent" />
,此时在子组件A中使用$listeners接收,拿到的是一个对象{customEvent: function(){...}},在three组件中再调用子组件four,并使用v-on将$listeners绑定在子组件上`` ,此时在子组件four中即可直接直接访问customEvent或使用$listeners访问customEvent。
父组件A
<template>
<div>
<custom-three :custom="custom" :custon="custon" @customEvent="customEvent"></custom-three>
</div>
</template>
<script>
import customThree from './chuanzhi/three'
export default {
data () {
return {
custom: 'tom',
custon: 'ton'
}
},
components: {
customThree
},
mounted () {},
methods: {
customEvent(data) {
console.log('data', data)
}
}
}
</script>
子组件three
<template>
<div>
<p>three---{{ custom }}</p>
<p>attr---{{$attrs}}</p>
<p>-------------------------------------</p>
<custom-four v-bind="$attrs" v-on="$listeners"></custom-four>
</div>
</template>
<script>
import customFour from './four'
export default {
data() {
return {}
},
components: {
customFour
},
props: ['custom'],
inheritAttrs:false
created() {
console.log('1', this.$listeners)
}
}
</script>
子组件four
<template>
<div>
<p>four---{{ custon }}</p>
<p>attr---{{$attrs}}</p>
<el-button @click="fashe">发射</el-button>
</div>
</template>
<script>
export default {
data() {
return {}
},
props: ['custon'],
inheritAttrs:false
created() {
console.log('2', this.$listeners)
},
methods: {
fashe() {
this.$emit('customEvent', 'piupiupiu')
}
}
}
</script>
observable实现状态管理
observable让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象。
返回的对象可以直接用于渲染函数和计算属性内,并且会在发生改变时触发相应的更新。也可以作为最小化的跨组件状态存储器,用于简单的场景:
在组件1中调用setCount使count加1或减1,各个组件内调用的count都将进行改变,并会触发组件刷新
store.js文件
import vue from 'vue';
export const store = vue.observable({count: 0});
export const mutation = {
setCount( count ){
store.count = count;
}
}
组件1
<template>
<div class="hello">
<p @click="setCount(testCount + 1)">+</p>
<p @click="setCount(testCount - 1)">-</p>
<test />
<p>{{testCount}}</p>
</div>
</template>
<script>
import test from './test'
import { store, mutation} from './store.js'
export default {
name: 'HelloWorld',
components: {
test
},
methods: {
setCount: mutation.setCount
},
computed: {
testCount(){
return store.count
}
}
}
组件2
<template>
<div>test{{testCount}}</div>
</template>
<script>
import { store } from './store.js';
export default {
computed: {
testCount(){
return store.count
}
}
}
</script>