Vue基础技能【五、组件数据通信】

1、方法1:父子关系进行通信(父子之间)

1.1、父传子

  • 思路: 父要获取到该子组件,然后给该子组件修改数据。

  • 核心:父要如何获取到子

  • 实现: 父组件内部 通过 this.$refs 来获取到子组件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
            #app{
                width: 400px;
                height: 400px;
                background-color: #eee;
            }
            .box{
                width: 200px;
                height: 200px;
                background-color: orange;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <h3>我是根组件</h3>
            {{msg}}
            <mydiv ref='mydiv'></mydiv>
        </div>
        
    
        <template id="mydiv">
            <div class="box">
                <h3>我是mydiv组件</h3>
                {{str}}
            </div>
        </template>
    
    </body>
    <script>
        Vue.component('mydiv',{
            template:'#mydiv',
            data(){
                return{
                    str:''
                }
            },
            methods:{
                show(){
                    console.log("我是mydiv组件的方法");
                }
            }
        })
    
        new Vue({
            el:"#app",
            data:{
                msg:"我是根的msg"
            },
            created(){
                console.log(this);
            },
            mounted(){
                            
                console.log(this.$refs.mydiv);
                //  父已经访问到了子    this.$refs.子组件名
                console.log(this.$refs.mydiv.nums);
                this.$refs.mydiv.str = this.msg
    
                // 父可以通过  this.$refs.变量名  获取子的所有属性和方法
    
                this.$refs.mydiv.show();
                
            }
        })
    
        // 父给子传递数据
    
            //  父的HTML模板里面    给组件添加上   ref属性   <组件名  ref='变量'></组件名>
            //  子组件有一个 str 的变量 值为空,  在他的模板里面  渲染str   {{str}}
            //  父的mounted生命周期函数里面, this.$refs.变量名 访问到子组件     
            //  父的mounted生命周期函数里面,给 子组件的对应变量赋值    this.$refs.变量名.str = 父里面的数据
    
            //【 核心:】 父组件获取到了子组件对象   this.$refs.变量名
    
                // 从而可以直接 修改子组件的数据 和 调用子组件的方法
    </script>
    </html>
    

1.2、子传父

  • 思路: 子组件要获取父组件,然后修改父组件的数据

  • 核心:子要如何获取到父

  • 实现: 子组件内部 通过 this.$parent 来获取到父组件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
            #app{
                width: 400px;
                height: 400px;
                background-color: #eee;
            }
            .box{
                width: 200px;
                height: 200px;
                background-color: orange;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <h3>我是根组件</h3>
            {{msg}}
            <mydiv ref='mydiv'></mydiv>
        </div>
        
    
        <template id="mydiv">
            <div class="box">
                <h3>我是mydiv组件</h3>
                {{str}}
            </div>
        </template>
    
    </body>
    <script>
       
        Vue.component('mydiv',{
            template:'#mydiv',
            data(){
                return{
                    str:'我是天下第一帅!'
                }
            },
            created(){
                console.log(this);
                console.log(this.$parent);
                console.log(this.$parent.msg);
                this.$parent.msg = this.str  // 赋给父
                console.log(this.$parent.change);
                this.$parent.change(); // 调用父的方法
            },
            methods:{
            }
        })
    
        new Vue({
            el:"#app",
            data:{
                msg:"我是根的msg"
            },
            created(){
            },
            methods:{
                change(){
                    console.log("我是父的change");
                    
                }
            }
        })
    
    
        // 子给父传递数据
    
        //  子通过 this.$parent 获取当前组件的父组件   给父组件的变量进行修改,  调用父组件的方法
    
            // 【核心:】  this.$parent
    
      
    </script>
    </html>
    

2、方法2:自定义属性、自定义事件(父子之间)

2.1、父传子:自定义属性

  • 如何定义自定义属性: 利用的props

  • 实现:

    • 在子组件里面的props配置选项里面,添加上一些自定义属性
    • 子组件的模板里面直接渲染这些属性
    • 父组件模板里面 在该子组件的标签上面给自定义的属性添加值
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
                #app{
                    width: 400px;
                    height: 400px;
                    background-color: #eee;
                }
                .box{
                    width: 200px;
                    height: 200px;
                    background-color: orange;
                }
            </style>
    </head>
    <body>
        <!-- input是输入框  -->
        <input type="text" value="1000">
    
    
        <div id="app">
            <h3>我是根组件</h3>
            <mydiv :ttt='parmsg' age='333333' ></mydiv>
        </div>
        
    
        <template id="mydiv">
            <div class="box">
                <h3>我是mydiv组件</h3>
                {{ttt}} <br>
                {{age}} <br>
            </div>
        </template>
    
    </body>
    <script>
        Vue.component('mydiv',{
            template:'#mydiv',
            props:['ttt','age'],  // 规定组件有哪些属性, 规定了组件有ttt属性,age属性
        })
    
        new Vue({
            el:"#app",
            data:{
                parmsg:"朕的天下"
            }
        })
    
        //  组件有一个porps属性。 props属性定了组件  有哪些可以接收外部数据的属性
        //  在父的模板里面   <子组件名 :子组件的属性名='父组件的变量' ></子组件名>
        //  子的 配置项里面   porps:['子组件的属性名']    
        //  子的 模板里面    {{子组件的属性名}}
    
    
        // 父传子 通过  props 传入
    </script>
    </html>
    
  • props验证

    • 验证该属性 是否必须传入

    • 验证该属性 数据类型是否正确

    • 设置该属性的默认值

    • 校验该属性的值是否符合条件

    • 代码实现:

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title></title>
          <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
          <style>
                  #app{
                      width: 400px;
                      height: 400px;
                      background-color: #eee;
                  }
                  .box{
                      width: 200px;
                      height: 200px;
                      background-color: orange;
                  }
              </style>
      </head>
      <body>
          <!-- input是输入框  -->
          <input type="text" value="1000">
      
      
          <div id="app">
              <h3>我是根组件</h3>
              <mydiv :ttt="22222"  :age='100' :nums='1900'  :childchange='change'></mydiv>
          </div>
          
      
          <template id="mydiv">
              <div class="box">
                  <h3>我是mydiv组件</h3>
                  {{ttt}} <br>
                  {{age}} <br>
                  {{nums}} <br>
                  <button @click='childchange'>22222</button>
              </div>
          </template>
      
      </body>
      <script>
          Vue.component('mydiv',{
              template:'#mydiv',
              // props:['ttt','age'],  // 规定组件有哪些属性, 规定了组件有ttt属性,age属性
              props:{
                  ttt:{
                      type:[String,Number],
                      default:"你好",
                      required:true
                  },
                  // age:Number
                  // age:{
                  //     default:'10000000'
                  // }
                  age:{
                      type:Number,
                      required:true
                  },
                  childchange:{
                      type:Function
                  },
                  nums:{
                      type:Number,
                      // default:function(){
                      //     // 如果default是一个函数,那么这个函数一定要有返回值
                      //     return 1111
                      // }
                      required:true,
                      validator:function(val){  
                          // validator 的值是一个函数, 这个函数有一个形参,形参就是传入的数据
                          // validator 对应的函数一定要返回一个布尔值,表示验证成功还是失败
                          if(val>300){
                              return true;
                          }else{
                              return false;
                          }
                      }
                  }
              },
              mounted(){
                  console.log(this);
              }
          })
      
          new Vue({
              el:"#app",
              data:{
                  parmsg:"朕的天下"
              },
              methods:{
                  change(){
                      console.log('父的change');
                  }
              }
          })
      
          //  组件有一个porps属性。 props属性定了组件  有哪些可以接收外部数据的属性
          //  在父的模板里面   <子组件名 :子组件的属性名='父组件的变量' ></子组件名>
          //  子的 配置项里面   porps:['子组件的属性名']    
          //  子的 模板里面    {{子组件的属性名}}
      
      
          // 父传子 通过  props 传入
      
      
          // props:['属性名','属性名2',...]
          /*
          // 描述验证
          props:{
              属性名:类型   String,Number,Boolean,Object,Array,Function    type:Stirng   type:[String,Number]
              属性名:{
                type:类型,  
                default:'默认值',
                default:function(){  // default 是函数一定要有返回值
                    return  数据
                }
                required:true/false,
                validator:function(val){  // 验证函数  val就是传入的值
                  // 该函数一定要有返回布尔值,代表验证通过还是没通过
                }
              }
          }
          */
      
          // props 也可以传入方法
      
      </script>
      </html>
      

