vue中组件之间的通信

vue组件化开发当中,经常需要涉及组件之间的通讯,常见的组件通讯,有以下几种:

 1). `props` ★★(使用的频率最高,一般常用在简单的数据传递的场景)

 2). `$emit/$on ` ★★ 事件总线

 3). `vuex`  ★★★

 4).`$parent/$children`

 5). `$attrs/$listeners`

 6). `provide/inject`  ★★★

常见的使用场景可以分为以下三大类:

props方法如下:

父组件给子组件传值方法;
父组件:
​​​​​​​<template>
    <div id="app">
        <Child v-bind:child="users"></Child> //前者自定义名称便于子组件调用,后者要传递数据名
    </div>
</template>
<script>
    import Child from "./components/Child" //子组件
    export default {
        name: 'App',
        data(){
            return{
              users:["Eric","Andy","Sai"],
              transfername:"any data"
            }
        },
        components:{
            "Child":Child
        }
    }
</script>

在父组件使用的时候v-blind:后面的参数名称需要对应子组件中的props中的值,后面=号跟着的变量值,可以是当前父组件data中的任意一个值:

例如,上述中=等号后面的可以是user也可以是transfername,根据需要可以传递父组件中的任意一个值到子组件,:后续的参数只能是child,这里和子组件中的props中的属性一一对应。

子组件:

<template>
    <div class="hello">
        <ul>
            <li v-for="item in child">{{ item }}</li> //遍历传递过来的值渲染页面
        </ul>
    </div>
</template>
<script>
    export default {
        name: 'Hello World',
        props:{
            child:{           //这个就是父组件中子标签自定义名字
              type:Array,     //对传递过来的值进行校验
              required:true   //必添
            }
          }
    }
</script>

该方法实现的是简单的将父组件的数据传递给子组件,通过v-bind-传递的需要接受的属性名称,child,和父组件中的bind后面的参数一一对应,

当前传值方法可以传递简单的数值,也可以传递数组,对象等等,详细的传递格式参考官网地址:https://cn.vuejs.org/v2/guide/components-props.html

传入一个对象的所有 property

如果你想要将一个对象的所有 property 都作为 prop 传入,你可以使用不带参数的 v-bind (取代 v-bind:prop-name)。例如,对于一个给定的对象 post

post: {
  id: 1,
  title: 'My Journey with Vue'
}

下面的模板:

<blog-post v-bind="post"></blog-post>

等价于:

<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"
></blog-post>

子组件给父组件传值方法,通过该方法,子组件可以主动给父组件传值:

子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件,vue`实例 作为事件总线(事件中心)用来触发事件和监听事件,可以通过此种方式进行组件间通信包括:父子组件、兄弟组件、跨级组件
创建bus文件
```
import Vue from 'vue'

export defult new Vue()
```
```
// gg组件
<template id="a">
  <div>
    <h3>gg组件</h3>
    <button @click="sendMsg">将数据发送给dd组件</button>
  </div>
</template>
<script>
import bus from './bus'
export default {
    methods: {
        sendMsg(){
            bus.$emit('sendTitle','传递的值')
        }
    }
}
</script>

当前组件通过on方法,接受传递过来的参数,传递的动作发生在bus组件当中。

<template>
    <div>
        接收gg传递过来的值:{{msg}}
    </div>
</template>
<script>
import bus from './bus'
export default {
    data(){
        return {
            mag: ''
        }
    }
    mounted(){
        bus.$on('sendTitle',(val)=>{
            this.mag = val
        })
    }
}

方法三,如果业务比较复杂,或者涉及到多层组件之间的互相传值,比较推荐的方法是vuex

vuex介绍如下:

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

vuex中核心概念
 * `state`:`vuex`的唯一数据源,如果获取多个`state`,可以使用`...mapState`。
     ```
     export const store = new Vuex.Store({   
     // 注意Store的S大写
     <!-- 状态储存 -->
        state: {
             productList: [
                {
                name: 'goods 1',
                price: 100
                    
                }
            ]
        }
    })

getter`: 可以将`getter`理解为计算属性,`getter`的返回值根据他的依赖缓存起来,依赖发生变化才会被重新计算。
    ```
    import Vue from 'vue'
    import Vuex from 'vuex';
    Vue.use(Vuex)
    
    export const store = new Vuex.Store({ 
        state: {
            productList: [
                {
                name: 'goods 1',
                price: 100
                },
            ]
        },
        // 辅助对象 mapGetter
        getters: {
            getSaledPrice: (state) => {
                let saleProduct = state.productList.map((item) => {
                    return {
                        name: '**' + item.name + '**',
                        price: item.price / 2
                    }
                })
                return saleProduct;
            }
        }
    })
 // 获取getter计算后的值
    export default {
        data () {
            return {
                productList : this.$store.getters.getSaledPrice 
            }
        }
    }
mutation`:更改`vuex`的`state`中唯一的方是提交`mutation`都有一个字符串和一个回调函数。回调函数就是使劲进行状态修改的地方。并且会接收`state`作为第一个参数`payload`为第二个参数,`payload`为自定义函数,`mutation`必须是同步函数。
    ```
    // 辅助对象 mapMutations
    mutations: {
        <!-- payload 为自定义函数名-->
        reducePrice: (state, payload) => {
            return state.productList.forEach((product) => {
                product.price -= payload;
            })
        }
    }

页面当中如果需要使用的时候:

     reducePrice(){
            this.$store.commit('reducePrice', 4)
        }
    }

该模块的介绍,后续还会继续补充.....

除了上述属性可以方便的用来传值之外,还可以使用localStorage,进行存储和读取。

方法四,vuex中数据存储 localStorage
 `vuex` 是 `vue` 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态,具体做法应该在`vuex`里数据改变的时候把数据拷贝一份保存到`localStorage`里面,刷新之后,如果`localStorage`里有保存的数据,取出来再替换`store`里的`state`。
let defaultCity = "上海"
try {    
// 用户关闭了本地存储功能,此时在外层加个try...catch
  if (!defaultCity){
  // f复制一份
        defaultCity = JSON.parse(window.localStorage.getItem('defaultCity'))
        }
    }catch(e){
        console.log(e)
    }
export default new Vuex.Store({
  state: {
    city: defaultCity
  },
  mutations: {
    changeCity(state, city) {
      state.city = city
      try {
      window.localStorage.setItem('defaultCity', JSON.stringify(state.city));
      // 数据改变的时候把数据拷贝一份保存到localStorage里面
      } catch (e) {}
    }
  }
})

方法五:`$attr/$listeners`
### 1-1 简介
#### 多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。但如果仅仅是传递数据,而不做中间处理,使用 vuex 处理,未免有点大材小用。为此Vue2.4 版本提供了另一种方法----`$attrs/$listeners`
* `$attrs`:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (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>
方法六,`provide/inject` 对当前模块的介绍后续会继续补充。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值