>  기사  >  웹 프론트엔드  >  Vue 명령어가 구성 요소 통신을 구현하는 방법

Vue 명령어가 구성 요소 통신을 구현하는 방법

藏色散人
藏色散人원래의
2023-01-31 16:03:401767검색

Vue 명령어는 구성 요소 통신 방법을 구현합니다. 1. 상위 구성 요소는 "props"를 통해 하위 구성 요소에 데이터를 전달하고 하위 구성 요소는 "$emit"를 통해 상위 구성 요소와 통신할 수 있습니다. 2. "ref/$refs를 통해; " 속성 컴포넌트 통신을 실현합니다. 3. eventBus 이벤트 버스를 통해 컴포넌트 통신을 실현합니다. 4. Vuex를 사용하여 컴포넌트 통신을 실현합니다. 5. "$attrs" 및 "$listeners" 등을 통해 컴포넌트 통신을 실현합니다.

Vue 명령어가 구성 요소 통신을 구현하는 방법

이 튜토리얼의 운영 환경: Windows 10 시스템, Vue 버전 3, DELL G3 컴퓨터

vue 명령은 구성 요소 통신을 어떻게 구현합니까?

Vue가 구성 요소 간 통신을 구현하는 7가지 방법

1.props / $emit

상위 구성 요소는 props$emit 하위 구성 요소는 상위 구성 요소와 통신할 수 있습니다. props的方式向子组件传递数据,而通过$emit 子组件可以向父组件通信:

  • 父传子:父组件通过import引入子组件,并注册,在子组件标签上添加要传递的属性,子组 件通过props接收,接收有两种形式一是通过数组形式[‘要接收的属性’ ],二是通过对象形式{ }
  • 子传父:父组件向子组件传递事件方法,子组件通过$emit触发事件,回调给父组件

props的特点:

  • props只能是父组件向子组件进行传值,props使得父子组件之间形成一个单向的下行绑定。子组件的数据会随着父组件的更新而响应式更新;但是子组件无法引起父组件的数据更新。
  • props可以显示定义一个或一个以上的数据,对于接收的数据,可以是各种数据类型,同样也可以是传递一个对象或函数。
  • props属性名规则:若在props中使用驼峰形式,模板中标签需要使用短横线的形式来书写。

 代码示例:

父传子(prop的用法)

父组件:

<template>
    <div id="father">
        <son :msg="msg" :fn="myFunc"></son>
    </div>
</template>

<script>
import son from "./son.vue";
export default {
    name: "father",
    components: {
        son
    },
    data() {
        msg: "我是父组件";
    },
    methods: {
        myFunc() {
            console.log("我是父组件的方法");
        }
    }
};
</script>

子组件:

<template>
    <div id="son">
        <p>{{msg}}</p>
        <button @click="fn">按钮</button>
    </div>
</template>
<script>
export default {
    name: "son",
    props: ["msg", "fn"]
};
</script>

子传父($emit的用法)

$emit 绑定一个自定义事件,当这个事件被执行的时候就会将参数传递给父组件,而父组件通过v-on监听并接收参数

父组件:

<template>
  <div id="father">
    <son :arrList="arrList" @changeIndex="changeIndex"></son>
    <p>{{currentIndex}}</p>
  </div>
</template>

<script>
import son from './son.vue'
export default {
  name: 'father',
  components: { son},
  data() {
    return {
      currentIndex: -1,
      arrList: ['龙族', '绘梨衣', '前端','后端']
    }
  },
  methods: {
    changeIndex(index) {
      this.currentIndex = index
    }
  }
}
</script>

子组件:

<template>
  <div>
    <div v-for="(item, index) in arrList" :key="index" @click="emitIndex(index)">{{item}}</div>
  </div>
</template>

<script>
export default {
  props: ['arrList'],
  methods: {
    emitIndex(index) {
      this.$emit('changeIndex', index) // 触发父组件的方法,并传递参数index
    }
  }
}
</script>

2.ref / $refs

ref:这个属性用在子组件上,它的引用就指向了该子组件的实例,可以通过实例来访问组件的数据和方法;如果在普通的 DOM 元素上使用,引用指向的就是 DOM元素

父组件:

<template>
  <child ref="child"></component-a>
</template>
<script>
  import child from './child.vue'
  export default {
    components: { child },
    mounted () {
      console.log(this.$refs.child.name);  // mySon
      this.$refs.child.sayHello();  // Hello father!
    }
  }
</script>

子组件:

<template>
  <div id="app"></div>
</template>
<script>
export default {
  name:'child',
  data () {
    return {
      name: 'mySon'
    }
  },
  methods: {
    sayHello () {
      console.log('Hello father!')
    }
  }
}
</script>

