用event bus解决vue中无法监听到this.$slots.default变化的

用event bus解决vue中无法监听到this.$slots.default变化 (包含去除$slots.default中的空白节点

    • this.$slots.default
    • 关于event bus
    • 代码实现

this.$slots.default

vue官网中提到:

default property 包括了所有没有被包含在具名插槽中的节点。

也就是说可以通过$slots.default获取到通过接收到的所有对象。
但是在用的时候我发现通过$slots.default打印出来的对象有时候会多n-1个空白节点:如下图,其实这里我只在处传入了3个节点,但打印出来却有5个。
用event bus解决vue中无法监听到this.$slots.default变化的_第1张图片
下面是我去除空白节点的代码节选,完整代码在最后

// Tab.js -- 这是外层组件
let allSlots = this.$slots.default
this.tabSlots = allSlots.filter(item => { // 这里是用来去除$slots.default中的空节点
   if(item.tag) {
     return item
    }else return   
})

关于event bus

event bus 是一个vue实例, 这个实例可以通过emit事件并监听这个事件的方式在兄弟component或不相干的两个component之间直接进行数据传递。具体使用如下:

main.js中进行声明 :export const bus = new Vue();
(这里要注意记得export哦,因为待会我们要在组件里对bus进行import才可以用。)

代码实现

以我自己写的一个标签页组件为例:(注意示例中把css都省略了)
可以去GitHub下载项目本地运行一下,这样会更容易理解一些哦。

main.js中声明一个名为bus的vue实例,在子组件中import,通过监听需要的事件,触发bus.$emit('newchange')方法,bus.$on('newchange', this.handleChange)监听到'newchange'发生,会立马触发this.handleChange方法。具体请看代码:

// EventBusDemo.vue --这是demo页面
<Tab>
	<TabItem tab-title='title1'><div class="tab_body">this is tab body.</div></TabItem>
    <TabItem tab-title='title2'><div class="tab_body">this is tab body.</div></TabItem>
</Tab>

以下是bus的配置和使用

// main.js
export const bus = new Vue();  // 声明一个名为bus的vue实例
// TabItem.js--这是内层组件
<template>
  <div class="tab_content">
    <slot></slot>  // 这里的slot与此次的bus无关,只是用于接收自定义tab内容
  </div>
</template>
<script>
import { bus } from '../../main'
export default {
    name: 'TabItem',
    props: {
        tabTitle: String
    },
    data() {
        return{
            totalTabs: ''
        }
    },
    updated() {
      this.totalTabs = this.$parent.$children.length // 获取到页面中一共传入几个TabItem
    },
    watch: {
      totalTabs() {
        bus.$emit('slot-changes') // 只要html的Tab中传入的TabItem发生变化,就会触发‘slot-changes’方法
      }
    }
}
</script>
// Tab.js -- 这是外层组件
<template>
  <div class="tab_container">
    <ul class="tab_head"><li v-for="(title, index) in tabTitle" :key='index'>{{title}}</li></ul>
    <slot></slot> <!-- slot接收从TabItem中传入的tab内容 -->
  </div>
</template>

<script>
import { bus } from '../../main'
export default {
    name: 'Tab',
    data() {
        return{
            tabSlots: [],
            tabTitle: []
        }
    },
    created() {
      bus.$on('slot-changes', this.getTabTitle); // 监听‘slot-changes’一旦被触发,就会调用this.getTabTitle方法
    },
    mounted() {
      this.getTabTitle();
    },
    methods: {
      getTabTitle() {
        // 获取传入tab的标签名
        let allSlots = this.$slots.default
        this.tabSlots = allSlots.filter(item => { // 这里是用来去除$slots.default中的空节点
          if(item.tag) {
            return item
          }else return          
        })
        this.tabTitle = this.tabSlots.map((tab, index) => {
          return this.tabSlots[index].componentOptions.propsData.tabTitle
        })
        // 获取传入tab的标签名 end
      }
    }
}
</script>

如果有帮到你,可以的话请帮忙去github给我一颗小星星哦。么么哒~
GitHub地址

你可能感兴趣的:(vuejs)