同时使用v-if和v-directive删除元素会导致渲染异常

在多个并列的元素上使用自定义指令删除元素,并且切换元素的 v-if 值时会导致渲染异常。

Vue.directive("permission", {
  inserted: function (el, info, vnode) {
    if (!whiteList.includes(info.arg)) {
      el.parentNode && el.parentNode.removeChild(el);
    }
  }
});

比方说现在有三个按钮同时需要条件渲染和权限控制。

按钮是否有权限切换前的v-if值切换后的v-if值
button1falsetrue
button2truetrue
button3truefalse

按照上面的表中的逻辑,初始化应该显示 button2,切换后应该显示 button1 和 button2。
但是实际情况是初始化渲染正常,切换后只显示了 button1,button2不见了。

目前找到的方案是不要将这些按钮放在同一层级下。

但是我感觉是因为上面自定义指令的问题,因为在自定义指令中删除了元素,但是vue本身并不知道这个变化,vnode中的elm会引用这个删除的dom节点,导致在做diff的时候出错了。

想问下能不能只修改自定义指令的实现,不去修改template?

这里提供了这个缺陷的复现地址

相关的代码如下:

// APP.vue
<template>
  <div id="app">
    <div>
      <a-button v-permission:btn1 v-if="showBtn1" type="primary">Button1</a-button>
      <a-button v-permission:btn2 v-if="showBtn2" type="primary">Button2</a-button>
      <a-button v-permission:btn3 v-if="showBtn3" type="primary">Button3</a-button>
    </div>
    <br />
    <button @click="onClick">Click me</button>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      showBtn1: false,
      showBtn2: true,
      showBtn3: true,
    };
  },
  methods: {
    onClick() {
      this.showBtn1 = !this.showBtn1;
      this.showBtn3 = !this.showBtn3;
    },
  },
};
</script>
// main.js
import Vue from "vue";
import App from "./App.vue";

const whiteList = ["btn1", "btn2"];

Vue.directive("permission", {
  inserted: function (el, info, vnode) {
    if (!whiteList.includes(info.arg)) {
      (el.parentNode && el.parentNode.removeChild(el)) ||
        (el.style.display = "none");
    }
  }
});

new Vue({
  render: (h) => h(App)
}).$mount("#app");
阅读 4k
1 个回答

根据你的描述,v-permission 和 v-if 确实最好不要作用在同一个元素上,会使元素状态变化非常混乱不可预测。
我觉得还是修改 template 会合理一些。

// v-if 可以改成 v-show (不排除其它代码会和 v-permission 里关于 display=none 的处理有冲突)
<button v-permission:btn1 v-show="showBtn1" type="button">Button1</button>

// 或者 a-button 外面再包一层 div 处理 permission
<div v-permission:btn1>
  <a-button v-if="showBtn1" type="primary">Button1</a-button>
</div>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题