props && 自定义方法
props 传数据给子组件使用 Vue 中父组件到子组件的通信主要由子组件的 props 属性实现。
这是最简单也是最原始的自定义事件传给自组件修改自己的 data
但是必须结合
- 使用
$emit
接收执行父组件传方法和props
parent.vue
<template>
<div>
<div>父组件的数据 number :{{ number }}</div>
<!-- change-number 是子组件接收的事件名, changNumber 是父组件的事件名 -->
<Son :number="number" @change-number="changeNumber" />
</div>
</template>
<script>
export default {
data() {
return {
number: 1000,
};
},
methods: {
changeNumber(number) {
this.number = number;
},
},
};
</script>
Son.vue
<template>
<div>
<div>子组件展示父组件的数据 number :{{ number }}</div>
<!-- 自定义事件 -->
<button @click="$emit('change-number', 2000)">点击修改</button>
</div>
</template>
<script>
export default {
props: {
number: {
type: Number,
},
},
methods: {
// v-model
handle() {
this.$emit("input", 1234);
},
},
};
</script>
.sync
parent.vue
<template>
<div>
<!-- 简化父组件定义方法传递子组件调用 -->
<!-- .sync 语法糖 .sync 是修饰符 -->
<!-- 其实子组件不需要展示 number 的话可以不传 :number="number" -->
<!-- 组件名是 update 也可以是 update:number $event 是子组件传过来的参数 -->
<Son :number="number" @update:number="number = $event" />
<Son :number="number" @update="number = $event" />
<!-- .sync 简写的方式 -->
<Son :number.sync="number" />
<!-- 传对象 -->
<Son v-bind.sync="obj" />
</div>
</template>
<script>
export default {
data() {
return {
number: 1000,
obj: {
a: 100,
b: 200,
},
};
},
};
</script>
Son.vue
<template>
<div>
<div>子组件展示父组件的数据 number :{{ number }}</div>
<!-- .sync -->
<div>子组件展示父组件的数据 obj.a :{{ a }}</div>
<div>子组件展示父组件的数据 obj.b :{{ b }}</div>
<!-- .sync 语法糖 -->
<!-- 传单个值 -->
<button @click="$emit('update:number', 20)">点击修改</button>
<button @click="$emit('update', 20)">点击修改</button>
<!-- 传多个值或者对象 -->
<button @click="$emit('update:a', 22)">点击修改 a</button>
<button @click="$emit('update:b', 23)">点击修改 b</button>
</div>
</template>
<script>
export default {
props: {
number: {
type: Number,
},
a:{
type:Number,
}
b:{
type:Number,
}
},
};
</script>
v-model
parent.vue
<template>
<div>
<!-- v-model -->
<!-- 有区别的就是 子组件接收要使用 value 接收 -->
<Son :value="number" @input="number = $event" />
<!-- 简写 -->
<Son v-model="number" />
</div>
</template>
<script>
export default {
data() {
return {
number: 1000,
};
},
};
</script>
Son.vue
<template>
<div>
<!-- v-model -->
<button @click="$emit('input',666)">修改 number</button>
<button @click="handle">修改 number</button>
</div>
</template>
<script>
export default {
methods: {
// v-model
handle() {
this.$emit("input", 1234);
},
},
};
</script>
$parent
父组件
<script>
export default {
data() {
return {
number: 1000,
};
},
};
</script>
子组件
<!-- $parent && $children -->
<button @click="$parent.number = 888">点击修改 $parent 888</button>
provide && inject
- 什么是 provide && inject
provide/inject 需要一起使用,允许一个祖先组件向其所有子孙后代注入一个依赖 provide,不论组件层次有多深,子组件都能用 inject 接收的到父组件的数据, 并在起上下游关系成立的时间里始终生效。 - provide 和 inject 只有父子孙组件之间才可以拿到。
总结
provide/inject 提供了一种新的组件间通信的方法。它允许父组件向子孙组件间进行跨层级的数据分发。但是 provide/inject 是非响应式的,如果要子孙组件根据父组件的值进行改变,provide/inject 机制不是一个好的选择。此时可以使用 Vuex 来管理状态。
- 在父组件中使用 provide(函数),写下数据
provide() {
x: 12,
},
- 在子组件中通过 inject(数组),拿到需要的父组件中的数据,使用数据的时候,等同于 data 里的数据使用方法。
inject: ["x"];
- provide 提供的数据是不可响应的
- 如果想提供响应数据,可以将数据做成响应的 Vue.abservable 或者 vuex
- 当需要提供的数据并不是直接在父组件 data 内写死的,需要在 created 或者 mounted 生命周期钩子内获取,那么直接提供是不行的。
- 此时需要提供一个方法,在父组件内定义一个方法,该方法返回需要的数据。然后将此方法当做 provide 提供的。
- 我们也可以将修改父组件的方法传递给子组件修改。
// Parent.vue
<div>父组件 provide 数据:{{ Obj.name }}</div>
<button @click="Obj.name = '小琴'">父组件修改</button>
<Son />
data() {
return {
Obj: null,
};
}
created() {
this.Obj = { name: "小五" };
},
methods: {
// ProObj() {
// return this.Obj;
// },
}
// 想要把父组件的数据传递必须要写成函数形式
provide() {
return {
x: 12,
};
},
provide() {
return {
// getObj: this.ProObj,
getObj: () => this.Obj,
setObj: (name) => (this.Obj.name = name),
};
},
//子组件 Son.vue
<div>子组件展示父组件的数据 provide {{ getObj().name }}</div>
<button @click="setObj('小义')">子组件修改</button>
// 把从父组件接收过来的值
inject: ["getObj", "setObj"],
$attrs && $listeners
- 是什么
$attrs
存储传递变量$listeners
存储传递事件
- 怎么用
-
通过父组件传递给子组件,子组件属性方法自动接收
-
与
$props比较,
$props
必须在组件中注册了props
才能用拿到值,所以在嵌套层级比较深的组件中$attrs
拿值更加便捷 -
只能父组件传递给子组件,子组件不能修改。
-
不会传递 props 声明的数据,和不含 .native 事件修饰符的事件。
-
App.vue
<template>
<div>
<Parent2
:age="age"
:obj="{ name: '小五' }"
@look="() => console.log(1)"
@click="handle"
/>
<button @click="handle">点击</button>
</div>
</template>
<script>
import Parent2 from "./components/Parent2";
export default {
name: "App",
components: {
Parent2,
},
data() {
return {
age: 1,
};
},
created() {
this.age = 666;
console.log("父组件的 age", this.age);
},
methods: {
handle() {
this.age = 999;
},
},
};
</script>
- Parent.vue
<template>
<div>
<div>父组件</div>
<Son2 v-bind="$attrs" v-on="$listeners" />
</div>
</template>
<script>
import Son2 from "./Son2";
export default {
name: "Parent2",
components: {
Son2,
},
created() {
// console.log(this);
console.log(this.$attrs); //存储变量 age:666 obj: {name: "小五"}
console.log(this.$listeners); // 存储事件 {look: ƒ, click: ƒ}
},
};
</script>
- Son.vue
<template>
<div>
<div>子组件</div>
</div>
</template>
<script>
export default {
name: "Son2",
data() {
return {
a: 2,
};
},
created() {
console.log("子组件的变量", this.$attrs); // age:666 obj: {name: "小五"}
console.log("子组件事件", this.$listeners); // {look: ƒ, click: ƒ}
this.$attrs.age = this.a; //改变 $attrs 的值
console.log(this.a); // 2
console.log("子组件的变量", this.$attrs); // age:2 obj: {name: "小五"}
},
};
</script>
<style></style>
.native
解释:.native
是给一个组件的根元素绑定一个原生的事件
例子:
<header @click.native></header>
<Home @click.native></Home>
<router-link @click.native="handle" tag="a" exact to="/?tab=all"></router-link>
<!-- 错误的写法 <header @number.native></header> 必须是原生的事件 click moussenter 等等才行-->
事件修饰符 .native 的作用是给组件的根元素的 dom 节点绑定事件 什么叫根元素(组件下的大儿子。例如: Li.vue 下的 <li></li>
)
注释:@moussenter.native="change(0)"
找到 Li
组件的根元素(<li></li>)
绑定原生的事件 @moussenter
滑过的时候执行