父子通信结合双向绑定(拆分双向绑定向父组件发送数据)

父子通信结合双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<div id="app">
  <cpn :cnum1="num1" :cnum2="num2"></cpn>
</div>
<template id="cpn">
  <div>
    <p>{{cnum1}}</p>
    <input type="text" v-model="cnum1">
    <p>{{cnum2}}</p>
    <input type="text" v-model="cnum2">
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      num1: 1,
      num2: 0
    },
    components: {
      cpn: {
        template: '#cpn',
        props: {
          cnum1: Number,
          cnum2: Number,
        }

      }
    }
  });
</script>
</body>
</html>

在这里插入图片描述

会残生以下报错:

在这里插入图片描述

如下修改

给子组件增加自己的data函数:

data() {
  return {
    dnum1: this.cnum1,
    dnum2: this.cnum2
  };
}

然后修改动态绑定的对象

<div>
  <p>{{cnum1}}</p>
  <input type="text" v-model="dnum1">
  <p>{{cnum2}}</p>
  <input type="text" v-model="dnum2">
</div>

[

子向父传递数据正确操作

如果想是实现父组件的num子组件里的的dnum变化,且dum1和dum2存在数量关系。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<div id="app">
  <cpn :cnum1="num1" :cnum2="num2"
       @num1change="num1Change"
       @num2change="num2Change">
  </cpn>
</div>
<template id="cpn">
  <div>
    <h2>prpos里的data:{{cnum1}}</h2>
    <h2>子组件的data:{{dnum1}}</h2>
    <!-- <input type="text" v-model="dnum1">-->
    <input type="text" :value="dnum1" @input="dnum1Change">
    <h2>prpos里的data:{{cnum2}}</h2>
    <h2>子组件的data:{{dnum2}}</h2>
    <!-- <input type="text" v-model="dnum2">-->
    <input type="text" :value="dnum2" @input="dnum2Change">
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  const 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: {
          cnum1: Number,
          cnum2: Number,
        },
        data() {
          return {
            dnum1: this.cnum1,
            dnum2: this.cnum2
          };
        },
        methods: {
          dnum1Change(event) {

            this.dnum1 = event.target.value;
            //发射函数,将改变后的子组件数据dnum1传给父组件
            this.$emit('num1change', this.dnum1);
            //同时修改dum2的值为num1的100倍
            this.dnum2 = this.dnum1 * 100;
            this.$emit('num2change', this.dnum2);
          },
          dnum2Change(event) {
            this.dnum2 = event.target.value;
            //发射函数,将改变后的子组件数据dnum2传给父组件
            this.$emit('num2change', this.dnum2);
            //同时修改dum1的值为num2的100倍
            this.dnum1 = this.dnum2 * 100;
            this.$emit('num1change', this.dnum1);
          }
        }

      }
    }

  });
</script>
</body>
</html>

上边说了,动态绑定不能是prpos里的变量,否则,子组件直接可以修改父组件,这里又要父组件跟着子组件数据修改,这不矛盾吗?

这其实不矛盾,这里父组件的数据修改,还是通过父组件自己的函数来修改自己,而不是直接由子组件行为来修改,我可以修改,但是必须是你子组件告诉我修改啥,我父组件自己修改,而不是你直接来给我修改。

具体步骤

1.拆分双向绑定为数据绑定和事件绑定

<div>
  <h2>prpos里的data:{{cnum1}}</h2>
  <h2>子组件的data:{{dnum1}}</h2>
  <input type="text" :value="dnum1" @input="dnum1Change">
  <h2>prpos里的data:{{cnum2}}</h2>
  <h2>子组件的data:{{dnum2}}</h2>
  <input type="text" :value="dnum2" @input="dnum2Change">
</div>

将v-model拆分为动态绑定 子组件data和输入框数据修改事件。

拆开的目的是因为我们要获取到子组件的实时数据,子组件的实时数据是输入框的value给的。如果直接使用v-model,发送出子组件实时data的步骤无法触发。我们没有地方来编写这个事件。

  methods: {
    dnum1Change(event) {

      this.dnum1 = event.target.value;
      //发射函数,将改变后的子组件数据dnum1传给父组件
      this.$emit('num1change', this.dnum1);
      //同时修改dum2的值为num1的100倍
      this.dnum2 = this.dnum1 * 100;
      this.$emit('num2change', this.dnum2);
    },
    dnum2Change(event) {
      this.dnum2 = event.target.value;
      //发射函数,将改变后的子组件数据dnum2传给父组件
      this.$emit('num2change', this.dnum2);
      //同时修改dum1的值为num2的100倍
      this.dnum1 = this.dnum2 * 100;
      this.$emit('num1change', this.dnum1);
    }
  }

}

