51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

[Vue] 组件间通信回顾

组件间通信回顾

回顾

1.事件注意事项

事件:

  • 系统事件、双击、鼠标事件等等。。
  • 自定义事件

事件分为:事件源、事件类型和事件回调

来一个学过的例子开个头:

<template>
  <div>
    <h1>EventTest组件</h1>
    <!-- 原生DOM绑定系统事件 -->
    <button @click="handler">原生DOM绑定原生事件</button>
    <!-- EVent1组件 -->
    <Event1 @click="handler"/>
  </div>
</template>
`<script>
import Event1 from './Event1'
export default {
name:'EventTest',
components:{
Event1
},
methods:{
handler(e){
console.log(e);
}
}
}
</script>`

结果就是:button绑定的事件是好用的,Event1绑定的事件用不了
因为Event1非原生DOM节点,绑定的click事件并非原生DOM事件,而被识别为了自定义事件

使用@click.native="handler"就可以强制识别为原生事件(不过这个方法在Vue3中被移除了)

还有一个值得注意的点就是,原生DOM是没办法绑定自定义事件的,因为原生DOM没法使用$emit触发自定义事件

2.v-model

v-model它是Vue框架中的指令,它主要结合表单元素一起使用(文本框、复选框、单选框等),它主要的作用是收集表单数据,实现数据双向绑定

可以通过value与input事件实现v-model的功能

<template>
  <div>
    <input type="text" :value="msg" @input="msg = $event.target.value" />
    <span>{{ msg }}</span>
  </div>
</template>
<script>
export default {
  name: "Vmodel",
  data() {
    return {
      msg: "test",
    };
  },
};
</script>

v-model可以实现父子数据互相传输同步

父组件:

<!--这里value是props @input是自定义事件 -->
<!-- <CustomInput :value="msg" @input="msg = val"/> -->
<!-- 可以直接简化为v-model 因为v-model的实现原理其实和上面的一样 -->
<CustomInput v-model="msg"/>

解释一下,@input里的 msg = val 就是当子组件发生输入行为的时候,就会触发父组件的自定义事件,从而把子组件的value赋值给父组件的msg

至于为什么是一个赋值语句?其实换成箭头函数就好理解了,val是形参 :(value)=>{msg = value}

子组件:

<template>
    <!-- 这里@input是原生的 -->
    <input type="text" :value="value" @input="$emit('input',$event.target.value)">
</template>
<script>
export default {
  name: "CustomInput",
  props:['value']
};
</script>

这个还是比较难理解的,主要是涉及到各种参数的传递,别弄混了(笑

参考资料 自定义组件的-v-model

属性修饰符sync

属性修饰符也是组件通信方式的一组,可以实现父子组件数据同步

格式:

  • 父组件: <text-document v-bind:title="doc.title" v-on:update:title="doc.title = $event"\></text-document>
  • 子组件:this.$emit('update:title', newTitle)

例子:

父组件:

<template>
  <div>
    <h1>我有{{ money }}元</h1>
    <h2>不使用sync修饰符</h2>
    <Child :money="money" @cost_money="(val) => (money = val)"></Child>
    <h2>使用sync修饰符</h2>
    <Child2 :money.sync="money"></Child2>
  </div>
</template>
<script>
    ...
  data() {
    return {
      money: 1000,
    }
  }
    ...
</script>

Child

<template>
<div>
    <span>我弟每次花100元</span>
    <button @click="$emit('cost_money',money-100)">花钱</button>
    我还剩{{money}}元
</div>
</template>
<script>
export default {
    name:'Child',
    props:['money']
}
</script>

Child2

<template>
<div>
    <span>我弟每次花100元</span>
    <button @click="$emit('update:money',money-100)">花钱</button>
    我还剩{{money}}元
</div>
</template>
<script>
export default {
    name:'Child2',
    props:['money']
}
</script>

Child1与child2作用相同

:money.sync 代表父组件给子组件传递props [money],给当前子组件绑定一个自定义事件update:money

其实就是一个语法糖(乐

$attrs与$listeners

$attrs属于组件的一个属性,可以获取到父组件传递过来的props数据

但这玩意是兜底的,如果你不写props的话,那么$attrs里面就有东西,但是使用了props接住了数据,那么相应的$attrs里面的东西就会被props取走

$listeners也是组件实例自身的一个属性,它可以获取到故组件给子组件传递的自定义事件

代码实现封装一个element button:

父组件:

<template>
  <div>
    <h2>自定义带Hover提示的按钮</h2>
    <!-- 当用户在使用我们封装的按钮的时候,需要向HintButton组件传递相应参数 (el-button进行二次封装) -->
    <HintButton type="success" icon="el-icon-delete" size="mini" title="提示按钮" @my_click="handler" />
  </div>
</template>
`<script>
import HintButton from "./HintButton";
export default {
name: "AttrsListenersTest",
components: {
HintButton,
},
methods:{
handler(){
alert('23333')
}
}
};
</script>`

子组件:

<template>
<!-- 可以巧妙地利用a标签实现按钮带有提示功能 -->
  <a :title="$attrs.title">
    <!-- 可以使用v-bind直接批量绑定attrs中的属性到组件标签中 -->
    <el-button v-bind="$attrs" @click="$listeners.my_click">添加</el-button>
  </a>
</template>
`<script>
export default {
name: "HintButton",
mounted() {
console.log(this.$attrs);
console.log(this.$listeners)
},
};
</script>`

$children与$parent

$children

$children组件实例的属性,可以获取当前组件的全部子组件,是一个数组形式的存在

如果我们想操作所有的子组件的话,使用$children就可以直接遍历操作了

/组件实例自带一个$children,可以获取当前组件当中所有的子组件
this.$children.forEach(ele=>{
    ele.money ++
})

这里有一个小坑,如果子组件很多的话,$children[0] 可能不是你认为的第一个元素,所以建议不要使用下标定位元素(

$parent

$parent组件实例属性,可以获取到当前子组件的父组件,进而可以操作父组件的数据和方法

赞(0)
未经允许不得转载:工具盒子 » [Vue] 组件间通信回顾