一、属性传值——父传子
父组件通过属性传值给子组件 父组件修改数据后会刷新页面并重新传值给子组件
子组件可以修改父组件传的值并刷新自己的页面 但是并不会修改父组件中的值
父组件App:
<template>
<div id="app">
<Box v-for="(item, index) in arr"
:key="item.id"
:employee="item.employee"
:salary="item.salary"></Box>
<p>总工资:{{total}}</p>
</div>
</template>
<script>
import Box from "./Box.vue";
export default {
data() {
return {
arr: [
{ id: 1, employee: "haha", salary: 3221 },
{ id: 2, employee: "xixi", salary: 4262 },
{ id: 3, employee: "yoyo", salary: 3122 }
]
};
},
components: {
Box
},
computed:{
total(){
let sum=0
for (let i = 0; i < this.arr.length; i++) {
sum+=this.arr[i].salary
}
return sum
}
}
};
</script>
子组件Box:
<template>
<div>
<span>员工:{{employee}} 工资:{{salary}}</span>
<button @click="change">涨工资</button>
</div>
</template>
<script>
export default {
props:["employee","salary"],
methods:{
change(){
this.salary+=500
}
}
}
</script>
结果显示:
二、反向传值——子传父$emit
在父组件中绑定事件 事件被触发后获取子组件传的值 修改data中的数据 刷新页面
在子组件修改数据后 触发子组件中的父组件的事件 并传新值$emit("事件","值")
父组件App:
<template>
<div id="app">
<Box @mychange="fn" v-for="(item, i) in arr"
:key="item.id"
:employee="item.employee"
:salary="item.salary"
:index="i"></Box>
<p>总工资:{{total}}</p>
</div>
</template>
<script>
import Box from "./Box.vue";
export default {
data() {
return {
arr: [
{ id: 1, employee: "haha", salary: 3221 },
{ id: 2, employee: "xixi", salary: 4262 },
{ id: 3, employee: "yoyo", salary: 3122 }
]
};
},
components: {
Box
},
methods:{
fn(newsalary,index){
//父组件接收到子组件传来的新值更新自己的数据 并重新传值 刷新页面
this.arr[index].salary=newsalary
this.$set(this.arr,index,this.arr[index])
}
},
computed:{
total(){
let sum=0
for (let i = 0; i < this.arr.length; i++) {
sum+=this.arr[i].salary
}
return sum
}
}
};
</script>
子组件Box:
<template>
<div>
<span>员工:{{employee}} 工资:{{salary}}</span>
<button @click="change">涨工资</button>
</div>
</template>
<script>
export default {
props:["employee","salary","index"],
methods:{
change(){
let newsalary=this.salary+500
//触发父组件的事件 同时将修改后的数据传给父组件
this.$emit("mychange",newsalary,this.index)
}
}
}
</script>
结果显示:
三、反向传值——子传父--sync
子:this.$emit("updata:a","更改的值")
父:<Box :a.sync="msg"></Box>
.sync 帮忙修改了父组件的数据 不用父组件再绑定事件获取新值修改自己的数据
父组件App:
<template>
<div>
<h1>app组件--{{msg}}</h1>
<Box :a1.sync="msg"></Box>
</div>
</template>
<script>
import Box from "./Box.vue"
export default {
data() {
return {
msg: "app的数据",
}
},
components: {
Box
},
}
</script>
子组件Box:
<template>
<div>
<h2>box组件--a1--{{a1}}</h2>
<button @click="change">修改a1中的数据</button>
</div>
</template>
<script>
export default {
props:["a1"],
methods:{
change(){
console.log("点击了按钮")
// 由以下两步操作,变为了一步:
//this.a1="box修改了a1的值"
// this.$emit("myevent","box修改了a1的值")
this.$emit("update:a1","box修改了a1的值")
}
}
}
</script>
结果显示:
四、反向传值——子传父--v-model
v=model <----语法糖----> :value="msg" @input="fn"
父:<Box :v-model="msg"></Box>
子:props:["value"] this.$emit("input","修改的值") 触发input事件
父组件中:
<template>
<div class="app">
<h2>app组件--{{msg}}</h2>
<Box v-model="msg"></Box>
</div>
</template>
<script>
import Box from "./Box.vue"
export default {
data() {
return {
msg:"app组件的数据"
}
},
components: {
Box
},
methods:{
}
}
</script>
子组件中:
<template>
<div class="box">
<h2>box组件--{{value}}</h2>
<button @click="change">change</button>
</div>
</template>
<script>
export default {
props:["value"],
methods:{
change(){
this.$emit("input","box修改了数据")
}
}
}
</script>
结果显示:
v-model指令的修饰符:
1、lazy修饰符--双向绑定时,当光标离开时才更新对应的变量
2、number修饰符--自动将用户的输入值转为数值类型
3.trim修饰符--自动忽略输入内容的首尾空白字符
五、多层(跨级)组件传值
父元素传的所有属性$attrs(属性传递)
父元素传的所有监听器$listener(事件传递)
App:<Box1 :b1="msg" @x="xchange"></Box1> 事件虽然绑在子组件 但是是孙组件在触发事件
Box1:<Box2 v-bind="$attrs" v-on="$listener"></Box2> Box1只是作为中间人 将绑定的属性和事件都传给子组件Box2
Box2:props:["b1"] 触发上层传下来的App的事件 修改App组件的数据 再更新数据 重新刷新页面
App组件中:
<template>
<div>
<h1>app-{{msg}}</h1>
<button @click="change1">点击修改app组件的msg</button>
<Box1 :b1="msg" @x="xchange"></Box1>
</div>
</template>
<script>
import Box1 from "./Box1.vue"
export default {
data() {
return {
msg: "app组件的数据"
}
},
methods:{
change1(){
this.msg="app组件修改了msg的数据"
},
xchange(arg){
this.msg=arg
}
},
components:{
Box1
}
}
</script>
Box1组件中:
<template>
<div>
<h1>{{$attrs.b1}}</h1>
<Box2 v-bind="$attrs" v-on="$listeners"></Box2>
</div>
</template>
<script>
import Box2 from "./Box2.vue"
export default {
components:{
Box2
},
methods:{
look(){
console.log(this.$attrs)
}
}
}
</script>
Box2组件中:
<template>
<div>
<h3>box2--{{b1}}</h3>
<button @click="change">change</button>
</div>
</template>
<script>
export default {
props:["b1"],
methods:{
change(){
this.$emit("x","box2修改了数据")
}
}
}
</script>
结果显示:
六、$ parent/$root、$children/$refs
App组件:
<template>
<div>
<h1>app组件--{{msg}}</h1>
<div>
<Box1></Box1>
<!--虽然Box1组件写在div里面 但是.$parent指的还是父组件App 而非div-->
</div>
</div>
</template>
<script>
import Box1 from "./Box1.vue"
export default {
data() {
return {
msg:"app组件的数据"
}
},
methods: {},
components: {
Box1
}
}
</script>
Box1组件:
<template>
<div>
<button @click="look">box1</button>
<Box2></Box2>
<Box2></Box2>
<p ref="p1">ref</p>
<button @click="getref">获取ref</button>
</div>
</template>
<script>
import Box2 from "./Box2.vue"
export default {
components: {
Box2
},
methods: {
getref(){
console.log(this.$refs)
},
look() {
console.log(this,this.$parent,this.$children,this.$root)
this.$parent.msg="box1修改了app的数据"
}
}
}
</script>
Box2组件:
<template>
<div>
<p>{{$parent.$parent.msg}}</p>
<button @click="change1">box2-change</button>
</div>
</template>
<script>
export default {
methods:{
change1(){
this.$parent.$parent.msg="box2修改了数据"
}
}
}
</script>
结果显示: