Vue(小码哥王洪元)笔记02--父子组件间的通信,props基本用法,props值的两种方式,子组件向父组件传值,子组件内部双向数据绑定,父子组件的访问$children,$refs,$parent

1、父子组件间的通信
  • 子组件不应该直接向服务器请求数据
  • 顶层组件请求数据之后,再向子组件传递数据(通信)
  • 父向子:通过props(属性)父组件向子组件传递数据
  • 子向父:通过事件子组件向父组件发送消息
    在这里插入图片描述
2、props基本用法
  • 1、在顶层vue实例中(父组件)创建需要用于传递的数据,并注册一个子组件cpn
var app=new Vue({
  el:"#app",
  
  data:{
    message:"关于父组件传值",
    movies:['一秒钟','我和我的家乡','夺冠','雪国列车']
  },
  components:{
    'cpn':sonCpn//这里也可以直接按es6的写法,写为cpn
  }
}
  
);
  • 2、创建子组件,并使用分离方式在html中写组件模板
const sonCpn={
  template:'#cpn',
  //子组件中定义props属性接受父组件传来的值
  props:['cmoives','cmessage'],
  //最好写下data,其实不写也可以
  data(){
    return {}
  }
}

组件模板,注意是通过id=‘cpn‘和子组件构成联系的

<template id="cpn">
  <!--在子组件是使用父组件传递过来的信息-->
  <div>
    <div>{{cmessage}}</div>
    <ul>
      <li v-for="item in cmoives">{{item}}</li>
    </ul>
  </div>
</template>
  • 3、在html中使用自定义父组件
<div id="app">
  <!--这里自定义了两个属性cmovices和cmessage向子组件传值(movies数组和message变量),实际就是使用props属性数据-->
  <cpn :cmoives='movies' :cmessage='message'></cpn>
</div>

完整代码:

<body>
<div id="app">
  <!--这里自定义了两个属性cmovices和cmessage向子组件传值(movies数组和message变量)-->
  <cpn :cmoives='movies' :cmessage='message'></cpn>
</div>
<template id="cpn">
  <!--在子组件是使用父组件传递过来的信息-->
  <div>
    <div>{{cmessage}}</div>
    <ul>
      <li v-for="item in cmoives">{{item}}</li>
    </ul>
  </div>
</template>

<script type="text/javascript">
const sonCpn={
  template:'#cpn',
  //子组件中定义props属性接受父组件传来的值
  props:['cmoives','cmessage'],
  //最好写下data,其实不写也可以
  data(){
    return {}
  }
}
var app=new Vue({
  el:"#app",
  
  data:{
    message:"关于父组件传值",
    movies:['一秒钟','我和我的家乡','夺冠','雪国列车']
  },
  components:{
    'cpn':sonCpn//这里也可以直接按est的写法,写为cpn
  }
}
  
);


</script>
</body>
3、props值的两种方式

props值有两组方式,

  • 方式1:字符串数组,数组中的元素就是传递的值就是传递时的名称
//props字符串数组
props:['cmoives','cmessage'],
--------
//子组件中字符串数组元素对应属性值
<cpn :cmoives='movies' :cmessage='message'></cpn>
  • 方式2:对象,对象可以设置传递时的类型,也可以设置默认值
    当需要对props进行类型等验证时,就需要对象写法了
    支持验证的类型包含:
    string
    number
    boolean
    array
    object
    date
    function
    symbol

格式:
使用对象

 props:{
    //使用对象时,对象名对应模板的属性,同时可以指定接受数据的类型
    cmoives:Array,
    cmessage:String
  },

提供默认值

<script type="text/javascript">
const sonCpn={
  template:'#cpn',
  //子组件中定义props属性接受父组件传来的值
  props:{
    //使用对象时,对象名对应模板的属性,同时可以指定接受数据的类型
    cmoives:Array,
    //提供默认值
    cmessage:{
      type:String,
      default:'我是默认值',
      require:true//必传属性
    }
  },

  //最好写下data,其实不写也可以
  data(){
    return {}
  }
}
var app=new Vue({
  el:"#app",
  
  data:{
    //message:"关于父组件传值",屏蔽掉message后,由默认值来显示
    movies:['一秒钟','我和我的家乡','夺冠','雪国列车']
  },
  components:{
    'cpn':sonCpn//这里也可以直接按est的写法,写为cpn
  }
}
  
);


</script>
4、props驼峰标识写法

props不要写驼峰对象名,应当如下

