>  기사  >  웹 프론트엔드  >  [요약] Vue 컴포넌트의 11가지 통신 방법

[요약] Vue 컴포넌트의 11가지 통신 방법

青灯夜游
青灯夜游앞으로
2023-04-18 17:03:291177검색

Vue 구성 요소 간에 어떻게 통신하나요? 다음 글은 Vue 컴포넌트의 11가지 통신 방법을 요약한 것입니다. 여러분에게 도움이 되기를 바랍니다.

[요약] Vue 컴포넌트의 11가지 통신 방법

구성 요소는 vue.js의 가장 강력한 기능 중 하나이며 구성 요소 인스턴스의 범위는 서로 독립적입니다. 즉, 서로 다른 구성 요소 간의 데이터가 서로 참조할 수 없습니다. Vue 컴포넌트 간 값 전송 방법은 다양하며, 이는 부모-자식 값 전송, 이벤트 값 전송에 국한되지 않습니다.

provide / inject

이 옵션 세트는 구성 요소 계층 구조의 깊이에 관계없이 상위 구성 요소가 모든 하위 구성 요소에 종속성을 주입할 수 있도록 함께 사용해야 하며, 업스트림 및 다운스트림 관계가 확립되면 항상 유효합니다. [관련 권장 사항: vuejs 비디오 튜토리얼, 웹 프론트 엔드 개발]

// provide 选项应该是一个对象或返回一个对象的函数
// inject 选项应该是:一个字符串数组,或一个对象,对象的 key 是本地的绑定名

// 父级组件提供 'foo'
var Provider = {
  provide: {
    foo: 'bar'
  },
  // ...
}

// 子组件注入 'foo' (数组形式)
var Child = {
  inject: ['foo'], 
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}

或 (对象形式)
var Child = {
  inject: {
  	foo: { 
  		from: 'bar', // 可选
  		default: 'self defined content' // 默认值
  	}
  }, 
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}

주의해야 할 점: Vue 2.2.1 이상에서는 props와 데이터가 초기화되기 전에 주입된 값을 얻습니다

// 使用一个注入的值作为数据(data)的入口 或者 属性(props)的默认值
const Child = {
  inject: ['foo'],
  data () {
    return {
      bar: this.foo // 输出bar的值与foo相同
    }
  }
}

const Child = {
  inject: ['foo'],
  props: {
    bar: {
      default () {
        return this.foo
      }
    }
  }
}

-----------------------------------------------------------------------------------------------
// 注入可以通过设置默认值使其变成可选项
const Child = {
  inject: {
    foo: { // 注意: 此处key值必须是父组件中provide的属性的key
      from: 'bar', // 属性是在可用的注入内容中搜索用的 key (字符串或 Symbol), data或者props中的可搜索值
      default: 'foo' // 属性是降级情况下使用的 value, 默认值为 ‘foo’
    }
  }
}

// 与 prop 的默认值类似
const Child = {
  inject: {
    foo: {
      from: 'bar',
      default: () => [1, 2, 3] // 默认值为引用类型时,需要使用一个工厂方法返回对象
    }
  }
}

소개Vue2.2.0에는 구성 요소 계층 구조의 깊이에 관계없이 상위 구성 요소가 모든 하위 구성 요소에 종속성을 주입할 수 있도록 하려면 이 옵션 쌍을 함께 사용해야 하며 다음과 같은 경우 항상 적용됩니다. 업스트림 및 다운스트림 관계가 설정됩니다. 간단히 말해서: 상위 구성 요소에서 공급자를 통해 변수를 제공한 다음 하위 구성 요소에 주입을 통해 변수를 주입합니다. 제공/주입 API는 주로 교차 수준 구성 요소 간의 통신 문제를 해결하지만, 사용 시나리오는 주로 하위 구성 요소가 상위 구성 요소의 상태를 획득하는 것이며 교차 수준 구성 요소 간에 활성 프로비저닝과 종속성 주입 간의 관계가 설정됩니다. .

CaseA.vue와 B.vue라는 두 가지 구성 요소가 있다고 가정합니다. B는 A

A.vue

export default {
  provide: {
    name: '浪里行舟'
  }
}

