transition.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import { isObj, requestAnimationFrame } from '../common/utils';
  2. const getClassNames = (name) => ({
  3. enter: `van-${name}-enter van-${name}-enter-active enter-class enter-active-class`,
  4. 'enter-to': `van-${name}-enter-to van-${name}-enter-active enter-to-class enter-active-class`,
  5. leave: `van-${name}-leave van-${name}-leave-active leave-class leave-active-class`,
  6. 'leave-to': `van-${name}-leave-to van-${name}-leave-active leave-to-class leave-active-class`,
  7. });
  8. export const transition = function (showDefaultValue) {
  9. return Behavior({
  10. properties: {
  11. customStyle: String,
  12. // @ts-ignore
  13. show: {
  14. type: Boolean,
  15. value: showDefaultValue,
  16. observer: 'observeShow',
  17. },
  18. // @ts-ignore
  19. duration: {
  20. type: null,
  21. value: 300,
  22. observer: 'observeDuration',
  23. },
  24. name: {
  25. type: String,
  26. value: 'fade',
  27. },
  28. },
  29. data: {
  30. type: '',
  31. inited: false,
  32. display: false,
  33. },
  34. methods: {
  35. observeShow(value, old) {
  36. if (value === old) {
  37. return;
  38. }
  39. value ? this.enter() : this.leave();
  40. },
  41. enter() {
  42. const { duration, name } = this.data;
  43. const classNames = getClassNames(name);
  44. const currentDuration = isObj(duration) ? duration.enter : duration;
  45. this.status = 'enter';
  46. this.$emit('before-enter');
  47. requestAnimationFrame(() => {
  48. this.checkStatus('enter');
  49. this.$emit('enter');
  50. this.setData({
  51. inited: true,
  52. display: true,
  53. classes: classNames.enter,
  54. currentDuration,
  55. });
  56. requestAnimationFrame(() => {
  57. this.checkStatus('enter');
  58. this.transitionEnded = false;
  59. this.setData({ classes: classNames['enter-to'] });
  60. });
  61. });
  62. },
  63. leave() {
  64. if (!this.data.display) {
  65. return;
  66. }
  67. const { duration, name } = this.data;
  68. const classNames = getClassNames(name);
  69. const currentDuration = isObj(duration) ? duration.leave : duration;
  70. this.status = 'leave';
  71. this.$emit('before-leave');
  72. requestAnimationFrame(() => {
  73. this.checkStatus('leave');
  74. this.$emit('leave');
  75. this.setData({
  76. classes: classNames.leave,
  77. currentDuration,
  78. });
  79. requestAnimationFrame(() => {
  80. this.checkStatus('leave');
  81. this.transitionEnded = false;
  82. setTimeout(() => this.onTransitionEnd(), currentDuration);
  83. this.setData({ classes: classNames['leave-to'] });
  84. });
  85. });
  86. },
  87. checkStatus(status) {
  88. if (status !== this.status) {
  89. throw new Error(`incongruent status: ${status}`);
  90. }
  91. },
  92. onTransitionEnd() {
  93. if (this.transitionEnded) {
  94. return;
  95. }
  96. this.transitionEnded = true;
  97. this.$emit(`after-${this.status}`);
  98. const { show, display } = this.data;
  99. if (!show && display) {
  100. this.setData({ display: false });
  101. }
  102. },
  103. },
  104. });
  105. };