事件函数有一个参数,调用时省略,会默认将事件event作为参数给这个形参。

如果没有参数,想调用,就是用$event来调用。

我们需要得到实时的输入框数据给子组件数据,同时为了修改父组件数据,那必须要让父组件知道,$emit发射出一个函数,带有子组件data值。

引号内是方法名,后边是参数。方法名是用来绑定父组件的方法的,

2。父组件自己的函数接受子组件的函数和参数。

//父组件定义自己的接受函数
methods: {
  num1Change(value) {
    this.num1 = parseFloat(value);
  },
  num2Change(value) {
    this.num2 = parseFloat(value);
  },

},
<cpn :cnum1="num1" :cnum2="num2"
     @num1change="num1Change"
     @num2change="num2Change">
</cpn>

这里父组件的函数定义一个参数是为了接受子组件传递的参数,直接调用不传参数,不会获取event事件。
类型必须转换,传过来的数字会被当成字符串,要转换回来

3.方法可以复用。

dnum1Change(event) {

  this.dnum1 = event.target.value;
  //发射函数,将改变后的子组件数据dnum1传给父组件
  this.$emit('num1change', this.dnum1);
  //同时修改dum2的值为num1的100倍
  this.dnum2 = this.dnum1 * 100;
  this.$emit('num2change', this.dnum2);
},

同时可以发送两个或多个方法出去,但是他们方法名和参数一样时,可以复用。同样的num2change既可以接受

this.dnum2 = event.target.value;
//发射函数,将改变后的子组件数据dnum2传给父组件
this.$emit('num2change', this.dnum2);

又可以接收

//同时修改dum2的值为num1的100倍
this.dnum2 = this.dnum1 * 100;
this.$emit('num2change', this.dnum2);

更一步说明了发射函数第一个参数会被创建成方法,不同地方发射函数的参数相同,会被当成同一方法,

总结

所谓动态绑定属性和事件的监听:不过是将一个自定义/系统定义的属性/方法名与另外一个自定义的属性/方法动态联系起来。一定是对应关系,一个属性与另一个属性,一个方法与另一个方法。语法糖可能省略。

等号后边的引号并不代表其是一个字符串,而是将其当作变量或方法名的标志。不要见到引号路边的就是字符串。

如果要实现响应式,就必须发生关联,这也就是动态绑定的目的。

何为系统定义属性/方法(事件):

:value="dnum1" @input="dnum1Change"

何为自定义的属性/方法(事件)

:cnum1="num1" 
:cnum2="num2"
@num1change="num1Change"
@num2change="num2Change"

我们绑定点击事件,是为了系统知道,触发点击事件,执行等号后边的方法。

绑定自定义方法也是一样的。

在这里插入图片描述

@click="btn01Click"

父子通信时方法名不要用驼峰命名,切记,否则不报错,就是不正确执行,在vue.js使用中,而不是脚手架中。

watch属性简写法
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>watch</title>
</head>
<body>
<div id="app">
  <cpn :cnum1="num1" :cnum2="num2"
       @num1change="num1Change"
       @num2change="num2Change">
  </cpn>
</div>
<template id="cpn">
  <div>
    <h2>prpos里的data:{{cnum1}}</h2>
    <h2>子组件的data:{{dnum1}}</h2>
    <input type="text" v-model="dnum1">
    <h2>prpos里的data:{{cnum2}}</h2>
    <h2>子组件的data:{{dnum2}}</h2>
    <input type="text" v-model="dnum2">
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  const 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: {
          cnum1: Number,
          cnum2: Number,
        },
        data() {
          return {
            dnum1: this.cnum1,
            dnum2: this.cnum2
          };
        },
        watch: {
          dnum1(newValue) {
            //同时修改dum2的值为dnum1实时数据的的100倍
            this.dnum2 = newValue * 100;
            /*同时将dnum1的实时数据发送出去*/
            this.$emit('num1change', newValue);
          },
          dnum2(newValue) {
            //同时修改dum1的值为num2的100倍
            this.dnum1 = newValue / 100;
            this.$emit('num2change', newValue);
          }
        }

      }
    }

  });
</script>
</body>
</html>

在这里插入图片描述

一旦观察的变量(键)发生变化,就会执行回调函数(值),很容易实现。

要注意的是,你想把什么东西发送出去,你目前得到的是什么数据。

可以有两个参数:newValue , oldVlue,默认只用写一个参数,获取实时的新值,也可以有俩个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值