B.vue

export default {
  inject: ['name'],
  mounted () {
    console.log(this.name);  // 浪里行舟
  }
}

A.vue에서 볼 수 있습니다. 우리 A는 제공: 이름은 Langli Pingzhou 값으로 설정됩니다. 해당 기능은 모든 하위 구성 요소에 이름 변수를 제공하는 것입니다. B.vue에서는 inject를 통해 컴포넌트 A에서 제공하는 name 변수가 주입됩니다. 그러면 컴포넌트 B에서는 this.name을 통해 이 변수에 직접 접근할 수 있으며, 그 값도 동일합니다. API 제공/주입의 핵심 사용법입니다.

제공 및 주입 바인딩은 응답하지 않는다는 점에 유의해야 합니다. 이는 의도적인 것입니다. 그러나 청취 가능한 객체를 전달하면 객체의 속성은 여전히 ​​반응합니다.---vue 공식 문서 따라서 위에서 A.vue의 이름이 변경되면 B.vue의 this.name은 변경되지 않고 여전히 파도를 타고 항해할 것입니다.

제공 및 주입 데이터 응답성을 구현하는 방법

일반적으로 두 가지 방법이 있습니다.

  • 상위 구성 요소의 인스턴스를 제공한 다음 하위 구성 요소에 종속성을 주입하여 하위 구성 요소에서 조상을 직접 수정할 수 있습니다. 그러나 이 방법은 이 인스턴스에 props 및 메서드 등 불필요한 것들이 많이 탑재된다는 단점이 있습니다. 반응형 제공을 최적화하려면 최신 2.6 API Vue.observable을 사용하세요. 예: Sun 구성 요소 D, E 및 F는 구성 요소 A가 전달한 색상 값을 얻고 응답성 데이터 변경을 실현할 수 있습니다. 즉, 구성 요소 A의 색상이 변경된 후에 구성 요소 D, E 및 F는 그에 따라 변경되지 않습니다. 핵심 코드는 다음과 같습니다. )
  • A 컴포넌트
  • <div>
          <h1>A 组件</h1>
          <button @click="() => changeColor()">改变color</button>
          <ChildrenB />
          <ChildrenC />
    </div>
    ......
      data() {
        return {
          color: "blue"
        };
      },
      // provide() {
      //   return {
      //     theme: {
      //       color: this.color //这种方式绑定的数据并不是可响应的
      //     } // 即A组件的color变化后,组件D、E、F不会跟着变
      //   };
      // },
      provide() {
        return {
          theme: this//方法一:提供祖先组件的实例
        };
      },
      methods: {
        changeColor(color) {
          if (color) {
            this.color = color;
          } else {
            this.color = this.color === "blue" ? "red" : "blue";
          }
        }
      }
      // 方法二:使用2.6最新API Vue.observable 优化响应式 provide
      // provide() {
      //   this.theme = Vue.observable({
      //     color: "blue"
      //   });
      //   return {
      //     theme: this.theme
      //   };
      // },
      // methods: {
      //   changeColor(color) {
      //     if (color) {
      //       this.theme.color = color;
      //     } else {
      //       this.theme.color = this.theme.color === "blue" ? "red" : "blue";
      //     }
      //   }
      // }
F 컴포넌트

<template functional>
  <div class="border2">
    <h3 :style="{ color: injections.theme.color }">F 组件</h3>
  </div>
</template>
<script>
export default {
  inject: {
    theme: {
      //函数式组件取值不一样
      default: () => ({})
    }
  }
};
</script>

프로바이더와 인젝션은 주로 고급 플러그인/컴포넌트 라이브러리에 대한 사용 사례를 제공하지만 비즈니스에서 능숙하게 사용할 수 있다면 절반의 노력으로 두 배의 결과를 얻으세요!

props(부모에서 아들로 전달)

// 创建组件
Vue.component(&#39;props-demo-advanced&#39;, {
  props: {
    age: {
      type: Number,
      default: 0
    }
  }
})

// 父组件中注册和使用组件,并传值
<props-demo-advanced :age="age"> </props-demo-advanced>
props/상위 구성 요소 A는 props를 통해 하위 구성 요소 B에 전달되고 B 구성 요소에서는 $emit를 통해 B에서 A로, A 구성 요소 방식에서는 v-on으로 전달됩니다. 달성하기 위해.

