vue2 透传

一、什么是透传

透传是一个通讯层面的概念,指的是在通讯中不管传输的业务内容如何,只负责将传输的内容由源地址传输到目的地址,而不对业务数据内容做任何改变。
在vue2上来讲,我们的组件存在深层嵌套的场景,例如:
A -> B -> C
我们会在A里带上业务中提供的数据,一层层的传递进去,在传递的过程中一般有两种方案:

  1. 通过props具名接收,再继续内层传递
  2. 通过$listeners$attrs变量配合v-onv-bind进行批量透传

二、属性透传:v-bind="$attrs" & 事件透传:v-on="$listeners"

<template>
  <div>
    <p @click="click()">CT</p>
    <p>{
   
   { a }} - {
   
   { c }}</p>
  </div>
</template>

<script>
export default {
      
      
  name: "CT",
  props: {
      
      
    a: {
      
      
      type: String,
      default: "",
    },
    c: {
      
      
      type: String,
      default: "",
    },
  },
  data() {
      
      
    return {
      
      };
  },
  methods: {
      
      
    click() {
      
      
      this.$emit("click");
    },
  },
};
</script>
<template>
  <div>
    <p>BT</p>
    <CT v-bind="$attrs" v-on="$listeners"></CT>
  </div>
</template>

<script>
import CT from "./CT.vue";

export default {
      
      
  name: "BT",
  components: {
      
       CT },
  data() {
      
      
    return {
      
      };
  },
  methods: {
      
      
    click() {
      
      
      this.$emit("click");
    },
  },
};
</script>
<template>
  <div>
    <p>AT</p>
    <BT a="b" c="t" @click="click()"></BT>
  </div>
</template>

<script>
import BT from "./BT.vue";

export default {
      
      
  name: "AT",
  components: {
      
       BT },
  data() {
      
      
    return {
      
      };
  },
  methods: {
      
      
    click() {
      
      
      console.log("AT");
    },
  },
};
</script>

A -> B -> C

  • v-bind="$attrs"会将A组件调用B组件时绑定的属性 全部透传C组件
  • v-on="$listeners"会将A组件调用B组件时绑定的事件 全部透传C组件

通过这样的方式A组件就可将想要传递给C组件属性事件传递下去了。

三、属性覆盖

<template>
  <div>
    <p @click="click()">CT</p>
    <p>{
   
   { a }} - {
   
   { c }}</p>
  </div>
</template>

<script>
export default {
      
      
  name: "CT",
  props: {
      
      
    a: {
      
      
      type: String,
      default: "",
    },
    c: {
      
      
      type: String,
      default: "",
    },
  },
  data() {
      
      
    return {
      
      };
  },
  methods: {
      
      
    click() {
      
      
      this.$emit("click");
    },
  },
};
</script>
<template>
  <div>
    <p>BT</p>
    <CT c="cc" v-bind="$attrs" v-on="$listeners" a="aa"></CT>
  </div>
</template>

<script>
import CT from "./CT.vue";

export default {
      
      
  name: "BT",
  components: {
      
       CT },
  data() {
      
      
    return {
      
      };
  },
  methods: {
      
      
    click() {
      
      
      this.$emit("click");
    },
  },
};
</script>

结果:

AT
BT
CT
aa - cc

不管属性的位置在v-bind前还是在v-bind后具名属性会都会覆盖 v-bind里绑定的同名属性。

四、事件合并

<template>
  <div>
    <p @click="click()">CT</p>
    <p>{
   
   { a }} - {
   
   { c }}</p>
  </div>
</template>

<script>
export default {
      
      
  name: "CT",
  props: {
      
      
    a: {
      
      
      type: String,
      default: "",
    },
    c: {
      
      
      type: String,
      default: "",
    },
  },
  data() {
      
      
    return {
      
      };
  },
  methods: {
      
      
    click() {
      
      
      this.$emit("click");
    },
  },
};
</script>
<template>
  <div>
    <p>BT</p>
    <CT c="cc" v-bind="$attrs" v-on="$listeners" a="aa" @click="clickBT()"></CT>
  </div>
</template>

<script>
import CT from "./CT.vue";

export default {
      
      
  name: "BT",
  components: {
      
       CT },
  data() {
      
      
    return {
      
      };
  },
  methods: {
      
      
    click() {
      
      
      this.$emit("click");
    },
    clickBT() {
      
      
      console.log("clickBT")
    }
  },
};
</script>

点击CTconsole控制台输出

clickBT                      BT.vue?ec36:22 
AT                           AT.vue?b678:19

同名事件合并在一起,都会被执行,先执行具名方法,再执行v-on里面绑定的同名方法

五、如何覆盖事件,而不做合并

<template>
  <div>
    <p @click="click()">CT</p>
    <p>{
   
   { a }} - {
   
   { c }}</p>
  </div>
</template>

<script>
export default {
      
      
  name: "CT",
  props: {
      
      
    a: {
      
      
      type: String,
      default: "",
    },
    c: {
      
      
      type: String,
      default: "",
    },
  },
  data() {
      
      
    return {
      
      };
  },
  methods: {
      
      
    click() {
      
      
      this.$emit("click");
    },
  },
};
</script>
<template>
  <div>
    <p>BT</p>
    <CT c="cc" v-bind="$attrs" v-on="{...$listeners, click: clickBT}" a="aa"></CT>
  </div>
</template>

<script>
import CT from "./CT.vue";

export default {
      
      
  name: "BT",
  components: {
      
       CT },
  data() {
      
      
    return {
      
      };
  },
  methods: {
      
      
    click() {
      
      
      this.$emit("click");
    },
    clickBT() {
      
      
      console.log("clickBT")
    }
  },
};
</script>

点击CTconsole控制台输出

clickBT                      BT.vue?ec36:22 
AT                           AT.vue?b678:19

使用扩展运算符可以做到覆盖事件,而不做合并

六、v-bind="$attrs" & v-on="$listeners"不是绝对的

$attrs是一个vue的内置变量,指的是调用本组件时上面绑定的属性$listeners同样是一个vue的内置变量,指的是调用本组件时上面绑定的事件
v-bind后面不一定必须是$attrsv-on后面不一定必须是$listeners。你可以像这样:
v-bind="$props"v-bind="xxx"v-bind="{a: 1, b: 2}"v-listeners="xxx"

参考

猜你喜欢

转载自blog.csdn.net/letianxf/article/details/128422082