transition.js 4.2 KB

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