weixin_39627408
weixin_39627408
2020-12-28 00:59

请教各位vue大神们,如何在router-view上监听transition的结束(vue1.x版本)

我在router-view上加了transition,因此当路由切换时,组件在enter和leave时会有一个过渡动画存在,我现在某一个路由对应的组件里面我需要知道当前的transition是否结束了,所以问题来了,我如何让我的这个组件知道我的transition结束了,因为我有一些组件需要在组件的元素加载到dom里面之后才能正确执行(比如目录组件,我需要知道页面有哪些h1,h2,h3,然后生成目录,再比如多说)。

假如说我这个需要知道transition结束的组件对应的路由是/foo/:id

当路由切换的时候,比如是从/bar进入/foo/:id时,倒是比较好监听,利用transition的afterEnter钩子,我可以监听到router-view上的动画结束,于是我可以在包裹router-view的父组件上绑定这个afterEnter钩子,在这个钩子里$dispatch一个事件,去告诉/foo/:id对应的组件“transition结束啦,该干嘛干嘛去”。

可是现在有个问题是,当浏览器打开的就是这个组件的路由地址/foo时,也就是浏览器打开进入的就是这个路由时,没有路由切换过程,这个时候并不会有transition,自然不会有transition的钩子执行,所以我想着要不就先在包裹router-view的父组件上的ready事件里$dispatch一次,可是发现父组件$dispatch时,/foo对应的组件还没有加载好,因此他没能成功监听到父组件的$dispatch。

而且如果是/foo/:id这种路由里面只是id变化时,因为是同一个组件,也是没有transition的,所以问题变得很复杂。

目前我增加了许多逻辑用来判断是否是直接进入的/foo/:id的和以及从其他不同id的/foo/:id转过来的 ,这种写法感觉很hack,也很复杂,感觉增加许多不必要的代码,请问大家有比较好的解决办法吗?

该提问来源于开源项目:Ma63d/kov-blog

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

7条回答

  • weixin_39627408 weixin_39627408 3月前

    是啊,绕了很多弯路啊一个:key 一个appear,完美搞定

    点赞 评论 复制链接分享
  • weixin_39632291 weixin_39632291 3月前

    这样一看,2.x比1.x省事儿多了,至少这些问题在2.x都很轻易解决

    点赞 评论 复制链接分享
  • weixin_39627408 weixin_39627408 3月前

    看来得早点抽时间把这个博客升级到Vue2.x了。

    点赞 评论 复制链接分享
  • weixin_39627408 weixin_39627408 3月前

    在Vue2.x可以通过appear增加组件在初始出现时的过渡:http://cn.vuejs.org/v2/guide/transitions.html#初始渲染的过渡

    google了一下发现很多人也有类似需求,可惜的是尤大只决定在vue2.x增加这个属性,在Vue1.x时只能通过先把v-show设置为false,然后在nextTick里恢复为true来hack实现组件的初始加载时的过渡进入。

    This is implemented in 2.0 as the appear prop. Although we'd like to backport it to 1.x, this is a non-critical change that requires non-trivial effort. Given the bandwidth we have, we are reducing the scope of 1.1 to a number of critical features and low hanging fruits, so unfortunately this will not be implemented for 1.x.

    点赞 评论 复制链接分享
  • weixin_39627408 weixin_39627408 3月前

    哥们 我思考了一下,第一种方法,在vue1.x上,因为没有:key,要想强制在相同路由只是params不同时也依然transition的话可以用canReuse钩子代替,canReuse返回false可以保证组件始终执行完整的退出和激活阶段,所以可以保证transition。

    但是后面提到的解决方法中的监听'transitionend'就不行了, 因为这个问题的本质在于直接网页打开时,直接就没有过渡动画,而是直接进入的组件(过渡动画只在组件过渡的时候才有),所以不管是你的这种在dom上监听'transitionend'事件,还是用vue的自带的'transitionend'钩子,都是不起效果的。而且这种在dom上监听事件的效果本质上和用vue的钩子没有区别,因为vue的'transitionend'钩子也是在dom已经加载到页面中,而且在经历了完整的transition过程之后再触发的,此时一方面不存在子组件没有加载好不能监听$dispatch的问题,另一方面dom变动已经完毕,$nextTick没有作用。

    点赞 评论 复制链接分享
  • weixin_39627408 weixin_39627408 3月前

    不好意思现在才看到, 非常好的思路~ 非常感谢。 关于第一个问题,竟然能在dom元素上直接捕捉transitionend事件,真是出乎我的意料,涨姿势了~ 我试试然后再回来反馈。

    点赞 评论 复制链接分享
  • weixin_39632291 weixin_39632291 3月前

    我没怎么试过1.x版本的,只知道2版本里给每个router-view加个唯一的key:key='一个唯一值'可以解决只是文章ID不同导致不能过渡的问题

    至于第一个问题,我的想法是在父组件的created钩子中

     js
    this.$nextTick(() => {
            document.querySelector('body').addEventListener('transitionend', (e) => {
              if (e.target === document.querySelector('router-view的selector')) {
                // TODO dispatch
              }
            })
          })
    

    本质上都是transition嘛,应该是可以监听的(transitionend需要考虑兼容性) 以上我都在VUE2.x中测试过

    点赞 评论 复制链接分享