踩坑实录(First Day)

2023 年一整年感觉我的进步都很小,所以自 2024 年起,我将专门开设专栏记录自己在工作期间踩过的所有坑,一来是为了有个记录,自己不会再踩,而来也是为了跟大家做一个分享,与大家进行讨论,提升自己的能力。

此为第一篇(2024 年 02 月 04 日)

问题一

问题背景:输入框输入数据后,关闭页签再次打开保留了上一次的数据。

问题描述:在 js 文件中定义了一个对象,以便对数据进行初始化,引入到需要使用的 vue 文件中,然后在 data 中定义一下。

下面是一个 demo 演示:

// index.js
exports const obj = {
   
    name: ''age: '',
    hobbies: ''
}
// 因为不确定后端会返回什么数据,所以此时我们都用空字符串进行初始化。

// 补充:js 是弱类型语言,即使定义为空字符串,后期将其他类型的值赋值过去,都是可以的,但是这会导致数据类型不安全,最好是避免这种写法。
<!-- index.vue -->

<template>
    <div>
        <input v-model="obj.name" />
        <input v-model="obj.age" />
        <input v-model="obj.hobbies" />
    </div>
</template>

<script>
    import {
      obj } from './model/index.js'
    export default {
     
        name: 'index',
        data () {
     
            return {
     
                obj,
            }
        }
    }
</script>
  • 分析过程:

    1. 首先我们可以看到,在 js 中定义了一个 obj ,它是一个对象,也就是“引用数据类型”的数据,此时它在堆中开辟一部分空间存储这个对象,然后提供一个地址值,指向这个对象,然后在栈中生成一个变量 obj ,将这个地址值赋值给栈中的变量 obj 。

    2. 第二步我们看到是在 index.vue 文件中,通过 import 将这个变量引入进来。

    3. 第三步又将引入的这个变量在 data 中定义了一下,将他变成一个响应式数据。

    到此,我们的思路就已经很清晰了,在 data 中存储的是一个地址值,指向的永远是在 index.js 文件中定义的那个对象,我们通过双向绑定,输入框输入赋值等操作,操作的永远是那一个 obj 对象,而根据 js 的垃圾回收机制,我们可以得出,js 在内存中生成的全局变量,只要不刷新浏览器,那么他不会被销毁,好的,问题到这里就分析完成了。

    结论:是因为 引用数据类型存储的是地址值,导致操作的始终是同一个变量。

  • 解决思路:

    既然是因为引用数据类型指向的是同一个对象引起的,那我们是不是可以在 data 中定义的时候,深拷贝一下这个 obj 对象去解决呢?答案是:当然可以!

    <!-- index.vue -->
    
    <template>
        <div>
            <input v-model="obj.name" />
            <input v-model="obj.age" />
            <input v-model="obj.hobbies" />
        </div>
    </template>
    
    <script>
        import {
            obj } from './model/index.js'
        export default {
           
            name: 'index',
            data () {
           
                return {
           
                    obj: JSON.parse(JSON.stringify(obj)),
                }
            }
        }
    </script>
    

    这样,我们就可以确保,每一次组件创建的时候,生成一份新的 obj 数据,而在组件销毁的时候,data 中的数据也会被销毁,问题就迎刃而解了~~~

问题二

问题背景:组长让解决控制台报错,于是在控制台看到了很多个 Invalid prop: custom validator check failed for prop "XXX" 的报错。大致看一眼就是说,XXX 变量没有通过校验。

问题描述:在子组件的 props 写了一个参数 XXX ,将他的 type 定义为了 String ,下面紧接着又写了一个 validate 自定义校验,然后在父组件中引用了子组件。

下面是一个 demo 演示:

<!-- subComponent.vue -->

<script>
    export default {
     
        name: 'subComponent',
        props: {
     
            identifying: {
     
                type: String,
                validator: (val) => {
     
                    return ['zhangsan'].includes(val)
                }
            }
        }
    }
</script>
<!-- parentComponent -->

<template>
    <subComponent :identifying="lisi"></subComponent>
</template>

<script>
    import subComponent from './subComponent.vue'
    export default {
     
        name: 'parentComponent',
        components: {
     
            subComponent
        }
    }
