如何使用v-show正确渲染元素?

时间:2020-06-02 21:51:19

标签: javascript vue.js dom vuejs2

我有一个轮播,仅在用户打开我的手风琴菜单时显示。

我正在使用v-show隐藏轮播,直到其打开为止。但是,除非我调整浏览器窗口的大小,否则它无法正确呈现轮播,第一张幻灯片会显示,但单击其他​​幻灯片不会显示出来。

网络检查会在加载时translate: transform()显示空白,直到调整浏览器窗口的大小为止。

我认为这与v-show及其在DOM中的呈现方式有关,我已经看到人们使用.$nextTick.$watch来解决类似问题,但我对它们的理解不够将它们应用于我的代码。

我是否可以使用带有.nextTick().watch()的v-show解决此问题?

<div :key="project.id">
  <!-- project header -->
  <li
    class="project accordion columns is-flex vcenter"
    @click="toggleItem"
    style="margin-left: 0; margin-right: 0;"
  >
    <h3 class="project-title column is-one-quarter">{{ project.Name }}</h3>
    <h4 class="project-summary column is-two-thirds">
      {{ project.Summary }}
    </h4>
    <span class="column is-one-half is-gapless project-icon">
    <img
      src="../static/SVG/Circle.svg"
      alt="circle icon for branding & identity"
    />
  </span>
</li>

我的隐藏内容在这里,仅当使用v-show打开手风琴时显示。

<div class="showcase-content columns" v-show="show">
  <p class="project-description column is-one-third">
    {{ project.Description }}
  </p>
  <agile :fade="true">
    <div
      class="image-box column is-two-thirds"
      v-for="image in project.image"
      :key="image.url"
    >
      <img :src="buildImageUrl(image.url)" alt="" />
    </div>
  </agile>
</div>

编辑我最初是在注入一些手风琴,并且重构了手风琴和我的代码,因为我怀疑注入可能没有反应,但仍然存在相同的问题。这个问题的代码是我当前的代码。

<script>
export default {
  name: 'ProjectItem',
  data: function () {
    return {
      show: false,
    }
  },
  props: ['project'],
  methods: {
    toggleItem: function () {
      this.show = !this.show
    },
    buildImageUrl(image) {
      if (!image) return '../static/images/SamB.png'
      return `http://localhost:1337${image}`
    },
  },
}
</script>

1 个答案:

答案 0 :(得分:2)

注意:将答案的这一部分保留下来,因为它可能对遇到类似问题的任何人有用。但是,当问题未指定滑块库时添加了它。要阅读实际答案,请跳到分隔符后

  • 使用v-show表示轮播使用display: none渲染
  • 大多数轮播在init版中设置幻灯片的大小,并在window.resize上更新

这意味着您的转盘正在init上,高度为0。而且,无论您的window.resize元素的display属性如何更改,它都只会在v-show上重新调整。

一个快速而肮脏的解决方法是在控制window.resize的属性发生更改时触发v-show。即:

toggleItem: function () {
  this.show = !this.show;
  window.dispatchEvent(new Event('resize'));
},

但是 它很脏 ,并且它可能也很昂贵,具体取决于正在听resize的其他组件/库。

更好的解决方案是在条件update发生变化时调用轮播库公开的任何v-show方法。
如果您不知道该怎么做,建议您在问题中添加轮播库(带有版本)。

另一个潜在的问题是轮播的容器是否具有动画效果(即:您在其上使用了某种过渡类型)。在这种情况下,当容器具有正确的大小时,您需要在动画结束时触发window.resize / carousel.update。这就是为什么提供minmal reproducible example的理想选择。
一个快速而又肮脏的解决方案是在动画元素上添加一个transitionend侦听器,并在该回调中分派window.resize,在这种情况下,您不再需要其他任何东西。另外,我实际上会检查v-show条件,仅在window.resize时才分派true。但是,同样,它不是真的很干净,并且可能会有副作用。


编辑:由于您使用的是vue-agile,因此您的问题已回答in documentation

也可以使用v-show,但是必须使用reload()方法。

这意味着应该这样做:

<template>
   <agile ref="slider" ... />
</template>

...

methods: {
  toggleItem: function () {
    this.show = !this.show;
    this.$nextTick(() => this.$refs.slider.reload());
  }
  ...
}

一个有效的示例here


注意:用v-show替换v-if是一种昂贵的解决方案,因为这意味着您的轮播会在条件每次发生变化时都从DOM中添加和删除。每次它将重建自身并重新加载滑块图像。这比v-show + window.resize解决方案还差。

注意:您可能想看看vue wrapper for Swiper,因为(可以说)Swiper比Slick更好。