vue 中被我忽略掉的知识点

1,329 阅读2分钟

前言

面试官:说一下常用的组件传参吧?
我: 父子组件中 props 方式;通过实例化 $refs 方式,vuex 如果是兄弟组件,可以通过 enentBus等方式,通过emit来进行子组件数据的回调,不过也有通过 $parent $children 的方式进行获取值,这种的项目中用的不是很多,具体的使用要看实际的场景,哪个方便用哪个。
面试官:那一个爷组件给孙子组件传值呢,一般用什么?
我:可以通过爷组件传值给子组件,然后再传值给孙组件,或者通过 vuex 进行通信
面试官:你的意思是传值两层给孙子组件吗
我:是的
面试官:那除了你说的,还有其他实现方案吗
我:其他的应该有吧,可能平常不怎么用
面试官:那你回去等通知吧

这是前不算太久得一个面试题,面试结束后想着去查查还有其他啥用法呢,然后一忙就给忘了,最近项目中针对element ui二次封装,看到了 v-bind="$attrs",这个属性陌生又熟悉,但是具体的用法不太清楚,就花了时间去了解了一下。

Attributes 与 $attrs 的使用

官方的文档,感觉不是那么好理解

image.png “透传 attribute”指的是传递给一个组件,却没有被该组件声明为 props 或 emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 classstyle 和 id

当一个组件以单个元素为根作渲染时,透传的 attribute 会自动被添加到根元素上

我们通过案例,来看一下

//爷组件
<template>
  <div class='app'>
      爷组件
      <child :name="name" :age="age" :job="job" class="grand" :style="{'font-size':'20px'}"></child>
  </div>
</template>
<script setup> 
import {ref} from "vue"
import child from './components/child.vue';
const name=ref("我是爷组件,我今年都98了")

const age=ref(98)
const job=ref('IT')

</script>
<style scoped>
.app{
  width: 600px;
  height: 600px;
  padding: 20px;
  background: #f4f6f8;
  color: #333;
}
</style>
//父组件
<template>
    <div class='app-child'>
        子组件
        <span style="color:red ;">{{ name }}</span>
    </div>
  </template>
  <script setup>
import { useAttrs } from 'vue';

    defineProps({
        name:{
            type:String
        }
    })
    const attrs=useAttrs()
    console.log(attrs)
  </script>
  <style scoped>
  .app-child{
    width: 400px;
    height: 400px;
    padding: 20px;
    background: #1b69b8;
    color: #333;
  }
  </style>

我们在爷组件中定义了三个属性,绑定在子组件中,同时加了 styleclass 属性。不同的是我们在子组件中,只有name 属性通过 props 接收,其他并没有进行定义接收,通过 useAttrs() 我们获取的值就是非 props 定义的数据。通过例子官方文档的第一句话就好理解了 image.png

我们来看第二句 当一个组件以单个元素为根作渲染时,透传的 attribute 会自动被添加到根元素上 此时我们的子组件的根组件是只有一个div,class style 属性是可以添加上去的,但是如果我们在子组件再加一个div 和,那么这是属性就无法传递过去了

<template>
    <div class='app-child'>
        子组件
        <span style="color:red ;">{{ name }}</span>
    </div>
    <div class="next-class">

    </div>
  </template>

在子组件引入孙子组件后 ,我们在孙子组件中想要获取爷组件传过来的值,此时我们在孙子组件中像子组件中那样获取值是获取不到的,那如何拿到值呢,我们可以在孙子组件中使用 $attrs

//子组件
<template>
    <div class='app-child'>
        子组件
        <span style="color:red ;">{{ name }}</span>
        <grandSun></grandSun>
    </div>
    <!-- <div class="next-class">

    </div> -->
  </template>
  <script setup>
  import grandSun from './grandSun.vue';
import { useAttrs } from 'vue';

    defineProps({
        name:{
            type:String
        }
    })
    const attrs=useAttrs()
    // console.log(attrs)
  </script>
  <style scoped>
  .app-child{
    width: 400px;
    height: 400px;
    padding: 20px;
    background: #1b69b8;
    color: #333;
  }
  </style>
  
//孙组件
<template>
    <div class='app-grand-sun'>
       孙子组件
    </div>
  </template>
  <script setup>
import { useAttrs } from 'vue';

    const attrs=useAttrs() //获取祖辈传过来的值(父组件也可能加,改值)
    console.log(attrs) 
  </script>
  <style scoped>
  .app-grand-sun{
    width: 200px;
    height: 200px;
    padding: 20px;
    background: #ccc;
    color: #333;
  }
  </style>

image.png

如果爷组件和父组件传同一个值,孙子组件会接收哪个值呢。遵循就近原则

attribute 与 $attrs 相关概念

attribute 是一个在HTML中的属性,用于给HTML元素添加额外的信息。它可以包含元素的名称、值和任何其他附加信息。attribute 可以用于控制元素的行为和样式。

$attrs 是Vue.js中的一个特殊属性,用于将父组件传递给子组件的所有属性集合传递给子组件。它是一个对象,包含了父组件传递给子组件的所有属性和值。在子组件中,可以使用 $attrs 来访问这些属性。

使用 $attrs 可以实现属性的透传,即将父组件的属性传递给子组件,并在子组件中使用这些属性。这在开发可复用的组件时非常有用,可以使得组件更加灵活和可配置。

inheritAttrs

假如说我不想要继承父辈传过来的属性,主要是html类 如 class style 等 v-on 等,可以使用inheritAttrs 属性来进行禁用。 下面是官方对于属性的解释
这个 $attrs 对象包含了除组件所声明的 props 和 emits 之外的所有其他 attribute,例如 classstylev-on 监听器等等。

我们通过代码来测试一下

// 子组件加个 class 属性
<grandSun v-bind="$attrs"  class="test-inheritAttrs"></grandSun>

image.png

此时可以看到我们添加的属性,我们修改一下孙子组件的代码

<template>
    <div class='app-grand-sun'>
       <div>
        孙子组件
        {{ $attrs.age }}
       </div>
    </div>
  </template>
  <script setup>
import { useAttrs } from 'vue';
    defineOptions({
      inheritAttrs: false
    }) //添加该属性
    const attrs=useAttrs()
    console.log(attrs)
  </script>
  <style scoped>
  .app-grand-sun{
    width: 200px;
    height: 200px;
    padding: 20px;
    background: #ccc;
    color: #333;
  }
  </style>

image.png

那如果我想让这个class属性加在孙子组件里层 div 上呢,那我们在这上面加上 v-bind="$attrs" 即可。改完我们看下效果

image.png

最后

虽然上面的这些知识点不是很难,但是还需要自己动手实现一下才能够知道他的用法。今天就到这里吧!