Case

: 상위 구성 요소가 하위 구성 요소에 값을 전달합니다. 다음 예는 상위 구성 요소가 하위 구성 요소에 값을 전달하는 방법을 보여줍니다. 상위 구성 요소에서 데이터를 가져오는 방법 하위 구성 요소의 App.vue Users.vue$emitApp.vue 상위 구성 요소

<template>
  <div id="app">
    <users v-bind:users="users"></users>//前者自定义名称便于子组件调用,后者要传递数据名
  </div>
</template>
<script>
import Users from "./components/Users"
export default {
  name: &#39;App&#39;,
  data(){
    return{
      users:["Henry","Bucky","Emily"]
    }
  },
  components:{
    "users":Users
  }
}
users 하위 구성 요소 users:["Henry","Bucky","Emily"]
<template>
  <div class="hello">
    <ul>
      <li v-for="user in users">{{user}}</li>//遍历传递过来的值,然后呈现到页面
    </ul>
  </div>
</template>
<script>
export default {
  name: &#39;HelloWorld&#39;,
  props:{
    users:{           //这个就是父组件中子标签自定义名字
      type:Array,
      required:true
    }
  }
}
</script>

Summary

: 상위 구성 요소는 props를 통해 하위 구성 요소에 데이터를 전달합니다.

참고

: 구성 요소에는 데이터, 소품, 계산의 세 가지 형태의 데이터가 있습니다. 형태) 다음 예는 하위 구성 요소가 상위 구성 요소에 값을 전달하는 방법을 보여줍니다. "Vue.js Demo"를 클릭하면 하위 구성 요소가 상위 구성 요소에 값을 전달하고 텍스트가 "값이 전달되었습니다"에서 "하위 구성 요소가 전달됩니다"로 변경됩니다. 상위 구성 요소에 대한 값." " 하위 구성 요소에서 상위 구성 요소로 값 전송을 실현합니다.

하위 구성 요소

