- props
- v-model
- .sync
- ref
- $emit
- slot
- $attrs
- $children / $pareent
- provide / indect
- EventBus
- Vuex
- $root
1. props
父组件向子组件传送数据,子组件接收到数据之后,不能直接修改父组件的数据。会报错,所以当父组件重新渲染时,数据会被覆盖。如果子组件内要修改的话推荐使用 computed
// Father.vue 传送
<template>
<child :msg="msg"></child>
</template>
// Son.vue 接收
export default {
// 写法一 用数组接收
props:['msg'],
// 写法二 用对象接收,可以限定接收的数据类型、设置默认值
props:{
msg:{
type:String, // 数据类型
default:'默认值'
}
},
mounted(){
console.log(this.msg)
},
}
2. v-model
可以实现将父组件传给子组件的数据为双向绑定,子组件通过 $emit 修改父组件的数据
// Father.vue
<template>
<child v-model="value"></child>
</template>
<script>
export default {
data(){
return {
value:1
}
}
}
// Son.vue
<template>
<input :value="value" @input="handlerChange">
</template>
export default {
props:["value"],
// 可以修改事件名,默认为 input
model:{
// prop:'value', // 上面传的是value这里可以不写,如果属性名不是value就要写
event:"updateValue"
},
methods:{
handlerChange(e){
this.$emit("input", e.target.value)
// 如果有上面的重命名就是这样
this.$emit("updateValue", e.target.value)
}
}
}
</script>
3. .sync
与v-model类似,区别在于:一个组件上只能有一个v-model,.sync修饰符可以有多个,但是在vue3中没有了.sync,将功能添加给了v-model。.sync可以帮我们实现父组件向子组件传递的数据 的双向绑定,所以子组件接收到数据后可以直接修改,并且会同时修改父组件的数据
// Parent.vue
<template>
<child :page.sync="page"></child>
</template>
<script>
export default {
data(){
return {
page:1
}
}
}
// Child.vue
export default {
props:["page"],
computed(){
// 当我们在子组件里修改 currentPage 时,父组件的 page 也会随之改变
currentPage {
get(){
return this.page
},
set(newVal){
this.$emit("update:page", newVal)
}
}
}
}
</script>
4. ref
ref 如果在普通的DOM元素上,引用指向的就是该DOM元素; 如果在子组件上,引用的指向就是子组件实例,然后父组件就可以通过 ref 主动获取子组件的属性或者调用子组件的方法
// Child.vue
export default {
data(){
return {
name:"张三"
}
},
methods:{
someMethod(msg){
console.log(msg)
}
}
}
// Parent.vue
<template>
<child ref="child"></child>
</template>
<script>
export default {
mounted(){
const child = this.$refs.child
console.log(child.name) // 张三
child.someMethod("调用了子组件的方法")
}
}
</script>
5. $emit
子组件通过派发事件的方式给父组件数据,或者触发父组件更新等操作
// Child.vue 派发
export default {
data(){
return { msg: "发给父组件的信息" }
},
methods: {
handleClick(){
this.$emit("sendMsg",this.msg)
}
},
}
// Parent.vue 响应
<template>
<child v-on:sendMsg="getChildMsg"></child>
// 或 简写
<child @sendMsg="getChildMsg"></child>
</template>
export default {
methods:{
getChildMsg(msg){
console.log(msg) // 父组件接收到的消息
}
}
}
6. slot
就是把子组件的数据通过插槽的方式传给父组件使用,然后再插回来
// Child.vue
<template>
<div>
<slot :user="user"></slot>
</div>
</template>
export default{
data(){
return {
user:{ name:"张三" }
}
}
}
// Parent.vue
<template>
<div>
<child v-slot="slotProps">
{{ slotProps.user.name }}
</child>
</div>
</template>
7. $attrs
多层嵌套组件传递数据时,如果只是传递数据,而不做中间处理的话就可以用这个,比如父组件向孙子组件传递数据时
// Parent.vue
<template>
<child :name="name" title="1111" ></child>
</template
export default{
data(){
return {
name:"张三"
}
}
}
// Child.vue
<template>
// 继续传给孙子组件
<sun-child v-bind="$attrs"></sun-child>
</template>
export default{
props:["name"], // 这里可以接收,也可以不接收
mounted(){
// 如果props接收了name 就是 { title:1111 },否则就是{ name:"张三", title:1111 }
console.log(this.$attrs)
}
}
8. $children / $pareent
$children: 多层嵌套组件传递数据时,如果只是传递数据,而不做中间处理的话就可以用这个,比如父组件向孙子组件传递数据时
$parent: 获取到一个父节点的 VueComponent 对象,同样包含父节点中所有数据和方法等
// Parent.vue
export default{
mounted(){
this.$children[0].someMethod() // 调用第一个子组件的方法
this.$children[0].name // 获取第一个子组件中的属性
}
}
// Child.vue
export default{
mounted(){
this.$parent.someMethod() // 调用父组件的方法
this.$parent.name // 获取父组件中的属性
}
}
9. provide / indect
provide / inject 为依赖注入,说是不推荐直接用于应用程序代码中,但是在一些插件或组件库里却是被常用
provide: 可以让我们指定想要提供给后代组件的数据或方法
inject:
在任何后代组件中接收想要添加在这个组件上的数据或方法,不管组件嵌套多深都可以直接拿来用
需要注意的是 provide 和 inject 传递的数据不是响应式的,也就是说用 inject 接收来数据后,provide 里的数据改变了,后代组件中的数据不会改变,除非传入的就是一个可监听的对象
// 父组件
export default{
// 方法一 不能获取 this.xxx,只能传写死的
provide:{
name:"张三",
},
// 方法二 可以获取 this.xxx
provide(){
return {
name:"张三",
msg: this.msg // data 中的属性
someMethod:this.someMethod // methods 中的方法
}
},
methods:{
someMethod(){
console.log("这是注入的方法")
}
}
}
// 后代组件
export default{
inject:["name","msg","someMethod"],
mounted(){
console.log(this.msg) // 这里拿到的属性不是响应式的,如果需要拿到最新的,可以在下面的方法中返回
this.someMethod()
}
}
10. EventBus
EventBus 是中央事件总线,不管是父子组件,兄弟组件,跨层级组件等都可以使用它完成通信操作
// 方法一
// 抽离成一个单独的 js 文件 Bus.js ,然后在需要的地方引入
// Bus.js
import Vue from "vue"
export default new Vue()
// 方法二 直接挂载到全局
// main.js
import Vue from "vue"
Vue.prototype.$bus = new Vue()
// 方法三 注入到 Vue 根对象上
// main.js
import Vue from "vue"
new Vue({
el:"#app",
data:{
Bus: new Vue()
}
})
以方法一按需引入为例:
// 在需要向外部发送自定义事件的组件内
<template>
<button @click="handlerClick">按钮</button>
</template>
import Bus from "./Bus.js"
export default{
methods:{
handlerClick(){
// 自定义事件名 sendMsg
Bus.$emit("sendMsg", "这是要向外部发送的数据")
}
}
}
// 在需要接收外部事件的组件内
import Bus from "./Bus.js"
export default{
mounted(){
// 监听事件的触发
Bus.$on("sendMsg", data => {
console.log("这是接收到的数据:", data)
})
},
beforeDestroy(){
// 取消监听
Bus.$off("sendMsg")
}
}
11. Vuex
Vuex是适用于在Vue项目开发时使用的状态管理工具。试想一下,如果一个项目开发中频繁的使用组件传参的方式来同步data中的值,一旦项目变得很庞大,管理和维护这些值将是相当麻烦的工作。为此,Vue为这些被多个组件频繁使用的值提供了一个统一管理的工具-Vuex。在具有Vuex的Vue项目中,我们只需要把这些值定义在Vuex中,即可在整个Vue项目的组件中进行使用。
12. $root
使用$root可以访问根实例的数据,访问/调用根实例的方法
创建一个根实例:
new Vue({
el:"#app",
data: {
foo: 1
},
computed: {
bar: function () { /* ... */ }
},
methods: {
baz: function () { /* ... */ }
}
})
使用$root可以访问
// 获取根组件的数据
this.$root.foo
// 写入根组件的数据
this.$root.foo = 2
// 访问根组件的计算属性
this.$root.bar
// 调用根组件的方法
this.$root.baz()