UNPKG

8.45 kBJavaScriptView Raw
1var __defProp = Object.defineProperty;
2var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3var __getOwnPropNames = Object.getOwnPropertyNames;
4var __hasOwnProp = Object.prototype.hasOwnProperty;
5var __export = (target, all) => {
6 for (var name2 in all)
7 __defProp(target, name2, { get: all[name2], enumerable: true });
8};
9var __copyProps = (to, from, except, desc) => {
10 if (from && typeof from === "object" || typeof from === "function") {
11 for (let key of __getOwnPropNames(from))
12 if (!__hasOwnProp.call(to, key) && key !== except)
13 __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14 }
15 return to;
16};
17var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18var stdin_exports = {};
19__export(stdin_exports, {
20 INDEX_BAR_KEY: () => INDEX_BAR_KEY,
21 default: () => stdin_default,
22 indexBarProps: () => indexBarProps
23});
24module.exports = __toCommonJS(stdin_exports);
25var import_vue = require("vue");
26var import_utils = require("../utils");
27var import_use = require("@vant/use");
28var import_use_touch = require("../composables/use-touch");
29var import_use_expose = require("../composables/use-expose");
30function genAlphabet() {
31 const charCodeOfA = "A".charCodeAt(0);
32 const indexList = Array(26).fill("").map((_, i) => String.fromCharCode(charCodeOfA + i));
33 return indexList;
34}
35const [name, bem] = (0, import_utils.createNamespace)("index-bar");
36const indexBarProps = {
37 sticky: import_utils.truthProp,
38 zIndex: import_utils.numericProp,
39 teleport: [String, Object],
40 highlightColor: String,
41 stickyOffsetTop: (0, import_utils.makeNumberProp)(0),
42 indexList: {
43 type: Array,
44 default: genAlphabet
45 }
46};
47const INDEX_BAR_KEY = Symbol(name);
48var stdin_default = (0, import_vue.defineComponent)({
49 name,
50 props: indexBarProps,
51 emits: ["select", "change"],
52 setup(props, {
53 emit,
54 slots
55 }) {
56 const root = (0, import_vue.ref)();
57 const sidebar = (0, import_vue.ref)();
58 const activeAnchor = (0, import_vue.ref)("");
59 const touch = (0, import_use_touch.useTouch)();
60 const scrollParent = (0, import_use.useScrollParent)(root);
61 const {
62 children,
63 linkChildren
64 } = (0, import_use.useChildren)(INDEX_BAR_KEY);
65 let selectActiveIndex;
66 linkChildren({
67 props
68 });
69 const sidebarStyle = (0, import_vue.computed)(() => {
70 if ((0, import_utils.isDef)(props.zIndex)) {
71 return {
72 zIndex: +props.zIndex + 1
73 };
74 }
75 });
76 const highlightStyle = (0, import_vue.computed)(() => {
77 if (props.highlightColor) {
78 return {
79 color: props.highlightColor
80 };
81 }
82 });
83 const getActiveAnchor = (scrollTop, rects) => {
84 for (let i = children.length - 1; i >= 0; i--) {
85 const prevHeight = i > 0 ? rects[i - 1].height : 0;
86 const reachTop = props.sticky ? prevHeight + props.stickyOffsetTop : 0;
87 if (scrollTop + reachTop >= rects[i].top) {
88 return i;
89 }
90 }
91 return -1;
92 };
93 const getMatchAnchor = (index) => children.find((item) => String(item.index) === index);
94 const onScroll = () => {
95 if ((0, import_utils.isHidden)(root)) {
96 return;
97 }
98 const {
99 sticky,
100 indexList
101 } = props;
102 const scrollTop = (0, import_utils.getScrollTop)(scrollParent.value);
103 const scrollParentRect = (0, import_use.useRect)(scrollParent);
104 const rects = children.map((item) => item.getRect(scrollParent.value, scrollParentRect));
105 let active = -1;
106 if (selectActiveIndex) {
107 const match = getMatchAnchor(selectActiveIndex);
108 if (match) {
109 const rect = match.getRect(scrollParent.value, scrollParentRect);
110 if (props.sticky && props.stickyOffsetTop) {
111 active = getActiveAnchor(rect.top - props.stickyOffsetTop, rects);
112 } else {
113 active = getActiveAnchor(rect.top, rects);
114 }
115 }
116 } else {
117 active = getActiveAnchor(scrollTop, rects);
118 }
119 activeAnchor.value = indexList[active];
120 if (sticky) {
121 children.forEach((item, index) => {
122 const {
123 state,
124 $el
125 } = item;
126 if (index === active || index === active - 1) {
127 const rect = $el.getBoundingClientRect();
128 state.left = rect.left;
129 state.width = rect.width;
130 } else {
131 state.left = null;
132 state.width = null;
133 }
134 if (index === active) {
135 state.active = true;
136 state.top = Math.max(props.stickyOffsetTop, rects[index].top - scrollTop) + scrollParentRect.top;
137 } else if (index === active - 1 && selectActiveIndex === "") {
138 const activeItemTop = rects[active].top - scrollTop;
139 state.active = activeItemTop > 0;
140 state.top = activeItemTop + scrollParentRect.top - rects[index].height;
141 } else {
142 state.active = false;
143 }
144 });
145 }
146 selectActiveIndex = "";
147 };
148 const init = () => {
149 (0, import_vue.nextTick)(onScroll);
150 };
151 (0, import_use.useEventListener)("scroll", onScroll, {
152 target: scrollParent,
153 passive: true
154 });
155 (0, import_vue.onMounted)(init);
156 (0, import_vue.watch)(() => props.indexList, init);
157 (0, import_vue.watch)(activeAnchor, (value) => {
158 if (value) {
159 emit("change", value);
160 }
161 });
162 const renderIndexes = () => props.indexList.map((index) => {
163 const active = index === activeAnchor.value;
164 return (0, import_vue.createVNode)("span", {
165 "class": bem("index", {
166 active
167 }),
168 "style": active ? highlightStyle.value : void 0,
169 "data-index": index
170 }, [index]);
171 });
172 const scrollTo = (index) => {
173 selectActiveIndex = String(index);
174 const match = getMatchAnchor(selectActiveIndex);
175 if (match) {
176 const scrollTop = (0, import_utils.getScrollTop)(scrollParent.value);
177 const scrollParentRect = (0, import_use.useRect)(scrollParent);
178 const {
179 offsetHeight
180 } = document.documentElement;
181 match.$el.scrollIntoView();
182 if (scrollTop === offsetHeight - scrollParentRect.height) {
183 onScroll();
184 return;
185 }
186 if (props.sticky && props.stickyOffsetTop) {
187 if ((0, import_utils.getRootScrollTop)() === offsetHeight - scrollParentRect.height) {
188 (0, import_utils.setRootScrollTop)((0, import_utils.getRootScrollTop)());
189 } else {
190 (0, import_utils.setRootScrollTop)((0, import_utils.getRootScrollTop)() - props.stickyOffsetTop);
191 }
192 }
193 emit("select", match.index);
194 }
195 };
196 const scrollToElement = (element) => {
197 const {
198 index
199 } = element.dataset;
200 if (index) {
201 scrollTo(index);
202 }
203 };
204 const onClickSidebar = (event) => {
205 scrollToElement(event.target);
206 };
207 let touchActiveIndex;
208 const onTouchMove = (event) => {
209 touch.move(event);
210 if (touch.isVertical()) {
211 (0, import_utils.preventDefault)(event);
212 const {
213 clientX,
214 clientY
215 } = event.touches[0];
216 const target = document.elementFromPoint(clientX, clientY);
217 if (target) {
218 const {
219 index
220 } = target.dataset;
221 if (index && touchActiveIndex !== index) {
222 touchActiveIndex = index;
223 scrollToElement(target);
224 }
225 }
226 }
227 };
228 const renderSidebar = () => (0, import_vue.createVNode)("div", {
229 "ref": sidebar,
230 "class": bem("sidebar"),
231 "style": sidebarStyle.value,
232 "onClick": onClickSidebar,
233 "onTouchstartPassive": touch.start
234 }, [renderIndexes()]);
235 (0, import_use_expose.useExpose)({
236 scrollTo
237 });
238 (0, import_use.useEventListener)("touchmove", onTouchMove, {
239 target: sidebar
240 });
241 return () => {
242 var _a;
243 return (0, import_vue.createVNode)("div", {
244 "ref": root,
245 "class": bem()
246 }, [props.teleport ? (0, import_vue.createVNode)(import_vue.Teleport, {
247 "to": props.teleport
248 }, {
249 default: () => [renderSidebar()]
250 }) : renderSidebar(), (_a = slots.default) == null ? void 0 : _a.call(slots)]);
251 };
252 }
253});