// 子组件Child, 负载payload可选
this.$emit(&#39;eventName&#39;, payload)

// 父组件 Parent
<Parent @evnetName="sayHi"></Parent>
상위 구성 요소
<template>
  <header>
    <h1 @click="changeTitle">{{title}}</h1>//绑定一个点击事件
  </header>
</template>
<script>
export default {
  name: &#39;app-header&#39;,
  data() {
    return {
      title:"Vue.js Demo"
    }
  },
  methods:{
    changeTitle() {
      this.$emit("titleChanged","子向父组件传值");//自定义事件  传递值“子向父组件传值”
    }
  }
}
</script>

요약: 하위 구성 요소는 이벤트를 통해 상위 구성 요소에 메시지를 보냅니다. 실제로 하위 구성 요소는 자체 데이터를 상위 구성 요소로 보냅니다.

$emit/$on这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案vuex。

1.具体实现方式:

var Event=new Vue();
Event.$emit(事件名,数据);
Event.$on(事件名,data => {});

案例 : 假设兄弟组件有三个,分别是A、B、C组件,C组件如何获取A或者B组件的数据

<div id="itany">
	<my-a></my-a>
	<my-b></my-b>
	<my-c></my-c>
</div>
<template id="a">
  <div>
    <h3>A组件:{{name}}</h3>
    <button @click="send">将数据发送给C组件</button>
  </div>
</template>
<template id="b">
  <div>
    <h3>B组件:{{age}}</h3>
    <button @click="send">将数组发送给C组件</button>
  </div>
</template>
<template id="c">
  <div>
    <h3>C组件:{{name}},{{age}}</h3>
  </div>
</template>
<script>
var Event = new Vue();//定义一个空的Vue实例
var A = {
	template: &#39;#a&#39;,
	data() {
	  return {
	    name: &#39;tom&#39;
	  }
	},
	methods: {
	  send() {
	    Event.$emit(&#39;data-a&#39;, this.name);
	  }
	}
}
var B = {
	template: &#39;#b&#39;,
	data() {
	  return {
	    age: 20
	  }
	},
	methods: {
	  send() {
	    Event.$emit(&#39;data-b&#39;, this.age);
	  }
	}
}
var C = {
	template: &#39;#c&#39;,
	data() {
	  return {
	    name: &#39;&#39;,
	    age: ""
	  }
	},
	mounted() {//在模板编译完成后执行
	Event.$on(&#39;data-a&#39;,name => {
	     this.name = name;//箭头函数内部不会产生新的this,这边如果不用=>,this指代Event
	})
	Event.$on(&#39;data-b&#39;,age => {
	     this.age = age;
	})
	}
}
var vm = new Vue({
	el: &#39;#itany&#39;,
	components: {
	  &#39;my-a&#39;: A,
	  &#39;my-b&#39;: B,
	  &#39;my-c&#39;: C
	}
});	
</script>

$on 监听了自定义事件 data-a和data-b,因为有时不确定何时会触发事件,一般会在 mounted 或 created 钩子中来监听。

eventBus(全局创建Vue实例)

进行事件监听和数据传递。同时vuex也是基于这个原理实现的

// 三步使用
// 1. 创建
window.$bus = new Vue()

// 2. 注册事件
window.$bus.$on(&#39;user_task_change&#39;, (payload) => {
  console.log(&#39;事件触发&#39;)
})

// 3. 触发
window.$bus.$emit(&#39;user_task_change&#39;, payload)

vuex (状态管理)

1.简要介绍Vuex原理Vuex实现了一个单向数据流,在全局拥有一个State存放数据,当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。

2.简要介绍各模块在流程中的功能

  • Vue Components:Vue组件。HTML页面上,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。
  • dispatch:操作行为触发方法,是唯一能执行action的方法。
  • actions:操作行为处理模块,由组件中的$store.dispatch('action 名称', data1)来触发。然后由commit()来触发mutation的调用 , 间接更新 state。负责处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。
  • commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
  • mutations:状态改变操作方法,由actions中的commit('mutation 名称')来触发。是Vuex修改state的唯一推荐方法。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。
  • state:页面状态管理容器对象。集中存储Vue components中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。
  • getters:state对象读取方法。图中没有单独列出该模块,应该被包含在了render中,Vue Components通过该方法读取全局state对象。

3.Vuex与localStoragevuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态,具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。

let defaultCity = "上海"
try {   // 用户关闭了本地存储功能,此时在外层加个try...catch
  if (!defaultCity){
    defaultCity = JSON.parse(window.localStorage.getItem(&#39;defaultCity&#39;))
  }
}catch(e){}
export default new Vuex.Store({
  state: {
    city: defaultCity
  },
  mutations: {
    changeCity(state, city) {
      state.city = city
      try {
      window.localStorage.setItem(&#39;defaultCity&#39;, JSON.stringify(state.city));
      // 数据改变的时候把数据拷贝一份保存到localStorage里面
      } catch (e) {}
    }
  }
})

这里需要注意的是:由于vuex里,我们保存的状态,都是数组,而localStorage只支持字符串,所以需要用JSON转换:

JSON.stringify(state.subscribeList);   // array -> string
JSON.parse(window.localStorage.getItem("subscribeList"));    // string -> array

Vuex文件 案例 : 目录结构如下:

[요약] Vue 컴포넌트의 11가지 통신 방법

其中vuex相关的三个文件counts.js、 index.js、 operate.js,内容如下:

[요약] Vue 컴포넌트의 11가지 통신 방법

index.js

import Vue from &#39;vue&#39;
import Vuex from &#39;vuex&#39;
import counter from &#39;./counter.js&#39;
import operate from &#39;./operate.js&#39;
Vue.use(Vuex)

const state = {
  name: &#39;zhaoyh&#39;
}

const getters = {
  getName (state) {
    return state.name
  }
}

const mutations = {
  changeName (state, payload) {
    state.name = `${state.name} ${payload}`
  }
}

const actions = {
  changeNameAsync (context, payload) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        context.commit(&#39;changeName&#39;, payload)
      }, 1000)
    })
  }
}

const store = new Vuex.Store({
  state,
  getters,
  mutations,
  actions,
  modules: {
    counter,
    operate
  }
})

export default store

counter.js

// 模块内方法调用本模块内的方法和数据
const state = {
  counterName: &#39;module > counter > zhaoyh&#39;
}
const getters = {
  // state, getters: 本模块内的state, getters
  // rootState, rootGetters: 根模块/根节点内的state, getters
  // rootState, rootGetters: 同时也包括各个模块中的state 和 getters
  getCounterName (state, getters, rootState, rootGetters) {
    // rootState.name
    // rootState.counter.counterName
    // rootState.operate.operateName
    console.log(rootState)
    // rootGetters.getName, 
    // rootGetters[&#39;counter/getCounterName&#39;]
    // rootGetters[&#39;operate/getOperateName&#39;]
    console.log(rootGetters)
    return state.counterName
  }
}
const mutations = {
  changeCounterName (state, payload) {
    state.counterName = `${state.counterName} ${payload}`
  }
}
const actions = {
  // context 与 store 实例具有相同方法和属性 ------  important!!!
  // context 包括: dispatch, commit, state, getters, rootState, rootGetters
  changeCounterNameAsync (context, payload) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {context.commit(&#39;changeCounterName&#39;, payload)}, 1000)
    })
  }
}
export default {
  // 注意此处是namespaced,而不是namespace,
  // 写错的话程序不会报错,vuex静默无法正常执行
  namespaced: true,
  state,
  getters,
  mutations,
  actions
}