</script>
  • 分析过程:

    1. 首先,在子组件的 props 中定义了一个参数,父组件在使用子组件的时候,需要将这个参数传递过来,但是我们看到这个参数没有写 required: true ,所以这个参数不是必传的。下面又写了一个 validator ,就是说,这个参数的校验是自己自定义的,好家伙,这么高级。

    2. 不难看出,这个自定义校验函数的意思是,只要你传递过来的 identifying 是 ‘zhangsan’ ,那么就返回 true ,否则返回 false 。

    3. 接下来我们看到父组件使用的时候,传进去了一个 identifying 是 ‘lisi’ ,并不是组件想要的 ‘zhangsan’ ,那么那个自定义校验返回的就是 false ,校验不通过。

    4. 再回过头看一下我们的报错信息:‘Invalid prop: custom validator check failed for prop “identifying”’ ,翻译一下的结果是:无效道具:道具“正在识别”的自定义验证程序检查失败。但是这只是一个警告,并不会阻塞页面渲染。

    到此,问题的思路就已经很清晰了,自定义校验没有通过,也就是说,我们只要传了 identifying 参数,就一定会对它进行校验,判断它是否是 ‘zhangsan’ ,这样是很不合理的,因为这个组件的背景是一个公共组件,此处有两种场景,需要 ‘zhangsan’ 和 ‘lisi’ 都成立。

  • 解决思路:

    在这里,我提供两种方案进行解决:

    1. 在不改变 validator 自定义校验的情况下,让组件兼容 ‘lisi’ 的情况,只需要在自定义校验方法体内的数组中,加入 ‘lisi’。
    <!-- subComponent.vue -->
    
    <script>
        export default {
           
            name: 'subComponent',
            props: {
           
                identifying: {
           
                    type: String,
                    validator: (val) => {
           
                        return ['zhangsan', 'lisi'].includes(val)
                    }
                }
            }
        }
    </script>
    
    1. 使用 props 的枚举【enum】。
    <!-- subComponent.vue -->
    
    <script>
        export default {
           
            name: 'subComponent',
            props: {
           
                identifying: {
           
                    type: String,
                    enum: ['zhangsan', 'lisi']
                }
            }
        }
    </script>
    

    这里我们就需要考虑一个问题,如果改为采用 enum 的话,需不需要让这个参数改成必填?那我们就要去看两个条件:1. 在使用 validator 自定义校验的时候是不是必填。2. 自己公司的业务场景需要我们做什么。但是在我们公司这里的业务场景是必填的,它只有两个场景,而且必须符合某一个场景,所以在这里我就不考虑第一种条件,直接改为必填了。

声明:

作者只记录自己在公司踩过的坑,以及提供自己的解决思路,如果有误请联系作者进行修改,不接受以任何形式的诋毁谩骂。如果有更好的方案也可以联系作者进行讨论,互相学习。

如需转载请注明文章来源。

相关推荐

  1. 实录(First Day)

    2024-02-07 04:04:01       25 阅读
  2. 实录(Second Day)

    2024-02-07 04:04:01       26 阅读
  3. 实现快速排序所

    2024-02-07 04:04:01       17 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-07 04:04:01       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-07 04:04:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-07 04:04:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-07 04:04:01       20 阅读

热门阅读

  1. 2024/2/5

    2024-02-07 04:04:01       30 阅读
  2. Linux内核与驱动面试经典“小”问题集锦(3)

    2024-02-07 04:04:01       32 阅读
  3. 大模型: 流式会话的实现方式

    2024-02-07 04:04:01       32 阅读
  4. 【PHP】TP5.0模型关联搜索查询

    2024-02-07 04:04:01       28 阅读
  5. C++ access 的作用

    2024-02-07 04:04:01       31 阅读
  6. 综合分享2

    2024-02-07 04:04:01       28 阅读
  7. 【量子通信】量子通信技术:前景与挑战

    2024-02-07 04:04:01       28 阅读
  8. docker 部署springboot项目详细步骤

    2024-02-07 04:04:01       31 阅读
  9. C#基础-线程暂停方案之重置事件

    2024-02-07 04:04:01       35 阅读