1
jydeng 2019-08-08 21:17:46 +08:00
上代码看看,想那么多没啥意思
|
2
mosade 2019-08-08 21:25:53 +08:00
试试```
this.items.push(...array); ``` |
3
FakeLeung 2019-08-08 21:27:16 +08:00
事实是,我用 this.data = [] this.data = res 这种方法是可以触发更新的。
|
4
shintendo 2019-08-08 21:39:14 +08:00
没代码不好猜,直觉告诉我跟 key 有关系
|
5
shintendo 2019-08-08 21:41:09 +08:00 5
其实问题只要能稳定复现,排查就是一件很有意思的事,反正我是这么觉得
|
6
gouflv 2019-08-08 23:36:07 +08:00 via iPhone
vue 是开源的,后面要做什么你懂了吧?
|
7
xalilo 2019-08-08 23:45:42 +08:00 via Android
明天我试试
|
8
SuperMild 2019-08-09 00:02:59 +08:00 1
这个你不先要怪自己,有可能是某个小地方不小心写错了,有时候一个意想不到的地方的小问题是很难发现。
|
9
mamahaha 2019-08-09 00:48:16 +08:00
你的父组件传到子组件还用原来的变量名吗?那你这个变量属于父组件还是子组件?
|
11
zazalu OP 问题解决了,虽然我不知道为啥(写程序以来, 第一次彻底放弃思考了 ,以前的问题我一般都会刨根问底的)
我就改了一个地方,就一切正常了.不会出现唯独 concat 方法不会触发 v-for 更新的问题, 如下 在我主题中说的子组件中其实还套用了另一个组件,叫 new-message, 我在其外围包裹了一个 div 后, v-for 的功能突然就一切正常了, 不会变得稀奇古怪的. ``` <template> <div> <p v-for="item in messageItems" :key="item.id">{{item.content}}</p> <div> <!-- 在此添加一个 div 来包裹 new-message 这个组件, 一切就都正常了 --> <new-message ref="newMessage" @on-success-valid="handleNewMessage"></new-message> </div> </div> </template> <script> export default { props: { messageItems: { type: Array } }, //..... } </script> ``` --------------- 顺便回复下楼上一些好心大佬的回答: 1. 我使用 push 也不会触发更新 2. 我检查了 key 是否重复,随后我故意重复发现 vue 会报错,也证明了我数据应该没有问题 3. 用 this.data = [] this.data = res 这种语法赋值会触发更新, 我已经说了,是唯独 concat 函数去更新不会触发 v-for 的更新 -------------- 总结: 第一次对 vue 产生了心理阴影, 也怪我不想看源码(实际上是太菜看的慢,一知半解=不懂, 所以只能不停的测试测试测试) 睡了, 让我自闭会 |
13
jorneyr 2019-08-09 06:49:27 +08:00
Vue 有的时候确实会出一些逻辑没错,但是就是有问题,我也遇到过,异步请求的复杂对象的数组中的数组显示不出来 (data 中已经预先定义了同样结构的数据显示到界面上),如果是同步请求就没问题、点击按钮创建同样的数据也能正常显示 (逻辑上和异步请求是一样的嘛),但就是异步请求得到的对象显示不出来,不管了,直接同步请求吧。
|
14
qyb 2019-08-09 07:05:29 +08:00
我觉得楼主已经很有条理了,应该没问题的
|
15
jatai 2019-08-09 07:16:30 +08:00 via Android
没用过 vue,但是看文档,好像都是建议用 setState 来更新数据的。不知道对不对
|
16
Biwood 2019-08-09 07:59:23 +08:00 via Android
你的 new-message 组件的 ref 值在遍历的时候重复了,要知道 ref 在当前组件里面必须是唯一的,是否因为这个导致了其他错误?
|
17
iamdhj 2019-08-09 08:41:58 +08:00
没代码不好确定问题,建议遇到问题可以把逻辑逐步精简,那样更容易找到问题根源
|
18
libook 2019-08-09 08:50:51 +08:00 3
楼主的目的在于抱怨,但其他 V 友在尝试帮楼主解决问题。
所以楼主干脆把完整代码发上来?可以存到 Github 上面然后发个链接出来。 我自己带实习生的时候,总是要求他们遇到问题先尝试自己解决,但如果两个小时仍然没有实质进展的话,再继续抠下去也没有多大帮助,这时候就需要提问,问身边的人或者去 StackOverflow 等社区提问,你英语好的话用英文提问应该没压力吧?实在罕见的问题去框架官方 GIthub 上提 issue。如果用的东西实在冷门,连官方都无暇回复,也可以自己研究源代码。 上面这段实际上就是程序员的日常,没有人生来就能解决所有问题,但不应该拒绝学习。 |
19
asdjgfr 2019-08-09 09:03:16 +08:00
codepen 上代码啊,大部分人为自己没问题的时候其实都是有问题的,特别 js 这种灵活的语言
|
20
1KN6sAqR0a57no6s 2019-08-09 09:06:29 +08:00 via Android 2
前端领域是热闹又孤独的。当你对 1+1 有疑惑的时候,所有人都能说上两句; 当你被 0.1 + 0.2 困住的时候,只能靠你自己。答非所问是搜索引擎的常态,也是人的常态。
|
21
zazalu OP @libook 谢谢。 我发帖确实感觉在抱怨。 标题其实也提了希望有人开导下,而不是帮我解决问题。 我在发帖后感觉看到大家的回复,觉得受到了一些鼓舞,所以就继续排查问题了。最终虽然不太完美的解决了。不过感觉我的心境好像发生了某种质的变化,这也是一种提升,所以我感觉我昨天的青春并没有浪费而不再感到难受了。谢谢大家
|
22
lscho 2019-08-09 09:18:36 +08:00
具体源码我也没看,但是组件内内容必须放到根元素里是官网提到的。。。https://cn.vuejs.org/v2/guide/components.html#%E5%8D%95%E4%B8%AA%E6%A0%B9%E5%85%83%E7%B4%A0
感觉大部分问题官网都有提到,一般问题都是不仔细看文档导致的 |
24
meepo3927 2019-08-09 09:26:02 +08:00
码农调试, 一个问题调一天是常有的事, 这就是成长啊!
|
25
SilentDepth 2019-08-09 09:26:36 +08:00
表示不能复现问题。
|
26
liximomo 2019-08-09 09:32:40 +08:00
你有那么多时间吐槽,你上个完整复现 demo,给 vue 提个 issue,问题说不定已经解决了?你这样子对待开源项目的 bug 才是让我觉得一片黑暗。
|
27
zazalu OP @jorneyr 对对,就是这种问题,感觉特别不好问别人,也不知道该不该问别人,看上去一切都是按照文档走的,但就是出问题,问别人,回答无非都是那些最常见的解法(可能你已经在问之前就已经尝试无数次无果的东西),js 用起来很方便,但是有时候又感觉不好控制,总是冷不丁一个神奇的错误冒出来。
|
28
liximomo 2019-08-09 09:38:24 +08:00
假设这真是个 bug, 以后还会有其他人不幸的遇到,而他们可能没办法那么幸运的解决,所以请提供一个最小可复现 demo, 使问题曝光并得到解决,让其他人不再同楼主这版焦头烂额。
|
29
a852695 2019-08-09 09:40:14 +08:00
写前端你还想明白???
|
30
zazalu OP @liximomo 我做了这方面努力,我想搞个完整复现 demo 出来,所以我去弄了,弄完后 demo 项目缺一点问题都没有(问题 3 所述)。所以意思就是产生问题的源头可能牵扯到项目更大范围我无法控制的地方。我这么一想,我怂了(也许这个行为就是你说的黑暗吧),我可能需要把全部源码搬上去也说不定。 所以内心还是想着自己解决。 你说的对,我也觉得这么做是不对的。 确实我的确是个弟弟和菜鸡
|
33
karnaugh 2019-08-09 09:47:17 +08:00
有个问题。。。你这个数据 messageItems 是 props 传进来的???那你修改啥啊。。。这操作就好比你要修改你爸妈传给你的基因一样。。。如果你不是写错了(本应在 data 里),那么你这个设计可能有点问题,想操作的话请再往外一层操作
|
34
TrickWu 2019-08-09 09:50:31 +08:00
我倒是觉得这种能够稳定复现的最好排查
知道问题出在哪 可以先写个最小 demo 看下结果 再或者就删代码调试 慢慢来 |
35
zazalu OP @karnaugh props 数据我是父组件里修改的,子组件只是使用 。我一般希望数据采集是在同一个地方发起,然后分发给给个组件去刷新数据的。这样对我来说感觉很有条理
|
37
zazalu OP @karnaugh 解决是解决了,就是解决的我有点莫名其妙。 新的一天重新打起精神,我先自己再看看吧。实在不行我就打算曝光我的垃圾源码给大家看了。。谢谢您
|
38
iyaozhen 2019-08-09 10:07:17 +08:00 via Android 1
楼主不必沮丧,几天查一个问题很常见。
首先楼主能想优雅的解决方案就已经不错了,很多人都是代码能跑就行 然后就是尝试最小集复现,问题一般都在业务中,要剥离出来,这一步有时候比较难,我的经验是复现问题不能想当然,自己做一些场景裁剪,往往会漏掉一些关键点,还是不断减少变量进行复现。 稳定复现就成功了一半,然后问同事、提 issue、论坛都行 |
39
yixiang 2019-08-09 10:07:36 +08:00
几年前过 vue。它的自动更新原理是用 Object.defineProperty 设置 getter/setter,好处是不用像 react 一样调用 setState,坏处是涉及到对象和数组的更新时,会有监听不到,不更新的情况,多半是这个原因。
相关文档: https://cn.vuejs.org/v2/guide/reactivity.html https://cn.vuejs.org/v2/guide/list.html#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9 相较之下,个人认为 react 的 setState 虽然感觉稍微罗嗦,但没啥大坑,设计上可能更好些。 |
40
shintendo 2019-08-09 10:30:28 +08:00
@zazalu 看你的补充,直觉再次告诉我是 key 的问题,你的 new-message 组件里面是什么东西,是不是个 p 元素?
|
41
shintendo 2019-08-09 10:40:13 +08:00
@yixiang
实际使用中,这种监听不到的边际情况其实影响很小。首先对象,只有新增的属性才会监听不到,但好的实践本就应该在一开始把数据结构定义好,实在需要中途新增属性也有$set 这种方式。其次数组,像 push, splice 这种方法 vue 都做了劫持,只有通过数组下标修改才会监听不到,但我实在想不到什么情况会用下标修改。 等 vue3 用 proxy 重写以后,这些边际情况也没有了。 |
44
CDL 2019-08-09 11:09:35 +08:00
push 不就行了,这个 concat 后再赋值是什么意思
|
45
zazalu OP |
50
CDL 2019-08-09 11:25:16 +08:00
@zazalu push 不行只能说明你数据有问题,你这个 concat 应该也是一样的情况,concat 返回的数据包含了原始数据的拦截器属性,直接赋值后导致设置拦截器属性失败,这里算是 bug 还是边界情况我没看源码就不清楚了
|
51
zazalu OP |
52
yinjy 2019-08-09 11:30:59 +08:00
之前遇到了类似问题,好像是用 this.$set()来更新数据就可以了
|
54
zazalu OP @liximomo 啊。搞错了 这个好像是加密图片。 我自己本地转成 gif 然后搞到 guthub 上去吧。 无视我上面的那条回复就行。
|
55
zazalu OP @Sendya 我 windows 上复现了,chrome 版本肯
也不低。 你页面上两个地方(模板语法和 v-for 语句)全部都会更新吗? |
56
Sendya 2019-08-09 11:41:32 +08:00
另外楼主要不要试试这样写法,好看点 哈哈哈
``` onClick() { this.fatherItems = [...this.fatherItems, { id: 3, content: "第三条通知" }] } ``` |
57
Sendya 2019-08-09 11:46:49 +08:00
是用了 `Drawer` 之后才不能更新的吗?
|
58
getElementBy1d 2019-08-09 11:46:51 +08:00
建议好好读一下官方文档 有很多问题官方文档已经写了
|
59
lxmfly123 2019-08-09 11:46:57 +08:00
Mac Chrome 可复现。
这个极有可能是 iView 的锅。那个 NewMessage 组件里,只有一个 iView 的 Drawer 组件,我把这个 NewMessage 换成不含 Drawer 的组件,就一切正常了。 具体怎么回事,估计要看 iView 的源码了。 |
61
Hoshinokozo 2019-08-09 11:47:58 +08:00
vue 的 v-for 确实坑很多,但是大部分都是跟 key 或者数组的更新检测有关,vue 不能检测到操作数组下标对数组赋值的改动,需要用$set,而且如果渲染的是不同类型的节点的话,需要加 key
|
62
finalwave 2019-08-09 11:48:00 +08:00
我在 linux 上复现了,chrome 版本 73.0.3683.86 (正式版本)
给 Drawer 的 transfer 属性赋值 false,也可以正常刷新数据,这个抽屉挺神奇的 |
63
lxmfly123 2019-08-09 11:49:14 +08:00
最后建议题主,尽量别用 iView。我也是一开始使用 iView,发现有很多地方有小问题,最后换了 element。顺便推荐一下 quasar,非常强大。
|
64
Sendya 2019-08-09 11:50:46 +08:00
@lxmfly123 @finalwave @zazalu 那我安利一下别用 iview 了,来 ant design 大法好把 https://vue.ant.design/docs/vue/introduce/
ant design pro vue 版本也有 https://github.com/sendya/ant-design-pro-vue |
65
zazalu OP @Sendya 是 我把 Drawer 去掉就好了. Drawer 源码在 node_modules/iview/src/components/drawer/drawer.vue
|
67
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 |
68
zazalu OP @finalwave 好的 等我恶补下 transfer 的概念... 意思就是说和 Drawer 无关 和 transfer 有关
|
69
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 |
70
rain0002009 2019-08-09 11:57:33 +08:00
其实我很好奇 drawer 到底干了啥 才会有这种效果
|
72
SilentDepth 2019-08-09 12:06:59 +08:00
@liximomo #47 Mac + Chrome 复现问题了。尝试移除里面用到的 iView Drawer 组件就可以解决问题,初步怀疑是 iView 做了什么。
|
73
Sendya 2019-08-09 12:07:02 +08:00 via Android
不知道对不对
|
74
SilentDepth 2019-08-09 12:09:11 +08:00
|
75
finalwave 2019-08-09 12:40:50 +08:00 1
测试了一下在 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 挂掉了 |
76
SilentDepth 2019-08-09 12:42:19 +08:00 2
|
77
watzds 2019-08-09 12:53:45 +08:00 via Android
iView 感觉挺难用的,虽然我只用过一星期不熟
不优雅 |
78
SilentDepth 2019-08-09 12:54:42 +08:00
楼主如果想保留组件模板的相对结构,可以把 v-for 部分或者 Drawer 部分包裹一个元素,或者在二者之间放一个 v-if="false" 的元素,总之就是不要让不稳定的 DOM 节点紧跟在 v-for 后面,这样就能让 v-for 效果正常。
|
79
shintendo 2019-08-09 13:11:51 +08:00
按理说 directive 里头操作 dom 没有问题,感觉如楼上所说是 diff 的问题,不确定这算是 vue 还是 iview 的锅。
话说 iview 作者不是在 v 站吗,可以召唤来看看 @Aresn |
80
crs0910 2019-08-09 13:14:21 +08:00
Programming is a cycle of feeling like an idiot and feeling like the smartest person alive. Don't let either feeling go to your head - [Brian Holt]( https://btholt.github.io/intro-to-web-dev-v2/final-thoughts/)
|
81
azh7138m 2019-08-09 13:14:52 +08:00
@Sendya 我觉得是,去掉之后就好了
https://codesandbox.io/s/array-replace-problem-in-vue-v-for-0odfy @SilentDepth 我觉得是 updator 更新不到那个元素了,因为被 iView 替换掉了 |
82
SilentDepth 2019-08-09 13:22:15 +08:00
@shintendo #79
Directive 提供了直接访问 DOM 的能力,但在「数据驱动视图」的思路下,直接修改 DOM 的做法应该是不被建议的(否则为了保证渲染结果符合预期就得全面比对 DOM 树,性能不行)。这次这个锅不能算 iView 的,应该是恰好碰到了 Vue 视图机制的雷区。 |
83
SilentDepth 2019-08-09 13:29:09 +08:00 1
@azh7138m #81
那好歹打个 warning 啊,DOM update 失败应该是挺值得关注的情况啊( |
84
zazalu OP 先做下感谢,@SilentDepth @finalwave 无私付出时间来帮我解决问题。
你们说的有些我还不太懂,没法第一时间参与讨论(哭) 我在慢慢看文档,源码和 google,把你们说的消化下。 我 java 出生,对 js 特别是 es,dom 这些还不太熟。vue 也只看了教程篇只会使用。 我后续会给一些总结(也观望下一些 iview vue 作者大佬的回答) 感谢感谢 |
85
azh7138m 2019-08-09 14:04:04 +08:00
@SilentDepth 失败是对我们来说的( UI 无反馈),updator 仍然可以执行成功(不报错)
|
86
crs0910 2019-08-09 14:05:06 +08:00 1
@zazalu #84 你可以用我这个最小化的 demo 做演示 https://codesandbox.io/s/wwu3n
|
87
galikeoy 2019-08-09 14:18:13 +08:00
我现在也在改 bug。。。这个问题我昨天改到现在了,没有丝毫头绪,,,,改得不爽就刷刷帖子吧。。。
|
88
leemove 2019-08-09 14:22:49 +08:00
其实很简单啦 你看看那个在线的例子,因为 vue 是用的 vdom,不是重新渲染所有 dom,而是在现有 dom 上做修改,因为你手动删除了页面上的元素,导致 vue 在增量渲染的时候报错了,我估计很有可能是调用了你删除元素上的方法,很有可能是 insertBefore
|
90
SilentDepth 2019-08-09 14:32:54 +08:00
@zazalu #84
如果没有前端知识基础,我建议不要挖掘框架源码,容易事倍功半还打击积极性。 我尝试简单地解释一下情况: 一个页面可以看做是由节点组成的树,更新页面内容就是在对一个或多个节点做属性更新。Vue 这类框架提供的功能是,你提供内容数据的定义(状态)和节点结构的描述(模板),它来自动更新节点属性。这个功能能够正常发挥作用的前提是,你不要替它更新节点属性,否则当它需要「在第 3 和第 4 个节点之间插入一个新节点」时,发现预期的第 4 个节点不存在了,它就迷茫了。你遇到的问题就是,组件模板的一部分在 Vue 掌控之外发生了变化,因此导致 Vue 产生了错误的视图更新结果。 |
91
leemove 2019-08-09 14:35:38 +08:00
@SilentDepth diff 是在 vnode 上展开的并不会根据当前 dom.是因为 diff 之后渲染过程中的错误啦.
|
92
zazalu OP @SilentDepth 恩,你说的话我已经理解了,我也结合了 @leemove 的回答, 意思就是说 vue 帮我去渲染第三条通知的时候,vue 是想直接用 insertBefore 这类方法(意思是在第四个节点前插入?),结果发现第四个节点不存在了, 因为第四个节点被第三方(比如 iview)非法的删除且没有通知 vue, 所以 vue 的 v-for 代码出问题了. 没错吧
|
93
zazalu OP 至少可以在我的项目代码里写个简单的注释了 不然平白无故的多个包括层, 看上去扎眼. 谢谢大家
|
94
leemove 2019-08-09 14:38:46 +08:00
其实 iview 这套组件库,还是有一些问题的,包括一些设计思想比较喜欢用 render 来代替模板和复杂渲染,我都不是很喜欢.
但是因为这个问题也算是揭开了前端 er 的伤疤吧,很简单的一个问题,被大家弄的越来越复杂...还有让看文档的,还有说别用 Iview 的还有完全就是乱回复方案的... 我觉得大家在回答一个技术问题之前,最好做一些简单的调研,抱着解决问题的态度来回复.而不是浪费你自己,浪费提出问题,浪费遇到同样问题正在看回复的人的时间. |
95
leemove 2019-08-09 14:40:07 +08:00
|
96
zazalu OP @leemove 恩 我看到你说的 insertBefore, 我的脑子好像就懂了. insertBefore next dom but next dom is disappear 没错吧
|
99
SilentDepth 2019-08-09 14:44:52 +08:00
@leemove #88 不认为是 insertBefore,因为元素本身并没有被从 DOM 树中移除,如果 insertBefore 了应当还可以渲染出来(只是不在正确的位置)
|
100
crs0910 2019-08-09 14:46:06 +08:00
https://github.com/vuejs/vue/blob/bd6cea0973247e2a8e1d4a2250614c0bf44f0b26/src/core/vdom/patch.js#L275
@leemove #95 @zazalu #96 @SilentDepth #99 旧版本会报错,新版本不会。可以看这里源码。 |