vue跨组件数据通信

本文介绍了Vue的多种组件通信和状态管理方法,包括vue.observer()、Vue Bus、props/$emit、vuex、provide/inject和$attrs/$listeners。详细说明了各方法的使用步骤,如创建文件、挂载等,还提及provide/inject实现数据响应式的优化方法。

1.vue.observer( )

  • 首先创建一个 store.js,包含一个 store和一个 mutations,分别用来指向数据和处理方法
import Vue from 'vue';

// 数据仓库
const store = Vue.observable({
  token: '',
  userInfo: {
    id: '',
    name: '',
  },

});

// 更新 state
const mutations = {

  // 更新 token
  updateToken(token) {
    store.token = token;
  },
  // 更新用户信息
  updateUserInfo(userInfo) {
    store.userInfo = {
      ...userInfo,
      ...store.userInfo,
    };
  },
}

// 全局挂载属性值
const storePlugin = {
  install(vue) {
    vue.prototype.$store = store;
    vue.prototype.$mutations = mutations;
  }
}

export {
  storePlugin,
}
  •  main.js中挂载
import { storePlugin } from './store';

Vue.use(storePlugin )
  •  使用
<template>
  <div class="container">
    <div @click="getUserInfo">gengxin</div>
    {{userInfo.name}}
  </div>
</template>
<script>
  export default {
    data() {
      return {
        name1: '主页的name'
      }
    },
    computed: {
      userInfo() {
        return this.$store.userInfo
      },
    },
    methods: {
      getUserInfo() {
        this.$mutations.updateUserInfo({
          name: '李四',
          id: parseInt(Math.random() * 100)
        })
      }
    }
  }
</script>

2.Vue Bus

  • 首先创建一个 bus.js
// bus.js
const eventBus = {
  install(Vue,options) {
    Vue.prototype.$bus = new Vue()
  }
};
export { eventBus}
  •  main.js中挂载
import { eventBus} from './bus';

Vue.use(eventBus)
  • 然后在组件中,可以使用$emit, $on, $off 分别来分发、监听、取消监听事件:
// 分发事件的组件
methods: {
  todo: function () {
    this.$bus.$emit('todoSth', params);  //params是传递的参数
    //...
  }
}


// 监听的组件 最好在组件销毁前 清除事件监听
created() {
  this.$bus.$on('todoSth', (params) => {  //获取传递的参数并进行操作
      //todo something
  })
},
beforeDestroy () {
  this.$bus.$off('todoSth');
},


// 如果需要监听多个组件,只需要更改 bus 的 eventName:
created() {
  this.$bus.$on('firstTodo', this.firstTodo);
  this.$bus.$on('secondTodo', this.secondTodo);
},
// 清除事件监听
beforeDestroy () {
  this.$bus.$off('firstTodo', this.firstTodo);
  this.$bus.$off('secondTodo', this.secondTodo);
},

3.父组件和子组件通信props/$emit

//父组件
<template>
  <div id="app">
    <users :users="users" @submitUser="submitUser"></users>
  </div>
</template>
<script>
import Users from "./components/Users"
export default {
  name: 'App',
  data(){
    return{
      users:["Henry","Bucky","Emily"]
    }
  },
  components:{
    "users":Users
  },
  methods:{
    // 子组件传递过来的指
    submitUser(data){
      console.log('data',data)
    }
  }
}


//子组件
<template>
  <div class="hello">
    <ul>
       //遍历传递过来的值,然后呈现到页面
      <li v-for="user in users" @click="submitUser">{{user}}</li>
    </ul>
  </div>
</template>
<script>
export default {
  props:{
    users:{           //这个就是父组件中子标签自定义名字
      type:Array,
      required:true
    }
  },
  methods:{
    submitUser() {
      // 自定义事件  传递值“子向父组件传值”
      this.$emit("submitUser","子向父组件传值");
    }
  }
}
</script>

4.vuex ,vue 的状态管理器

https://vuex.vuejs.org/zh/

5.provide/inject 

主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。

需要注意的是:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的----vue官方文档

假设有两个组件: A.vue 和 B.vue,B 是 A 的子组件 .A.vue 的 name 如果改变了,B.vue 的 this.name 是不会改变的

// A.vue
export default {
  provide: {
    name: '浪里行舟'
  }
}

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

provide与inject 怎么实现数据响应式 

  • provide祖先组件的实例,然后在子孙组件中注入依赖,这样就可以在子孙组件中直接修改祖先组件的实例的属性,不过这种方法有个缺点就是这个实例上挂载很多没有必要的东西比如props,methods
  • 使用2.6最新API Vue.observable 优化响应式 provide(推荐)

我们来看个例子:孙组件D、E和F获取A组件传递过来的color值,并能实现数据响应式变化,即A组件的color变化后,组件D、E、F会跟着变(核心代码如下:)

image

// 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>

6.$attrs/$listeners

  • $attrs:包含了父作用域中不被 prop 所识别 (props没接收的) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 interitAttrs 选项一起使用。
  • $listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$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>

 

 

### ### 跨层级组件通信的实现方式 在 Vue 应用中,跨层级组件通信可以通过多种方式进行实现。其中最常用的方式包括 `Provide / Inject`、全局事件总线(EventBus)、以及使用状态管理库如 Vuex。 #### Provide / Inject `Provide / Inject` 是一种适用于祖先组件向深层嵌套的后代组件传递数据的方式。这种方式不需要逐层传递 props,而是通过祖先组件提供数据,后代组件直接注入并使用这些数据。这种方法非常适合处理多层嵌套场景下的数据共享问题[^1]。 ```javascript // 祖先组件 export default { provide() { return { theme: 'dark' }; } }; // 后代组件 export default { inject: ['theme'] }; ``` #### 全局事件总线(EventBus) 对于非父子关系或跨层级组件之间的通信,可以使用全局事件总线来实现。通过创建一个全局的 Vue 实例作为事件中心,不同组件之间可以通过 `$emit` 和 `$on` 方法进行通信。这种机制类似于发布/订阅模式,能够轻松地在任意两个组件之间传递消息[^4]。 ```javascript // 创建 Event Bus const EventBus = new Vue(); // 发送事件的组件 EventBus.$emit('event-name', data); // 接收事件的组件 EventBus.$on('event-name', (data) => { // 处理逻辑 }); ``` #### Vuex 状态管理 对于大型复杂应用,推荐使用 Vuex 进行全局状态管理。Vuex 提供了一个集中式的存储空间,所有组件都可以访问到这个存储中的数据,并且支持响应式的更新机制。它不仅解决了跨层级组件通信的问题,还能很好地管理整个应用程序的状态变化[^3]。 ```javascript // store.js import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); export default new Vuex.Store({ state: { message: '' }, mutations: { setMessage(state, message) { state.message = message; } }, actions: { updateMessage({ commit }, message) { commit('setMessage', message); } } }); // 组件A export default { methods: { sendMessage() { this.$store.dispatch('updateMessage', 'Hello from A'); } } }; // 组件B export default { computed: { message() { return this.$store.state.message; } } }; ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值