3.eventBus(事件总线)

其原理就是:事件订阅发布,eventBus

  • 상위 구성 요소에서 하위 구성 요소로 전달: 상위 구성 요소는 가져오기를 통해 하위 구성 요소를 소개하고 등록한 후 전달할 속성을 추가합니다. 구성 요소는 props를 통해 수신합니다. 수신 형식에는 두 가지가 있습니다. 하나는 배열 형식['수신할 속성']을 통하는 것이고, 다른 하나는 객체 형식을 통하는 것입니다. {}
  • 아들에서 상위로: 상위 구성 요소는 이벤트 메서드를 하위 구성 요소에 전달하고, 하위 구성 요소는 $emit를 통해 이벤트를 트리거하고 상위 구성 요소를 다시 호출합니다

props의 특징:

  • Prop는 상위 구성 요소에서 하위 구성 요소로만 전송될 수 있으며 값을 전달하며 prop은 상위 구성 요소와 하위 구성 요소 간의 단방향 다운스트림 바인딩을 형성합니다. 하위 구성 요소의 데이터는 상위 구성 요소가 업데이트됨에 따라 업데이트됩니다. 그러나 하위 구성 요소로 인해 상위 구성 요소의 데이터가 업데이트될 수는 없습니다.
  • Props는 하나 이상의 데이터를 명시적으로 정의할 수 있으며, 수신된 데이터는 다양한 데이터 유형일 수도 있고 객체나 함수를 전달할 수도 있습니다.
  • Props 속성 이름 규칙: Props에 카멜 표기법을 사용하는 경우 템플릿의 태그를 대시 형식으로 작성해야 합니다.

코드 예:

pass from father to son(prop 사용법)

상위 구성 요소:

// event-bus.js

import Vue from 'vue'
export const EventBus = new Vue()

하위 구성 요소:

<template>
  <div>
    <first-com></first-com>
    <second-com></second-com>
  </div>
</template>

<script>
import firstCom from './firstCom.vue'
import secondCom from './secondCom.vue'
export default {
  components: { firstCom, secondCom }
}
</script>

pass from son to parent ($ Emit 사용법)

$emit는 이 이벤트가 실행되면 매개변수가 상위 구성요소로 전달되고 상위 구성요소는 v-on

부모 구성요소를 통해 매개변수를 수신하고 수신합니다.
<template>
  <div>
    <button @click="add">点击增加</button>    
  </div>
</template>

<script>
import {EventBus} from './event-bus.js' // 引入事件中心

export default {
  data(){
    return{
      num:0
    }
  },
  methods:{
    add(){
      EventBus.$emit('addition', {
        num:this.num++
      })
    }
  }
}
</script>
🎜 하위 구성 요소: 🎜
<template>
  <div>求和: {{count}}</div>
</template>

<script>
import { EventBus } from './event-bus.js'
export default {
  data() {
    return {
      count: 0
    }
  },
  mounted() {
    EventBus.$on('addition', param => {
      this.count = this.count + param.num;
    })
  }
}
</script>
🎜2.ref / $refs🎜🎜ref: 이 속성은 하위 구성 요소에 사용되며 해당 참조는 하위 구성 요소의 인스턴스를 가리킵니다. 일반 DOM 요소에 사용되는 참조는 DOM 요소 를 가리킵니다. 🎜🎜상위 구성 요소: 🎜
// index.js
 
// 自动挂载指定目录下的store
import Vue from 'vue'
import Vuex from 'vuex'
 
Vue.use(Vuex)
 
let modules = {}
 
// @/store/module 目录下的文件自动挂载为 store 模块
const subModuleList = require.context('@/store/modules', false, /.js$/)
subModuleList.keys().forEach(subRouter => {
  const moduleName = subRouter.substring(2, subRouter.length - 3)
  modules[moduleName] = subModuleList(subRouter).default
})
//也可自己手动挂载(自行选择)
 
export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  modules
})
🎜하위 구성 요소: 🎜
// user.js
 
import user from '@/utils/user.js'
import userApi from '@/apis/user'
import { OPEN_ACCOUNT_STAGE, STAGE_STATUS } from '@/constant'
 
let getUserPromise = null
 
export default {
  namespaced: true,
  state() {
    return {
      userInfo: null, // 用户信息
      isLogined: !!user.getToken(), // 是否已经登录
    }
  },
  mutations: {
    // 更新用户信息
    updateUser(state, payload) {
      state.isLogined = !!payload
      state.userInfo = payload
    },
  },
  actions: {
    // 获取当前用户信息
     getUserInfo(context, payload) {
      //相关代码
    },
 
    // 登出
     logout(context, payload = {}) {
      // 是否手动退出
      const { manual } = payload
      if (manual) {
        await userApi.postLogout()
      }
      user.clearToken()
      context.commit('updateUser', null)
    },
  }
}

