123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- import { isHidden } from '../utils/dom/style';
- import { unitToPx } from '../utils/format/unit';
- import { createNamespace, isDef, isServer } from '../utils';
- import { getScrollTop, getElementTop, getScroller } from '../utils/dom/scroll';
- import { BindEventMixin } from '../mixins/bind-event';
- var _createNamespace = createNamespace('sticky'),
- createComponent = _createNamespace[0],
- bem = _createNamespace[1];
- export default createComponent({
- mixins: [BindEventMixin(function (bind, isBind) {
- if (!this.scroller) {
- this.scroller = getScroller(this.$el);
- }
- if (this.observer) {
- var method = isBind ? 'observe' : 'unobserve';
- this.observer[method](this.$el);
- }
- bind(this.scroller, 'scroll', this.onScroll, true);
- this.onScroll();
- })],
- props: {
- zIndex: [Number, String],
- container: null,
- offsetTop: {
- type: [Number, String],
- default: 0
- }
- },
- data: function data() {
- return {
- fixed: false,
- height: 0,
- transform: 0
- };
- },
- computed: {
- offsetTopPx: function offsetTopPx() {
- return unitToPx(this.offsetTop);
- },
- style: function style() {
- if (!this.fixed) {
- return;
- }
- var style = {};
- if (isDef(this.zIndex)) {
- style.zIndex = this.zIndex;
- }
- if (this.offsetTopPx && this.fixed) {
- style.top = this.offsetTopPx + "px";
- }
- if (this.transform) {
- style.transform = "translate3d(0, " + this.transform + "px, 0)";
- }
- return style;
- }
- },
- watch: {
- fixed: function fixed(isFixed) {
- this.$emit('change', isFixed);
- }
- },
- created: function created() {
- var _this = this;
- // compatibility: https://caniuse.com/#feat=intersectionobserver
- if (!isServer && window.IntersectionObserver) {
- this.observer = new IntersectionObserver(function (entries) {
- // trigger scroll when visibility changed
- if (entries[0].intersectionRatio > 0) {
- _this.onScroll();
- }
- }, {
- root: document.body
- });
- }
- },
- methods: {
- onScroll: function onScroll() {
- var _this2 = this;
- if (isHidden(this.$el)) {
- return;
- }
- this.height = this.$el.offsetHeight;
- var container = this.container,
- offsetTopPx = this.offsetTopPx;
- var scrollTop = getScrollTop(window);
- var topToPageTop = getElementTop(this.$el);
- var emitScrollEvent = function emitScrollEvent() {
- _this2.$emit('scroll', {
- scrollTop: scrollTop,
- isFixed: _this2.fixed
- });
- }; // The sticky component should be kept inside the container element
- if (container) {
- var bottomToPageTop = topToPageTop + container.offsetHeight;
- if (scrollTop + offsetTopPx + this.height > bottomToPageTop) {
- var distanceToBottom = this.height + scrollTop - bottomToPageTop;
- if (distanceToBottom < this.height) {
- this.fixed = true;
- this.transform = -(distanceToBottom + offsetTopPx);
- } else {
- this.fixed = false;
- }
- emitScrollEvent();
- return;
- }
- }
- if (scrollTop + offsetTopPx > topToPageTop) {
- this.fixed = true;
- this.transform = 0;
- } else {
- this.fixed = false;
- }
- emitScrollEvent();
- }
- },
- render: function render() {
- var h = arguments[0];
- var fixed = this.fixed;
- var style = {
- height: fixed ? this.height + "px" : null
- };
- return h("div", {
- "style": style
- }, [h("div", {
- "class": bem({
- fixed: fixed
- }),
- "style": this.style
- }, [this.slots()])]);
- }
- });
|