vue 中由浅拷贝引发问题的一些场景

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

在工作的过程中踩了很多的由浅拷贝导致的坑今天总结在这里希望对大家有所帮助

1. 组件中直接抛出一个引用类型变量

🌰举个例子 ps: 以下代码为伪代码主要展示逻辑用

子组件uploadImg定义一个上传图片的组件

基础功能a. 上传图片上传成功后抛出change 事件。

                 b. 上传成功的图片平铺展示并展示删除按钮。点击删除按钮弹出二次确认框。点击确认则删除点击取消则不删除。

// uploadImg.vue
// 上传图片组件——子组件 
<template>
   <upload @change="uploadSuccess"></upload>
   <div>
    <div v-for="(item, fileIndex) in imgUrls" :key="fileIndex" class="file-content">
          <div class="file-item">
            <div @click="delFile(fileIndex)" class="file-close">
              <el-tooltip class="item" effect="dark" content="删除" placement="right-start">
                <el-icon class="el-icon-close"></el-icon>
              </el-tooltip>
            </div>
            </div>
          </div>
        </div>
</div>
</template>
<script>
data(){
    return {
        imgUrls: []
    }
},
methods: {
    // 上传成功
    uploadSuccess (files) {
      files.forEach(item => {
        this.imgUrls.push({
          ...item,
          fileName: item.fileName
        })
      })
      this.$emit('change', this.imgUrls)
    },
    // 删除文件
    delFile (fileIndex) {
      this.$confirm('图片删除后不能恢复确认删除', '提示').then(() => {
        this.imgUrls.splice(fileIndex, 1)
      })
      this.$emit('change', this.imgUrls)  
    }
}
</script>

父组件使用方法1

<template>
    <upload-img @change="change"></upload-img>
</template>
<script>
    data(){
        return {
            imageList
        }
    },
    methods: {
        change(list) {
              this.imageList = list
              console.log(this.imageList)
        }
    }
</script>

我们使用以上方法点击删除图片确认删除。

获取到的 this.imageList是删除成功之后的图片数组无异常。删除和上传给父组件的值都是正确的。

父组件使用方法2

<template>
    <upload-img @change="change"></upload-img>
</template>
<script>
    data(){
        return {
            imageList
        }
    },
    methods: {
        change(list) {
              this.imageList = list.map(item => item.url)
              console.log(this.imageList)
        }
    }
</script>

我们使用以上方法点击删除图片确认删除。

获取到的 this.imageList是删除之前的图片数组有异常。

为啥会产生这样的异常呐我们来分析一下

 由上图可见抛出change事件的时机和弹出二次确认弹窗的时间是异步的。

即在弹出二次确认弹窗的时候chang事件就已经触发了。反而在点击二次确认弹窗的确定按钮的时候并未触发chang事件。

那么问题来了为啥第一种方式无异常咧因为我们change事件抛出的是一个引用类型的数据并且父组件对该值进行了浅拷贝。等子组件的imgUrls值更新之后父组件的imageList的值也进行了更新。

第二种方式由异常的原因第二种方法在赋值之前使用了一个map 的方法map 会返回一个新数组即进行了深拷贝。

2. 直接将引用类型赋值给一个新的变量对新变量进行处理

🌰举个例子

form表单中输入一些数据调用后端接口传参数是需要对数据进行一些处理比如金额需要由元转成分

这时直接进行转化就是导致页面上的展示数据也会进行相应的变动。

常见于数据长度变多或者变少对象修改了某一个key 的值却无变化。

常见的浅拷贝的方法

1. Object.assign()

2. 解构赋值

3. ‘=’赋值

常见解决方法

1. 手写深拷贝递归复制

2. JSON做字符串转换

var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1))

该方法有副作用

        a. 它会抛弃对象的constructor。也就是深拷贝之后不管这个对象原来的构造函数是什么在深拷贝之后都会变成Object。

        b.RegExp对象是无法通过这种方式深拷贝

        c.function没办法转成JSON

        

3. 使用Object.create()方法

直接使用var newObj = Object.create(oldObj)可以达到深拷贝的效果。

附上创建对象的一些方法的差异

附上创建对象的一些方法的差异Object.create()、new Object()和{}的区别 - 掘金

4. 三方函数常用

如lodash

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: vue