记录一次升级ant-design-vue的遇见的bug

使用版本:
"version": "2.5.2"
"ant-design-vue": "1.4.2",

vue模板内容

  1. <template>
  2. <div>
  3. <a-table :columns="columns" :dataSource="data" :rowSelection="rowSelection" :locale="{emptyText:'sdfsd'}"/>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. data() {
  9. return {
  10. data:[ {
  11. key: 1,
  12. address: 'New York No. 1 Lake Park',
  13. }] ,
  14. columns: [
  15. {
  16. title: 'Address',
  17. dataIndex: 'address',
  18. width: '100%',
  19. key: 'address',
  20. },
  21. ],
  22. rowSelection:{
  23. onChange: () => {},
  24. onSelect: () => {},
  25. onSelectAll: () => {},
  26. }
  27. };
  28. },
  29. };
  30. </script>

chrome控制台显示如下:

打开Sources看到是_traverse方法报错

  1. function _traverse (val, seen) {
  2. var i, keys;
  3. var isA = Array.isArray(val);
  4. if ((!isA && !isObject(val)) || !Object.isExtensible(val)) {
  5. return
  6. }
  7. if (val.__ob__) {
  8. var depId = val.__ob__.dep.id;
  9. if (seen.has(depId)) {
  10. return
  11. }
  12. seen.add(depId);
  13. }
  14. if (isA) {
  15. i = val.length;
  16. while (i--) { _traverse(val[i], seen); }
  17. } else {
  18. keys = Object.keys(val);
  19. i = keys.length;
  20. while (i--) { _traverse(val[keys[i]], seen); }
  21. }
  22. }

该方法存在于vue项目src/core/observer/traverse.js中,
traverse 的逻辑也很简单,它实际上就是对一个对象做深层递归遍历,因为遍历过程中就是对一个子对象的访问,会触发它们的 getter 过程,这样就可以收集到依赖,也就是订阅它们变化的 watcher
下面的代码就会触发traverse:

  1. watch: {
  2. a: {
  3. deep: true, // deep属性为true是关键
  4. handler(newVal) {
  5. console.log(newVal)
  6. }
  7. }
  8. }

在 watcher 执行 get 求值的过程中有一段逻辑:

  1. get() {
  2. let value = this.getter.call(vm, vm)
  3. // ...
  4. if (this.deep) {
  5. traverse(value)
  6. }
  7. }

在traverse中打断点,打印出递归的traverse的参数name,发现异常:

如果深度遍历一个vnode节点,每一个vnode都保存有父节点和子节点的引用,遍历所有的vnode确实会导致栈溢出,但是怎么会遍历到一个vnode节点呢?
再看前面遍历到的一个对象,在ant-design-vue文档中查到是渲染rowSelection用到的,于是在ant-desing-vue的源码查到了 renderRowSelection方法:

  1. renderRowSelection: function renderRowSelection(prefixCls, locale) {
  2. ......
  3. selectionColumn.title = selectionColumn.title
  4. || h(SelectionCheckboxAll, {
  5. attrs: {
  6. store: this.store,
  7. locale: locale,
  8. data: data,
  9. getCheckboxPropsByItem: this.getCheckboxPropsByItem,
  10. getRecordKey: this.getRecordKey,
  11. disabled: checkboxAllDisabled,
  12. prefixCls: prefixCls,
  13. selections: rowSelection.selections,
  14. hideDefaultSelections: rowSelection.hideDefaultSelections,
  15. getPopupContainer: this.generatePopupContainerFunc()
  16. },
  17. on: {
  18. 'select': this.handleSelectRow
  19. }
  20. });
  21. ......

SelectionCheckboxAll组件的locale属性就包含了emptyText,filterReset等,找到了位置,调试一下在renderTable中发现如下代码:

  1. // locale至少是一个空对象
  2. var locale = _extends({}, contextLocale, this.locale);
  3. if (!locale || !locale.emptyText) {
  4. mergedLocale.emptyText = renderEmpty(h, 'Table');
  5. }
  6. ......
  7. var columns = this.renderRowSelection(prefixCls, mergedLocale);

问题在于如果locale,经过排查international的LocaleReceiver.js,发现locale中有数据,又不存在emptyText字段,导致emptyText赋值为renderEmpty方法返回的组件,渲染SelectionCheckboxAll组件的时候,对属性遍历就会报栈溢出。

解决方案比较简单:给a-table组件加一个locale属性,同时locale的属性emptyText不为空。

之前的项目中为什么没有报错?

经过对比package.json和node_modules中的版本,发现旧项目ant-design-vue的版本是1.2.4,回退回去之后,问题消失了。

官网上为什么能够正常使用呢?

自己下载了一个浏览器版本的vue和antd-vue,测试正常,怀疑是vue版本的问题,对比了traverse方法

  1. function _traverse (val: any, seen: SimpleSet) {
  2. let i, keys
  3. const isA = Array.isArray(val)
  4. if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) {
  5. return
  6. }
  7. if (val.__ob__) {
  8. const depId = val.__ob__.dep.id
  9. if (seen.has(depId)) {
  10. return
  11. }
  12. seen.add(depId)
  13. }
  14. if (isA) {
  15. i = val.length
  16. while (i--) _traverse(val[i], seen)
  17. } else {
  18. keys = Object.keys(val)
  19. i = keys.length
  20. while (i--) _traverse(val[keys[i]], seen)
  21. }
  22. }

多了 val instanceof VNode这句判断,问题就解决了。