3.eventBus(이벤트 버스)

🎜원칙: 이벤트 구독 게시, eventBus라고도 함 Vue에서 통신 브리지 개념으로 사용할 수 있는 이벤트 버스이므로 모든 구성 요소가 동일한 이벤트 센터를 공유하는 것과 같습니다. 이벤트를 센터에 보내거나 수신하도록 등록하면 구성 요소가 다른 구성 요소에 알릴 수 있습니다. 🎜🎜단계는 다음과 같습니다. 🎜🎜 (1) 구성 요소 간의 통신을 관리하기 위한 이벤트 센터 만들기 🎜
import Vue from 'vue'
import App from '@/app.vue'
import { router } from '@/router'
import store from '@/store/index'
 
const vue = new Vue({
  el: '#app',
  name: 'root',
  router,
  store,
  render: h => h(App),
})
🎜 (2) 이벤트 보내기 두 개의 형제 구성 요소인 firstCom과 secondCom이 있다고 가정합니다. 🎜🎜firstCom과 secondCom의 상위 구성 요소: 🎜
this.$store.state.user.isLogined
this.$store.state.user.userInfo
this.$store.commit('user/updateUser', {})
 await this.$store.dispatch('user/logout', { manual: true })
🎜 firstCom 구성 요소에서 이벤트 보내기: 🎜
<template>
   <child :name="name" :age="age" :infoObj="infoObj" @updateInfo="updateInfo" @delInfo="delInfo" />
</template>
<script>
    import Child from '../components/child.vue'
    export default {
        name: 'father',
        components: { Child },
        data () {
            return {
                name: '绘梨衣',
                age: 22,
                infoObj: {
                    from: '河北',
                    job: 'superman',
                    hobby: ['reading', 'writing', 'eating']
                }
            }
        },
        methods: {
            updateInfo() {
                console.log('update info');
            },
            delInfo() {
                console.log('delete info');
            }
        }
    }
</script>
🎜 (3) 이벤트 받기 🎜🎜 secondCom 구성 요소에서 이벤트 받기: 🎜
<template>
    <!-- 通过 $listeners 将父作用域中的事件,传入 grandSon 组件,使其可以获取到 father 中的事件 -->
    <grand-son :height="height" :weight="weight" @addInfo="addInfo" v-bind="$attrs" v-on="$listeners"  />
</template>
<script>
    import GrandSon from '../components/grandSon.vue'
    export default {
        name: 'child',
        components: { GrandSon },
        props: ['name'],
        data() {
          return {
              height: '170cm',
              weight: '55kg'
          };
        },
        created() {
            console.log(this.$attrs); 
       // 结果:age, infoObj, 因为父组件共传来name, age, infoObj三个值,由
             //于name被 props接收了,所以只有age, infoObj属性
            console.log(this.$listeners); // updateInfo: f, delInfo: f
        },
        methods: {
            addInfo () {
                console.log('add info')
            }
        }
    }
</script>
🎜 위 코드에서 이는 이벤트 버스에 num 값을 저장하는 것과 같습니다. 구성 요소에 직접 액세스할 수 있습니다. 이벤트 버스는 브리지와 동일하며 구성 요소는 이를 통해 통신하지 않습니다. 비교적 간단한 것처럼 보이지만 이 방법에는 상수가 있습니다. 프로젝트가 너무 크면 나중에 이 방법을 통신에 사용하기가 어렵습니다. 🎜🎜4.Vuex🎜🎜Vuex는 Vue.js 애플리케이션용으로 특별히 개발된 상태 관리 패턴입니다. 중앙 집중식 저장소를 사용하여 애플리케이션의 모든 구성 요소 상태를 관리하고 해당 규칙을 사용하여 상태가 예측 가능한 방식으로 변경되도록 합니다. 🎜🎜🎜Vuex는 동일한 상태와 다양한 동작에 의존하는 여러 보기의 필요성을 해결합니다. views 동일한 상태를 변경하는 문제는 개발자의 에너지를 구성 요소 간 데이터 전송보다는 데이터 업데이트에 집중합니다🎜🎜🎜Vuex 모듈:🎜
  • state:用于数据的存储,是store中的唯一数据源
  • getters:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算
  • mutations:类似函数,改变state数据的唯一途径,且不能用于处理异步事件
  • actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作
  • modules:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护

