Vue2组件之间的传值通信

父子组件

Vue中常见的是父与子组件间的通信,所要用到的关键字段是props和$emit。

props接受父组件传给子组件信息的字段,它的类型:Array<string> | Object;详细解释可以参考https://cn.vuejs.org/v2/api/#props

$emit由子组件触发事件向上传播给父级消息。

示例:

// Parent

<template><divclass="parent">
    我是父组件
    <p>来自子级的回答:{{ childMsg }}</p><Child:msg="msg" @click="handleClick"/></div></template><script>importChildfrom"./Child";
exportdefault {
  name: "Parent",
  components: {
    Child
  },
  data() {
    return {
      msg: "叫你吃饭了",
      childMsg: ''
    };
  },
  methods: {
    // 接收来自子级的事件消息handleClick(val) {
      this.childMsg = val;
    } 
  }
};
</script>

// Child
<template><divclass="child"><p>我是子组件</p><p>父级来的信息: {{ msg }}</p><button @click="handleClick">回答父级</button></div></template><script>exportdefault {
  name: "Child",
  // 接收父级传来的信息props: {
    msg: String
  },
  methods: {
    // 向父级传播事件消息handleClick() {
      this.$emit('click', '我知道了');
    }
  },
};
</script>

祖孙组件

有时候我们可能会碰到组件间的无限嵌套,这时我们使用props时无法向下无限极传递数据的,我们可以用到provide/inject;provide可以向其子孙组件传递数据,而不关子孙组件的层级有多深,使用inject都可以拿到数据。详细解释可以参考https://cn.vuejs.org/v2/api/#provide-inject

示例:

// Grand
<template><divclass="grand"><p>我是祖父</p><Parent /></div></template><script>exportdefault{
  name: "Grand",
  provide: {
    grandMsg: '都来吃饭'
  },
  components: {
    Parent
  }
};
</script>

// Parent
<template><divclass="parent">
    我是父组件
    <p>祖父的信息:{{ grandMsg }}</p><Child /></div></template><script>importChildfrom"./Child";
exportdefault{
  name: "Parent",
  components: {
    Child
  },
  inject: {
    grandMsg: {
      default: ''
    }
  }
};

// Child<template><div class="child">
    <p>我是子组件</p>
    <p>爷爷的信息: {{ grandMsg }}</p></div></template>
<script>exportdefault{
  name: "Child",
  inject: {
    grandMsg: {
      default: ''
    }
  }
};
</script>

provide 和 inject 绑定并不是可响应的。我们可以通过传递祖父级的实例this或着使用observable来使传递的数据是响应的。
// Grand
<template><divclass="grand"><p>我是祖父</p><inputtype="text"v-model="msg"placeholder="输入祖父的消息"/><Parent /></div></template><script>importParentfrom"./Parent";
exportdefault {
  name: "Grand",
  provide() {
    return { // 利用函数 provide 返回对象grandVm: this// 传递实例
    };
  },
  ...
  data() {
    return {
      msg: ""
    };
  }
};
</script>

// Child
<template><divclass="child"><p>我是子组件</p><p>爷爷的实例信息: {{ grandVmMsg }}</p></div></template><script>exportdefault {
  name: "Child",
  inject: {
    grandVm: {
      default: () => {
        "";
      }
    }
  },
  computed: {
    grandVmMsg() {
      returnthis.grandVm.msg;
    }
  }
};
</script>

使用observable让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象。

示例:

// Grand
provide() {
  this.read = Vue.observable({
    msg: ''
  })
  return {
    read: this.read
  };
}复制代码

兄弟组件

同级别组件相互间的通信,我们可以使用EventBus或着Vuex。

简单的EventBus示例:

// Bus.jsimportVuefrom"vue";
exportdefaultnewVue();

// Child<divclass="child"><p>我是子组件一</p><button @click="handleClick">组件一事件</button></div><script>importBusfrom"./Bus";
exportdefault {
  name: "Child",
  methods: {
    handleClick() {
      Bus.$emit("click", "嘿,老铁");
    }
  }
};
</script>// ChildOne<divclass="child"><p>我是子组件二</p><p>兄弟叫我:{{ msg }}</p></div><script>importBusfrom"./Bus";
exportdefault {
  name: "ChildOne",
  data() {
    return {
      msg: ""
    };
  },
  mounted() {
    Bus.$on("click", msg => {
      this.msg = msg;
    });
  }
};
</script>

v-model与sync

v-model是我们用ElementUI常见的表单绑定值方式;可以直接修改子组件修改父组件传入的值,简化了我们组件通信的逻辑。

示例:

// ModelCom
<div class="child">
  <inputtype="text" @input="handleInput"></div><script>exportdefault {
  name: "ModelSync",
  methods: {
    // 通过绑定表单input中的input事件,向上触发input事件来修改值handleInput(e) {
      const value = e.target.value;
      this.$emit('input', value);
    }
  }
};
</script>// Home<ModelSyncv-model="msg"/>

sync修饰符也可以是我们的prop进行双向绑定

它需要我们在子组件内触发this.$emit('update:prop', val)事件

// ModelCom
<input type="text"@input="handleChange">
...
props: ['value'],
methods: {
  handleChange(e) {
    const value = e.target.value;
    // 触发更新this.$emit('update:value', value);
  }
}

// Home
<ModelSync :value.sync="syncMsg"/>复制代码

$children与$parent

