当前位置: 首页 > news >正文

踩坑实录(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. 自己公司的业务场景需要我们做什么。但是在我们公司这里的业务场景是必填的,它只有两个场景,而且必须符合某一个场景,所以在这里我就不考虑第一种条件,直接改为必填了。

声明:

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

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

相关文章:

  • SpringBoot之整合PageHelper分页插件
  • 代码随想录算法训练营DAY14 | 二叉树 (1)
  • vue3 之 组合式API—computed
  • 代码随想录算法训练营第四十一天| 343. 整数拆分、96.不同的二叉搜索树
  • 忘记 RAG:拥抱Agent设计,让 ChatGPT 更智能更贴近实际
  • 【多模态大模型】视觉大模型SAM:如何使模型能够处理任意图像的分割任务?
  • LeAPI 后端接口开发 - 发布、下线接口
  • 导出pdf 加密、加水印、加页脚
  • 计组学习笔记2024/2/5
  • 框架学习Maven
  • Gson源码解读
  • 自动化报告pptx-python|高效通过PPT模版制造报告(三)
  • Jupyter Notebook中的%matplotlib inline详解
  • A系统数据表同步到B系统数据表
  • 2.6作业
  • 【知识碎片】第三方登录弹窗效果
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • create-react-app做的留言板
  • iOS | NSProxy
  • Java,console输出实时的转向GUI textbox
  • Java反射-动态类加载和重新加载
  • jdbc就是这么简单
  • MaxCompute访问TableStore(OTS) 数据
  • Quartz初级教程
  • Spring Boot快速入门(一):Hello Spring Boot
  • spring-boot List转Page
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • vuex 学习笔记 01
  • 包装类对象
  • 表单中readonly的input等标签,禁止光标进入(focus)的几种方式
  • 初识 beanstalkd
  • 从伪并行的 Python 多线程说起
  • 大主子表关联的性能优化方法
  • 分类模型——Logistics Regression
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 区块链将重新定义世界
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 跳前端坑前,先看看这个!!
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • PostgreSQL 快速给指定表每个字段创建索引 - 1
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • ​MySQL主从复制一致性检测
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (003)SlickEdit Unity的补全
  • (14)Hive调优——合并小文件
  • (done) 两个矩阵 “相似” 是什么意思?
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (三) diretfbrc详解
  • (转)c++ std::pair 与 std::make
  • (转)VC++中ondraw在什么时候调用的
  • (转)大道至简,职场上做人做事做管理
  • (转)关于多人操作数据的处理策略