小白使用 vue2.6.10 的 v-for 遇到的一个问题从而引发了一个对于这一行业的思考,希望有人可以开导我
2019-08-08 21:07:20 +08:00
zazalu
我遇到的问题是这样的,我描述下:
问题 1:
父组件使用"props"传递一个数组"items"给子组件,
子组件使用 v-for 处理这个"items"来循环打印"item"中的 content 字段内容,
过了一段时间后,我会去触发一次父组件的 items 更新,类似如下代码:
```
this.items = this.items.concat([{id:11, content: "第十一条通知"}])
```
因为 vue 官方文档说过,如果是非变异方法改变数组内容,直接使用"replace a array"的方式,也就是我上面的方式.
所以我认为我的代码是没问题的.
但是事实却痛击了我, 不知道为啥 v-for 循环并没有刷新数据.
于是我先使用{{items}}检查了 props 的数据是否已经更新.
结果是{{items}}确实已经更新了第十一条通知的内容进去.
并且我使用 slice 方法去更新数组内容,是可以的, 就唯独 concat 方法不行
问题 2:
问题 2 是我在问题 1 后出现的一个新问题.
我将{{items}}放到了 v-for 所在组件的后面(问题 1 中我是放在最前面验证的), 这时候神奇的事情发生了.
v-for 居然更新了内容.
所以 vue 内部到底发生了什么... 我该怎么去解... 文档我也上下翻了好几次, google,baidu 了类似问题,但是很遗憾没有和我遇到一样问题的伙伴出现
问题 3:
我依旧不服, 想着在单元测试中也试试会不会存在这个问题,
所以我使用 vue-cli 创建了一个超级简单的 vue 单组件项目作为我的单元测试项目, 然后我将一些核心代码移了过去,重新测试了下
(我强调下, 单元测试的代码肯定是和我真正项目中用的是一样的! )
结果是没有任何问题, v-for 工作完全正常!
我.................................................................................
总结:
到最后, 我没法搞定这个问题(我采用的是问题 2 中描述的折中但是非常不优雅的写法), 感觉内心非常的难受, 关电脑, 回宿舍, 简单的吃了下晚饭, 吃着吃着差点掉眼泪 , 感觉写代码也至少一年多了, 这类问题以前在使用 jsp 的时候其实也遇到过类似的. 结果,一年过去了, 我连这种问题都没法搞定, 还谈什么设计模式,算法呢, 一年来感觉压根没有多大提升, 除了找资料和看英文文档能力感觉比以前强了以外, 能做的无非只有 crud.
这么一个问题, 搞得我焦头烂额,浪费了一下午+晚上几个小时的青春. 我想真诚的问下各位前辈们, 是不是我这种人不适合做程序员
121 条回复
Hoshinokozo
2019-08-09 11:47:58 +08:00
vue 的 v-for 确实坑很多,但是大部分都是跟 key 或者数组的更新检测有关,vue 不能检测到操作数组下标对数组赋值的改动,需要用$set,而且如果渲染的是不同类型的节点的话,需要加 key
finalwave
2019-08-09 11:48:00 +08:00
我在 linux 上复现了,chrome 版本 73.0.3683.86 (正式版本)
给 Drawer 的 transfer 属性赋值 false,也可以正常刷新数据,这个抽屉挺神奇的
lxmfly123
2019-08-09 11:49:14 +08:00
最后建议题主,尽量别用 iView。我也是一开始使用 iView,发现有很多地方有小问题,最后换了 element。顺便推荐一下 quasar,非常强大。
zazalu
2019-08-09 11:51:15 +08:00
@
Sendya 是 我把 Drawer 去掉就好了. Drawer 源码在 node_modules/iview/src/components/drawer/drawer.vue
zazalu
2019-08-09 11:53:12 +08:00
@
Sendya 等我搞定这些东西后,试试用你说的框架去重构下
finalwave
2019-08-09 11:53:50 +08:00
就是这个 transfer 的问题了
我把 newmessage.vue 改成
<template>
<div>
<!-- <Drawer v-model="show">This is two-level drawer.</Drawer> -->
trytry
</div>
</template>
加上
mounted() {
this.$nextTick(() => {
const body = document.querySelector("body");
if (body.append) {
body.append(this.$el);
} else {
body.appendChild(this.$el);
}
});
}
插入到 body,也不会更新数据,不需要用 drawer
zazalu
2019-08-09 11:57:04 +08:00
@
finalwave 好的 等我恶补下 transfer 的概念... 意思就是说和 Drawer 无关 和 transfer 有关
finalwave
2019-08-09 11:57:22 +08:00
测试了一下用 div 包裹 p v-for 可以刷新,p v-for 换成 div v-for 也不能刷新
在 v-for 元素和 transfer 元素间插入 div、p、br 也能刷新
看来是 v-for 的元素紧贴着 transfer 元素的 bug
rain0002009
2019-08-09 11:57:33 +08:00
其实我很好奇 drawer 到底干了啥 才会有这种效果
Sendya
2019-08-09 12:00:53 +08:00
@
finalwave iview 的 drawer 居然不是起一个新 Vue 实例。。难怪会这样
SilentDepth
2019-08-09 12:06:59 +08:00
@
liximomo #47 Mac + Chrome 复现问题了。尝试移除里面用到的 iView Drawer 组件就可以解决问题,初步怀疑是 iView 做了什么。
Sendya
2019-08-09 12:07:02 +08:00
不知道对不对
SilentDepth
2019-08-09 12:09:11 +08:00
@
lxmfly123 #63 @
Sendya #64
Not personal,但我也是建议别用 iView,bug 目前看起来还是有点多。
finalwave
2019-08-09 12:40:50 +08:00
测试了一下在 newmessage 的 mounted 里
const el = this.$el;
const home = document.createElement("div");
const parentNode = el.parentNode;
parentNode.replaceChild(home, el);
也是更新数据挂掉
取消所有 js 代码直接在 f12 里删除元素也会挂掉更新数据(甚至可以更新一条再删除相邻挂掉后续更新
应该就是 iview 在 transfer-dom.js 里 parentNode.replaceChild(home, el)直接修改 dom 导致 vue 懵了,所以相邻的 v-for 挂掉了
SilentDepth
2019-08-09 12:42:19 +08:00
问题出在 iView 的 v-transfer-dom 上,源码第 27 行通过 Node.replaceChild( ) 将原本是组件根元素的元素替换为一个注释节点(实际上替换成任意节点都可以复现问题)。v-for 的逻辑其实正常执行了,新的元素也生成了(可以通过 $refs 访问),但没有正确 attach 到 DOM 树中。怀疑这个过程紧挨着 v-for 后面发生会影响 VDOM Diff ?不确定这算不算 Vue 的 bug,等 dalao 进一步解析。
/cc @
liximomo @
sodatea
watzds
2019-08-09 12:53:45 +08:00
iView 感觉挺难用的,虽然我只用过一星期不熟
不优雅
SilentDepth
2019-08-09 12:54:42 +08:00
楼主如果想保留组件模板的相对结构,可以把 v-for 部分或者 Drawer 部分包裹一个元素,或者在二者之间放一个 v-if="false" 的元素,总之就是不要让不稳定的 DOM 节点紧跟在 v-for 后面,这样就能让 v-for 效果正常。
shintendo
2019-08-09 13:11:51 +08:00
按理说 directive 里头操作 dom 没有问题,感觉如楼上所说是 diff 的问题,不确定这算是 vue 还是 iview 的锅。
话说 iview 作者不是在 v 站吗,可以召唤来看看 @
Aresn
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
https://www.v2ex.com/t/590284
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.