缺点:如果组件嵌套层次多的话,数据传递比较繁琐
1)父组件向子组件传值 props
<body>
<div id="app">
<compa :propa='username' :propb='true' :propc="[1,2,3]" :propd='{name:"dny"}' :prope='abc' :propf='["apple","banana"]' proph='默认父组件传递'></compa>
</div>
<script>
const compa={
props:{
propa:String,
propb:{
type:Boolean,
required:true//必传
},
propc:{
type:Array
},
propd:{
type:Object,
required:true
},
prope:{
type:Function,
required:true
},
propf:{
validator:function(value){
if(value.indexOf('banana')>-1){
return true
}else{
return false
}
},
required:true
},
//设置默认值 如果父组件没有传 就走默认值
proph:{
default(){
return '设置默认值'
}
}
},
template:`{{proph}}
`,
}
var vm=new Vue({
el:"#app",
data:{
username:'dny'
},
components:{
compa
},
methods:{
abc(){
}
}
})
</script>
</body>
2)子组件向父组件传值 —$emit
<body>
<div id="app">
{{countF}}
<gp-18 @counterchanger='handlerChange'></gp-18>
</div>
<script type="text/template" id="gp-18Temp">
<div>
<h1>gp-counter</h1>
<button @click='decrement(1)'>-</button>
{{count}}
<button @click='increment(1)'>+</button>
</div>
</script>
<script>
//全局组件
Vue.component('gp-18',{
template:'#gp-18Temp',
data(){
return{
count:0
}
},
methods:{
increment(num){
this.count++
this.$emit('counterchanger',this.count)
},
decrement(num){
this.count--
this.$emit('counterchanger',this.count)
}
}
})
var vm=new Vue({
el:'#app',
data:{
countF:0
},
methods:{
//子组件的值将作为第一个参数
handlerChange(num){
this.countF=num
}
}
})
</script>
</body>
缺点:$refs 只会在组件渲染完成之后生效,并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs。
<body>
<div id="app">
<input type="text" ref='myinput'>
<compa ></compa>
</div>
<script>
const compb={
data(){
return{
title:"孙子组件的数据"
}
},
template:'compb-{{$root.username}}
',
mounted(){
//获取根组件的内容
console.log(this.$root.username)
//获取父组件的内容
console.log(this.$parent.title)
console.log(this.$parent.start())
}
}
const compa={
props:['user'],
data(){
return{
title:'父组件的数据'
}
},
template:`
compa
`,
components:{
compb
},
methods:{
start(){
console.log('父组件的方法');
}
},
mounted(){
console.log(this.$refs.refcomb.title);
}
}
var vm=new Vue({
el:"#app",
data:{
username:'dny'
},
components:{
compa
},
mounted(){
console.log(this.$refs.myinput);
}
})
</script>
</body>
缺点:依赖注入将应用程序中的组件与它们当前的组织方式耦合起来,使重构变得更加困难。同时所提供的属性是非响应式的
<body>
<div id="app">
<input type="text" ref='myinput'>
<compa></compa>
</div>
<!-- 数据不是响应式的 -->
<script>
const compb = {
inject: ['username'],
template: 'compb-{{username}}
',
mounted(){
console.log(this.foo()) // dny
}
}
const compa = {
template: `
compa
`,
components: {
compb
},
}
var vm = new Vue({
el: "#app",
data: {
username: 'dny'
},
//返回内容在子组件和孙子组件都可以访问到
provide: function () {
return {
username: this.username,
foo:()=>{
return this.username
}
}
},
})
</script>
</body>
不支持响应式
<body>
<div id="app">
<compa></compa>
</div>
<script>
var eventbus=new Vue()
const compb = {
template: 'compb-
',
mounted(){
eventbus.$on('message',function(msg){
console.log(msg);
})
}
}
const compa = {
template: `
compa
`,
components: {
compb
},
}
var vm = new Vue({
el: "#app",
data: {
username: 'dny'
},
components: {
compa
},
methods:{
handleback(){
eventbus.$emit('message','hello world')
}
}
})
</script>
</body>
在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件都没有明显的变更来源。这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<parent-component></parent-component>
</div>
<script>
let ChildComponent={
props:['title'],
template:`
-Child------
`,
mounted(){
this.$emit('update:title',"def")
}
}
let ParentComponent={
template:`
parent-component-----{{title}}
`,
data(){
return{
title:"abc"
}
},
components:{
ChildComponent
}
}
var vm= new Vue({
el:"#app",
components:{
ParentComponent
}
})
</script>
</body>
</html>
支持响应式,但是数据的读取和修改需要按照流程来操作,不适合小型项目
<body>
<div id="app">
<counter-btn type='decrement'></counter-btn>
<counter-span></counter-span>
<counter-btn type='increment'></counter-btn>
</div>
<script>
Vue.component('counter-btn',{
props:['type'],
template:``,
computed:{
btntext(){
return this.type==='decrement'?'-':'+'
}
},
methods:{
handleClick(){
if(this.type==='increment'){
// this.$store.state.count++
//调用mutations的方法
// this.$store.commit('increment',{num:3})
store.dispatch('add',{num:3})
}else{
// this.$store.state.count--
this.$store.commit('decrement',{num:2})
}
}
}
})
Vue.component('counter-span',{
template:`{{$store.state.count}}`
})
var store=new Vuex.Store({
state:{
count:0
},
//同步数据修改
mutations:{
increment(state,obj){
state.count+=obj.num
},
decrement(state,obj){
state.count-=obj.num
}
},
//异步数据修改
actions:{
add(context,obj){
setTimeout(()=>{
context.commit('increment',obj)
},3000)
}
}
})
var em=new Vue({
el:"#app",
store
})
</script>
</body>