vue中如何实现组件通信

1. 父子组件通信

1. props和emits

我们最常见的组件通信就是父子组件数据通信。父子组件实现数据通信需要使用props和emit两个api。
在父组件中我们通过props将数据绑定给子组件,在子组件中我们可以通过props对象来收集到父组件传递的数据。
在子组件想要修改的props中的数据时,我们可以使用emit对象来触发一个自定义事件,在父组件中监听这个自定义事件并修改数据。(Vue中数据必须保证单向数据流,父组件的数据不能由子组件直接修改,而是通过通知父组件的收段让父组件来修改数据)

1.script setup实现

在script setup语法糖中,我们可以使用defineProps和defineEmits两个宏函数来创建props和emit对象。

<script setup>
  // 创建props和emit对象
  const props = defineProps({
    message: {
      type: String,
      default: 'hello'
    }
  })
  const emit = defineEmits(['change'])
</script>

defineProps注意事项

  1. 这两个宏函数在script setup语法糖中会隐式导入,并不需要我们手动导入。
  2. defineProps函数接收一个对象或者数组作为参数:
    • 为对象时,该对象中的属性即为父组件绑定的props名称,属性值可以是一个该数据对应的类型构造函数或者是一个包含该数据类型的对象配置对象,如上代码。(这里的配置对象下面会详解)
    • 为数组时,该数组每一项均为对应的props名称字符串。
  3. 在3.5以后的版本中,如果父组件的传递的props是响应式的,那我们在子组件中接解构props获取的值仍然是响应式的。可以通过watch和watchEffect来监听props的变化。我们能在setup中访问一个props解构的值时,其本质上是自动为调用的props.变量名.
    const props = defineProps(['foo'])
    
    watchEffect(() => {
      // 在 3.5 之前只运行一次
      // 在 3.5+ 中在 "foo" prop 变化时重新执行
      console.log(foo)
    })
    watchEffect(() => {
      // `foo` 由编译器转换为 `props.foo`
      console.log(props.foo)
    })
    
  4. 在模板中我们可以使用小驼峰命名法(camelCase)为props命名,也可以是使用短横线命名法(kebab-case),但为了和 HTML保持一致,推荐使用短横线命名法。
  5. 上面我们说到的配置对象中,除了type属性外,还可以按照如下的方式编写:
    defineProps({
      // 1. 基础类型检查
      // (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
      propA: Number,
    
      // 2. 多种可能的类型
      propB: [String, Number],
    
      // 3. 必传,且为 String 类型
      propC: {
        type: String,
        required: true
      },
    
      // 4.必传但可为 null 的字符串
      propD: {
        type: [String, null],
        required: true
      },
    
      // 5.Number 类型的默认值
      propE: {
        type: Number,
        default: 100
      },
    
      // 6.对象类型的默认值
      propF: {
        type: Object,
        // 对象或数组的默认值
        // 必须从一个工厂函数返回。
        // 该函数接收组件所接收到的原始 prop 作为参数。
        default(rawProps) {
          return { message: 'hello' }
        }
      },
    
      // 7.自定义类型校验函数
      // 在 3.4+ 中完整的 props 作为第二个参数传入
      propG: {
        validator(value, props) {
          // The value must match one of these strings
          return ['success', 'warning', 'danger'].includes(value)
        }
      },
    
      // 8.函数类型的默认值
      propH: {
        type: Function,
        // 不像对象或数组的默认,这不是一个
        // 工厂函数。这会是一个用来作为默认值的函数
        default() {
          return 'Default function'
        }
      }
    })
    

当 prop 的校验失败后,Vue 会抛出一个控制台警告 (在开发模式下)。

defineEmits注意事项

  1. 该函数接收一个数组作为参数,数据每一项是事件名称,函数返回一个emit实例。
  2. 该函数必须放在script setup的顶级作用作用域中才能使用
  3. 在触发事件时,我们需要使用emit函数触发一个自定义事件,并传递参数。
    const emit = defineEmits(['change'])
    emit('change', 'hello')
    
2.setup函数中实现