operate.js

// 模块内方法调用和获取本模块之外的方法和数据
const state = {
  operateName: &#39;module > operate > zhaoyh&#39;
}
// 如果你希望使用全局 state 和 getter
// rootState 和 rootGetter 会作为第三和第四参数传入
// 也会通过 context 对象的属性传入 action
const getters = {
  // state, getters: 本模块内的state, getters
  // rootState, rootGetters: 根模块/根节点内的state, getters, 包括各个模块中的state 和 getters
  getOperateName (state, getters, rootState, rootGetters) {
    return state.operateName
  }
}
const mutations = {
  operateChangeCounterName (state, payload) {
    state.counterName = `${state.counterName} ${payload}`
  }
}
// 如果你希望使用全局 state 和 getter,
// 也会通过 context 对象的属性传入 action
const actions = {
  // context 与 store 实例具有相同方法和属性---- !!important!!!
  // context 包括:
  // dispatch, commit, state, getters, rootState, rootGetters
  operateChangeCounterNameAsync (context, payload) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
	    /*
	      * 若需要在全局命名空间内分发 action 或提交 mutation,
	      * 将 {root: true} 作为第三参数传给 dispatch 或 commit 即可
	    */
	      context.commit(&#39;counter/changeCounterName&#39;, payload, { root: true })
	      // 或 context.dispatch(&#39;counter/changeCounterNameAsync&#39;, null, { root: true })
      }, 1000)
    })
  }
}
export default {
  // 注意此处是namespaced,而不是namespace,
  // 写错的话程序不会报错,vuex静默无法正常执行
  namespaced: true,
  state,
  getters,
  mutations,
  actions
}

vuex属性、方法的引用方式: common-operate.vue

<template>
  <div>
    <h2>{{title}}</h2>
    <ul>
      <li>name: {{name}}</li>
      <li>getName: {{getName}}</li>
      <li><button @click="changeName(&#39;lastName&#39;)">Mutation操作</button></li>
      <li><button @click="changeNameAsync(&#39;lastName&#39;)">Action操作</button></li>
    </ul>
  </div>
</template>

