transition.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import { isObj } 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. const nextTick = () => new Promise((resolve) => setTimeout(resolve, 33.333333333333336));
  9. export const transition = function (showDefaultValue) {
  10. return {
  11. data() {
  12. return {
  13. type: '',
  14. inited: false,
  15. display: false
  16. };
  17. },
  18. props: {
  19. customStyle: String,
  20. // @ts-ignore
  21. show: {
  22. type: Boolean,
  23. value: showDefaultValue,
  24. observer: 'observeShow'
  25. },
  26. // @ts-ignore
  27. duration: {
  28. type: null,
  29. value: 300,
  30. observer: 'observeDuration'
  31. },
  32. name: {
  33. type: String,
  34. value: 'fade'
  35. }
  36. },
  37. beforeMount() {
  38. if (this.show) {
  39. this.enter();
  40. }
  41. },
  42. methods: {
  43. observeShow(value) {
  44. if (value) {
  45. this.enter();
  46. } else {
  47. this.leave();
  48. }
  49. },
  50. enter() {
  51. const { duration, name } = this;
  52. const classNames = getClassNames(name);
  53. const currentDuration = isObj(duration) ? duration.enter : duration;
  54. this.status = 'enter';
  55. this.$emit('before-enter');
  56. Promise.resolve()
  57. .then(nextTick)
  58. .then(() => {
  59. this.checkStatus('enter');
  60. this.$emit('enter');
  61. this.setData({
  62. inited: true,
  63. display: true,
  64. classes: classNames.enter,
  65. currentDuration
  66. });
  67. })
  68. .then(nextTick)
  69. .then(() => {
  70. this.checkStatus('enter');
  71. this.transitionEnded = false;
  72. this.setData({
  73. classes: classNames['enter-to']
  74. });
  75. })
  76. .catch(() => {});
  77. },
  78. leave() {
  79. if (!this.display) {
  80. return;
  81. }
  82. const { duration, name } = this;
  83. const classNames = getClassNames(name);
  84. const currentDuration = isObj(duration) ? duration.leave : duration;
  85. this.status = 'leave';
  86. this.$emit('before-leave');
  87. Promise.resolve()
  88. .then(nextTick)
  89. .then(() => {
  90. this.checkStatus('leave');
  91. this.$emit('leave');
  92. this.setData({
  93. classes: classNames.leave,
  94. currentDuration
  95. });
  96. })
  97. .then(nextTick)
  98. .then(() => {
  99. this.checkStatus('leave');
  100. this.transitionEnded = false;
  101. setTimeout(() => this.onTransitionEnd(), currentDuration);
  102. this.setData({
  103. classes: classNames['leave-to']
  104. });
  105. })
  106. .catch(() => {});
  107. },
  108. checkStatus(status) {
  109. if (status !== this.status) {
  110. throw new Error(`incongruent status: ${status}`);
  111. }
  112. },
  113. onTransitionEnd() {
  114. if (this.transitionEnded) {
  115. return;
  116. }
  117. this.transitionEnded = true;
  118. this.$emit(`after-${this.status}`);
  119. const { show, display } = this;
  120. if (!show && display) {
  121. this.setData({
  122. display: false
  123. });
  124. }
  125. }
  126. }
  127. };
  128. };