zazalu
V2EX  ›  Vue.js

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

  •  
  •   zazalu · Aug 8, 2019 · 11633 views
    This topic created in 2643 days ago, the information mentioned may be changed or developed.
    我遇到的问题是这样的,我描述下:

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

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

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

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

    希望有大佬可以帮忙! vue 内部到底发生了什么!
    Supplement 2  ·  Aug 9, 2019
    环境:

    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"
    Supplement 3  ·  Aug 9, 2019
    我看很多人说无法复现. 所以我上传了 gif 图来表现我自己的情况.
    Supplement 4  ·  Aug 9, 2019
    感谢 @crs0910 提供的在线演示 demo

    https://codesandbox.io/s/wwu3n

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

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

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

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

    上面这段实际上就是程序员的日常,没有人生来就能解决所有问题,但不应该拒绝学习。
    asdjgfr
    asdjgfr
    Aug 9, 2019
    19
    codepen 上代码啊,大部分人为自己没问题的时候其实都是有问题的,特别 js 这种灵活的语言
    1KN6sAqR0a57no6s
    1KN6sAqR0a57no6s
    Aug 9, 2019 via Android❤️2
    20
    前端领域是热闹又孤独的。当你对 1+1 有疑惑的时候,所有人都能说上两句; 当你被 0.1 + 0.2 困住的时候,只能靠你自己。答非所问是搜索引擎的常态,也是人的常态。
    zazalu
    zazalu
    OP
    Aug 9, 2019 via Android
    21
    @libook 谢谢。 我发帖确实感觉在抱怨。 标题其实也提了希望有人开导下,而不是帮我解决问题。 我在发帖后感觉看到大家的回复,觉得受到了一些鼓舞,所以就继续排查问题了。最终虽然不太完美的解决了。不过感觉我的心境好像发生了某种质的变化,这也是一种提升,所以我感觉我昨天的青春并没有浪费而不再感到难受了。谢谢大家
    lscho
    lscho
    Aug 9, 2019
    22
    具体源码我也没看,但是组件内内容必须放到根元素里是官网提到的。。。https://cn.vuejs.org/v2/guide/components.html#%E5%8D%95%E4%B8%AA%E6%A0%B9%E5%85%83%E7%B4%A0

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

    ```
    onClick() {
    this.fatherItems = [...this.fatherItems, {
    id: 3,
    content: "第三条通知"
    }]
    }
    ```
    Sendya
    Sendya
    Aug 9, 2019
    57
    是用了 `Drawer` 之后才不能更新的吗?
    getElementBy1d
    getElementBy1d
    Aug 9, 2019
    58
    建议好好读一下官方文档 有很多问题官方文档已经写了
    lxmfly123
    lxmfly123
    Aug 9, 2019
    59
    Mac Chrome 可复现。
    这个极有可能是 iView 的锅。那个 NewMessage 组件里,只有一个 iView 的 Drawer 组件,我把这个 NewMessage 换成不含 Drawer 的组件,就一切正常了。
    具体怎么回事,估计要看 iView 的源码了。
    zazalu
    zazalu
    OP
    Aug 9, 2019
    60
    @Sendya js 真的很灵活啊.我没想到可以这么写
    Hoshinokozo
    Hoshinokozo
    Aug 9, 2019
    61
    vue 的 v-for 确实坑很多,但是大部分都是跟 key 或者数组的更新检测有关,vue 不能检测到操作数组下标对数组赋值的改动,需要用$set,而且如果渲染的是不同类型的节点的话,需要加 key
    finalwave
    finalwave
    Aug 9, 2019
    62
    我在 linux 上复现了,chrome 版本 73.0.3683.86 (正式版本)
    给 Drawer 的 transfer 属性赋值 false,也可以正常刷新数据,这个抽屉挺神奇的
    lxmfly123
    lxmfly123
    Aug 9, 2019
    63
    最后建议题主,尽量别用 iView。我也是一开始使用 iView,发现有很多地方有小问题,最后换了 element。顺便推荐一下 quasar,非常强大。
    Sendya
    Sendya
    Aug 9, 2019
    64
    @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
    zazalu
    OP
    Aug 9, 2019
    65
    @Sendya 是 我把 Drawer 去掉就好了. Drawer 源码在 node_modules/iview/src/components/drawer/drawer.vue
    zazalu
    zazalu
    OP
    Aug 9, 2019
    66
    @Sendya 等我搞定这些东西后,试试用你说的框架去重构下
    finalwave
    finalwave
    Aug 9, 2019
    67
    就是这个 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
    zazalu
    OP
    Aug 9, 2019
    68
    @finalwave 好的 等我恶补下 transfer 的概念... 意思就是说和 Drawer 无关 和 transfer 有关
    finalwave
    finalwave
    Aug 9, 2019
    69
    测试了一下用 div 包裹 p v-for 可以刷新,p v-for 换成 div v-for 也不能刷新
    在 v-for 元素和 transfer 元素间插入 div、p、br 也能刷新
    看来是 v-for 的元素紧贴着 transfer 元素的 bug
    rain0002009
    rain0002009
    Aug 9, 2019
    70
    其实我很好奇 drawer 到底干了啥 才会有这种效果
    Sendya
    Sendya
    Aug 9, 2019
    71
    @finalwave iview 的 drawer 居然不是起一个新 Vue 实例。。难怪会这样
    SilentDepth
    SilentDepth
    Aug 9, 2019
    72
    @liximomo #47 Mac + Chrome 复现问题了。尝试移除里面用到的 iView Drawer 组件就可以解决问题,初步怀疑是 iView 做了什么。
    Sendya
    Sendya
    Aug 9, 2019 via Android
    73
    不知道对不对
    SilentDepth
    SilentDepth
    Aug 9, 2019
    74
    @lxmfly123 #63 @Sendya #64
    Not personal,但我也是建议别用 iView,bug 目前看起来还是有点多。
    finalwave
    finalwave
    Aug 9, 2019❤️1
    75
    测试了一下在 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
    SilentDepth
    Aug 9, 2019❤️2
    76
    问题出在 iView 的 v-transfer-dom 上,源码第 27 行通过 Node.replaceChild( ) 将原本是组件根元素的元素替换为一个注释节点(实际上替换成任意节点都可以复现问题)。v-for 的逻辑其实正常执行了,新的元素也生成了(可以通过 $refs 访问),但没有正确 attach 到 DOM 树中。怀疑这个过程紧挨着 v-for 后面发生会影响 VDOM Diff ?不确定这算不算 Vue 的 bug,等 dalao 进一步解析。
    /cc @liximomo @sodatea
    watzds
    watzds
    Aug 9, 2019 via Android
    77
    iView 感觉挺难用的,虽然我只用过一星期不熟
    不优雅
    SilentDepth
    SilentDepth
    Aug 9, 2019
    78
    楼主如果想保留组件模板的相对结构,可以把 v-for 部分或者 Drawer 部分包裹一个元素,或者在二者之间放一个 v-if="false" 的元素,总之就是不要让不稳定的 DOM 节点紧跟在 v-for 后面,这样就能让 v-for 效果正常。
    shintendo
    shintendo
    Aug 9, 2019
    79
    按理说 directive 里头操作 dom 没有问题,感觉如楼上所说是 diff 的问题,不确定这算是 vue 还是 iview 的锅。
    话说 iview 作者不是在 v 站吗,可以召唤来看看 @Aresn
    catoncat
    catoncat
    Aug 9, 2019
    80
    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
    azh7138m
    Aug 9, 2019
    81
    @Sendya 我觉得是,去掉之后就好了
    https://codesandbox.io/s/array-replace-problem-in-vue-v-for-0odfy

    @SilentDepth 我觉得是 updator 更新不到那个元素了,因为被 iView 替换掉了
    SilentDepth
    SilentDepth
    Aug 9, 2019
    82
    @shintendo #79
    Directive 提供了直接访问 DOM 的能力,但在「数据驱动视图」的思路下,直接修改 DOM 的做法应该是不被建议的(否则为了保证渲染结果符合预期就得全面比对 DOM 树,性能不行)。这次这个锅不能算 iView 的,应该是恰好碰到了 Vue 视图机制的雷区。
    SilentDepth
    SilentDepth
    Aug 9, 2019❤️1
    83
    @azh7138m #81
    那好歹打个 warning 啊,DOM update 失败应该是挺值得关注的情况啊(
    zazalu
    zazalu
    OP
    Aug 9, 2019 via Android
    84
    先做下感谢,@SilentDepth @finalwave 无私付出时间来帮我解决问题。

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

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

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

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

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