props:{
    cmoives:Array,
    //非驼峰写法
    cmessage:{
      type:String,
      default:'我是默认值'
    }
  },
5、子组件向父组件传值
  • 通常是在子组件上发生了事件,在发生事件的同时,向父组件返回信息
  • 使用$emit()来传值,第一个参数是自定义事件名,第二个参数是发射出去的信息,传给父组件的监听函数

具体的执行过程

  • 1、创建子组件
//创建子组件
const sonCpn={
  //关联字符串模板
  template:'#cpn',
  //子组件的data必须是函数function而不能是对象
  data(){
    return {
      categories:[
        {id:'aa',name:'热门推荐'},
        {id:'bb',name:'手机数码'},
        {id:'cc',name:'家用电器'},
        {id:'dd',name:'电脑显卡'},
      ]
    }
  },
  • 2、子组件关联template模板字符串
  <!--子组件模板-->
<template id="cpn">
  <div>
    <button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button><br/>
  </div>
</template>
  • 3、创建父组件(这里使用顶级root的vue实例作为父组件)
var app=new Vue({
  el:"#app",
  
  data:{
    
  },
  methods:{
    //创建父组件的监听函数,item是子组件$emit()传递过来的值
    cpnClick(item){
      console.log(item.name);
    }
  },
  components:{
    'cpn':sonCpn//这里也可以直接按es6的写法,写为cpn
  }
}
  
);
  • 4、在html根中使用父组件
<!--父组件模板-->
<div id="app">
  <!--父组件监听子组件传来的值,itemClick是自定义事件名-->
  <cpn @item-click="cpnClick"></cpn>
</div>
  • 5、子组件设定自定义按钮点击事件函数,将子组件数据装载到函数参数中进行传递
<template id="cpn">
  <div>
    <button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button><br/>
  </div>
</template>
  • 6、子组件添加按钮事件响应函数的执行逻辑,通过$emit()函数将子组件的值发射出去
 methods:{
    //创建子组件向父组件传值的事件响应函数
    btnClick(item){
      //向父组件传值,定义一个子组件发出的自定义事件(itemClick)
      //第一个参数是自定义事件名
      //第二个参数是发射出去的信息,传给父组件的监听函数
      this.$emit('item-click',item)

    }
  }
  • 7、父组件监听子组件来之值
<!--父组件模板-->
<div id="app">
  <!--父组件监听子组件传来的值,itemClick是$emit()里面自定义的事件名-->
  <cpn @item-click="cpnClick"></cpn>
</div>
  • 8、创建父组件中监听来值的处理函数
methods:{
    //创建父组件的监听函数,item是子组件$emit()传递过来的值
    cpnClick(item){
      console.log(item.name);
    }
  },

完整的代码:

 <body>
<!--父组件模板-->
<div id="app">
  <!--父组件监听子组件传来的值,itemClick是$emit()里面自定义的事件名-->
  <cpn @item-click="cpnClick"></cpn>
</div>
  <!--子组件模板-->
<template id="cpn">
  <div>
    <button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button><br/>
  </div>
</template>

<script type="text/javascript">
//创建子组件
const sonCpn={
  //关联字符串模板
  template:'#cpn',
  //子组件的data必须是函数function而不能是对象
  data(){
    return {
      categories:[
        {id:'aa',name:'热门推荐'},
        {id:'bb',name:'手机数码'},
        {id:'cc',name:'家用电器'},
        {id:'dd',name:'电脑显卡'},
      ]
    }
  },
  
  methods:{
    //创建子组件向父组件传值的事件响应函数
    btnClick(item){
      //向父组件传值,定义一个子组件发出的自定义事件(itemClick)
      //第一个参数是自定义事件名
      //第二个参数是发射出去的信息,传给父组件的监听函数
      this.$emit('item-click',item)

    }
  }

}
var app=new Vue({
  el:"#app",
  
  data:{
    
  },
  methods:{
    //创建父组件的监听函数,item是子组件$emit()传递过来的值
    cpnClick(item){
      console.log(item.name);
    }
  },
  components:{
    'cpn':sonCpn//这里也可以直接按es6的写法,写为cpn
  }
}
  
);

</script>
</body>
6、子组件内部双向数据绑定
  • 1、子组件内要创建data进行绑定
data(){
        return{
          //通过vue实例的data来改变子组件里的值
          dnumber1:this.number1,
          dnumber2:this.number2
        }
      }
  • 2、子组件内要创建data进行绑定
    在子组件中进行v-model双向绑定,不要在父组件中进行双向数据绑定
    模板中
<template id="cpn">
  <div>
    <h2>props:{{number1}}</h2>
    <h2>data:{{dnumber1}}</h2>
    <input type="text" v-model="dnumber1"/>
    <h2>props:{{number2}}</h2>
    <h2>data:{{dnumber2}}</h2>
    <input type="text" v-model="dnumber2"/>

  </div>
</template>

组件定义中

components:{
    'cpn':{
      template:"#cpn",
      props:{
        number1:Number,
        number2:Number
      },
      data(){
        return{
          //通过vue实例的data来改变子组件里的值
          dnumber1:this.number1,
          dnumber2:this.number2
        }
      }
    }
  },
  • 3、子组件模板内进行双向绑定
    通过:value=“dnumber1”进行单向绑定(父传子)
    通过:input=‘自定义事件处理函数’,进行反向数据帮当
    完整代码(子传父)
<template id="cpn">
  <div>
    <h2>props:{{number1}}</h2>
    <h2>data:{{dnumber1}}</h2>
    <!--子组件模板内绑定数据,:value实现单向绑定(父传子),@input实现反向绑定(通过事件子传父)-->
    <input type="text" :value="dnumber1" @input='nubmer1input'/>
    <h2>props:{{number2}}</h2>
    <h2>data:{{dnumber2}}</h2>
    <input type="text" :value="dnumber2" @input='nubmer2input'/>

  </div>
</template>
  • 4、子组件模板内进行数据和事件回调方法逻辑的编写
components:{
    'cpn':{
      template:"#cpn",
      props:{
        number1:Number,
        number2:Number
      },
      data(){
        return{
          //通过vue实例的data来改变子组件里的值
          dnumber1:this.number1,
          dnumber2:this.number2
        }
      },
      methods:{
        nubmer1input(event){
          this.dnumber1=event.target.value
        },
        nubmer2input(event){
          this.dnumber2=event.target.value
        }
      },
    }
  },
  • 5、继续改造子组件,将子组件传来的信息传出去(传到父组件去)
 methods:{
        nubmer1input(event){
          this.dnumber1=event.target.value;
          this.$emit('num1change',this.dnumber1);
        },
        nubmer2input(event){
          this.dnumber2=event.target.value;
          this.$emit('num2change',this.dnumber2);
        }
      },
  • 6、在父组件中监听从子组件发过来的值
<!--父组件模板-->
<div id="app">
  <!--父组件监听子组件传来的值,通过自定义的num1change事件来调用num1change获得子组件传来的值-->
  <cpn :number1="num1" :number2="num2" @num1change='num1change' @num1change='num2change'></cpn>
  
</div>
  • 6、在父组件中实现自定义监听事件传来的值,调用自定义处理函数
methods:{
    num1change(value){
      this.num1=value;
    },
    num1change(value){
      this.num2=value;
    },
  },
  • 7、进一步修改自定义方法,让连个数值框出现某种倍数关系
methods:{
        nubmer1input(event){
          //1、将input中的vlaue复制到dnumber中
          this.dnumber1=event.target.value;
          //2、为了让父组件可以修改值,发出一个事件
          this.$emit('num1change',this.dnumber1);
          //3、同时修改dnumber2的值
          this.dnumber2=this.dnumber1*100
          this.$emit('num2change',this.dnumber2);
        },
        nubmer2input(event){
          this.dnumber2=event.target.value;
          this.$emit('num2change',this.dnumber2);
          this.dnumber1=this.dnumber2/100;
          this.$emit('num1change',this.dnumber1);
        }
      },

完整案例代码

<!DOCTYPE html>
<html>
<head>
<script src="vue.js"></script>
<style type="text/css">

</style>
</head>
<body>
<!--父组件模板-->
<div id="app">
  <!--父组件监听子组件传来的值,通过自定义的num1change事件来调用num1change获得子组件传来的值-->
  <cpn :number1="num1"
        :number2="num2" 
        @num1change='num1change' 
        @num2change='num2change'>
  </cpn>
  
</div>
  <!--子组件模板-->
<template id="cpn">
  <div>
    <h2>props:{{number1}}</h2>
    <h2>data:{{dnumber1}}</h2>
    <!--子组件模板内绑定数据,:value实现单向绑定(父传子),@input实现反向绑定(通过事件子传父)-->
    <input type="text" :value="dnumber1" @input='nubmer1input'/>
    <h2>props:{{number2}}</h2>
    <h2>data:{{dnumber2}}</h2>
    <input type="text" :value="dnumber2" @input='nubmer2input'/>

  </div>
</template>

<script type="text/javascript">

var app=new Vue({
  el:"#app",
  
  data:{
    num1:1,
    num2:0
  },
  methods:{
    num1change(value){
      this.num1=parseFloat(value);
    },
    num2change(value){
      this.num2=parseFloat(value);
    },
  },
  components:{
    'cpn':{
      template:"#cpn",
      props:{
        number1:Number,
        number2:Number
      },
      data(){
        return{
          //通过vue实例的data来改变子组件里的值
          dnumber1:this.number1,
          dnumber2:this.number2
        }
      },
      methods:{
        nubmer1input(event){
          //1、将input中的vlaue复制到dnumber中
          this.dnumber1=event.target.value;
          //2、为了让父组件可以修改值,发出一个事件
          this.$emit('num1change',this.dnumber1);
          //3、同时修改dnumber2的值
          this.dnumber2=this.dnumber1*100
          this.$emit('num2change',this.dnumber2);
        },
        nubmer2input(event){
          this.dnumber2=event.target.value;
          this.$emit('num2change',this.dnumber2);
          this.dnumber1=this.dnumber2/100;
          this.$emit('num1change',this.dnumber1);
        }
      },
    }
  },
  
}
  
);


</script>
</body>
</html>
7、父子组件的访问方式$children及 $refs
  • 有时候需要使用父组件直接访问子组件,子组件直接访问父主键,或者子组件之间访问
    父访问子:使用$children或 $refs(引用)
    子访问父:使用 $parent
  • $children 的访问
    this. $children是一个数组类型,包含所有子组件对象
    通过遍历取出所有子组件的message状态

使用$children[n].拿到子组件

<body>
<!--父组件模板-->
<div id="app">
  <cpn ></cpn>
  <button @click='btnclick'>打印子组件message</button>

</div>
  <!--子组件模板-->
<template id="cpn">
  <div>我是子组件 </div>
</template>

<script type="text/javascript">

var app=new Vue({
  el:"#app",
  
  data:{
    message:'hello world'
  },
  methods:{
    btnclick(){
      this.$children[0].showMessage();
      console.log(this.$children[0].name); 

    }
  },
  components:{
    'cpn':{
      template:"#cpn",
      data(){
        return{
          name:'我是子组件的属性'
        }
      },
      methods:{
        showMessage(){
          console.log('show son component message');
        }
      }
      
    }
  },
  
}
  
);


</script>
</body>

使用下标值去拿对象不是特别好,有可能拿错,可以通过$refs去拿

  • 1、在html使用组件时对自定义组件设置一个属性(customProp)
 <div id="app">
  <cpn ref='customProp'></cpn>
  <button @click='btnclick'>打印子组件message</button>
- 2、取值路径为:
this.$refs.customProp.name

完整代码为:

<body>
<!--父组件模板-->
<div id="app">
  <cpn ref='customProp'></cpn>
  <button @click='btnclick'>打印子组件message</button>

</div>
  <!--子组件模板-->
<template id="cpn">
  <div>我是子组件 </div>
</template>

<script type="text/javascript">

var app=new Vue({
  el:"#app",
  
  data:{
    message:'hello world'
  },
  methods:{
    btnclick(){
     console.log(this.$refs.customProp.name);
    }
  },
  components:{
    'cpn':{
      template:"#cpn",
      data(){
        return{
          name:'我是子组件的属性'
        }
      },
      methods:{
        showMessage(){
          console.log('show son component message');
        }
      }
      
    }
  },
  
}
  
);


</script>
</body>
8、子组件访问父组件(少用)$parent
<body>
<!--父组件模板-->
<div id="app">
  <cpn></cpn>

</div>
  <!--子组件模板-->
<template id="cpn">
  <div>
    <div>我是子组件 </div>
    <button @click='btnclick'>按钮</button>
  </div>
</template>

<script type="text/javascript">

var app=new Vue({
  el:"#app",
  
  data:{
    message:'hello world'
  },
  methods:{
    
  },
  components:{
    'cpn':{
      template:"#cpn",
      data(){
        return{
          name:'我是子组件的属性'
        }
      },
      methods:{
        btnclick(){
          //1、访问父组件
          console.log(this.$parent);
          //访问根组件
          console.log(this.$root);
        }
      }
      
    }
  },
  
}
  
);


</script>
</body>
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值