V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zazalu
V2EX  ›  Vue.js

小白使用 vue2.6.10 的 v-for 遇到的一个问题从而引发了一个对于这一行业的思考,希望有人可以开导我

  •  
  •   zazalu · 2019-08-08 21:07:20 +08:00 · 8432 次点击
    这是一个创建于 1694 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我遇到的问题是这样的,我描述下:

    问题 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.

    这么一个问题, 搞得我焦头烂额,浪费了一下午+晚上几个小时的青春. 我想真诚的问下各位前辈们, 是不是我这种人不适合做程序员
    第 1 条附言  ·  2019-08-09 11:03:23 +08:00
    太好了!!!! 我复现了! 总算不用把我所有的垃圾代码曝光了(脸皮厚...)

    完整复现 demo 已上传! 按照我写的复线流程操作可以复现!

    https://github.com/zazaluMonster/array-replace-problem-in-vue-v-for-demo

    希望有大佬可以帮忙! vue 内部到底发生了什么!
    第 2 条附言  ·  2019-08-09 11:20:38 +08:00
    环境:

    ubuntu18.04

    chrome Version 75.0.3770.142 (Official Build) unknown (64-bit) (直接黏贴了 chrome 汇报的版本)

    node -v
    v10.16.0

    npm -v
    6.10.1

    "core-js": "^2.6.5",

    "iview": "^3.4.2",

    "vue": "^2.6.10"
    第 3 条附言  ·  2019-08-09 11:46:07 +08:00
    我看很多人说无法复现. 所以我上传了 gif 图来表现我自己的情况.
    第 4 条附言  ·  2019-08-09 14:12:55 +08:00
    感谢 @crs0910 提供的在线演示 demo

    https://codesandbox.io/s/wwu3n

    虽然代码实现不同, 但是问题本质是一样的(比我的更精简)
    第 5 条附言  ·  2019-08-09 15:01:16 +08:00
    已解决问题根源, 是手动操作 DOM 结构, 导致 vue 懵逼的问题.(现在留有的唯一疑惑是 vue 不给出一些警告或者提示)
    121 条回复    2019-08-10 14:01:42 +08:00
    1  2  
    jydeng
        1
    jydeng  
       2019-08-08 21:17:46 +08:00
    上代码看看,想那么多没啥意思
    mosade
        2
    mosade  
       2019-08-08 21:25:53 +08:00
    试试```
    this.items.push(...array);
    ```
    FakeLeung
        3
    FakeLeung  
       2019-08-08 21:27:16 +08:00
    事实是,我用 this.data = [] this.data = res 这种方法是可以触发更新的。
    shintendo
        4
    shintendo  
       2019-08-08 21:39:14 +08:00
    没代码不好猜,直觉告诉我跟 key 有关系
    shintendo
        5
    shintendo  
       2019-08-08 21:41:09 +08:00   ❤️ 5
    其实问题只要能稳定复现,排查就是一件很有意思的事,反正我是这么觉得
    gouflv
        6
    gouflv  
       2019-08-08 23:36:07 +08:00 via iPhone
    vue 是开源的,后面要做什么你懂了吧?
    xalilo
        7
    xalilo  
       2019-08-08 23:45:42 +08:00 via Android
    明天我试试
    SuperMild
        8
    SuperMild  
       2019-08-09 00:02:59 +08:00   ❤️ 1
    这个你不先要怪自己,有可能是某个小地方不小心写错了,有时候一个意想不到的地方的小问题是很难发现。
    mamahaha
        9
    mamahaha  
       2019-08-09 00:48:16 +08:00
    你的父组件传到子组件还用原来的变量名吗?那你这个变量属于父组件还是子组件?
    airyland
        10
    airyland  
       2019-08-09 03:00:46 +08:00
    @gouflv 阴阳怪气,不知所云。
    zazalu
        11
    zazalu  
    OP
       2019-08-09 03:01:34 +08:00
    问题解决了,虽然我不知道为啥(写程序以来, 第一次彻底放弃思考了 ,以前的问题我一般都会刨根问底的)

    我就改了一个地方,就一切正常了.不会出现唯独 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 产生了心理阴影, 也怪我不想看源码(实际上是太菜看的慢,一知半解=不懂, 所以只能不停的测试测试测试)

    睡了, 让我自闭会
    zazalu
        12
    zazalu  
    OP
       2019-08-09 03:02:53 +08:00
    @shintendo 是的, 我认同.
    jorneyr
        13
    jorneyr  
       2019-08-09 06:49:27 +08:00
    Vue 有的时候确实会出一些逻辑没错,但是就是有问题,我也遇到过,异步请求的复杂对象的数组中的数组显示不出来 (data 中已经预先定义了同样结构的数据显示到界面上),如果是同步请求就没问题、点击按钮创建同样的数据也能正常显示 (逻辑上和异步请求是一样的嘛),但就是异步请求得到的对象显示不出来,不管了,直接同步请求吧。
    qyb
        14
    qyb  
       2019-08-09 07:05:29 +08:00
    我觉得楼主已经很有条理了,应该没问题的
    jatai
        15
    jatai  
       2019-08-09 07:16:30 +08:00 via Android
    没用过 vue,但是看文档,好像都是建议用 setState 来更新数据的。不知道对不对
    Biwood
        16
    Biwood  
       2019-08-09 07:59:23 +08:00 via Android
    你的 new-message 组件的 ref 值在遍历的时候重复了,要知道 ref 在当前组件里面必须是唯一的,是否因为这个导致了其他错误?
    iamdhj
        17
    iamdhj  
       2019-08-09 08:41:58 +08:00
    没代码不好确定问题,建议遇到问题可以把逻辑逐步精简,那样更容易找到问题根源
    libook
        18
    libook  
       2019-08-09 08:50:51 +08:00   ❤️ 3
    楼主的目的在于抱怨,但其他 V 友在尝试帮楼主解决问题。

    所以楼主干脆把完整代码发上来?可以存到 Github 上面然后发个链接出来。

    我自己带实习生的时候,总是要求他们遇到问题先尝试自己解决,但如果两个小时仍然没有实质进展的话,再继续抠下去也没有多大帮助,这时候就需要提问,问身边的人或者去 StackOverflow 等社区提问,你英语好的话用英文提问应该没压力吧?实在罕见的问题去框架官方 GIthub 上提 issue。如果用的东西实在冷门,连官方都无暇回复,也可以自己研究源代码。

    上面这段实际上就是程序员的日常,没有人生来就能解决所有问题,但不应该拒绝学习。
    asdjgfr
        19
    asdjgfr  
       2019-08-09 09:03:16 +08:00
    codepen 上代码啊,大部分人为自己没问题的时候其实都是有问题的,特别 js 这种灵活的语言
    YuxiangLuo
        20
    YuxiangLuo  
       2019-08-09 09:06:29 +08:00 via Android   ❤️ 2
    前端领域是热闹又孤独的。当你对 1+1 有疑惑的时候,所有人都能说上两句; 当你被 0.1 + 0.2 困住的时候,只能靠你自己。答非所问是搜索引擎的常态,也是人的常态。
    zazalu
        21
    zazalu  
    OP
       2019-08-09 09:18:32 +08:00 via Android
    @libook 谢谢。 我发帖确实感觉在抱怨。 标题其实也提了希望有人开导下,而不是帮我解决问题。 我在发帖后感觉看到大家的回复,觉得受到了一些鼓舞,所以就继续排查问题了。最终虽然不太完美的解决了。不过感觉我的心境好像发生了某种质的变化,这也是一种提升,所以我感觉我昨天的青春并没有浪费而不再感到难受了。谢谢大家
    lscho
        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

    感觉大部分问题官网都有提到,一般问题都是不仔细看文档导致的
    zazalu
        23
    zazalu  
    OP
       2019-08-09 09:22:50 +08:00 via Android
    @lscho 但是很奇怪的是我项目很多地方都是一样的风格 都没问题,唯独这里必须要根元素包裹
    meepo3927
        24
    meepo3927  
       2019-08-09 09:26:02 +08:00
    码农调试, 一个问题调一天是常有的事, 这就是成长啊!
    SilentDepth
        25
    SilentDepth  
       2019-08-09 09:26:36 +08:00
    表示不能复现问题。
    liximomo
        26
    liximomo  
       2019-08-09 09:32:40 +08:00
    你有那么多时间吐槽,你上个完整复现 demo,给 vue 提个 issue,问题说不定已经解决了?你这样子对待开源项目的 bug 才是让我觉得一片黑暗。
    zazalu
        27
    zazalu  
    OP
       2019-08-09 09:38:07 +08:00 via Android
    @jorneyr 对对,就是这种问题,感觉特别不好问别人,也不知道该不该问别人,看上去一切都是按照文档走的,但就是出问题,问别人,回答无非都是那些最常见的解法(可能你已经在问之前就已经尝试无数次无果的东西),js 用起来很方便,但是有时候又感觉不好控制,总是冷不丁一个神奇的错误冒出来。
    liximomo
        28
    liximomo  
       2019-08-09 09:38:24 +08:00
    假设这真是个 bug, 以后还会有其他人不幸的遇到,而他们可能没办法那么幸运的解决,所以请提供一个最小可复现 demo, 使问题曝光并得到解决,让其他人不再同楼主这版焦头烂额。
    a852695
        29
    a852695  
       2019-08-09 09:40:14 +08:00
    写前端你还想明白???
    zazalu
        30
    zazalu  
    OP
       2019-08-09 09:42:04 +08:00 via Android
    @liximomo 我做了这方面努力,我想搞个完整复现 demo 出来,所以我去弄了,弄完后 demo 项目缺一点问题都没有(问题 3 所述)。所以意思就是产生问题的源头可能牵扯到项目更大范围我无法控制的地方。我这么一想,我怂了(也许这个行为就是你说的黑暗吧),我可能需要把全部源码搬上去也说不定。 所以内心还是想着自己解决。 你说的对,我也觉得这么做是不对的。 确实我的确是个弟弟和菜鸡
    zazalu
        31
    zazalu  
    OP
       2019-08-09 09:43:27 +08:00 via Android
    @liximomo 嗯 我今天会继续,心结依旧存在,刚睡醒,打起精神来继续干了
    liximomo
        32
    liximomo  
       2019-08-09 09:47:09 +08:00
    @zazalu 可以使用二分法,逐步确定产生影响的代码范围。
    karnaugh
        33
    karnaugh  
       2019-08-09 09:47:17 +08:00
    有个问题。。。你这个数据 messageItems 是 props 传进来的???那你修改啥啊。。。这操作就好比你要修改你爸妈传给你的基因一样。。。如果你不是写错了(本应在 data 里),那么你这个设计可能有点问题,想操作的话请再往外一层操作
    TrickWu
        34
    TrickWu  
       2019-08-09 09:50:31 +08:00
    我倒是觉得这种能够稳定复现的最好排查
    知道问题出在哪
    可以先写个最小 demo 看下结果
    再或者就删代码调试
    慢慢来
    zazalu
        35
    zazalu  
    OP
       2019-08-09 09:51:18 +08:00 via Android
    @karnaugh props 数据我是父组件里修改的,子组件只是使用 。我一般希望数据采集是在同一个地方发起,然后分发给给个组件去刷新数据的。这样对我来说感觉很有条理
    karnaugh
        36
    karnaugh  
       2019-08-09 09:54:57 +08:00
    @zazalu 要不把父组件的代码贴来看看?(其实截图效果蛮不错的)毕竟看你如此难受还是想帮你解决一下😂
    zazalu
        37
    zazalu  
    OP
       2019-08-09 10:00:12 +08:00 via Android
    @karnaugh 解决是解决了,就是解决的我有点莫名其妙。 新的一天重新打起精神,我先自己再看看吧。实在不行我就打算曝光我的垃圾源码给大家看了。。谢谢您
    iyaozhen
        38
    iyaozhen  
       2019-08-09 10:07:17 +08:00 via Android   ❤️ 1
    楼主不必沮丧,几天查一个问题很常见。
    首先楼主能想优雅的解决方案就已经不错了,很多人都是代码能跑就行
    然后就是尝试最小集复现,问题一般都在业务中,要剥离出来,这一步有时候比较难,我的经验是复现问题不能想当然,自己做一些场景裁剪,往往会漏掉一些关键点,还是不断减少变量进行复现。
    稳定复现就成功了一半,然后问同事、提 issue、论坛都行
    yixiang
        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 虽然感觉稍微罗嗦,但没啥大坑,设计上可能更好些。
    shintendo
        40
    shintendo  
       2019-08-09 10:30:28 +08:00
    @zazalu 看你的补充,直觉再次告诉我是 key 的问题,你的 new-message 组件里面是什么东西,是不是个 p 元素?
    shintendo
        41
    shintendo  
       2019-08-09 10:40:13 +08:00
    @yixiang
    实际使用中,这种监听不到的边际情况其实影响很小。首先对象,只有新增的属性才会监听不到,但好的实践本就应该在一开始把数据结构定义好,实在需要中途新增属性也有$set 这种方式。其次数组,像 push, splice 这种方法 vue 都做了劫持,只有通过数组下标修改才会监听不到,但我实在想不到什么情况会用下标修改。
    等 vue3 用 proxy 重写以后,这些边际情况也没有了。
    zazalu
        42
    zazalu  
    OP
       2019-08-09 11:04:07 +08:00
    @shintendo 啊! 大佬! 我上传了一个最小复现 demo! 这次是真的来求助了! 弟弟真的搞不懂啊
    zazalu
        43
    zazalu  
    OP
       2019-08-09 11:04:26 +08:00
    @shintendo 在主题的 APPEND 里
    CDL
        44
    CDL  
       2019-08-09 11:09:35 +08:00
    push 不就行了,这个 concat 后再赋值是什么意思
    zazalu
        45
    zazalu  
    OP
       2019-08-09 11:11:45 +08:00
    @CDL concat 不会影响原数组,而是返回一个新数组 所以要赋值回去.
    实际代码中数据量大,所以 push 要循环, 直接用 concat 方法方便..
    我也用了 push,也是不行的!
    zazalu
        46
    zazalu  
    OP
       2019-08-09 11:16:45 +08:00
    @karnaugh 我上传了最小复现 demo,在 APPEND 里, 这次是货真价实的求助了.
    liximomo
        47
    liximomo  
       2019-08-09 11:17:08 +08:00
    @zazalu Mac 下 chrome 无法复现,请说明你的环境
    zazalu
        48
    zazalu  
    OP
       2019-08-09 11:21:06 +08:00
    @liximomo 哭了! mac 下正常吗. 我也有有台 mac,我试试. 我的环境在 APPEND 里说了
    zazalu
        49
    zazalu  
    OP
       2019-08-09 11:23:58 +08:00
    @liximomo 我录个小视频然后转 gif 发上来,给您看下
    CDL
        50
    CDL  
       2019-08-09 11:25:16 +08:00
    @zazalu push 不行只能说明你数据有问题,你这个 concat 应该也是一样的情况,concat 返回的数据包含了原始数据的拦截器属性,直接赋值后导致设置拦截器属性失败,这里算是 bug 还是边界情况我没看源码就不清楚了
    zazalu
        51
    zazalu  
    OP
       2019-08-09 11:30:14 +08:00
    yinjy
        52
    yinjy  
       2019-08-09 11:30:59 +08:00
    之前遇到了类似问题,好像是用 this.$set()来更新数据就可以了
    Sendya
        53
    Sendya  
       2019-08-09 11:35:04 +08:00
    @zazalu Windows 下 chrome , firefox, edge (均 Latest )无法复现
    zazalu
        54
    zazalu  
    OP
       2019-08-09 11:36:29 +08:00 via Android
    @liximomo 啊。搞错了 这个好像是加密图片。 我自己本地转成 gif 然后搞到 guthub 上去吧。 无视我上面的那条回复就行。
    zazalu
        55
    zazalu  
    OP
       2019-08-09 11:40:43 +08:00 via Android
    @Sendya 我 windows 上复现了,chrome 版本肯
    也不低。 你页面上两个地方(模板语法和 v-for 语句)全部都会更新吗?
    Sendya
        56
    Sendya  
       2019-08-09 11:41:32 +08:00
    另外楼主要不要试试这样写法,好看点 哈哈哈

    ```
    onClick() {
    this.fatherItems = [...this.fatherItems, {
    id: 3,
    content: "第三条通知"
    }]
    }
    ```
    Sendya
        57
    Sendya  
       2019-08-09 11:46:49 +08:00
    是用了 `Drawer` 之后才不能更新的吗?
    getElementBy1d
        58
    getElementBy1d  
       2019-08-09 11:46:51 +08:00
    建议好好读一下官方文档 有很多问题官方文档已经写了
    lxmfly123
        59
    lxmfly123  
       2019-08-09 11:46:57 +08:00
    Mac Chrome 可复现。
    这个极有可能是 iView 的锅。那个 NewMessage 组件里,只有一个 iView 的 Drawer 组件,我把这个 NewMessage 换成不含 Drawer 的组件,就一切正常了。
    具体怎么回事,估计要看 iView 的源码了。
    zazalu
        60
    zazalu  
    OP
       2019-08-09 11:47:26 +08:00
    @Sendya js 真的很灵活啊.我没想到可以这么写
    Hoshinokozo
        61
    Hoshinokozo  
       2019-08-09 11:47:58 +08:00
    vue 的 v-for 确实坑很多,但是大部分都是跟 key 或者数组的更新检测有关,vue 不能检测到操作数组下标对数组赋值的改动,需要用$set,而且如果渲染的是不同类型的节点的话,需要加 key
    finalwave
        62
    finalwave  
       2019-08-09 11:48:00 +08:00
    我在 linux 上复现了,chrome 版本 73.0.3683.86 (正式版本)
    给 Drawer 的 transfer 属性赋值 false,也可以正常刷新数据,这个抽屉挺神奇的
    lxmfly123
        63
    lxmfly123  
       2019-08-09 11:49:14 +08:00
    最后建议题主,尽量别用 iView。我也是一开始使用 iView,发现有很多地方有小问题,最后换了 element。顺便推荐一下 quasar,非常强大。
    Sendya
        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
    zazalu
        65
    zazalu  
    OP
       2019-08-09 11:51:15 +08:00
    @Sendya 是 我把 Drawer 去掉就好了. Drawer 源码在 node_modules/iview/src/components/drawer/drawer.vue
    zazalu
        66
    zazalu  
    OP
       2019-08-09 11:53:12 +08:00
    @Sendya 等我搞定这些东西后,试试用你说的框架去重构下
    finalwave
        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
    zazalu
        68
    zazalu  
    OP
       2019-08-09 11:57:04 +08:00
    @finalwave 好的 等我恶补下 transfer 的概念... 意思就是说和 Drawer 无关 和 transfer 有关
    finalwave
        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
    rain0002009
        70
    rain0002009  
       2019-08-09 11:57:33 +08:00
    其实我很好奇 drawer 到底干了啥 才会有这种效果
    Sendya
        71
    Sendya  
       2019-08-09 12:00:53 +08:00
    @finalwave iview 的 drawer 居然不是起一个新 Vue 实例。。难怪会这样
    SilentDepth
        72
    SilentDepth  
       2019-08-09 12:06:59 +08:00
    @liximomo #47 Mac + Chrome 复现问题了。尝试移除里面用到的 iView Drawer 组件就可以解决问题,初步怀疑是 iView 做了什么。
    Sendya
        73
    Sendya  
       2019-08-09 12:07:02 +08:00 via Android
    不知道对不对
    SilentDepth
        74
    SilentDepth  
       2019-08-09 12:09:11 +08:00
    @lxmfly123 #63 @Sendya #64
    Not personal,但我也是建议别用 iView,bug 目前看起来还是有点多。
    finalwave
        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 挂掉了
    SilentDepth
        76
    SilentDepth  
       2019-08-09 12:42:19 +08:00   ❤️ 2
    问题出在 iView 的 v-transfer-dom 上,源码第 27 行通过 Node.replaceChild( ) 将原本是组件根元素的元素替换为一个注释节点(实际上替换成任意节点都可以复现问题)。v-for 的逻辑其实正常执行了,新的元素也生成了(可以通过 $refs 访问),但没有正确 attach 到 DOM 树中。怀疑这个过程紧挨着 v-for 后面发生会影响 VDOM Diff ?不确定这算不算 Vue 的 bug,等 dalao 进一步解析。
    /cc @liximomo @sodatea
    watzds
        77
    watzds  
       2019-08-09 12:53:45 +08:00 via Android
    iView 感觉挺难用的,虽然我只用过一星期不熟
    不优雅
    SilentDepth
        78
    SilentDepth  
       2019-08-09 12:54:42 +08:00
    楼主如果想保留组件模板的相对结构,可以把 v-for 部分或者 Drawer 部分包裹一个元素,或者在二者之间放一个 v-if="false" 的元素,总之就是不要让不稳定的 DOM 节点紧跟在 v-for 后面,这样就能让 v-for 效果正常。
    shintendo
        79
    shintendo  
       2019-08-09 13:11:51 +08:00
    按理说 directive 里头操作 dom 没有问题,感觉如楼上所说是 diff 的问题,不确定这算是 vue 还是 iview 的锅。
    话说 iview 作者不是在 v 站吗,可以召唤来看看 @Aresn
    crs0910
        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/)
    azh7138m
        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 替换掉了
    SilentDepth
        82
    SilentDepth  
       2019-08-09 13:22:15 +08:00
    @shintendo #79
    Directive 提供了直接访问 DOM 的能力,但在「数据驱动视图」的思路下,直接修改 DOM 的做法应该是不被建议的(否则为了保证渲染结果符合预期就得全面比对 DOM 树,性能不行)。这次这个锅不能算 iView 的,应该是恰好碰到了 Vue 视图机制的雷区。
    SilentDepth
        83
    SilentDepth  
       2019-08-09 13:29:09 +08:00   ❤️ 1
    @azh7138m #81
    那好歹打个 warning 啊,DOM update 失败应该是挺值得关注的情况啊(
    zazalu
        84
    zazalu  
    OP
       2019-08-09 14:00:18 +08:00 via Android
    先做下感谢,@SilentDepth @finalwave 无私付出时间来帮我解决问题。

    你们说的有些我还不太懂,没法第一时间参与讨论(哭) 我在慢慢看文档,源码和 google,把你们说的消化下。 我 java 出生,对 js 特别是 es,dom 这些还不太熟。vue 也只看了教程篇只会使用。

    我后续会给一些总结(也观望下一些 iview vue 作者大佬的回答)

    感谢感谢
    azh7138m
        85
    azh7138m  
       2019-08-09 14:04:04 +08:00
    @SilentDepth 失败是对我们来说的( UI 无反馈),updator 仍然可以执行成功(不报错)
    crs0910
        86
    crs0910  
       2019-08-09 14:05:06 +08:00   ❤️ 1
    @zazalu #84 你可以用我这个最小化的 demo 做演示 https://codesandbox.io/s/wwu3n
    galikeoy
        87
    galikeoy  
       2019-08-09 14:18:13 +08:00
    我现在也在改 bug。。。这个问题我昨天改到现在了,没有丝毫头绪,,,,改得不爽就刷刷帖子吧。。。
    leemove
        88
    leemove  
       2019-08-09 14:22:49 +08:00
    其实很简单啦 你看看那个在线的例子,因为 vue 是用的 vdom,不是重新渲染所有 dom,而是在现有 dom 上做修改,因为你手动删除了页面上的元素,导致 vue 在增量渲染的时候报错了,我估计很有可能是调用了你删除元素上的方法,很有可能是 insertBefore
    leemove
        89
    leemove  
       2019-08-09 14:25:01 +08:00
    @leemove 已经复现了, 详情可以看下面的链接 console 里面会报错
    SilentDepth
        90
    SilentDepth  
       2019-08-09 14:32:54 +08:00
    @zazalu #84
    如果没有前端知识基础,我建议不要挖掘框架源码,容易事倍功半还打击积极性。

    我尝试简单地解释一下情况:

    一个页面可以看做是由节点组成的树,更新页面内容就是在对一个或多个节点做属性更新。Vue 这类框架提供的功能是,你提供内容数据的定义(状态)和节点结构的描述(模板),它来自动更新节点属性。这个功能能够正常发挥作用的前提是,你不要替它更新节点属性,否则当它需要「在第 3 和第 4 个节点之间插入一个新节点」时,发现预期的第 4 个节点不存在了,它就迷茫了。你遇到的问题就是,组件模板的一部分在 Vue 掌控之外发生了变化,因此导致 Vue 产生了错误的视图更新结果。
    leemove
        91
    leemove  
       2019-08-09 14:35:38 +08:00
    @SilentDepth diff 是在 vnode 上展开的并不会根据当前 dom.是因为 diff 之后渲染过程中的错误啦.
    zazalu
        92
    zazalu  
    OP
       2019-08-09 14:36:48 +08:00
    @SilentDepth 恩,你说的话我已经理解了,我也结合了 @leemove 的回答, 意思就是说 vue 帮我去渲染第三条通知的时候,vue 是想直接用 insertBefore 这类方法(意思是在第四个节点前插入?),结果发现第四个节点不存在了, 因为第四个节点被第三方(比如 iview)非法的删除且没有通知 vue, 所以 vue 的 v-for 代码出问题了. 没错吧
    zazalu
        93
    zazalu  
    OP
       2019-08-09 14:38:31 +08:00
    至少可以在我的项目代码里写个简单的注释了 不然平白无故的多个包括层, 看上去扎眼. 谢谢大家
    leemove
        94
    leemove  
       2019-08-09 14:38:46 +08:00
    其实 iview 这套组件库,还是有一些问题的,包括一些设计思想比较喜欢用 render 来代替模板和复杂渲染,我都不是很喜欢.
    但是因为这个问题也算是揭开了前端 er 的伤疤吧,很简单的一个问题,被大家弄的越来越复杂...还有让看文档的,还有说别用 Iview 的还有完全就是乱回复方案的...
    我觉得大家在回答一个技术问题之前,最好做一些简单的调研,抱着解决问题的态度来回复.而不是浪费你自己,浪费提出问题,浪费遇到同样问题正在看回复的人的时间.
    zazalu
        96
    zazalu  
    OP
       2019-08-09 14:40:13 +08:00
    @leemove 恩 我看到你说的 insertBefore, 我的脑子好像就懂了. insertBefore next dom but next dom is disappear 没错吧
    zazalu
        97
    zazalu  
    OP
       2019-08-09 14:42:31 +08:00
    @leemove 我看不到报错啊. console(0) problems(0) 点了 button 也一样
    zazalu
        98
    zazalu  
    OP
       2019-08-09 14:43:40 +08:00
    @leemove catch 里没有进去
    SilentDepth
        99
    SilentDepth  
       2019-08-09 14:44:52 +08:00
    @leemove #88 不认为是 insertBefore,因为元素本身并没有被从 DOM 树中移除,如果 insertBefore 了应当还可以渲染出来(只是不在正确的位置)
    crs0910
        100
    crs0910  
       2019-08-09 14:46:06 +08:00
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4484 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 38ms · UTC 10:01 · PVG 18:01 · LAX 03:01 · JFK 06:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.