组件间通信回顾
回顾
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组件实例属性,可以获取到当前子组件的父组件,进而可以操作父组件的数据和方法