当前位置:   article > 正文

踩坑实录(First Day)

踩坑实录(First Day)

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

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

问题一

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

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

下面是一个 demo 演示:

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

// 补充:js 是弱类型语言,即使定义为空字符串,后期将其他类型的值赋值过去,都是可以的,但是这会导致数据类型不安全,最好是避免这种写法。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
<!-- 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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 分析过程:

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    这样,我们就可以确保,每一次组件创建的时候,生成一份新的 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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
<!-- parentComponent -->

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

<script>
    import subComponent from './subComponent.vue'
    export default {
        name: 'parentComponent',
        components: {
            subComponent
        }
    }
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 分析过程:

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. 使用 props 的枚举【enum】。
    <!-- subComponent.vue -->
    
    <script>
        export default {
            name: 'subComponent',
            props: {
                identifying: {
                    type: String,
                    enum: ['zhangsan', 'lisi']
                }
            }
        }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

声明:

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/数据科学灵魂/article/detail/62738?site
推荐阅读
相关标签
  

闽ICP备14008679号