Vuex使用步骤:

(1)这里我们先新建 store文件夹, 对Vuex进行一些封装处理

在 store 文件夹下添加 index.js 文件

// index.js
 
// 自动挂载指定目录下的store
import Vue from 'vue'
import Vuex from 'vuex'
 
Vue.use(Vuex)
 
let modules = {}
 
// @/store/module 目录下的文件自动挂载为 store 模块
const subModuleList = require.context('@/store/modules', false, /.js$/)
subModuleList.keys().forEach(subRouter => {
  const moduleName = subRouter.substring(2, subRouter.length - 3)
  modules[moduleName] = subModuleList(subRouter).default
})
//也可自己手动挂载(自行选择)
 
export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  modules
})

(2)在 store 文件夹下添加 module 文件夹,在module文件夹再新建 user.js 文件

// user.js
 
import user from '@/utils/user.js'
import userApi from '@/apis/user'
import { OPEN_ACCOUNT_STAGE, STAGE_STATUS } from '@/constant'
 
let getUserPromise = null
 
export default {
  namespaced: true,
  state() {
    return {
      userInfo: null, // 用户信息
      isLogined: !!user.getToken(), // 是否已经登录
    }
  },
  mutations: {
    // 更新用户信息
    updateUser(state, payload) {
      state.isLogined = !!payload
      state.userInfo = payload
    },
  },
  actions: {
    // 获取当前用户信息
     getUserInfo(context, payload) {
      //相关代码
    },
 
    // 登出
     logout(context, payload = {}) {
      // 是否手动退出
      const { manual } = payload
      if (manual) {
        await userApi.postLogout()
      }
      user.clearToken()
      context.commit('updateUser', null)
    },
  }
}

(3)然后在项目的 main.js 文件中引入

import Vue from 'vue'
import App from '@/app.vue'
import { router } from '@/router'
import store from '@/store/index'
 
const vue = new Vue({
  el: '#app',
  name: 'root',
  router,
  store,
  render: h => h(App),
})

(4)封装很愉快结束了了,然后就正常操作即可

this.$store.state.user.isLogined
this.$store.state.user.userInfo
this.$store.commit('user/updateUser', {})
 await this.$store.dispatch('user/logout', { manual: true })

5.$attrs与 $listeners

现在我们来讨论另一种情况:如果我们给出的组件关系图中A组件与D组件是隔代关系, 那它们之前进行通信有哪些方式呢?

  1. 使用props绑定来进行一级一级的信息传递, 如果D组件中状态改变需要传递数据给A, 使用事件系统一级级往上传递
  2. 使用eventBus,这种情况下还是比较适合使用, 但是碰到多人合作开发时, 代码维护性较低, 可读性也低
  3. 使用Vuex来进行数据管理, 但是如果仅仅是传递数据, 而不做中间处理,使用Vuex处理感觉有点大材小用了.

所以就有了 $attrs / $listeners ,通常配合 inheritAttrs 一起使用。

inheritAttrs

默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。

通过设置 inheritAttrs 到 false,这些默认行为将会被去掉。而通过实例 property $attrs 可以让这些 attribute 生效,且可以通过 v-bind 显性的绑定到非根元素上。

注意:这个选项不影响 class 和 style 绑定,Vue对class和style做了特殊处理

简单来说就是

  • inheritAttrs:true 时继承除props之外的所有属性
  • inheritAttrs:false 只继承class 和 style属性
  • $attrs:包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。当一个组件没有声明任何 props 时,它包含所有父作用域的绑定 (class 和 style 除外)。
  • $listeners:包含了父作用域中的 (不含 .native 修饰符) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件。它是一个对象,里面包含了作用在这个组件上的所有事件监听器,相当于子组件继承了父组件的事件。

代码示例:

父组件:

<template>
   <child :name="name" :age="age" :infoObj="infoObj" @updateInfo="updateInfo" @delInfo="delInfo" />
</template>
<script>
    import Child from '../components/child.vue'
    export default {
        name: 'father',
        components: { Child },
        data () {
            return {
                name: '绘梨衣',
                age: 22,
                infoObj: {
                    from: '河北',
                    job: 'superman',
                    hobby: ['reading', 'writing', 'eating']
                }
            }
        },
        methods: {
            updateInfo() {
                console.log('update info');
            },
            delInfo() {
                console.log('delete info');
            }
        }
    }
</script>

 儿子组件:

<template>
    <!-- 通过 $listeners 将父作用域中的事件,传入 grandSon 组件,使其可以获取到 father 中的事件 -->
    <grand-son :height="height" :weight="weight" @addInfo="addInfo" v-bind="$attrs" v-on="$listeners"  />
