zoukankan      html  css  js  c++  java
  • props 子组件更改父组件引用类型的问题

    1. 传递引用类型引发的问题

    vue开发中,我们向子组件传递一个引用类数据[Array/Object]作为子组件的初始值 ,

    现在我的结构是这样的 父组件(father)下面有两个子组件child1,child2

    在通过props把数组类型同一个值传递给child1,child2,当我们通过child2来更改props的值时(原则上子组件不可以改变父组件传递过来的props值,如果时基本类型会报错),更改后父组件也会相应变化,父组件变化了相应的子组件也发生了变化,所以当点击child2修改值时,把father组件的值更改了,从而也改变了child1的值,下面会讲到如何来解决这个问题?

    父组件father

    <template>
       <div>
          <h2>孩子1</h2>
          <child1 :testArr="testObj.testArr"></child1>
          <hr>
          <h2>孩子2</h2>
          <child2 :testArr="testObj.testArr"></child2>
    
          <hr>
    
       </div>
    </template>
    
    <script>
    import Child1 from './demo/Child1'
    import Child2 from './demo/Child2'
    
    export default {
      data(){
        return {
          testObj:{
            require:true,
            testArr:[
              {
                id:1,
                name:"张三"
              },
               {
                id:2,
                name:"赵四"
              }
            ]
          }
        }
      },
      components:{
        Child1,
        Child2
      }
    }
    </script>
    
    <style>
    
    </style>
    

    子组件Child1

    <template>
       <div class="child1">
           <div v-for="(item,index) in testArr" :key="index">{{item.id}}---{{item.name}}</div>
       </div>
    </template>
    
    <script>
    export default {
      props:{
          testArr:Array
      }
    }
    </script>
    
    <style>
    
    </style>
    

    子组件child2

    <template>
       <div class="child2">
           <div v-for="(item,index) in testArr" :key="index">{{item.id}}---{{item.name}}</div>
           <button @click="changeName">点击改变数组第一个的值</button>
       </div>
    </template>
    
    <script>
    export default {
      props:{
          testArr:Array
      },
      methods:{
          changeName() {
              this.testArr[1].name="花花";
          }
      }
    }
    </script>
    
    <style>
    
    </style>
    

    当点击child2修改值时,把father组件的值更改了,从而也改变了child1的值

    怎么解决这个问题?

    可以把props传过来的数据保存在data里面,注意要深拷贝

    错误写法

     data(){
          return {
              testData:this.testArr
          }
      }
    

    深拷贝代码参考

    // 递归实现一个深拷贝
    function deepClone(source) {
      if (!source || typeof source !== 'object') {
        throw new Error('error arguments', 'shallowClone');
      }
      var targetObj = source.constructor === Array ? [] : {};
      for (var keys in source) {
        if (source.hasOwnProperty(keys)) {
          if (source[keys] && typeof source[keys] === 'object') {
            targetObj[keys] = source[keys].constructor === Array ? [] : {};
            targetObj[keys] = deepClone(source[keys]);
          } else {
            targetObj[keys] = source[keys];
          }
        }
      }
      return targetObj;
    }
      
    

    但是这种情况下父组件改变参数时,子组件无法更新参数,需要时可以通过watch或者computed来实现实时更新

    先来一种不是深拷贝的赋值,错误写法

    注意:用watch监听时,第一次时不会执行的,后面值改变了才会执行,所以要换一种写法

      data() {
        return {
            testData:[]
        }
      },
    
      watch:{
          testArr(newValue){
              this.testData=newValue
          } 
      }
    

    不是深拷贝的赋值,正确写法

    watch: {
        testArr: {
          handler(newValue, lodValue) {
            this.testData = newValue;
          },
          immediate: true  //代表在watch生命了testArr这个方法之后会立即去执行handler方法,自己理解,初次改变会执行这个方法
        }
      }
    

    上面的这种写法 还是会出现更改了child2从而改变child1的值,刚说的用深拷贝就不会出现这种问题了

    深拷贝错误写法

    报错:vue.runtime.esm.js?2b0e:1888 ReferenceError: deepClone is not defined

    当watch监听到testArr变化时,可能method里面的方法我们还访问不到,所以不要写在method方法里面,我们可以在外面定义一个文件,然后在里面引入

      watch: {
        testArr: {
          handler(newValue, lodValue) {
            this.testData = this.deepClone(newValue);
          },
          immediate: true  //代表在watch生命了testArr这个方法之后会立即去执行handler方法,自己理解,初次改变会执行这个方法
        }
      },
      methods: {
        changeName() {
          this.testData[1].name = "花花";
        },
        // 递归实现一个深拷贝
        deepClone(source) {
          if (!source || typeof source !== "object") {
            throw new Error("error arguments", "shallowClone");
          }
          var targetObj = source.constructor === Array ? [] : {};
          for (var keys in source) {
            if (source.hasOwnProperty(keys)) {
              if (source[keys] && typeof source[keys] === "object") {
                targetObj[keys] = source[keys].constructor === Array ? [] : {};
                targetObj[keys] = deepClone(source[keys]);
              } else {
                targetObj[keys] = source[keys];
              }
            }
          }
          return targetObj;
        }
      }
    

    正确写法

    utils.js文件

    export function  deepClone(source) {
        if (!source || typeof source !== "object") {
          throw new Error("error arguments", "shallowClone");
        }
        var targetObj = source.constructor === Array ? [] : {};
        for (var keys in source) {
          if (source.hasOwnProperty(keys)) {
            if (source[keys] && typeof source[keys] === "object") {
              targetObj[keys] = source[keys].constructor === Array ? [] : {};
              targetObj[keys] = deepClone(source[keys]);
            } else {
              targetObj[keys] = source[keys];
            }
          }
        }
        return targetObj;
      }
    

    在需要用到函数的地方引入,然后直接用就可以了

    import {deepClone} from './demo/utils.js'
    

    child2最后代码

    <template>
      <div class="child2">
        <div v-for="(item,index) in testData" :key="index">{{item.id}}---{{item.name}}</div>
        <button @click="changeName">点击改变数组第一个的值</button>
      </div>
    </template>
    
    <script>
    import { deepClone } from "./utils.js";
    export default {
      props: {
        testArr: Array
      },
      data() {
        return {
          testData: []
        };
      },
    
      watch: {
        testArr: {
          handler(newValue, lodValue) {
            this.testData = deepClone(newValue);
          },
          immediate: true  //代表在watch生命了testArr这个方法之后会立即去执行handler方法,自己理解,初次改变会执行这个方法
        }
      },
      methods: {
        changeName() {
          this.testData[1].name = "花花";
        }
        // 递归实现一个深拷贝
     
      }
    };
    </script>
    
    <style>
    </style>
    

    现在点击child2里面的按钮,更改数据,就不会改到child1的数据了

  • 相关阅读:
    HDU 3401 Trade
    POJ 1151 Atlantis
    HDU 3415 Max Sum of MaxKsubsequence
    HDU 4234 Moving Points
    HDU 4258 Covered Walkway
    HDU 4391 Paint The Wall
    HDU 1199 Color the Ball
    HDU 4374 One hundred layer
    HDU 3507 Print Article
    GCC特性之__init修饰解析 kasalyn的专栏 博客频道 CSDN.NET
  • 原文地址:https://www.cnblogs.com/wlhappy92/p/props.html
Copyright © 2011-2022 走看看