首页 > 解决方案 > vuetify `v-tabs` 的子组件将 offsetWidth 返回为 0

问题描述

这是重现场景的代码笔: https ://codepen.io/anon/pen/vzqgJB

我有一个router-view内部 Vuetify 的v-app.

<div id="app">
  <v-app>
    <v-content>
      <v-container>
        {{$route.path}}
        <router-view/>
      </v-container>
    </v-content>
  </v-app>
</div>

路由配置如下:

const routes = [
    { path: '', component: tabsComponent, 
      children:[
        { path: '', component: component1 },
        { path: 'component2', component: component2 }
      ]
    },
]

我正在使用v-tabsVuetify 的组件来渲染 2 个分别加载component1和的选项卡component2

var tabsComponent = Vue.component('tabsComponent',{
  components:{
    component2,
    component1
  },
  name:'tabsComponent',
  template: `
     <v-tabs>
        <v-tab to="/">Tab 1</v-tab>
       <v-tab to="/component2">Tab 2</v-tab>
       <v-tabs-items>
          <v-tab-item id="/">
            <component1></component1>
          </v-tab-item>
          <v-tab-item id="/component2">
            <component2></component2>
          </v-tab-item>
        </v-tabs-items>
     </v-tabs>
`,
   mounted(){
    this.$nextTick(()=>{
      console.log("tabs")
      console.log(this.$el.offsetWidth)
    })
  }
})

我面临的问题是,当component1安装时,this.$el.offsetWidth返回为0.

  var component1 = Vue.component('component1',{
    name: 'component1',
      template: `
         <v-container fluid>John </v-container>
      `,
      mounted(){
        this.$nextTick(()=>{
          console.log("component1")
          console.log(this.$el.offsetWidth) // This is printed as 0
        })
      }
    })

即使父组件的 offsetWidth 非零,我也无法弄清楚为什么宽度返回为 0。任何帮助,将不胜感激。

标签: vue.jsvuejs2vue-routervuetify.js

解决方案


mounted子组件中的钩子在父组件中的挂载钩子之前触发:在子组件中挂载钩子,在父组件中挂载钩子,最后渲染到 dom。因此,在子组件中,您距离 render 仅两步之遥。您可以使用两个折叠$nextTick或使用setTimeout(在 vue 完成所有工作后 setTimeout 回调获得控制)来做您想做的事情:

mounted(){
  this.$nextTick(()=>{
    this.$nextTick(()=>{
      console.log("component1")
      console.log(this.$el.offsetWidth)
    })
  })
}

或者

mounted(){
  setTimeout(()=> {
    console.log("component1")
    console.log(this.$el.offsetWidth)
  })
}

来自Vue 父子生命周期钩子的插图:

在此处输入图像描述


更新您的评论:

是的,您无法offsetWidth使用display: none. 但是所有选项卡的偏移量彼此相等吗?无论如何,您可以动态跟踪活动选项卡。使用v-modeltabsComponent添加手表方法,在可见标签时,您可以在其中获取指标。此外,您应该添加ref到您的组件和内部容器(通过将组件的引用名称设置为您可以activeTab用来访问活动组件内部引用的选项卡路径)。

在模板中:

<v-container fluid ref="div">John</v-container>
# ...
<div id="component2" ref="div">Jinny</div>
# ...
<v-tabs v-model='activeTab'>
# ...
<component1 ref="/"></component1>
<component2 ref="/jinny"></component2>

在脚本中:

data: function () {
  return {
    activeTab: null
  }
},
watch: {
  activeTab: function () {
    this.$nextTick(()=> {
      console.log(this.$refs[this.activeTab].$refs.div.offsetWidth) 
    })
  }
}

使用 watch 方法更新了 codepen:https ://codepen.io/anon/pen/qMeYGZ


推荐阅读