Ma63d / kov-blog

A blog platform built with koa,vue and mongoose. 使用 koa ,vue 和 mongo 搭建的博客页面和支持markdown语法的博客编写平台,自动保存草稿。博客地址:https://chuckliu.me
MIT License
636 stars 103 forks source link

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

Closed Ma63d closed 7 years ago

Ma63d commented 7 years ago

我在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,也很复杂,感觉增加许多不必要的代码,请问大家有比较好的解决办法吗?

jo0ger commented 7 years ago

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

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

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

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

Ma63d commented 7 years ago

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

Ma63d commented 7 years ago

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

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

Ma63d commented 7 years ago

@BubblyPoker 在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.

Ma63d commented 7 years ago

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

jo0ger commented 7 years ago

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

Ma63d commented 7 years ago

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