captain-ui
Version:
有赞vue wap业务组件库
197 lines (170 loc) • 6.27 kB
JavaScript
var _components;
import Utils from '../../../common/scroll';
import Nav from './nav';
import { NAV_STATE } from '../constants';
window.requestAnimFrame = function () {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) {
window.setTimeout(callback, 1000 / 60);
};
}();
export default {
render: function render() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
return _c('div', {
staticClass: "cap-category"
}, [_c('cap-category-nav', {
ref: "nav",
attrs: {
"nav-list": _vm.navList,
"window-height": _vm.windowHeight,
"state": _vm.navState,
"active": _vm.currentActive
},
on: {
"click": _vm.handleNavClick
}
}), _c('div', {
staticClass: "cap-category-container"
}, [_c('h1', {
staticClass: "cap-category-container__active-title",
class: {
'cap-category-container__active-title--fixed': _vm.groupTitleFixed
}
}, [_vm._v("\n " + _vm._s(_vm.navList[_vm.currentTitleActive].title) + "\n ")]), _vm._t("default")], 2)], 1);
},
name: 'cap-category-base',
components: (_components = {}, _components[Nav.name] = Nav, _components),
props: {
navList: {
type: Array,
default: function _default() {
return [];
}
}
},
data: function data() {
return {
navState: NAV_STATE.NORMAL,
windowHeight: window.innerHeight,
currentActive: 0,
currentTitleActive: 0,
shouldCheckNav: true
};
},
computed: {
groupTitleFixed: function groupTitleFixed() {
// 当前主分类的名称是否吸顶
return this.navState !== NAV_STATE.NORMAL;
}
},
mounted: function mounted() {
this.scrollEl = Utils.getScrollEventTarget(this.$el); // 滚动元素
this.navScrollEl = Utils.getScrollEventTarget(this.$refs.nav.$el); // 左侧导航栏滚动元素
this.scrollEl.addEventListener('scroll', this.handleScroll);
this.init();
},
destroyed: function destroyed() {
this.scrollEl.removeEventListener('scroll', this.handleScroll);
},
methods: {
init: function init() {
var _this = this;
this.$nextTick(function () {
_this.getDOMHeight();
_this.handleScroll();
});
},
getDOMHeight: function getDOMHeight() {
this.groups = [].slice.call(this.$slots.default[0].elm.childNodes);
this.elHeight = Utils.getVisibleHeight(this.$el);
this.navHeight = Utils.getVisibleHeight(this.$refs.nav.$el);
this.groupHeightList = this.groups.map(function (group) {
return Utils.getVisibleHeight(group);
}); // 各分组的高度
},
// 处理滚动
handleScroll: function handleScroll() {
var elHeight = this.elHeight,
navHeight = this.navHeight;
var elToTop = Utils.getElementTop(this.$el); // 文档顶部到元素的距离
var scrollTop = Utils.getScrollTop(this.scrollEl); // 滚动距离
var navState = NAV_STATE.NORMAL;
if (navHeight + scrollTop - elToTop - elHeight > 0) {
// 如果(左侧导航栏高度 + 滚动高度) > (右侧到文档顶部距离 + 右侧内容高度),则滚出屏幕
navState = NAV_STATE.SCROLL_OUT;
} else if (scrollTop - elToTop > 0) {
// 如果滚动高度 > 元素到文档顶部距离,则吸顶
navState = NAV_STATE.FIXED;
}
this.navState = navState;
var oldActive = this.currentActive;
if (this.shouldCheckNav) {
// 如果是滚动导致的 active 改变,则更新左侧导航栏的 active
this.updateActive(scrollTop - elToTop);
}
if (this.navState === NAV_STATE.FIXED && oldActive !== this.currentActive) {
// 如果导航栏已经吸顶,并且 active 已改变,则调整导航栏的位置
this.setActiveNavVisible(this.currentActive);
}
},
// 更新导航栏 active 项
updateActive: function updateActive(scrollTop) {
var _this2 = this;
var totalHeight = 0;
this.groupHeightList.some(function (groupHeight, index) {
totalHeight += groupHeight;
if (totalHeight > scrollTop) {
_this2.currentActive = index;
_this2.currentTitleActive = index;
return true;
}
});
},
// 使导航栏的 active 分类保持在屏幕中部位置
setActiveNavVisible: function setActiveNavVisible(activeIndex) {
var activeNav = this.$refs.nav.$refs.badges[activeIndex].$el;
var _activeNav$getBoundin = activeNav.getBoundingClientRect(),
top = _activeNav$getBoundin.top,
bottom = _activeNav$getBoundin.bottom;
if (top < 0 || bottom > this.windowHeight / 3) {
this.scrollAnim(this.navScrollEl, this.$refs.nav.$el.scrollTop, activeNav.offsetTop - this.windowHeight / 3);
}
},
handleNavClick: function handleNavClick(index) {
var _this3 = this;
var groupToTop = Utils.getElementTop(this.groups[index]);
var scrollTop = Utils.getScrollTop(this.scrollEl);
var navList = this.navList,
windowHeight = this.windowHeight;
var lastIndex = navList.length - 1;
var lastGroup = document.querySelectorAll('.cap-category-container__group')[lastIndex];
var offsetHeight = lastGroup.offsetHeight;
if (index === navList.length - 1 && offsetHeight < windowHeight) {
this.currentTitleActive = index - 1;
} else {
this.currentTitleActive = index;
}
this.currentActive = index;
this.shouldCheckNav = false;
this.scrollAnim(this.scrollEl, scrollTop, groupToTop);
setTimeout(function () {
_this3.shouldCheckNav = true;
}, 300);
},
// 滚动切换动画
scrollAnim: function scrollAnim(element, scrollTop, targetTop) {
var progress = 0; // 进度
var diff = targetTop - scrollTop; // 距离
var anim = function anim() {
progress += 8;
Utils.setScrollTop(element, scrollTop + diff * Math.min(progress / 100, 1));
if (progress < 100) {
window.requestAnimFrame(anim);
}
};
anim();
}
}
};