el-tabs作为子组件使用页面空白


前言

如果el-tabs是子组件,父组件传值value / v-model为空字符,这个时候在watch中监听value / v-model就会发现监听的数据会被调用为‘0’。一定是作为子组件引用,且在watch进行监听,且vuex没有缓存。就刚进入页面的时候会出现空白页面,点击tab之后就不会再有问题了,因为value / v-model数据更新了。
当然如果你的tabPanes中的code原本就为‘0’,那就不会出现这个问题了,因为value / v-model匹配的到页面。

一、问题展示

base-tabs组件
<template>
  <el-tabs class="base-pane" v-model="activeName">
    <el-tab-pane v-for="pane in tabPanes" :key="pane.code" :label="pane[label]" :name="pane[name]">
      <slot :name="pane[name]" :pane="pane"></slot>
    </el-tab-pane>
  </el-tabs>
</template>

<script>

export default {
  name: 'basePane',
  props: {
    value: {
      type: String,
      default: '',
    },
    tabPanes: {
      type: Array,
      default: [],
    },
    // 标签显示属性
    label: {
      type: String,
      default: 'label',
    },
    // 标签绑定id属性、插槽绑定id
    name: {
      type: String,
      default: 'code',
    },
    // 是否要缓存,页面路由
    tabId: String,
  },
  data() {
    return {
      activeName: this.value,
    };
  },
  mounted() {
  	// 这里是如果store有缓存,将缓存中的数据进行赋值
    if (this.tabId && this.$store.state.setHistoryTab[this.tabId]) {
      this.activeName = this.$store.state.setHistoryTab[this.tabId];
    }
  },
  // watch只有在数据变化了之后才会调用
  watch: {
    value: {
      deep: true,
      handler(val) {
        console.log('value', val);
        this.activeName = val;
      },
    },
    activeName(val) {
      console.log('activeName', val);
      this.$emit('input', val);
      if (this.tabId) {
        this.$store.commit('setHistoryTab', {
          key: this.tabId,
          value: val,
        });
      }
    },
  },
};
</script>


引用
<base-pane v-model="activeName" :tabPanes="tabPanes" :tabId="$route.fullPath">
  </base-pane>
  
activeName:'', // 这里一定是空字符串

getTabsData() {
      this.$post('xxx/xxx/xxx')
        .then((res) => {
          this.tabPanes = res.rspData;
          // 这里是如果store没有缓存,才将数组中的第一个进行赋值
          if (this.tabPanes.length && !this.$store.state.setHistoryTab[this.$route.fullPath]) {
            this.activeName = this.tabPanes[0].code;
          }
        })
        .catch();
    },

打印结果
在这里插入图片描述
子组件这里watch中的activeName竟然是0,这也就导致了,vuex中缓存的数据是0,activeName 找不到对应的code,页面就不会显示了

二、源码分析

在elementui文件夹中的tabs.vue文件中。这里将data和watch放出来就是为了显示currentName是value / v-model的数据,setCurrentName的方法就是对currentName 进行数据修改。

data() {
      return {
        currentName: this.value || this.activeName,
        panes: []
      };
    },

    watch: {
      activeName(value) {
        this.setCurrentName(value);
      },
      value(value) {
        this.setCurrentName(value);
      },
      currentName(value) {
        if (this.$refs.nav) {
          this.$nextTick(() => {
            this.$refs.nav.$nextTick(_ => {
              this.$refs.nav.scrollToActiveTab();
            });
          });
        }
      }
    },
created() {
	// 在if中'',0都会被认为是false。这就会导致currentName会被设置为’0’。base-tabs子组件就会调用watch
      if (!this.currentName) {
        this.setCurrentName('0');
      }

      this.$on('tab-nav-update', this.calcPaneInstances.bind(null, true));
    },

测试结果
在这里插入图片描述

三、解决方案

父组件、子组件两种方式各选一个就可以了。这样可以的原因是因为base-tabs组件里的watch一开始就不会执行,vuex中就不会存储数据,也就会直接执行父组件的【将数组中的第一个进行赋值】的操作。而之前不可以的原因是因为,el-tabs的源码中将空字符串变成了’0’,base-tabs组件里的watch一开始就会执行,vuex中就会存储数据,也就不会直接执行父组件的【将数组中的第一个进行赋值】的操作,而tabPans中的code匹配不到‘0’,页面就不会显示了,但是你点击别的之后页面又会出现了,因为那个时候的activeName就会是正常的code,也就不会再有问题了

base-tabs组件

<script>

export default {
 
  data() {
    return {
      activeName: this.value || '1',
    };
  },
 
};
</script>


父组件引用
activeName:'1',

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值