在Vue使用$attrs实现构建高级组件

目录
  • 什么是 $attrs
  • attrs V3 vs $attrs V2
  • 事例
    • 添加一些属性
    • 添加标题和值
    • $attrs 救场
  • inheritAttrs: false

这节课,我们来看下 Vue3 中的 $attrs 属性。首先,我们会介绍它的用途以及它的实现与 Vue2 有哪些不两同点,并通过事例来加深对它的理解。

真正理解了 $attrs 属性有助于我们构建易于使用和可扩展的高级组件

什么是 $attrs

对 $attrs 定义, Vue2 与 Vue3 是不一样的,这里我们主要来介绍 Vue3 的版本:

$attrs 对象包含了除组件所声明的 props 和 emits 之外的所有其他 attribute,例如 class,style,v-on 监听器等等。

$attrs 也可以被看作是一个安全网,它可以捕获任何我们没有在组件中声明的东西。我们考虑一个只有一个属性和事件处理程序的组件,如下所示:

<template>
  <h1 @click="$emit('custom', '改变标题')">{{ title }}</h1>
</template>
<script>
export default {
  name: 'Example',
  props: ['title'],
  emits: ['custom'],
}
</script>

如果在父组件中像下面这样实例化上面的组件:

<template>
  <div id="app">
    <SimpleEvent
      id="myId"
      class="myClass"
      data-cy="cypress-testing"
      @blur="onBlur"
      title="测试$attrs"
      description="没有声明 props"
      @custom="onCustom"
    />
  </div>
</template>

<script setup>
import SimpleEvent from './components/Button.vue'

const onBlur = () => {
  // todo
}
const onCustom = () => {
  // todo
}

</script>

如果在组件中把 $attrs 打印出来,我们会得到如下内容:

{
  id: 'myId',
  class: 'myClass',
  'data-cy': 'cypress-testing',
  description: '没有声明 props',
  onBlur: () => { // todo } 
}

上面这些信息,感觉没啥用,其实不然,我们下面会介绍如何利用这些信息。

attrs V3 vs $attrs V2

这小节,我们来看下 Vue2 与 Vue3 中的 attrs 属性的区别,先来看张图:

与 Vue2 的区别主要有:

  • 自定义事件放在 @listerner 对象中
  • 不包含 class 属性

而 Vue3 中的 attrs 对象包含了除组件所声明的 props 和 emits 之外的所有其他 attribute,这有利于我们方便使用这些属性。

下面我们来看些事例。

事例

事例地址

首先我们创建一个 Slider 组件,内容如下所示:

<template>
  <input 
    type="range"  
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
    class="slider__input" />
</template>

<script>
export default {
  name: "Slider-1",
  props: {
    modelValue: [Number, String],
  }
};
</script>
<style lang="scss">
// 这里省略一堆样式,自行看事例
</style>

上面代码我们创建一个 slider,还实现了一个双向绑定。然后可以像下面这样使用该组件:

 <Slider-1 v-model="value" />

添加一些属性

目前我们的 Slier 组件还很简单,不太符合实际情况。所以,我们添加几个属性(minmaxclassiddata-cy@keydown 和 aria-label)。

  <Slider-1
      v-model="value"
      min="0"
      max="50"
      class="blue_slider"
      id="special_id"
      data-cy="cypress-slider"
      @keydown="() => true"
      aria-label="Example slider"
    />

运行后,通过控制检查元素,我们可以看下,我们新加的属性都被添加到了 HTML 元素上了:

看到这里,大家可能有疑问了,既然所有的 "非属性/事件" 属性都已经自动应用于内部的HTML元素,为什么还要对 $attrs 做这么大的介绍?

添加标题和值

新增需求:作为一个滑块的使用者,用户希望能够看到一个标题,以及它在屏幕上显示的数字形式的值。

我们在调整一下 Slider 组件,内容如下:

// Slider-2.vue

<template>
  <div class="slider">
    <h1>{{ title }}</h1>
    <input 
      type="range" 
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
      class="slider__input" />
      <div>Value: {{ value }}</div>
  </div>
</template>

<script>
export default {
  name: "Slider-2",
  props: {
    modelValue: [Number, String]
    title: [String],
    value: [Number, String],
  }
};
</script>

乍一看,好像没啥问题,但如果我们仔细观察,可以看到有些东西是不对的。

首先,Slider 不是蓝色的。第二,value 远远超过了50,最后,检查一下HTML,会看到我们所有的额外属性(min, max, data-cy)都被分配给了根元素,而不是我们的 input 元素。

解决上述问题的最好方法是找到一种方法,将所有的属性、类、参数和事件直接 "应用" 到 input  字段上,而不需我们手动的一个个声明。这就是 $attrs 出场的地方。

$attrs 救场

在本文的开头,我们介绍了 $attrs。它是一个存放所有 "未声明"的属性和事件的地方,而这正是我们需要解决的问题。

要使用这个功能,我们只需将 $attrs 属性应用于一个或多个HTML元素,使用 v-bind 操作符。

<template>
  <div class="slider">
    <h1>{{ title }}</h1>
    <input 
      type="range"  
      v-bind="$attrs"
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
      class="slider__input" />
      <div>Value: {{ modelValue }}</div>
  </div>
</template>

在组件中,我们使用 attrs 充当桥梁,将所有的属性(类、属性、属性和自定义事件)复制到一个或多个元素上。Slider 组件又回到了正常模式上了。

还有一个问题--我们添加的属性不仅被分配给了 input 元素上,也分配给了 root元素。

通常情况下,这可能对界面没啥影响,但有的属性确实会生产一些副作用,下面,我们来解决这个问题。

inheritAttrs: false

默认情况下,任何被传递给组件的额外参数都会自动应用于根元素(以及所有有 $attrs 绑定的元素)。

为了关闭这个功能,并控制哪些元素可接受这个额外的属性,我们可以使用一个名为 inheritAttrs 的标志,并将其设置为false

经过这样的改变,我们的HTML就变得漂亮且干净了。所有的额外属性都只作用于 input 元素。

以上就是在Vue使用$attrs实现构建高级组件的详细内容,更多关于Vue $attrs构建高级组件的资料请关注我们其它相关文章!

(0)

相关推荐

  • vue $attrs的使用全面解析

    目录 $attrs的使用vue 以下是$attrs的使用示例 1.父组件(Father.vue) 2.儿子组件(Child.vue) 3.孙子组件(GrandChild.vue) $attrs到底是什么? 先来看看官方文档给的定义 $attrs的使用vue $attrs是在vue的2.40版本以上添加的. 项目中有多层组件传参可以使用$attrs,可以使代码更加美观,更加简洁,维护代码的时候更方便.如果使用普通的父子组件传参prop和$emit,$on会很繁琐:如果使用vuex会大材小用,只是在

  • Vue封装组件利器之$attrs、$listeners的使用

    目录 前言 $attrs 例子: $listeners (官网解释) 使用场景 总结 前言 多级组件嵌套需要传递数据时,通常使用的方法是通过vuex.但仅仅是传递数据,不做中间处理,使用 vuex 处理,未免有些大材小用了.所以就有了 $attrs . $listeners两个属性 ,通常配合 inheritAttrs 一起使用. $attrs 从父组件传给自定义子组件的属性,如果没有 prop 接收会自动设置到子组件内部的最外层标签上,如果是 class 和 style 的话,会合并最外层标签

  • vue中通过使用$attrs实现组件之间的数据传递功能

    组件之间传递数据的方式有很多种,之所以有这么多种方式,是为了满足在不同场景不同条件下的使用. 一般有三种方式: props vuex Vue Event Bus 本文介绍的是使用$attrs的方式. 这是$attrs的官网api https://cn.vuejs.org/v2/api/#vm-attrs 这个api是在2.4版本中添加的,那么为什么要添加这个特性呢? 看看官网是怎么解释的 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 ( class  和  style  除外

  • Vue组件通信$attrs、$listeners实现原理解析

    前言 vue通信手段有很多种,props/emit.vuex.event bus.provide/inject 等.还有一种通信方式,那就是$attrs和$listeners,之前早就听说这两个api,趁着有空来补补.这种方式挺优雅,使用起来也不赖.下面例子都会通过父.子.孙子,三者的关系来说明使用方式. $attrs 官方解释: 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class和style除外).当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定

  • 在Vue使用$attrs实现构建高级组件

    目录 什么是 $attrs attrs V3 vs $attrs V2 事例 添加一些属性 添加标题和值 $attrs 救场 inheritAttrs: false 这节课,我们来看下 Vue3 中的 $attrs 属性.首先,我们会介绍它的用途以及它的实现与 Vue2 有哪些不两同点,并通过事例来加深对它的理解. 真正理解了 $attrs 属性有助于我们构建易于使用和可扩展的高级组件 什么是 $attrs 对 $attrs 定义, Vue2 与 Vue3 是不一样的,这里我们主要来介绍 Vue

  • 使用 Vue cli 3.0 构建自定义组件库的方法

    本文旨在给大家提供一种构建一个完整 UI 库脚手架的思路:包括如何快速并优雅地构建UI库的主页.如何托管主页.如何编写脚本提升自己的开发效率.如何生成 CHANGELOG 等 前言 主流的开源 UI 库代码结构主要分为三大部分: 组件库本身的代码:这部分代码会发布到 npm 上 预览示例和查看文档的网站代码:类似 Vant.ElementUI 这类网站. 配置文件和脚本文件:用于打包和发布等等 编写此博文的灵感 UI 框架库( vue-cards ),PS:此 UI框架库相对于Vant.Elem

  • Vue高级组件之函数式组件的使用场景与源码分析

    目录 介绍 使用场景 源码分析 总结 介绍 Vue提供了一种可以让组件变为无状态.无实例的函数化组件.从原理上说,一般子组件都会经过实例化的过程,而单纯的函数组件并没有这个过程,它可以简单理解为一个中间层,只处理数据,不创建实例,也是由于这个行为,它的渲染开销会低很多.实际的应用场景是,当我们需要在多个组件中选择一个来代为渲染,或者在将children,props,data等数据传递给子组件前进行数据处理时,我们都可以用函数式组件来完成,它本质上也是对组件的一个外部包装. 使用场景 定义两个组件

  • Vue.js 前端路由和异步组件介绍

    目录 文章目标 P6 P6+ ~ P7 一.背景 二.前端路由特性 三.面试!!! 四.Hash 原理及实现 1.特性 2.如何更改 hash 3.手动实现一个基于 hash 的路由 五.History 原理及实现 1.HTML5 History 常用的 API 2.pushState/replaceState 的参数 3.History 的特性 4.面试!!! 5.手动实现一个基于 History 的路由 六.Vue-Router 1.router 使用 2.动态路由匹配 3.响应路由参数的变

  • Vue传参一箩筐(页面、组件)

    Vue页面.组件之间传参方式繁多,此处罗列出常用的几种方式,欢迎审阅补充. 一丶路由传参 这里的路由传参以编程式 router.push(...) 为例,声明式 <router-link :to="..."> 与之类似.此处模拟情景为从 componentsA.vue 页面跳转到 componentsB.vue 页面传参.首先,路由配置信息如下: router.js import Vue from 'vue' import Router from 'vue-router'

  • vue webpack多页面构建的实例代码第1/3页

    项目示例地址: https://github.com/ccyinghua/webpack-multipage 项目运行: 下载项目之后 # 下载依赖 npm install # 运行 npm run dev http://localhost:3000/login.html http://localhost:3000/index.html 一.开发环境 node v6.11.0 二.安装vue-cli脚手架 npm install vue-cli@2.8.2 -g 三.初始化项目 vue init

  • vue-image-crop基于Vue的移动端图片裁剪组件示例

    本文介绍了vue-image-crop基于Vue的移动端图片裁剪组件示例,分享给大家,具体如下: 代码地址:https://github.com/jczzq/vue-image-crop vue-image-crop 基于Vue的移动端图片裁剪组件 组件使用URL.createObjectURL()等新特性,使用前注意兼容问题.IE >= 10 注意:该组件适用于 PC 端,不推荐手机端使用. 功能预览 快速开始 安装Node >= 8.9.0(推荐LTS = 8.11.0) # 安装 vue

  • Vue.js 中制作自定义选择组件的代码附演示demo

    定制 select 标签的设计非常困难.有时候,如果不使用样式化的 div 和自定义 JavaScript 的结合来构建自己的脚本,那是不可能的.在本文中,你将学习如何构建使用完全自定义 CSS 设置样式的 Vue.js 组件. Demo: https://codesandbox.io/s/custom-vuejs-select-component-8nqgd HTML <template> <div class="custom-select" :tabindex=&

  • Vue实现动态查询规则生成组件

    1. 动态查询规则 动态查询规则,大致如下图所示.是可以按照用户的自定义进行组织查询语句的一种复杂组件,大致可以实现SQL查询的where条件,下面是摘自mongodb的某一软件. 2.组件构建思路 按照规则组件的组织形式,可以把其视为一棵树,有树干和树叶,这样看起来就不难了. 2.1 组件属性 data: 是树结构的内容,我们定义为: { condition: 'AND', rules: [], } fieldList: 字段列表数组,可供选择的字段集合: operatorList: 操作列表

  • Vue项目首屏性能优化组件实战指南

    目录 Vue首屏性能优化组件 描述 IntersectionObserver requestIdleCallback 实现 总结 Vue首屏性能优化组件 简单实现一个Vue首屏性能优化组件,现代化浏览器提供了很多新接口,在不考虑IE兼容性的情况下,这些接口可以很大程度上减少编写代码的工作量以及做一些性能优化方面的事情,当然为了考虑IE我们也可以在封装组件的时候为其兜底,本文的首屏性能优化组件主要是使用IntersectionObserver以及requestIdleCallback两个接口. 描

随机推荐