setup函数中我们可以通过setup函数的两个参数来获取到props和emit对象。

  1. setup 函数传递两个参数,第一个参数就是父组件传入的props对象,第二个参数一个上下文对象,该上下文对象后续还会说到。
  2. props对象还需要通过选项式的写法来声明,才能使用。选项的值与上面的defineProps函数接收的参数一致。
    export default {
      props: ['foo'],
      setup(props,context) {
        // setup() 接收 props 作为第一个参数
        console.log(props.foo)
      }
    }
    
  3. context上挂载了emit对象,该对象本质是一个函数,与使用defineEmits函数创建的emit对象一致。
3.在template模板中使用
  1. 前面两个api都可以在template中直接通过关键是调用。
  2. props和emit对象通过 p r o p s 和 props和 propsemit来调用。

注意
如果子组件注册的事件与原生事件相同,则子组件只会触发注册事件,不会再响应原生事件。

2. defineModel(3.2+)

相信大家都知道Vue3中的v-model指令本质上是props名为modelValue和emit事件名为update:modelValue的组合。
因此在Vue3.2 版本之后,官方直接将这个组合封装到了defineModel宏函数中,以后再为组件绑定v-mode时,我们只需要在子组件中通过defineModel函数来声明即可。减少了代码量。
同时可以实现父子组件的数据通信.

  1. 这个宏函数接收一个配置参数
参数默认值描述
requiredfalse是否必传,如果为true,则父组件必须绑定v-model的值
defaultPropundefined默认的值,当父组件传递的值为undefined时会使用
  1. 该函数返回一个ref对象,并且如果在父组件中使用这个子组件,为子组件绑定一个v-model时,这个v-model的值就会被绑定给这个ref对象的value属性。一但这个ref变化就会触发父组件的数据更新,父组件数据主动更新也会触发子组件的更新。(这个宏函数的本质就是modelValue与update:modelValue的进一步封装)

3. 组件实例

在Vue中我们可以通过变量来绑定组件实例,在特定的生命周期函数中我们就可以通过变量来获取到组件实例对象。因此,我们就可以拿到组件暴露出来的属性与方法,从而时间组件间的数据通信。
步骤

  1. 父组件通过ref绑定来获取到子组件实例
  2. 子组件主动暴露某些属性与方法
  3. 父组件通过变量获取到子组件的属性与方法
    <!-- 父组件 -->
     <script setup>
    import { useTemplateRef, onMounted } from 'vue'
    import Child from './Child.vue'
    
    const childRef = useTemplateRef('child')
    
    onMounted(() => {
      // childRef.value 将持有 <Child /> 的实例
    })
    </script>
    
    <template>
      <Child ref="child" />
    </template>
    
    
    <!-- 子组件 -->
    <script setup>
    import { ref } from 'vue'
    
    const a = 1
    const b = ref(2)
    
    // 像 defineExpose 这样的编译器宏不需要导入
    defineExpose({
      a,
      b
    })
    </script>
    

注意事项

  1. 在最新版本的Vue中(3.5+)我们可以使用useTemplateRef hook函数来创建一个ref对象,并通过ref绑定到组件上。在3.5之前可以直接使用ref函数来创建。
  2. 在子组件使用script setup语法糖时,默认的组件实例是不会暴露任何的属性与方法(子组件私有),因此如果需要在父组件中获取到子组件属性与方法就需要使用defineExpose函数来暴露。该函数接收一个作为参数,每一个属性就是一个暴露的属性名称。
  3. 如果不使用script setup语法糖,此时访问到的就是整个子组件实例对象,包括props,data等等。此时访问到的就是子组件中的this上下文。

2. 依赖注入

上面我们提到数据通信方法仅限于父子组件之间,如果两个组件嵌套层级过深,子级组件如果想要访问父级组件的数据,就需要一层一层的传递props,这样显然是不合理的。因此Vue提供了依赖注入的方式来实现跨组件通信。

1.provide(提供)