看看vue升级记录:
fix: do not traverse VNodes when regsitering dependencies

最终的解决方案:升级vue版本到2.6.x.
本文结束

记录一次升级ant-design-vue的遇见的bug的更多相关文章

  1. 基于Ant Design Vue封装一个表单控件

    开源代码 https://github.com/naturefwvue/nf-vue3-ant 有缺点本来是写在最后的,但是博文写的似乎有点太长了,估计大家没时间往下看,于是就把有缺点写在前面了,不喜 ...

  2. Ant Design Vue select下拉列表设置默认值

    在项目中需要为Ant Design Vue 的 select 组件设置一个默认值,如下图所示的状态下拉选择框,默认选择全部 代码如下: <a-select v-model="query ...

  3. Ant Design Vue Pro 项目实战-项目初始化(一)

    写在前面 时间真快,转眼又是新的一年.随着前后端技术的不断更新迭代,尤其是前端,在目前前后端分离开发模式这样的一个大环境下,交互性.兼容性等传统的开发模式已经显得有些吃力.之前一直用的是react,随 ...

  4. 使用ant design vue的日历组件,实现一个简单交易日与非交易日的切换

    使用ant design vue的日历组件,实现一个简单交易日与非交易日的切换 需求: 日历区分交易日.非交易日 可以切换面板查看整年交易日信息 可以在手动调整交易日.非交易日 演示实例 序--使用软 ...

  5. 使用npm安装 Ant Design Vue 时报错—ant-design-vue@latest(sha1-qsf / gCIFcRYxyGmOKgx7TmHf1z4 =)seems to be corrupted.

    安装 Ant Design Vue 时报错: npm install ant-design-vue --save ant-design-vue @ latest(sha1-qsf / gCIFcRYx ...

  6. Vue3学习(二)之集成Ant Design Vue

    一.集成Ant Design Vue npm install ant-design-vue@2.0.0-rc.3 --save 兼容性 Ant Design Vue 2.x 支持所有的现代浏览器. 如 ...

  7. Ant Design Vue项目解析-前言

    源码系列文章很长时间没有更新,一是在考虑文章用什么方式写质量会更高,用什么方式总结更易于扩展和总结知识点,加上工作.看书.健身占用的时间比较多所以也没时间去整理.最近在网上看到一篇文章感觉这种方式不错 ...

  8. jeecg ant design vue 一些收藏

    1关于 进来清除上次记录 找到src/permission.js下的

  9. 文档驱动 —— 表单组件(五):基于Ant Design Vue 的表单控件的demo,再也不需要写代码了。

    源码 https://github.com/naturefwvue/nf-vue3-ant 特点 只需要更改meta,既可以切换表单 可以统一修改样式,统一升级,以最小的代价,应对UI的升级.切换,应 ...

  10. jeecg ant design vue一级菜单跳到外部页面——例如跳到百度

    需求:点击首页跳到百度新打开的页面 找到SideMenu.vue   对应的inde.js找到renderMenuItem 函数.加一个判断 if(menu.meta.url=='https://ww ...

随机推荐

  1. 有关 HashMap 面试会问的一切

    前言 HashMap 是无论在工作还是面试中都非常常见常考的数据结构. 比如 Leetcode 第一题 Two Sum 的某种变种的最优解就是需要用到 HashMap 的,高频考题 LRU Cache ...

  2. CentOS7 开机进入emergency mode

    今天突然操作了一下磁盘挂载,然后系统启动之后,就直接进入emergency模式了,然后只能输入密码进行救援,截图如下: 突然想了一下最近的一次操作,是因为要挂在镜像,然后每次开机都要挂载一次,觉得比较 ...

  3. tomcat中AJP协议和HTTP协议的区别

    tomcat的server.xml中的AJP和HTTP连接器区别 HTTP协议:连接器监听8080端口,负责建立HTTP连接.在通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个连接器. ...

  4. Spring Boot2+Resilience4j实现容错之Bulkhead

    Resilience4j是一个轻量级.易于使用的容错库,其灵感来自Netflix Hystrix,但专为Java 8和函数式编程设计.轻量级,因为库只使用Vavr,它没有任何其他外部库依赖项.相比之下 ...

  5. Python 简明教程 ---10,Python 列表

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 程序 = 算法 + 数据结构 -- Nicklaus Wirth 目录 从这句话程序 = 算法 + ...

  6. springBoot--集成RocketMQ

    1.导入依赖 <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>sprin ...

  7. python文件处理-将图像根据坐标切割成若干小图

    代码涉及到:遍历目标路径,选取csv后缀的文件,遍历csv每一行,读取坐标,用cv操作图片 # !/usr/bin/python # -*- coding: UTF- -*- import panda ...

  8. 在MFC下绘制直线,使用橡皮筋技术,可以使直线效果跟随鼠标移

    void CGraphic1View::OnMouseMove(UINT nFlags, CPoint point) {        if(MK_LBUTTON == nFlags)    {    ...

  9. Python 中的元类到底是什么?这篇恐怕是最清楚的了

    类作为对象 在理解元类之前,您需要掌握 Python 的类.Python 从 Smalltalk 语言中借用了一个非常特殊的类概念. 在大多数语言中,类只是描述如何产生对象的代码段.在 Python ...

  10. Vue.js 组件复用和扩展之道

    软件编程有一个重要的原则是 D.R.Y(Don't Repeat Yourself),讲的是尽量复用代码和逻辑,减少重复.组件扩展可以避免重复代码,更易于快速开发和维护.那么,扩展 Vue 组件的最佳 ...