父子通信中的子传父-使用v-model实现双向数据绑定

注意:vue组件是此组件的根组件,是该组件中所有注册的组件的父组件

  • 现有需求:通过子组件中的输入框来动态绑定父组件中data中的数据。

  • 代码实现

  1. 父组件使用porps来向子组件传值
  2. 子组件通过自己定义的两个属性(number1,number2)来接受父组件的值(num1,num2)
  3. 通过v-model属性将输入框与子组件的number1和number2来进行绑定
  • 结果

    • 上面功能的实现的确没有问题,但思路有问题,而且在一般情况下,vue是不建议通过这种方式来直接修改父组件中的值的。

    • 代码如下:

      <body>
        <div id="app">
          <cpn :number1="num1" :number2="num2"></cpn>
        </div>
      
        <template id="cpm">
          <div>
            <h2>props:{{number1}}</h2>
            <h2>data:{{dnumber1}}</h2>
            <input type="text" v-model="number1">
           
            <h2>props:{{number2}}</h2>
            <h2>data:{{dnumber2}}</h2>
            <input type="text" v-model="number2">
      
          </div>
        </template>
      
        <script>
          const app = new Vue({
            el: '#app',
            data: {
              num1: 1,
              num2: 0
            },
            components: {
              cpn: {
                template: '#cpm',
                props: {
                  number1: Number,
                  number2: Number
                },
              },
            },
          })
        </script>
      </body>

分析:注册了一个cpn组件,使用父传子的方式传了两个值,一个是number1,一个是number2。cpn组件在声明的时候,使用v-bind单方向绑定了父组件data中的num1,和nmu2。在cpn组件内部,在表单中使用v-model动态绑定number1,和number2。这样就可实现在子组件中设置值,父组件中的data也可以跟着修改的需求。

  • 运行截图

Snipaste_2022-05-20_17-15-07

反思:这样虽然可以实现子组件向组件传值,但这种方法在vue看来是极为不推荐的。

  • 代码改进
    • 代码实现
      • 在上面的基础上,我在子组件中定义两个data属性(dnumber1,dnumber2),用来保存父组件传过来的值
      • 将input绑定的属性从number1改为dnumber1,number2同理
<body>
  <div id="app">
    <cpn :number1="num1" :number2="num2"></cpn>
  </div>

  <template id="cpm">
    <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>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        num1: 1,
        num2: 0
      },
      components: {
        cpn: {
          template: '#cpm',
          props: {
            number1: Number,
            number2: Number
          },
          data() {
            return {
              dnumber1: this.number1,
              dnumber2: this.number2
            }

          }
        },
      },
    })
  </script>
</body>
  • 运行截图

Snipaste_2022-05-20_17-28-25

反思:这样是不报错了,但是父组件中的值没有被修改呀,看来得使用自定义事件来向父组件传值了!

  • 代码改进

    • 自组件使用$emit自定义事件创建一个自定义事件dnumber1change,dnumber2change,并将dnumber1,和dnumber2传递过去。

      • 父组件定义监听函数number1chage,number2change,在这个函数中,将取得的值value传递给父组件data中的值,从而将num1,和num2的值进行修改。
<body>
  <div id="app">
    <cpn :number1="num1" :number2="num2" @dnumber1change="number1chage" @dnumber2change="number2change"></cpn>
  </div>

  <template id="cpm">
    <div>
      <!-- 用来查看父子组件中,值的变化情况 -->
      <h2>props:{{number1}}</h2>
      <h2>data:{{dnumber1}}</h2>
      <input type="text" :value="dnumber1" @input="num1Input">
      <!-- 用来查看父子组件中,值的变化情况 -->
      <h2>props:{{number2}}</h2>
      <h2>data:{{dnumber2}}</h2>
      <input type="text" :value="dnumber2" @input="num2Input">
    </div>
  </template>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        num1: 1,
        num2: 0
      },
      methods: {
        number1chage(value) {
          this.num1 = parseInt(value)
        },
        number2change(value) {
          this.num2 = parseInt(value)

        }
      },
      components: {
        cpn: {
          template: '#cpm',
          props: {
            number1: Number,
            number2: Number
          },
          data() {
            return {
              dnumber1: this.number1,
              dnumber2: this.number2
            }
          },
          methods: {
            num1Input(event) {
              this.dnumber1 = event.target.value;
              // 为了父组件可以修改值,发出一个事件
              this.$emit('dnumber1change', this.dnumber1);
            },
            num2Input(event) {
              this.dnumber2 = event.target.value;
              //  为了父组件可以修改值,发出一个事件
              this.$emit('dnumber2change', this.dnumber2);
            }
          }
        },
      }
    })
  </script>
</body>
      
  • 运行截图

    Snipaste_2022-05-20_18-02-13

总结:v-model的本质

  1. < input type=“text” v-model=“dnumber1”>
  2. < input type=“text” v-bind:value=“dnumber1” @input=“dnumber1=$event.target.value”>

下面的代码等同于上面的代码, 这也就是需求实现的关键

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