vue跨组件数据通信

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>

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值