我们可以在数据提供的组件中通过provide函数来提供数据,该函数接收两个参数:

  1. 第一个参数被称为注入名,可以是一个字符串或是一个 Symbol。后代组件会用注入名来查找期望注入的值。一个组件可以多次调用 provide(),使用不同的注入名,注入不同的依赖值。

  2. 第二个参数是提供的值,值可以是任意类型,包括响应式的状态.

    <script setup>
    import { provide } from 'vue'
    
    provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
    </script>
    
    <!--  如果不使用 <script setup>,请确保 provide() 是在 setup() 同步调用的: -->
    <script>
    import { provide } from 'vue'
    
    export default {
      setup() {
        provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
      }
    }
    </script>
    

注意事项

  1. 该函数无论在那种写法下都需要显示的导入,且必须爱setup中才能使用。
  2. 该函数在Vue全局的app实例上默认是挂载的,因此我们可以通过app.provide来提供数据,这样所有的Vue组件均可以访问到该数据。(该方法也被称为应用级Provide)
    
    import { createApp } from 'vue'
    
    const app = createApp({})
    
    app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
    

2. Inject (注入)

上面在父级组件中通过provide函数提供了数据,那么在子级组件中如何获取到该数据呢?Vue提供了inject函数来获取到父级组件提供的数据。

<script setup>
import { inject } from 'vue'

const message = inject('message')
</script>

该函数接受两个参数:

  1. 第一个参数就是注入数据的名称,可以为字符串或 Symbol。
  2. 第二个参数是默认值,当没有任何的组件提供该数据时,会使用这个默认值。

注意事项

  1. 该函数无论在那种写法下都需要显示的导入,且必须爱setup中才能使用。
  2. 在一些场景中,默认值可能需要通过调用一个函数或初始化一个类来取得。为了避免在用不到默认值的情况下进行不必要的计算或产生副作用,我们可以使用工厂函数来创建默认值。同时需要为该函数提供第三个参数并设置为true,代表第二个参数是一个工厂函数。
  3. 和响应式数据配合使用,这里可以注入一个ref响应式数据,通过在提供数据的时候为该数据提供一个修改的函数,作为一个对象的setter,这样就可以在子组件中修改该数据。
    <!-- 在供给方组件内 -->
    <script setup>
    import { provide, ref } from 'vue'
    
    const location = ref('North Pole')
    
    function updateLocation() {
      location.value = 'South Pole'
    }
    
    provide('location', {
      location,
      updateLocation
    })
    </script>
    
    <!-- 在注入方组件 -->
    <script setup>
    import { inject } from 'vue'
    
    const { location, updateLocation } = inject('location')
    </script>
    
    <template>
      <button @click="updateLocation">{{ location }}</button>
    </template>
    

3. 全局状态状态管理

如果我们的应用及其复杂,那么我们可能需要一个全局的状态管理来帮助我们更好的组织代码。
所谓的全局状态管理就是将应用中需要共享的数据抽取出来,在任意组件中都可以访问到这些数据。

1.VueX

VueX是一个专门为Vue.js设计的状态管理工具,它采用集中式存储管理应用的所有组件的状态。并且以响应的规则保证状态以一种可预测的方式发生变化。
基本使用

  1. 安装VueX

    npm install vuex --save
    
  2. 创建store实例

    import { createStore } from 'vuex'
    const store = createStore({
      state() {
        return { count: 0 }
      },
      mutations: {
        increment(state) {
          state.count++
        }
      },
      actions: {},
      getters: {}
      modules: {}
    })
    
  3. 在Vue实例中注册store

    import { createApp } from 'vue'
    import App from './App.vue'
    import store from './store'
    const app = createApp(App)
    app.use(store)
    app.mount('#app')
    
  4. 在组件中访问store

    <template>
      <div>{{ count }}</div>
      <button @click="increment">+</button>
    </template>
    <script setup>
      import { useStore } from 'vuex'
      const store = useStore()
      </script>
    

注意事項:

  1. 虽然vuex仍然可以作为vue3的全局状态管理,但官方不在推荐使用vuex,而是推荐使用pinia。因此这里只是简单的介绍一下vuex的使用。

2.Pinia

pinia为Vue3官方推荐的状态管理工具,基本使用和vuex类似。

