index.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import {getRect} from '../common/utils';
  2. import {VantComponent} from '../common/component';
  3. import {isDef} from '../common/validator';
  4. import {pageScrollMixin} from '../mixins/page-scroll';
  5. const ROOT_ELEMENT = '.van-sticky';
  6. VantComponent({
  7. props: {
  8. zIndex: {
  9. type: Number,
  10. value: 99,
  11. },
  12. offsetTop: {
  13. type: Number,
  14. value: 0,
  15. observer: 'onScroll',
  16. },
  17. disabled: {
  18. type: Boolean,
  19. observer: 'onScroll',
  20. },
  21. container: {
  22. type: null,
  23. observer: 'onScroll',
  24. },
  25. scrollTop: {
  26. type: null,
  27. observer(val) {
  28. this.onScroll({scrollTop: val});
  29. },
  30. },
  31. },
  32. mixins: [
  33. pageScrollMixin(function (event) {
  34. if (this.data.scrollTop != null) {
  35. return;
  36. }
  37. this.onScroll(event);
  38. }),
  39. ],
  40. data: {
  41. height: 0,
  42. fixed: false,
  43. transform: 0,
  44. },
  45. mounted() {
  46. this.onScroll();
  47. },
  48. methods: {
  49. onScroll({scrollTop} = {}) {
  50. const {container, offsetTop, disabled} = this.data;
  51. if (disabled) {
  52. this.setDataAfterDiff({
  53. fixed: false,
  54. transform: 0,
  55. });
  56. return;
  57. }
  58. this.scrollTop = scrollTop || this.scrollTop;
  59. if (typeof container === 'function') {
  60. Promise.all([getRect(this, ROOT_ELEMENT), this.getContainerRect()])
  61. .then(([root, container]) => {
  62. if (offsetTop + root.height > container.height + container.top) {
  63. this.setDataAfterDiff({
  64. fixed: false,
  65. transform: container.height - root.height,
  66. });
  67. } else if (offsetTop >= root.top) {
  68. this.setDataAfterDiff({
  69. fixed: true,
  70. height: root.height,
  71. transform: 0,
  72. });
  73. } else {
  74. this.setDataAfterDiff({fixed: false, transform: 0});
  75. }
  76. })
  77. .catch(() => {
  78. });
  79. return;
  80. }
  81. getRect(this, ROOT_ELEMENT).then((root) => {
  82. if (!isDef(root) || (!root.width && !root.height)) {
  83. return;
  84. }
  85. if (offsetTop >= root.top) {
  86. this.setDataAfterDiff({fixed: true, height: root.height});
  87. this.transform = 0;
  88. } else {
  89. this.setDataAfterDiff({fixed: false});
  90. }
  91. });
  92. },
  93. setDataAfterDiff(data) {
  94. wx.nextTick(() => {
  95. const diff = Object.keys(data).reduce((prev, key) => {
  96. if (data[key] !== this.data[key]) {
  97. prev[key] = data[key];
  98. }
  99. return prev;
  100. }, {});
  101. if (Object.keys(diff).length > 0) {
  102. this.setData(diff);
  103. }
  104. this.$emit('scroll', {
  105. scrollTop: this.scrollTop,
  106. isFixed: data.fixed || this.data.fixed,
  107. });
  108. });
  109. },
  110. getContainerRect() {
  111. const nodesRef = this.data.container();
  112. if (!nodesRef) {
  113. return Promise.reject(new Error('not found container'));
  114. }
  115. return new Promise((resolve) => nodesRef.boundingClientRect(resolve).exec());
  116. },
  117. },
  118. });