目录
- 一、属性传值——父传子
- 二、反向传值——子传父$emit
- 三、反向传值——子传父--sync
- 四、反向传值——子传父--v-model
- v-model指令的修饰符:
- 五、多层(跨级)组件传值
- 六、$ parent/$root、$children/$refs
- 七、Vue 依赖注入 - Provide/Inject(重点)
- 八、中央事件总线bus
一、属性传值——父传子
父组件通过属性传值给子组件 父组件修改数据后会刷新页面并重新传值给子组件
子组件可以修改父组件传的值并刷新自己的页面 但是并不会修改父组件中的值
父组件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修饰符--双向绑定时,当光标离开时才更新对应的变量
- 用户使用v-model之后,用户每次修改输入内容,都会将后台的数据同时绑定。
- 为了避免这种情况的发生,使用lazy修饰符来进行限定。
- 只有当用户的input中失去焦点或用户点击回车后,才会将后台的数据进行修改更新。
- 类似于懒加载和防抖的设计。
<input type="text" v-model.lazy="message">
2、number修饰符--自动将用户的输入值转为数值类型
- 当用户在input中输入数字时,浏览器会默认将输入的数字转化为string类型。
- 使用number修饰符来将输入的数字重新转为number类型。
<input type="text" v-model.number="age">
3.trim修饰符--自动忽略输入内容的首尾空白字符
- 用户可能输入的字符串中含有空格,这样系统在处理时可能会出现错误。
- 使用trim修饰符来去掉字符串首部或者尾部的所有空格。
<input type="text" v-model.trim="userName">
五、多层(跨级)组件传值
父元素传的所有属性$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
$root: 访问根组件vm对象,所有的子组件都可以将这个实例作为一个全局 store 来访问或使用,现在有更好的技术vuex代替。
$parent:访问父组件对象,直接操作父组件的data数据,不需要再使用属性传值,但是容易出现渲染混乱之后只渲染一个的情况 可以连点 this.parent.parent...
$children:访问子组件对象数组,不是子元素 不能保证顺序,没有按照顺序加载,加载顺序是混乱的也不是响应式的
$refs:只会在组件渲染完成之后生效,并且它们不是响应式的。应该避免在模板或计算属性中访问 $refs。在组件或者原生元素绑定ref属性(类似于id) 在父组件中可以通过 this.$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> |
结果显示:
七、Vue 依赖注入 - Provide/Inject(重点)
注:Provide和Inject绑定并不是可响应的
父组件使用:provide:提供数据
把data中的数据提供给子孙组件
// provide选项提供变量 | |
provide: { | |
message: 'provided by father' | |
}, |
inject:["message"]
八、中央事件总线bus
自定义事件的语法:
Vue提供的技术:某继承Vue的组件有三个功能:
1.触发x组件的a事件:x.$emit("a事件",参数)
2.给x组件绑定a事件:x.$on("a事件",监听器函数)
3.给x组件解绑a事件:x.$off("a事件",监听器函数)
通过创建一个新的vm对象,专门统一注册事件,供所有组件共同操作,达到所有组件随意隔代传值的效果:
main.js:
Vue.prototype.$bus = new Vue({ | |
methods: { | |
//绑定事件 | |
on(eventname, callback) { | |
this.$on(eventname, callback) | |
}, | |
//触发事件 | |
emit(eventname, ...arg) { | |
this.$emit(eventname, ...arg) | |
}, | |
//解绑事件 | |
off(eventname, callback) { | |
this.$off(eventname, callback) | |
}, | |
} | |
}) |
使用:
this.$bus.on("事件",监听器函数)
this.$bus.emit("事件","参数")
this.$bus.off("事件",监听器函数)
示例:
//组件1: | |
this.$bus.on('changedFormObject',(val) =>{ | |
//接受并处理传过来的值:val | |
this.msg = val; | |
}); | |
//组件2: | |
this.$bus.emit('changedFormObject',this.inputValue);//把组件2的data中的给inputValue值传给组件1 |