1. 基本使用
  1. 安装

    npm install pinia --save
    
  2. 创建pinia实例

    import { createPinia } from 'pinia'
    const pinia = createPinia()
    export default pinia
    
  3. 创建store hook函数

    import { defineStore } from 'pinia'
    export const useStore = defineStore("main",{
      state: () => {
        return { count: 0 }
      },
      getters: {},
      actions: {}
    })
    
  4. 在Vue实例中注册pinia

    import { createApp } from 'vue'
    import App from './App.vue'
    import pinia from './pinia'
    const app = createApp(App)
    app.use(pinia)
    app.mount('#app')
    
  5. 在组件中访问store

    <template>
      <div>{{ count }}</div>
    </template>
    <script setup>
      import { useStore } from './store'
      const store = useStore()
    </script>
    
2.pinia各部分解析

(1).pinia创建

  • 在vue中我们如果需要使用pinia,就需要创建一个pinia实例,然后将实例挂载到app上。
  • 这里的创建pinia实例需要使用createPinia函数,该函数会返回一个pinia实例。使用时需要从pinia导入这个函数。

(2).store hook函数
我们需要在pinia中存放数据就需要由store,pinia提供了hook函数方式来创建store。我们首选需要从pinia中导入defineStore函数,该函数接收两个参数。

  1. 第一个 参数是个字符串,用来定义store的名称。
  2. 第二个参数可以是一个对象,也可以是一个工厂函数。
    • 如果是对象,则该对象中需要定义state,getters,actions三个属性。其中state属性是一个函数,用来定义state数据,getters属性是一个对象,用来定义getters(计算属性),actions属性是一个对象,用来定义actions(方法)。(state定义的数据均为响应式数据)
    • 如果为函数,急需要在该函数中返回一个对象,该对象的属性就会被作为store的属性。这里返回的对象的属性值一般是响应式数据。可以通过ref,computed等来定义。如果属性值为ref对象,则会被自动解包。同时作为store的state存在,如果是computed对象,则会被自动处理为getters(也会自动解包)。如果是一个函数,则会被自动处理为action。
  3. defineStore函数会返回一个hook函数,该函数可以用来创建store实例。调用这个函数不需要传入任何参数,该函数会返回一个store实例。
  4. 因此我们一般把这些hook函数通过一个文件统一导出,便于在组件中导入使用。

(3).组件内部使用
我们将hook函数导入之后,直接通过无参调用,即可得到有个store实例,可以在组件中直接调用对应的属性获取到数据。

3. 数据持久化

pinia本身的数据是存于内存当中,当再次刷新页面时,数据就会丢失。如果我们需要将数据持久化,可以使用pinia的插件来实现。pinia-plugin-persist

  1. 安装pinia-plugin-persist
    npm install pinia-plugin-persist --save
    
  2. 在pinia实例中注册插件
    import { createPinia } from 'pinia'
    import piniaPluginPersist from 'pinia-plugin-persist'
    const pinia = createPinia()
    pinia.use(piniaPluginPersist)
    export default pinia
    
  3. 在store中开启持久化
    import { defineStore } from 'pinia'
    export const useStore = defineStore("main",{
      state: () => {
        return { count: 0 }
      },
      getters: {},
      actions: {},
      persist: {
        enabled: true,
        strategies: [
          {
            key: 'main',
            storage: localStorage,
            paths: ['count']
          }
        ]
      }
    })
    
  • persist属性是一个对象,该对象中需要定义enabled和strategies两个属性。
  • enabled属性是一个布尔值,用来开启或关闭持久化。
  • strategies属性是一个数组,用来定义持久化的策略。该数组中可以定义多个策略,每个策略都是一个对象,该对象中需要定义key,storage和paths三个属性。
  • key属性是一个字符串,用来定义持久化的key。
  • storage属性是一个对象,用来定义持久化的存储方式。可以是localStorage,sessionStorage,cookie等。
  • paths属性是一个数组,用来定义需要持久化的属性。如果不定义,则默认持久化所有属性。
  • 如果需要持久化所有属性,则可以不定义paths属性。

如果defineStore函数中定义的是工厂函数,则该函数会接受第三个参数,该参数是一个对象,该对象中需要定义persist属性。属性的值和上面一样。同时persist属性可以简写,接收一个布尔值作为值,表示开启或关闭持久化。其缓存策略默认会使用localStorage。key默认会使用store的名称。paths默认会使用所有属性。

拓展: 这个插件通过指定保存策略的不同,也可以在uniapp中使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/887027.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【学习资源】人在环路的机器学习

说明&#xff1a;本文图片和内容来源 Human-in-the-Loop Machine Learning Human-in-the-Loop Machine Learning Active learning and annotation for human-centered AI by Robert (Munro) Monarch, June 2021 介绍Human-in-the-Loop的目标&#xff0c;学习过程&#xff0c…

gdb 调试 linux 应用程序的技巧介绍

使用 gdb 来调试 Linux 应用程序时&#xff0c;可以显著提高开发和调试的效率。gdb&#xff08;GNU 调试器&#xff09;是一款功能强大的调试工具&#xff0c;适用于调试各类 C、C 程序。它允许我们在运行程序时检查其状态&#xff0c;设置断点&#xff0c;跟踪变量值的变化&am…

基于Arduino的宠物食物分配器

创作本文的初衷是本人的一个养宠物的梦想&#xff08;因为家里人对宠物过敏&#xff0c;因此养宠物的action一直没有落实&#xff09;&#xff0c;但是梦想总是要有的哈哈哈哈哈。上周正好是和一个很好的朋友见面&#xff0c;聊到了养宠物的事情&#xff0c;她大概是讲到了喂宠…

震撼!工业史上第一家万级别规模的工业数字化设备效果图平台

耗时八年打造&#xff0c;国内第一家万级别规模的工业数字化设备效果图平台 平台&#xff1a;www.kingview3d.cn 创作者&#xff1a;kingview3d郭工 行业&#xff1a;煤矿综合自动化、污水处理、净水处理、楼宇暖通、环保工程、医药废水处理、二供、无负压加压站、提升泵站、一…

《NoSQL》非关系型数据库MongoDB 学习笔记!

Mongo基础&#xff1a; 使用数据库&#xff1a; 使用use 命令 后面跟着要使用的数据库名字即可&#xff0c; 例如&#xff1a;use cities, 值得注意的是&#xff0c; mongo中不像mysql&#xff0c; 还需要先创建数据库&#xff0c;后访问&#xff0c; mongo中&#xff0c;你无…

【WebGis开发 - Cesium】如何确保Cesium场景加载完毕

目录 引言一、监听场景加载进度1. 基础代码2. 加工代码 二、进一步封装代码1. 已知存在的弊端2. 封装hooks函数 三、使用hooks方法1. 先看下效果2. 如何使用该hooks方法 三、总结 引言 本篇为Cesium开发的一些小技巧。 判断Cesium场景是否加载完毕这件事是非常有意义的。 加载…

在 Elasticsearch Serverless 上使用 Eland

作者&#xff1a;来自 Elastic Quentin Pradet 本博客将向你展示如何使用 Eland 将机器学习模型导入 Elasticsearch Serverless&#xff0c;然后如何使用类似 Pandas 的 API 探索 Elasticsearch。 Elasticsearch Serverless 中的 NLP 自 Elasticsearch 8.0 起&#xff0c;可以…

SQL专项练习第二天

在数据处理和分析中&#xff0c;Hive 是一个强大的工具。本文将通过五个 Hive 相关的问题展示其在不同场景下的应用技巧。 先在home文件夹下建一个hivedata文件夹&#xff0c;把我们所需的数据写成txt文件导入到/home/hivedata/文件夹下面。 一、找出连续活跃 3 天及以上的用户…

【AI论文精读1】针对知识密集型NLP任务的检索增强生成(RAG原始论文)

目录 一、简介一句话简介作者、引用数、时间论文地址开源代码地址 二、摘要三、引言四、整体架构&#xff08;用一个例子来阐明&#xff09;场景例子&#xff1a;核心点&#xff1a; 五、方法 &#xff08;架构各部分详解&#xff09;5.1 模型1. RAG-Sequence Model2. RAG-Toke…

Python+Matplotlib创建y=sinx、y=cosx、y=sinx+cosx可视化