2.2、子传父:自定义事件

  • 如何定义一个自定义事件

    <自定义组件名 @自定义事件名='事件函数'></自定义组件名>
    
  • 如何触发一个自定义事件

    this.$emit('自定义事件名',传参数);
    
  • 子传父实现的原理:

    		// 1、父的里面  组件mydiv上面 定义好自定义事件mytest, 自定义事件mytest的触发函数是父的change
        // 2、子的模板里面 有个按钮  绑定了子的myalert事件。
        // 3、myalert事件里面的触发了自定义事件 【this.$emit('自定义事件名')】 从而触发了父的change
        // 4、myalert事件里面的触发了自定义事件 且传入的了参数 【this.$emit('自定义事件名','传参')】
        // 5、父的change函数里面 定义好了形参接收传入的数据
        // 6、父的change函数里面, 用传入的数据 更新 自己的数据, 从而实现了子的数据来更新父的数据,也就是子传入了数据给父
    
    
    
  • 代码实现:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
                #app{
                    width: 400px;
                    height: 400px;
                    background-color: #eee;
                }
                .box{
                    width: 200px;
                    height: 200px;
                    background-color: orange;
                }
            </style>
    </head>
    <body>
        <div id="app">
            <!-- <h3 @click='change'>我是根组件</h3> -->
            <h3>我是根组件</h3>
            {{nums}}
            <mydiv @mytest='change'></mydiv>
            <!-- @随便写事件名='父的事件函数' -->
            <!-- mytest是mydiv的自定义事件 -->
        </div>
        <template id="mydiv">
            <div class="box">
                <h3>我是mydiv组件</h3>
                <button @click='myalert'>点击自己的myalert方法</button>
            </div>
        </template>
    
    </body>
    <script>
        Vue.component('mydiv',{
            template:'#mydiv',
            data(){
                return{ }
            },
            methods:{
                myalert(){
                    console.log('子的myalert方法');
                    // 触发自定义事件
                    // this.$emit('自定义事件名','传递数据');
                    this.$emit('mytest',200);
                }
            }
        })
        new Vue({
            el:"#app",
            data:{
                nums:-10000
            },
            methods:{
                change(x){
                    console.log(x);
                    this.nums = x;
                    console.log("我是父的change");
                }
            }
        })
    
       // 总结: 子给父传数据   是通过  自定义事件
    
        // 1、父的里面  组件mydiv上面 定义好自定义事件mytest, 自定义事件mytest的触发函数是父的change
        // 2、子的模板里面 有个按钮  绑定了子的myalert事件。
        // 3、myalert事件里面的触发了自定义事件 【this.$emit('自定义事件名')】 从而触发了父的change
        // 4、myalert事件里面的触发了自定义事件 且传入的了参数 【this.$emit('自定义事件名','传参')】
        // 5、父的change函数里面 定义好了形参接收传入的数据
        // 6、父的change函数里面, 用传入的数据 更新 自己的数据, 从而实现了子的数据来更新父的数据,也就是子传入了数据给父
    
    
    </script>
    </html>
    
  • 原理图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CtcBGqtS-1582019279741)(./imgs/aa.png)]