</template>
<script>
    import GrandSon from '../components/grandSon.vue'
    export default {
        name: 'child',
        components: { GrandSon },
        props: ['name'],
        data() {
          return {
              height: '170cm',
              weight: '55kg'
          };
        },
        created() {
            console.log(this.$attrs); 
       // 结果:age, infoObj, 因为父组件共传来name, age, infoObj三个值,由
             //于name被 props接收了,所以只有age, infoObj属性
            console.log(this.$listeners); // updateInfo: f, delInfo: f
        },
        methods: {
            addInfo () {
                console.log('add info')
            }
        }
    }
</script>

孙子组件:

<template>
    <div>
        {{ $attrs }} --- {{ $listeners }}
    <div>
</template>
<script>
    export default {
        props: ['weight'],
        created() {
            console.log(this.$attrs); // age, infoObj, height 
            console.log(this.$listeners) 
          // updateInfo: f, delInfo: f, addInfo: f
            this.$emit('updateInfo') 
          // 可以触发 father 组件中的updateInfo函数
        }
    }
</script>

6.$parent / $children

  • 使用$parent可以让组件访问父组件的实例(访问的是上一级父组件的属性和方法)。
  • 使用 $children 可以让组件访问子组件的实例,但是, $children 并不能保证顺序,并且访问的数据也不是响应式的。

注意:

  • 通过 $parent 访问到的是上一级父组件的实例,可以使用 $root 来访问根组件的实例
  • 在组件中使用$children拿到的是所有的子组件的实例,它是一个数组,并且是无序的
  • 在根组件 #app 上拿 $parent 得到的是 new Vue()的实例,在这实例上再拿 $parent 得到的是undefined,而在最底层的子组件拿 $children 是个空数组
  • $children 的值是数组,而 $parent是个对象

用法:

子组件:

<template>
  <div>
    <span>{{message}}</span>
    <p>父组件的值为:  {{parentVal}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Vue'
    }
  },
  computed:{
    parentVal(){
      return this.$parent.msg;
    }
  }
}
</script>

父组件:

<template>
  <div class="app">
    <div>{{msg}}</div>
    <child></child>
    <button @click="change">点击改变子组件值</button>
  </div>
</template>

<script>
import child from './child.vue'
export default {
  components: { child },
  data() {
    return {
      msg: 'Hello'
    }
  },
  methods: {
    change() {
      // 获取到子组件
      this.$children[0].message = 'JavaScript'
    }
  }
}
</script>

7.依赖注入(provide / inject)

这种方式就是vue中依赖注入,该方法用于 父子组件之间 的通信。当然这里所说的父子不一定是真正的父子,也可以是祖孙组件,在层数很深的情况下,可以使用这种方式来进行传值。就不用一层一层的传递数据了。

provide和inject是vue提供的两个钩子,和data、methods是同级的。并且provide的书写形式和data一样。

  • provide 钩子用来发送数据或方法
  • inject钩子用来接收数据或方法

注意: 依赖注入所提供的属性是非响应式的。

用法:

父组件:

provide() { 
    return {     
        num: this.num  
    };
}

子组件:

inject: ['num']

还有另一种写法,这种写法可以访问父组件中的所有属性:

provide() {
 return {
    app: this
  };
}
data() {
 return {
    num: 111
  };
}

inject: ['app']
console.log(this.app.num)

总结

1.父子组件间通信

  • 子组件通过 props 属性来接受父组件的数据,然后父组件在子组件上注册监听事件,子组件通过 emit 触发事件来向父组件发送数据。
  • 通过 ref 属性给子组件设置一个名字。父组件通过 $refs 组件名来获得子组件,子组件通过 $parent 获得父组件,这样也可以实现通信。
  • 使用 provide/inject,在父组件中通过 provide提供变量,在子组件中通过 inject 来将变量注入到组件中。不论子组件有多深,只要调用了 inject 那么就可以注入 provide中的数据

2.跨代组件间通信

跨代组件间通信其实就是多层的父子组件通信,同样可以使用上述父子组件间通信的方法,只不过需要多层通信会比较麻烦。

3.兄弟组件间通信

通过 $parent + $refs 以父组件为中间人来获取到兄弟组件,也可以进行通信。

4.任意组件间通信

使用 eventBus ,其实就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。它的本质是通过创建一个空的 Vue 实例来作为消息传递的对象,通信的组件引入这个实例,通信的组件通过在这个实例上监听和触发事件,来实现消息的传递。

推荐学习:《vue.js视频教程

위 내용은 Vue 명령어가 구성 요소 통신을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.