y sin x (奇函数)&#xff1a; 图像关于原点对称。 对于任何 x&#xff0c;sin(-x) -sin(x)&#xff0c;符合奇函数定义。 y cos x (偶函数)&#xff1a; 图像关于 y 轴对称。 对于任何 x&#xff0c;cos(-x) cos(x)&#xff0c;符合偶函数定义。 y sin x cos x (既…

安全帽头盔检测数据集 3类 12000张 安全帽数据集 voc yolo

安全帽头盔检测数据集 3类 12000张 安全帽数据集 voc yolo 安全帽头盔检测数据集介绍 数据集名称 安全帽头盔检测数据集 (Safety Helmet and Person Detection Dataset) 数据集概述 该数据集专为训练和评估基于YOLO系列目标检测模型&#xff08;包括YOLOv5、YOLOv6、YOLOv7…

LabVIEW机床加工监控系统

随着制造业的快速发展&#xff0c;机床加工的效率与稳定性成为企业核心竞争力的关键。传统的机床监控方式存在效率低、无法远程监控的问题。为了解决这些问题&#xff0c;开发了一种基于LabVIEW的机床加工监控系统&#xff0c;通过实时监控机床状态&#xff0c;改进生产流程&am…

Spring MVC__入门

目录 一、SpringMVC简介1、什么是MVC2、什么是SpringMVC 二、Spring MVC实现原理2.1核心组件2.2工作流程 三、helloworld1、开发环境2、创建maven工程3、配置web.xml4、创建请求控制器5、创建springMVC的配置文件6、测试HelloWorld7、总结 一、SpringMVC简介 1、什么是MVC MV…

html5 + css3(上)

目录 HTML初识基础认知web标准vscode的简介和使用注释 HTML标签学习排版标签标题和段落换行和水平线标签 文本格式化标签媒体标签图片标签图片-基本使用图片-属性 路径绝对路径相对路径 音频标签视频标签链接标签 HTML基础列表标签列表-无序和有序列表-自定义 表格标签表格-使用…

【JAVA开源】基于Vue和SpringBoot的周边产品销售网站

本文项目编号 T 061 &#xff0c;文末自助获取源码 \color{red}{T061&#xff0c;文末自助获取源码} T061&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

Java网络通信—UDP

0.小记 1.udp通信不需要建立socket管道&#xff0c;一边只管发&#xff0c;一边只管收 2.客户端&#xff1a;将数据&#xff08;byte&#xff09;打包成包裹&#xff08;DatagramPacket&#xff09;&#xff0c;写上地址&#xff08;IP端口&#xff09;&#xff0c;通过快递站&…

【HTML并不简单】笔记1-常用rel总结:nofollow、noopener、opener、noreferrer,relList

文章目录 rel"nofollow"rel"noopener"与rel"opener"rel"noreferrer"relList对象 《HTML并不简单&#xff1a;Web前端开发精进秘籍》张鑫旭&#xff0c;一些摘要&#xff1a; HTML&#xff0c;这门语言的知识体系非常庞杂&#xff0c;涉…

Nagle 算法:优化 TCP 网络中小数据包的传输

1. 前言 在网络通信中&#xff0c;TCP&#xff08;传输控制协议&#xff09;是最常用的协议之一&#xff0c;广泛应用于各种网络应用&#xff0c;如网页浏览、文件传输和在线游戏等。然而&#xff0c;随着互联网的普及&#xff0c;小数据包的频繁传输成为一个不容忽视的问题。…

php email功能实现:详细步骤与配置技巧?

php email发送功能详细教程&#xff1f;如何使用php email服务&#xff1f; 无论是用户注册、密码重置&#xff0c;还是订单确认&#xff0c;电子邮件都是与用户沟通的重要手段。AokSend将详细介绍如何实现php email功能&#xff0c;并提供一些配置技巧&#xff0c;帮助你更好…

spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理)

文章目录 【README】【1】文件上传与MultipartResolver【1.1】使用MultipartResolver进行文件上传【1.2】springmvc处理multipart多部件请求流程【1.3】使用springmvc上传文件代码实现&#xff08;springmvc6.10版本&#xff09;&#xff1a; 【2】Handler与HandlerAdaptor&…