我们可以在组件中通过当前的实例对象访问到组件的$children和$parent来找到各自组件的父级组件或子级组件实例。

示例:

// Child
<divclass="child"><p>我是子组件</p><p>来自父组件的msg: {{ msg }}</p></div>
...
<script>exportdefault {
  name: "ChildParent",
  data() {
    return {
      value: ''
    }
  },
  computed: {
    msg() {
      returnthis.$parent.value;
    }
  },
  created() {
    console.log(this.$parent); 
  }
}

// Parent
<input v-model="value" />
复制代码

通过在父组件中输入值可以看到子组件数据也同时更新了

$attrs与$listeners

$attrs可以通过 v-bind="$attrs" 将组件上的特性都(class 和 style 除外)传入内部组件;传入的值与inheritAttrs的设置有关,通常封装高级组件。

当我们inheritAttrs 设置 true;组件渲染DOM时写在组件的特性会渲染上去;

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

具体详细可见https://cn.vuejs.org/v2/api/?#vm-attrs

示例:

// Attr
<divclass="child"><p>Attr</p><p>这是$attrs:{{ placeholder }}</p><p>这是$listeners:{{ test }}</p><button @click="$listeners.click">监听了$listeners</button></div>
...
<script>exportdefault {
  name: "AttrListen",
  inheritAttrs: true,
  props: {
    test: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      placeholder: this.$attrs.placeholder
    }
  }
};
</script>

// Home
<AttrListenplaceholder="这是个attr":test="value"v-bind="$attrs"v-on="$listeners" @click="handleListen"/>复制代码

通过封装查找组件

通过封装函数来向上或向下派发事件
// emitter.js
function broadcast(componentName, eventName, params) {
    this.$children.forEach(child => {
        const name = child.$options.name;

        if(name === componentName) {
            child.$emit.apply(child, [eventName].concat(params));
        } else {
            broadcast.apply(child, [componentName, eventName].concat([params]));
        }
    });
}
export default {
    methods: {
        dispatch(componentName, eventName, params) {
            let parent = this.$parent || this.$root;
            let name = parent.$options.name;

            while (parent && (!name || name !== componentName)) {
                parent = parent.$parent;

                if (parent) {
                    name = parent.$options.name;
                }
            }
            if (parent) {
                parent.$emit.apply(parent, [eventName].concat(params));
            }
        },
        broadcast(componentName, eventName, params) {
            broadcast.call(this, componentName, eventName, params);
        }
    }
};
复制代码
通过封装函数来查找指定任意组件
// 由一个组件,向上找到最近的指定组件
function findComponentUpward (context, componentName) {
    let parent = context.$parent;
    let name = parent.$options.name;

    while (parent && (!name || [componentName].indexOf(name) < 0)) {
        parent = parent.$parent;
        if (parent) name = parent.$options.name;
    }
    return parent;
}
export { findComponentUpward };

// 由一个组件,向上找到所有的指定组件
function findComponentsUpward (context, componentName) {
    let parents = [];
    const parent = context.$parent;

    if (parent) {
        if (parent.$options.name === componentName) parents.push(parent);
        return parents.concat(findComponentsUpward(parent, componentName));
    } else {
        return [];
    }
}
export { findComponentsUpward };

// 由一个组件,向下找到所有指定的组件
function findComponentsDownward (context, componentName) {
    returncontext.$children.reduce((components, child) => {
        if (child.$options.name === componentName) components.push(child);
        const foundChilds = findComponentsDownward(child, componentName);
        return components.concat(foundChilds);
    }, []);
}
export { findComponentsDownward };

// 由一个组件,找到指定组件的兄弟组件
function findBrothersComponents (context, componentName, exceptMe = true) {
    let res = context.$parent.$children.filter(item => {
        returnitem.$options.name === componentName;
    });
    let index = res.findIndex(item => item._uid === context._uid);
    if (exceptMe) res.splice(index, 1);
    return res;
}
export { findBrothersComponents };
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue 中,组件之间递数据可以通过 props、事件、vuex 等方式来实现。 1. Props Props 是父组件向子组件递数据的一种方式,子组件通过 props 来接收父组件递过来的数据。具体使用方法如下: // 父组件 <template> <child-component :msg="message"></child-component> </template> <script> import ChildComponent from './ChildComponent.vue' export default { components: { ChildComponent }, data () { return { message: 'Hello World' } } } </script> // 子组件 <template> <div>{{ msg }}</div> </template> <script> export default { props: ['msg'] } </script> 2. 事件 事件是子组件向父组件通信的一种方式,子组件通过 $emit 触发一个事件,并且可以递数据。父组件通过在子组件上监听事件来接收数据。具体使用方法如下: // 子组件 <template> <button @click="emitEvent">Click Me!</button> </template> <script> export default { methods: { emitEvent () { this.$emit('my-event', 'Hello World') } } } </script> // 父组件 <template> <child-component @my-event="handleEvent"></child-component> </template> <script> import ChildComponent from './ChildComponent.vue' export default { components: { ChildComponent }, methods: { handleEvent (msg) { console.log(msg) // 'Hello World' } } } </script> 3. Vuex Vuex 是 Vue.js 的状态管理库,它可以在不同组件之间共享状态。通过 Vuex,我们可以将数据放到全局的 store 中,在需要的组件中读取或者修改数据。具体使用方法可以参考 Vuex 的官方文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李宏伟~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值