<script>
import { mapState, mapGetters, mapActions, mapMutations } from &#39;vuex&#39;
export default {
  data () {
    return {
      title: &#39;vuex常规操作1&#39;
    }
  },
  computed: {
    ...mapState([&#39;name&#39;]),
    ...mapGetters([&#39;getName&#39;])
  },
  methods: {
    ...mapMutations([&#39;changeName&#39;]),
    ...mapActions([&#39;changeNameAsync&#39;])
  }
}
</script>

<style scoped>
ul, li{
  padding: 0;
  margin: 0;
  padding: 8px 15px;
}
</style>

common-operate2.vue

<template>
  <div>
    <h2>{{title}}</h2>
    <ul>
      <li>name: {{name}}</li>
      <li>getName: {{getName}}</li>
      <li><button @click="changeName(&#39;lastName&#39;)">Mutation操作</button></li>
      <li><button @click="changeNameAsync(&#39;lastName&#39;)">Action操作</button></li>
    </ul>
  </div>
</template>

<script>
import { mapState, mapGetters } from &#39;vuex&#39;
export default {
  data () {
    return {
      title: &#39;vuex常规操作2&#39;
    }
  },
  computed: {
    ...mapState([&#39;name&#39;]),
    ...mapGetters([&#39;getName&#39;])
  },
  methods: {
    // mutation
    changeName () {
      this.$store.commit(&#39;changeName&#39;, &#39;lastName&#39;)
    },
    // actions
    changeNameAsync () {
      this.$store.dispatch(&#39;changeNameAsync&#39;, &#39;lastName&#39;)
    }
  }
}
</script>

<style scoped>
ul, li{
  padding: 0;
  margin: 0;
  padding: 8px 15px;
}
</style>

module-operate.vue

<template>
  <div>
    <h2>{{title}}</h2>
    <ul>
      <li>name: {{counterName}}</li>
      <li>getName: {{getCounterName}}</li>
      <li><button @click="changeName(&#39;lastName&#39;)">Mutation操作</button></li>
      <li><button @click="changeNameAsync(&#39;lastName&#39;)">Action操作</button></li>
    </ul>
  </div>
</template>

<script>
import { mapState, mapGetters } from &#39;vuex&#39;
export default {
  data () {
    return {
      title: &#39;模块的基本操作方法&#39;
    }
  },
  computed: {
    ...mapState(&#39;counter&#39;, [&#39;counterName&#39;]),
    ...mapGetters(&#39;counter&#39;, [&#39;getCounterName&#39;])
  },
  methods: {
    // mutation
    changeName () {
      this.$store.commit(&#39;counter/changeCounterName&#39;, &#39;lastName&#39;)
    },
    // actions
    changeNameAsync () {
      this.$store.dispatch(&#39;counter/changeCounterNameAsync&#39;, &#39;lastName&#39;)
    }
  }
}
</script>

<style scoped>
ul, li{
  padding: 0;
  margin: 0;
  padding: 8px 15px;
}
</style>

module-operate2.vue

<template>
  <div>
    <h2>{{title}}</h2>
    <ul>
      <li>name: {{counterName}}</li>
      <li>getName: {{getCounterName}}</li>
      <li><button @click="changeCounterName(&#39;lastName&#39;)">Mutation操作</button></li>
      <li><button @click="changeCounterNameAsync(&#39;lastName&#39;)">Action操作</button></li>
      <li><button @click="rename(&#39;rename&#39;)">Action操作</button></li>
    </ul>
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions } from &#39;vuex&#39;
export default {
  data () {
    return {
      title: &#39;模块内方法调用本模块内内的方法和数据&#39;
    }
  },
  computed: {
    ...mapState(&#39;counter&#39;, [&#39;counterName&#39;]),
    ...mapGetters(&#39;counter&#39;, [&#39;getCounterName&#39;])
  },
  methods: {
    ...mapMutations(&#39;counter&#39;, [&#39;changeCounterName&#39;]),
    ...mapActions(&#39;counter&#39;, [&#39;changeCounterNameAsync&#39;]),
    // 多模块方法引入的方法名重命名
    ...mapActions(&#39;counter&#39;, {
      rename: &#39;changeCounterNameAsync&#39;
    }),
    otherMethods () {
      console.log(&#39;继续添加其他方法。&#39;)
    }
  }
}
</script>

<style scoped>
ul, li{
  padding: 0;
  margin: 0;
  padding: 8px 15px;
}
</style>

module-operate3.vue

<template>
  <div>
    <h2>{{title}}</h2>
    <ul>
      <li>name: {{counterName}}</li>
      <li>getName: {{getCounterName}}</li>
      <li><button @click="operateChangeCounterNameAsync(&#39;operate lastName&#39;)">Action操作</button></li>
    </ul>
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions } from &#39;vuex&#39;
export default {
  data () {
    return {
      title: &#39;模块内方法调用和获取本模块之外的方法和数据&#39;
    }
  },
  computed: {
    ...mapState(&#39;counter&#39;, [&#39;counterName&#39;]),
    ...mapGetters(&#39;counter&#39;, [&#39;getCounterName&#39;])
  },
  methods: {
    ...mapMutations(&#39;operate&#39;, [&#39;operateChangeCounterName&#39;]),
    ...mapActions(&#39;operate&#39;, [&#39;operateChangeCounterNameAsync&#39;]),
    otherMethods () {
      console.log(&#39;继续添加其他方法。&#39;)
    }
  }
}
</script>

<style scoped>
ul, li{
  padding: 0;
  margin: 0;
  padding: 8px 15px;
}
</style>

###### $parent / $children / $refs (获取组件实例)$refs 获取对应组件实例,如果是原生dom,那么直接获取的是该dom$parent / $children 该属性只针对vue组件,获取父/子组件实例 注: 节制地使用$parent $children - 它们的主要目的是作为访问组件的应急方法。更推荐用 props 和 events 实现父子组件通信

<!--  父组件,HelloWorld.vue-->
<template>
  <div class="hello">
    <ipc ref="ipcRef"></ipc>
  </div>
</template>

<script>
import ipc from &#39;./ipc&#39;
export default {
  name: &#39;HelloWorld&#39;,
  data () {
    return {
      parentVal: &#39;parent content&#39;
    }
  },
  mounted () {
    console.log(this.$refs.ipcRef.$data.child1) // "child1 content"
    console.log(this.$children[0].$data.child2) // "child2 content"
  },
  components: {
    ipc
  }
}
</script>
<!-- 子组件, ipc.vue-->
<template>
  <div>
  </div>
</template>

<script>
export default {
  props: {
  },
  data () {
    return {
      child1: &#39;child1 content&#39;,
      child2: &#39;child2 content&#39;
    }
  },
  mounted () {
    console.log(this.$parent.parentVal) // "parent content"
  }
}
</script>

ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例$parent / $children:访问父 / 子实例

需要注意的是:这两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据。我们先来看个用 ref来访问组件的例子:

component-a 子组件

export default {
  data () {
    return {
      title: &#39;Vue.js&#39;
    }
  },
  methods: {
    sayHello () {
      window.alert(&#39;Hello&#39;);
    }
  }
}

父组件

<template>
  <component-a ref="comA"></component-a>
</template>
<script>
  export default {
    mounted () {
      const comA = this.$refs.comA;
      console.log(comA.title);  // Vue.js
      comA.sayHello();  // 弹窗
    }
  }
</script>

不过,这两种方法的弊端是,无法在跨级或兄弟间通信。

parent.vue

<component-a></component-a>
<component-b></component-b>
<component-b></component-b>

我们想在 component-a 中,访问到引用它的页面中(这里就是 parent.vue)的两个 component-b 组件,那这种情况下,就得配置额外的插件或工具了,比如 Vuex 和 Bus 的解决方案。

多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。但如果仅仅是传递数据,而不做中间处理,使用 vuex 处理,未免有点大材小用。为此Vue2.4 版本提供了另一种方法----$attrs/$listeners

$attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 inheritAttrs 选项一起使用。

$listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件

$attrs

1) 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外) 2) 当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外) 可以通过v-bind="$attrs" 将所有父作用域的绑定 (class、style、 ref 除外) 传入内部组件注: 在创建高级别的组件时非常有用

根组件HelloWorld.vue 中引入 ipc.vue

<ipc
   koa="ipcRef"
   name="go"
   id="id"
   ref="ref"
   style="border: 1px solid red;"
   class="className"
   >
</ipc>

ipc.vue  中引入 ipcChild.vue

<template>
  <div>
    <ipcChild v-bind="$attrs" selfDefine="selfDefine"></ipcChild>
  </div>
</template>

<script>
import ipcChild from &#39;./ipcChild&#39;
export default {
  components: {
    ipcChild
  },
  mounted () {
    console.log(this.$attrs) // {id: "id", name: "go", koa: "ipcRef"}
  }
}
</script>

// ipcChild.vue中打印接收到的$attrs

<script>
export default {
  created () {
    console.log(this.$attrs) // "{"selfDefine":"selfDefine","koa":"ipcRef","name":"go","id":"id"}"
  }
}
</script>

$listeners

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器 通过 v-on="$listeners" 将父作用域的时间监听器传入内部组件

A、B、C三个组件依次嵌套, B嵌套在A中,C嵌套在B中。 借助 B 组件的中转,从上到下props依次传递,从下至上,$emit事件的传递,达到跨级组件通信的效果。$attrs以及$listeners 的出现解决的的问题,B 组件在其中传递props以及事件的过程中,不必在写多余的代码,仅仅是将 $attrs以及$listeners 向上或者向下传递即可。

跨级通信的案例

index.vue

<template>
  <div>
    <h2>浪里行舟</h2>
    <child-com1
      :foo="foo"
      :boo="boo"
      :coo="coo"
      :doo="doo"
      title="前端工匠"
    ></child-com1>
  </div>
</template>
<script>
const childCom1 = () => import("./childCom1.vue");
export default {
  components: { childCom1 },
  data() {
    return {
      foo: "Javascript",
      boo: "Html",
      coo: "CSS",
      doo: "Vue"
    };
  }
};
</script>

childCom1.vue

<template class="border">
  <div>
    <p>foo: {{ foo }}</p>
    <p>childCom1的$attrs: {{ $attrs }}</p>
    <child-com2 v-bind="$attrs"></child-com2>
  </div>
</template>
<script>
const childCom2 = () => import("./childCom2.vue");
export default {
  components: {
    childCom2
  },
  inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性
  props: {
    foo: String // foo作为props属性绑定
  },
  created() {
    console.log(this.$attrs); // { "boo": "Html", "coo": "CSS", "doo": "Vue", "title": "前端工匠" }
  }
};
</script>

childCom2.vue

<template>
  <div class="border">
    <p>boo: {{ boo }}</p>
    <p>childCom2: {{ $attrs }}</p>
    <child-com3 v-bind="$attrs"></child-com3>
  </div>
</template>
<script>
const childCom3 = () => import("./childCom3.vue");
export default {
  components: {
    childCom3
  },
  inheritAttrs: false,
  props: {
    boo: String
  },
  created() {
    console.log(this.$attrs); // { "coo": "CSS", "doo": "Vue", "title": "前端工匠" }
  }
};
</script>

childCom3.vue

<template>
  <div class="border">
    <p>childCom3: {{ $attrs }}</p>
  </div>
</template>
<script>
export default {
  props: {
    coo: String,
    title: String
  }
};
</script>

$attrs表示没有继承数据的对象,格式为{属性名:属性值}。Vue2.4提供了$attrs , $listeners 来传递数据与事件,跨级组件之间的通讯变得更简单。

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

Vue.observable

mixin

mixin (混入) (谨慎使用全局混入, 如有必要可以设计插件并引入使用)参见官方文档

  • 一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项

  • 当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。

  • 同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。

  • 值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。

路由传值 /引用数据类型值传递实现父子间数据的共享

总结

일반적인 사용 시나리오는 세 가지 범주로 나눌 수 있습니다.

아버지와 자녀의 의사소통: 부모는 props를 통해 자식에게 데이터를 전달하고, 자식은 이벤트($emit)를 통해 부모에게 전달합니다. 통신은 부모 체인/자식 체인을 통해서도 수행될 수 있습니다. ($parent / $children); refAPI 제공/주입에도 액세스할 수 있습니다. /code>props,子向父是通过 events($emit);通过父链 / 子链也可以通信($parent / $children)ref 也可以访问组件实例;provide / inject API$attrs/$listeners兄弟通信BusVuex跨级通信BusVuexprovide / inject API$attrs/$listenersBrother 통신

: Vuex

교차 수준 통신: Vuex; 제공 / inject API, $attrs/$listeners(동영상 공유 학습: vuejs 입문 튜토리얼

, 🎜기본 프로그래밍 영상🎜)🎜

위 내용은 [요약] Vue 컴포넌트의 11가지 통신 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제