| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- <template>
- <view :class="classes">
- <view class="nut-elevator__list" ref="listview" :style="{ height: isNaN(+height) ? height : `${height}px` }">
- <view class="nut-elevator__list__item" v-for="item in indexList" :key="item[acceptKey]" :ref="setListGroup">
- <view class="nut-elevator__list__item__code">{{ item[acceptKey] }}</view>
- <view
- class="nut-elevator__list__item__name"
- :class="{
- 'nut-elevator__list__item__name--highcolor': currentData.id === subitem.id && currentKey === item[acceptKey]
- }"
- v-for="subitem in item.list"
- :key="subitem['id']"
- @click="handleClickItem(item[acceptKey], subitem)"
- v-html="subitem.name"
- ></view>
- </view>
- </view>
- <view class="nut-elevator__code--current" v-show="scrollStart" v-if="indexList.length">{{
- indexList[currentIndex][acceptKey]
- }}</view>
- <view class="nut-elevator__bars" @touchstart="touchStart" @touchmove.stop.prevent="touchMove" @touchend="touchEnd">
- <view class="nut-elevator__bars__inner">
- <view
- class="nut-elevator__bars__inner__item"
- :data-index="index"
- v-for="(item, index) in indexList"
- :key="item[acceptKey]"
- @click="handleClickIndex(item[acceptKey])"
- >{{ item[acceptKey] }}</view
- >
- </view>
- </view>
- </view>
- </template>
- <script lang="ts">
- import { computed, reactive, toRefs, nextTick, ref, Ref, watch } from 'vue';
- import { createComponent } from '@/packages/utils/create';
- import { useExpose } from '@/packages/utils/useExpose/index';
- const { componentName, create } = createComponent('elevator');
- interface ElevatorData {
- name: string;
- id: number | string;
- [key: string]: string | number;
- }
- export default create({
- props: {
- height: {
- type: [Number, String],
- default: '200px'
- },
- acceptKey: {
- type: [String],
- default: 'title'
- },
- indexList: {
- type: Array,
- default: () => {
- return [];
- }
- }
- },
- emits: ['click-item', 'click-index'],
- setup(props: any, context: any) {
- const spaceHeight = 23;
- const listview: Ref<any> = ref(null);
- const state = reactive({
- anchorIndex: 0,
- listHeight: [] as number[],
- listGroup: [] as HTMLLIElement[],
- touchState: {
- y1: 0,
- y2: 0
- },
- scrollStart: false,
- currentIndex: 0,
- currentData: {} as ElevatorData,
- currentKey: ''
- });
- const classes = computed(() => {
- const prefixCls = componentName;
- return {
- [prefixCls]: true
- };
- });
- //重置滚动参数
- const resetScrollState = () => {
- state.anchorIndex = 0;
- state.listHeight = [];
- state.listGroup = [];
- state.currentIndex = 0;
- state.scrollStart = false;
- state.touchState = {
- y1: 0,
- y2: 0
- };
- };
- const getData = (el: HTMLElement, name: string): string | void => {
- const prefix = 'data-';
- return el.getAttribute(prefix + name) as string;
- };
- const setListGroup = (el: HTMLLIElement) => {
- nextTick(() => {
- if (!state.listGroup.includes(el) && el != null) {
- state.listGroup.push(el);
- }
- });
- };
- const calculateHeight = () => {
- let height = 0;
- state.listHeight.push(height);
- for (let i = 0; i < state.listGroup.length; i++) {
- let item = state.listGroup[i];
- height += item.clientHeight;
- state.listHeight.push(height);
- }
- };
- const scrollTo = (index: number) => {
- if (!index && index !== 0) {
- return;
- }
- if (index < 0) index = 0;
- if (index > state.listHeight.length - 2) index = state.listHeight.length - 2;
- state.currentIndex = index;
- listview.value.scrollTo(0, state.listHeight[index]);
- };
- const touchStart = (e: TouchEvent) => {
- state.scrollStart = true;
- let index = getData(e.target as HTMLElement, 'index');
- let firstTouch = e.touches[0];
- state.touchState.y1 = firstTouch.pageY;
- state.anchorIndex = +index;
- state.currentIndex = +index;
- scrollTo(+index);
- };
- const touchMove = (e: TouchEvent) => {
- let firstTouch = e.touches[0];
- state.touchState.y2 = firstTouch.pageY;
- let delta = ((state.touchState.y2 - state.touchState.y1) / spaceHeight) | 0;
- state.currentIndex = state.anchorIndex + delta;
- scrollTo(state.currentIndex);
- };
- const touchEnd = () => {
- resetScrollState();
- };
- const handleClickItem = (key: string, item: ElevatorData) => {
- context.emit('click-item', key, item);
- state.currentData = item;
- state.currentKey = key;
- };
- const handleClickIndex = (key: string) => {
- context.emit('click-index', key);
- };
- useExpose({
- scrollTo
- });
- watch(
- () => state.listGroup.length,
- () => {
- state.listHeight = [];
- nextTick(calculateHeight);
- }
- );
- return {
- classes,
- ...toRefs(state),
- setListGroup,
- listview,
- touchStart,
- touchMove,
- touchEnd,
- handleClickItem,
- handleClickIndex
- };
- }
- });
- </script>
|