Vue---如何更好的封装组件?几个小技巧助你成为组件封装达人,让我们封装的组件更加优雅易用

在进行组件通信时,经常会遇到这样的需求:
父组件A给子组件B传值,B组件又继续传递给C,最终执行的是C。
也就是说,B只是中间起了传递作用,啥也没干。
如果是这样的需求,按父子组件的通信的规则,B得接收信息,并继续传递,对B组件来说是冗余;而用vuex呢?那更是大材小用杀鸡用牛刀了。
那咋办呢?如何能快速达到目的、而且代码不拖沓?
$attrs和$listeners就派上了用场。

一、$attrs

正常情况下,Vue推荐用props向子组件参数。但是在特定场景下,使用$attrs 会更方便。

$attrs其实相当于传输数据的一个桥梁,传递子组件中非prop定义的v-bind属性。

我们在使用组件的过程中,有时需要给被封装的子组件传递Prop,但是如果每一个Prop都需要父组件声明,再一个一个传递给子组件,那就太麻烦了。

此时我们可以利用组件实例上的$attrs属性来简化这个过程:

父组件.vue

<template>
  <div>
    <h2>attrs-listeners</h2>
    <children :attrsValue="attrsValue" ></children>
  </div>
</template>
<script>
import children from "./components/children.vue";

export default {
  components: {
    children,
  },
  data() {
    return {
      attrsValue: "muzidigbig",
    };
  },
  
};
</script>

子组件.vue

<template>
  <div class="mystyle">
    <p>attrs-listeners----子组件</p>
    <hr>
    <sub-children v-bind="$attrs" v-on="$listeners"></sub-children>
  </div>
</template>
<script>
import subChildren from "./sub-children.vue";
export default {
  components: {
    subChildren,
  },
  data() {
    return {};
  },
  created() {
    // 接收父组件可能传递过来的 非prop
    console.log(this.$attrs, this.$listeners);
  },
};
</script>

孙组件.vue

<template>
  <div class="mystyle">
    <p>attrs-listeners----孙组件</p>
    <p>孙传不传都可以---{{ attrsValue }}</p>
    <input
      type="text"
      v-model="attrsValue"
    />
  </div>
</template>
<script>
export default {
  // inheritAttrs: false, // 解决:prop作为HTML属性绑定到组件的根元素上
  // props: {
  //   attrsValue: {
  //     default: "muzi",
  //   },
  // },
  data() {
    return {
      attrsValue: "",
    };
  },
  created() {
    // 接收父组件可能传递过来的 非prop
    console.log(this.$attrs);
    this.attrsValue = this.$attrs.attrsValue;
  },
};
</script>

查看打印结果:

 

这里面就包含的有我们传入的attrsValue属性,

但需要注意的一点是,Vue会将组件被传入,但未声明的prop作为HTML属性绑定到组件的根元素上:

 

因此我们需要用下面的属性来处理这种情况:

 解决:

 

总结:

  1. Vue 3.x中所有的属性,包括class/style都可以通过$attrs 传递,这个与Vue2.x不同.

  2. v-bind="$attrs" 指令,能够指定dom节点,完成属性绑定。

  3. $attrs 只适合传递原生属性/事件,其它的属性还是老老实实用propsevents传递吧。

二、$listeners

定义:

包含了父作用域中的 (不含 .native 修饰器的v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

理解:

所谓$listeners其实就相当于一个中间件,当出现多级组件嵌套时,孙组件想传递数据给爷组件,那么就需要在父组件中给孙组件设置v-on="$listeners",然后通过@键的方式监听孙组件传递过来的数据。

为什么要用$listeners?

因为$listeners可以很好的解决在多级组件嵌套中,组件C传给组件A传递数据的问题。

刚才我们介绍了如何将prop传递给子组件,如果我们想将事件处理函数传递给子组件时。

原始做法:
我们先将一个事件处理函数绑定到子组件上

父组件.vue

<template>
  <div>
    <h2>attrs-listeners</h2>
    <children :attrsValue="attrsValue" @handleInp="handleInp"></children>
  </div>
</template>
<script>
import children from "./components/children.vue";

export default {
  components: {
    children,
  },
  data() {
    return {
      attrsValue: "muzidigbig",
    };
  },
  methods: {
    handleInp(params,event) {
      console.log(params);
      console.log("input",event);
    },
  },
};
</script>

子组件.vue

 孙组件.vue

<template>
  <div class="mystyle">
    <p>attrs-listeners----孙组件</p>
    <p>孙传不传都可以---{{ attrsValue }}</p>
    <input
      type="text"
      v-model="attrsValue"
      @input="$listeners.handleInp(attrsValue, $event)"
    />
  </div>
</template>
<script>
export default {
  inheritAttrs: false, // 解决:prop作为HTML属性绑定到组件的根元素上
  // props: {
  //   attrsValue: {
  //     default: "muzi",
  //   },
  // },
  data() {
    return {
      attrsValue: "",
    };
  },
  created() {
    // 接收父组件可能传递过来的 非prop
    console.log(this.$attrs, this.$listeners);
    this.attrsValue = this.$attrs.attrsValue;
  },
};
</script>

最终执行的是subChild.vue。

 

$attrs和$listeners的使用场景:

对一些UI库进行二次封装用,比如element-ui,里面的组件不能满足自己的使用场景的时候,会二次封装,但是又想保留他自己的属性和方法,那么这个时候时候$attrs和$listners是个完美的解决方案。

简单来说:$attrs与$listeners 是两个对象,$attrs 里存放的是父组件中绑定的非 Props 属性,$listeners里存放的是父组件中绑定的非原生事件。

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值