3、方法3:事件传播器(任意组件之间)

  • 原理: node.js中 有一个events的模块

  • 核心方法: on 添加事件 emit 触发事件

    let EventEmitter = require('events')
    let myevent = new EventEmitter();
    // 定义一个事件
    myevent.on('change',function(x){
     		console.log('change被触发了')
        console.log(x)
    })
    
    // 触发该事件
    setTimeout(function(){
      myevent.emit('change',20);
    },2000)
    
    
  • Vue中的也有 $on 和 $emit 方法

  • 如何实现任意组件之间的通信呢?

    • 创建一个空的Vue实例作为事件传播器
    • 在这个事件传播器上面 添加自定义事件(A组件中),然后在触发这些自定义事件(B组建中)
  • 代码实现:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
            #box{
                background-color:#eee;
                width: 400px;
                height: 400px;
            }
            .aa,.bb{
                float: left;
                width: 200px;
                height: 180px;
            }
            .aa{
                background-color: red;
            }
            .bb{
                background-color: orange;
            }
    
        </style>
    </head>
    <body>
        <div id="box">
            <h3>我是根组件</h3>
            <aa></aa>
            <bb></bb>
        </div>
        <template id='aa'>
            <div class="aa">
                我是aa组件
                <button @click='achange'>传给bbb</button>
                <hr>
                {{msg}}
            </div>
        </template>
        <template id='bb'>
            <div class="bb">
                我是bb组件
                <button @click='bchange'>传给aaa</button>
                <hr>
                {{msg}}
            </div>
        </template>
    </body>
    <script>
        // 创建Vue实例  代替 事件传播器
    
        let bus = new Vue();
    
        Vue.component('aa',{
            template:"#aa",
            data(){
                return{
                    str:'我是天下第一帅的aa',
                    msg:'aaaa'
                }
            },
            created(){
                // 给bus添加了一个自定义事件fn1, 修改了当前组件的msg
                bus.$on('fn1',txt=>{
                    this.msg = txt;
                })
            },
            methods:{
                achange(){
                    console.log("我是aa组件的achange");
                    bus.$emit('fn2',this.str);
                }
            }
        })
        Vue.component('bb',{
            template:"#bb",
            data(){
                return{
                    str:'我是天下第一帅的bb',
                    msg:'bbbb'
                }
            },
            created(){
                bus.$on('fn2',txt=>{
                    this.msg = txt;
                });
            },
            methods:{
                bchange(){
                    console.log("我是bb组件的bchange");
                    bus.$emit('fn1',this.str);
                }
            }
        })
    
        new Vue({
            el:"#box",
            data:{}
        })
    </script>
    </html>
    

4、方法4:本地存储(任意组件之间)

  • 原理: A组件存, B组件取
发布了10 篇原创文章 · 获赞 0 · 访问量 127

猜你喜欢

转载自blog.csdn.net/qq_32620027/article/details/104379388