面对产品的需求,这几天了解了一些强制更新组件的方法(vue版)

390 阅读3分钟

动态组件

业务需求是这样的,最开始需求是一个tabs切换展示不同内容。为了方便我们循环去配合component去实现。这样省力。

<component :is="item.component" :key="item.id"></component>

const tabs = [
  {
    id: "1",
    title: "zh1",
    component: Example1,
  },
  {
    id: "2",
    title: "zh2",
    component: Example2,
  },
  {
    id: "3",
    title: "zh3",
    component: Example3,
  },
  {
    id: "4",
    title: "zh4",
    component: Example4,
  },
];

image.png

但是做完后,产品说新加一个分配项目的功能。当点击进入项目详情,也就是这个tabs切换页面时,如果项目未分配,我们需要先分配项目,然后才可以操作项目。于是我们就在动态组件中加上了v-show / v-if去做这种操作。

<component :is="item.component" :key="item.id" v-show="!isDisabled"></component>
<div v-show="isDisabled">
    待分配 
    <br>
    <button @click="handlebtn">按钮</button>
</div>

image.png

当我们做完后,产品又说了我们希望第二个tab在没有分配项目的时候也可以让用户点击。这个问题就很棘手了。我们只能在动态组件外层做判断,不能深入到内部做判断啊。于是我们就把动态组件换成了普通的v-if / v-show去做这种tabs切换。

image.png 虽然可以限制tabs-item的点击状态,但是我们是在外层做统一的判断,所以我们点击第二个tab,也不会显示组件本身,而是分配按钮组件。

如果有这种需求的同志们,不要使用动态组件去开发,这样会避免一些不必要的麻烦。

<TabPane
  v-for="item in tabs"
  :key="item.id"
  :tab="item.title"
  :disabled="isDisabled && item.id != '1' && item.id != '2'"
>
  <component :is="item.component" :key="item.id" v-show="!isDisabled" ></component>

  <div v-show="isDisabled">
    待分配 
    <br>
    <button @click="handlebtn">按钮</button>
  </div>
</TabPane>

v-show,导致子组件高度渲染有问题,echarts图表展示有问题

依旧是tabs,只不过这个是移动端。当我们使用v-show去控制tabs内容的展示时,由于使用的是v-show,他会加载组件,但是display: none, 导致echarts初始化,拿到父元素的宽高为0。导致图像渲染有问题。这个问题也很离奇。因为我们在外层父元素设置的宽度是100%,v-show导致在图标渲染时,父级宽高为0,所以应该不展示才对。但是他会出现默认的100px x 100px。

解决办法

  • 把外层v-show换成v-if,让切换时组件重新加载即可。
  • 直接设置父元素宽高固定值。注意由于是移动端,我们需要动态计算宽度。所以需要使用calc()
  • 或者在使用组件的地方加上key,绑定activeKey,当切换tabs时,强制更新组件。vue中的diff算法比对key时,不一样就会重新渲染该组件。
  • 或者监听tabs的切换,然后调用组件的$forceUpdate方法,强制组件的重新加载。

image.png

v-if "正确"的使用

今天写移动端时,遇见了这样一个问题,就是我们通过props向子组件传递一个id,在子组件中通过watch监听id变化,然后请求详情接口,做表单编辑回写数据。当用户不想编辑了,点击popup以外的元素关闭popup,我们需要清空表单,防止用户点击添加后,有原来的旧数据,体验不是很好。

我们就监听popup关闭事件,将表单数据重置。但是这样的话,我们再次点击相同的项目时,由于id相同watch是不会重新触发的,以至于不能回写数据。所以这时候我们就需要强制组件重新加载渲染。所以我们就可以在组件中使用v-if绑定popup的显隐值。