lwj-scroll-nav
Version:
218 lines (207 loc) • 8.4 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.LUtils = factory());
})(this, (function () { 'use strict';
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _typeof(obj) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
}, _typeof(obj);
}
function _toPrimitive(input, hint) {
if (_typeof(input) !== "object" || input === null) return input;
var prim = input[Symbol.toPrimitive];
if (prim !== undefined) {
var res = prim.call(input, hint || "default");
if (_typeof(res) !== "object") return res;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return (hint === "string" ? String : Number)(input);
}
function _toPropertyKey(arg) {
var key = _toPrimitive(arg, "string");
return _typeof(key) === "symbol" ? key : String(key);
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
Object.defineProperty(Constructor, "prototype", {
writable: false
});
return Constructor;
}
function _defineProperty(obj, key, value) {
key = _toPropertyKey(key);
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
var ScrollNav = /*#__PURE__*/function () {
function ScrollNav() {
var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, ScrollNav);
_defineProperty(this, "scrollContainer", null);
_defineProperty(this, "scrollItemList", []);
_defineProperty(this, "navItemList", []);
_defineProperty(this, "activeNavItemClass", '');
_defineProperty(this, "indexKey", '');
_defineProperty(this, "offset", 0);
_defineProperty(this, "scrollTop", 0);
_defineProperty(this, "option", null);
this.option = {
scrollContainer: obj.scrollContainer || '.scroll-container',
scrollItem: obj.scrollItem || '.scroll-container .scroll-item',
navItem: obj.navItem || '.nav .nav-item',
activeNavItemClass: obj.activeNavItemClass || 'active',
indexKey: obj.indexKey || 'value-key',
offset: obj.offset || 10
};
// 滚动容器(overflow: auto)
this.scrollContainer = document.querySelector(this.option.scrollContainer);
// 滚动项
this.scrollItemList = Array.from(document.querySelectorAll(this.option.scrollItem));
// 导航项
this.navItemList = Array.from(document.querySelectorAll(this.option.navItem));
// 导航被激活的class
this.activeNavItemClass = this.option.activeNavItemClass;
// 导航索引
this.indexKey = this.option.indexKey;
// 偏移距离
this.offset = this.option.offset;
// 滚动距离
this.scrollTop = 0;
this.addEventListener();
this.handleScroll(); // 根据当前滚动距离激活默认菜单
}
// 添加事件监听
_createClass(ScrollNav, [{
key: "addEventListener",
value: function addEventListener() {
var _this = this;
if (this.scrollContainer) this.scrollContainer.addEventListener('scroll', this.handleScroll.bind(this));
// 导航栏点击事件
if (this.navItemList && this.navItemList.length) {
this.navItemList.forEach(function (item, index) {
item.onclick = function () {
_this.handleNavClick(item, index);
};
});
}
}
// 移除事件监听
}, {
key: "removeEventListener",
value: function removeEventListener() {
if (this.scrollContainer) this.scrollContainer.removeEventListener('scroll', this.handleScroll.bind(this));
}
// 滚动事件
}, {
key: "handleScroll",
value: function handleScroll() {
var _this2 = this;
var offset = this.scrollContainer.offsetTop;
this.scrollItemList.forEach(function (scrollItem, index) {
var offsetTop = _this2.scrollItemList[index].offsetTop - offset - _this2.scrollContainer.scrollTop;
var navItem = _this2.getNavItemByScrollItem(scrollItem, index);
if (offsetTop < _this2.offset && navItem) {
_this2.navItemList.forEach(function (item) {
item.classList.remove(_this2.activeNavItemClass);
});
navItem.classList.add(_this2.activeNavItemClass);
}
});
this.scrollTop = this.scrollContainer.scrollTop;
}
// nav 点击事件
}, {
key: "handleNavClick",
value: function handleNavClick(item, index) {
var _this3 = this;
var scrollItem = this.getScrollItemByNavItem(item, index);
this.scrollToElement(scrollItem);
setTimeout(function () {
// 若滚动距离不够,已经到底
if (!item.classList.contains(_this3.activeNavItemClass)) {
_this3.navItemList.forEach(function (navItem) {
navItem.classList.remove(_this3.activeNavItemClass);
});
item.classList.add(_this3.activeNavItemClass);
}
}, 50);
}
// 根据navItem查找对应的scrollItem
}, {
key: "getScrollItemByNavItem",
value: function getScrollItemByNavItem(navItem, index) {
var _this4 = this;
// 没有指定元素唯一值,则使用索引确定元素
if (!this.indexKey) return this.scrollItemList[index];
var indexKey = navItem.getAttribute(this.indexKey);
if (!indexKey) return this.scrollItemList[index];
// 指定了元素唯一值,则使用唯一值确定元素
var scrollItem = null;
Array.prototype.forEach.call(this.scrollItemList, function (item) {
if (item.getAttribute(_this4.indexKey) === indexKey) scrollItem = item;
});
return scrollItem;
}
// 根据scrollItem查找对应的navItem
}, {
key: "getNavItemByScrollItem",
value: function getNavItemByScrollItem(scrollItem, index) {
var _this5 = this;
// 没有指定元素唯一值,则使用索引确定元素
if (!this.indexKey) return this.navItemList[index];
var indexKey = scrollItem.getAttribute(this.indexKey);
if (!indexKey) return this.navItemList[index];
// 指定了元素唯一值,则使用唯一值确定元素
var navItem = null;
Array.prototype.forEach.call(this.navItemList, function (item) {
if (item.getAttribute(_this5.indexKey) === indexKey) navItem = item;
});
return navItem;
}
// 获取当前激活的导航
}, {
key: "getActiveNavItem",
value: function getActiveNavItem() {
return document.querySelector("".concat(this.option.navItem, ".").concat(this.option.activeNavItemClass));
}
// 滚动至目标项
}, {
key: "scrollToElement",
value: function scrollToElement(scrollItem) {
if (!scrollItem) return;
this.scrollTop = scrollItem.offsetTop - this.scrollContainer.offsetTop;
this.scrollContainer.scrollTop = this.scrollTop;
}
}]);
return ScrollNav;
}();
return ScrollNav;
}));