From bd99a5211f3a5fcaa051e5da868d87bb870148f5 Mon Sep 17 00:00:00 2001
From: quanyawei <401863037@qq.com>
Date: Fri, 01 Mar 2024 09:58:45 +0800
Subject: [PATCH] fix:手持设备
---
uni_modules/uview-ui/components/u-index-list/u-index-list.vue | 440 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 440 insertions(+), 0 deletions(-)
diff --git a/uni_modules/uview-ui/components/u-index-list/u-index-list.vue b/uni_modules/uview-ui/components/u-index-list/u-index-list.vue
new file mode 100644
index 0000000..d712618
--- /dev/null
+++ b/uni_modules/uview-ui/components/u-index-list/u-index-list.vue
@@ -0,0 +1,440 @@
+<template>
+ <view class="u-index-list">
+ <!-- #ifdef APP-NVUE -->
+ <list
+ :scrollTop="scrollTop"
+ enable-back-to-top
+ :offset-accuracy="1"
+ :style="{
+ maxHeight: $u.addUnit(scrollViewHeight)
+ }"
+ @scroll="scrollHandler"
+ ref="uList"
+ >
+ <cell
+ v-if="$slots.header"
+ ref="header"
+ >
+ <slot name="header" />
+ </cell>
+ <slot />
+ <cell v-if="$slots.footer">
+ <slot name="footer" />
+ </cell>
+ </list>
+ <!-- #endif -->
+ <!-- #ifndef APP-NVUE -->
+ <scroll-view
+ :scrollTop="scrollTop"
+ :scrollIntoView="scrollIntoView"
+ :offset-accuracy="1"
+ :style="{
+ maxHeight: $u.addUnit(scrollViewHeight)
+ }"
+ scroll-y
+ @scroll="scrollHandler"
+ ref="uList"
+ >
+ <view v-if="$slots.header">
+ <slot name="header" />
+ </view>
+ <slot />
+ <view v-if="$slots.footer">
+ <slot name="footer" />
+ </view>
+ </scroll-view>
+ <!-- #endif -->
+ <view
+ class="u-index-list__letter"
+ ref="u-index-list__letter"
+ :style="{ top: $u.addUnit(letterInfo.top || 100) }"
+ @touchstart="touchStart"
+ @touchmove.stop.prevent="touchMove"
+ @touchend.stop.prevent="touchEnd"
+ @touchcancel.stop.prevent="touchEnd"
+ >
+ <view
+ class="u-index-list__letter__item"
+ v-for="(item, index) in uIndexList"
+ :key="index"
+ :style="{
+ backgroundColor: activeIndex === index ? activeColor : 'transparent'
+ }"
+ >
+ <text
+ class="u-index-list__letter__item__index"
+ :style="{color: activeIndex === index ? '#fff' : inactiveColor}"
+ >{{ item }}</text>
+ </view>
+ </view>
+ <u-transition
+ mode="fade"
+ :show="touching"
+ :customStyle="{
+ position: 'fixed',
+ right: '50px',
+ top: $u.addUnit(indicatorTop),
+ zIndex: 2
+ }"
+ >
+ <view
+ class="u-index-list__indicator"
+ :class="['u-index-list__indicator--show']"
+ :style="{
+ height: $u.addUnit(indicatorHeight),
+ width: $u.addUnit(indicatorHeight)
+ }"
+ >
+ <text class="u-index-list__indicator__text">{{ uIndexList[activeIndex] }}</text>
+ </view>
+ </u-transition>
+ </view>
+</template>
+
+<script>
+ const indexList = () => {
+ const indexList = [];
+ const charCodeOfA = 'A'.charCodeAt(0);
+ for (let i = 0; i < 26; i++) {
+ indexList.push(String.fromCharCode(charCodeOfA + i));
+ }
+ return indexList;
+ }
+ import props from './props.js';
+ // #ifdef APP-NVUE
+ // ������weex������������KPI���������������������������������������������������������������������������dom���������������������
+ const dom = uni.requireNativePlugin('dom')
+ // #endif
+ /**
+ * IndexList ������������
+ * @description ������������������������������������
+ * @tutorial https://uviewui.com/components/indexList.html
+ * @property {String} inactiveColor ������������������������������ ( ������ '#606266' )
+ * @property {String} activeColor ��������������������������� ( ������ '#5677fc' )
+ * @property {Array} indexList ���������������������������������
+ * @property {Boolean} sticky ������������������������������ ( ������ true )
+ * @property {String | Number} customNavHeight ��������������������������� ( ������ 0 )
+ * */
+ export default {
+ name: 'u-index-list',
+ mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
+ // #ifdef MP-WEIXIN
+ // ���������������������������������������������������Vue������������������������������������flex������
+ options: {
+ virtualHost: true
+ },
+ // #endif
+ data() {
+ return {
+ // ������������������������������������
+ activeIndex: -1,
+ touchmoveIndex: 1,
+ // ���������������������
+ letterInfo: {
+ height: 0,
+ itemHeight: 0,
+ top: 0
+ },
+ // ������������������������������������������������������������������������������������������������������������������������������������
+ indicatorHeight: 50,
+ // ������������������������top���������������������������������������������
+ // indicatorTop: 0
+ // ���������������������������������
+ touching: false,
+ // ���������������top���
+ scrollTop: 0,
+ // scroll-view���������
+ scrollViewHeight: 0,
+ // ������������
+ sys: uni.$u.sys(),
+ scrolling: false,
+ scrollIntoView: '',
+ }
+ },
+ computed: {
+ // ������������������������indexList������������������������������������������������A-Z������
+ uIndexList() {
+ return this.indexList.length ? this.indexList : indexList()
+ },
+ // ������������������������top���������������������������������������������
+ indicatorTop() {
+ const {
+ top,
+ itemHeight
+ } = this.letterInfo
+ return Math.floor(top + itemHeight * this.activeIndex + itemHeight / 2 - this.indicatorHeight / 2)
+ }
+ },
+ watch: {
+ // ������������������������������������������������
+ uIndexList: {
+ immediate: true,
+ handler() {
+ uni.$u.sleep().then(() => {
+ this.setIndexListLetterInfo()
+ })
+ }
+ }
+ },
+ created() {
+ this.children = []
+ this.anchors = []
+ this.init()
+ },
+ mounted() {
+ this.setIndexListLetterInfo()
+ },
+ methods: {
+ init() {
+ // ���������������������������������������������
+ //������this.customNavHeight���������this.scrollViewHeight���������maxHeight
+ //���������u-index-list������������tabbar���������,scroll-view������������������������������
+ this.scrollViewHeight = this.sys.windowHeight - this.customNavHeight
+ },
+ // ���������������������
+ touchStart(e) {
+ // ���������������������
+ const touchStart = e.changedTouches[0]
+ if (!touchStart) return
+ this.touching = true
+ const {
+ pageY
+ } = touchStart
+ // ������������������������������������������������������������������������
+ const currentIndex = this.getIndexListLetter(pageY)
+ this.setValueForTouch(currentIndex)
+ },
+ // ������������������������������������
+ touchMove(e) {
+ // ���������������������
+ let touchMove = e.changedTouches[0]
+ if (!touchMove) return;
+
+ // ������������������������������������������������ touching ��� false ��������������� indicator ������
+ if (!this.touching) {
+ this.touching = true
+ }
+ const {
+ pageY
+ } = touchMove
+ const currentIndex = this.getIndexListLetter(pageY)
+ this.setValueForTouch(currentIndex)
+ },
+ // ������������
+ touchEnd(e) {
+ // ���������������������������������������������������������������������������������������������������������������u-transition���show���������������
+ uni.$u.sleep(300).then(() => {
+ this.touching = false
+ })
+ },
+ // ������������������������������������������������������������
+ getIndexListLetterRect() {
+ return new Promise(resolve => {
+ // ������������������������������dom������
+ // #ifndef APP-NVUE
+ this.$uGetRect('.u-index-list__letter').then(size => {
+ resolve(size)
+ })
+ // #endif
+
+ // #ifdef APP-NVUE
+ const ref = this.$refs['u-index-list__letter']
+ dom.getComponentRect(ref, res => {
+ resolve(res.size)
+ })
+ // #endif
+ })
+ },
+ // ������indexList���������������������
+ setIndexListLetterInfo() {
+ this.getIndexListLetterRect().then(size => {
+ const {
+ height
+ } = size
+ const sys = uni.$u.sys()
+ const windowHeight = sys.windowHeight
+ let customNavHeight = 0
+ // ���������������������������������������������������������������������������������������������������
+ if (this.customNavHeight == 0) {
+ // #ifdef H5
+ customNavHeight = sys.windowTop
+ // #endif
+ // #ifndef H5
+ // ������H5���������������������������������������������windowHeight���������������������������������������������������������������������������
+ customNavHeight = -(sys.statusBarHeight + 44)
+ // #endif
+ } else {
+ customNavHeight = uni.$u.getPx(this.customNavHeight)
+ }
+ this.letterInfo = {
+ height,
+ // ������������������������������������������������������������������������������������������������������������������������
+ top: (windowHeight - height) / 2 + customNavHeight / 2,
+ itemHeight: Math.floor(height / this.uIndexList.length)
+ }
+ })
+ },
+ // ������������������������������������
+ getIndexListLetter(pageY) {
+ const {
+ top,
+ height,
+ itemHeight
+ } = this.letterInfo
+ // ���H5���pageY���������������������������uni-app���������������H5���������������������������H5���������������������������������
+ // #ifdef H5
+ pageY += uni.$u.sys().windowTop
+ // #endif
+ // ���������������������������������������������������������������������������������������������������������������������������������
+ if (pageY < top) {
+ return 0
+ } else if (pageY >= top + height) {
+ // ���������������������������������������
+ return this.uIndexList.length - 1
+ } else {
+ // ���������������Y������������������������������������top������������������������������������������������������������������������������������
+ return Math.floor((pageY - top) / itemHeight);
+ }
+ },
+ // ������������������������������������������
+ setValueForTouch(currentIndex) {
+ // ������������������������������������������������������������������������������������������������
+ if (currentIndex === this.activeIndex) return
+ this.activeIndex = currentIndex
+ // #ifndef APP-NVUE || MP-WEIXIN
+ // ������nvue������������anchor���item������u-index-item���������������������index-item������������
+ this.scrollIntoView = `u-index-item-${this.uIndexList[currentIndex].charCodeAt(0)}`
+ // #endif
+ // #ifdef MP-WEIXIN
+ // ���������������������scroll-view���scroll-into-view���������������slot���������������id���������������������������scrollTop���������������������������
+ this.scrollTop = this.children[currentIndex].top
+ // #endif
+ // #ifdef APP-NVUE
+ // ���nvue������������cell���header������������������������������������������header(anchor)������������
+ const anchor = `u-index-anchor-${this.uIndexList[currentIndex]}`
+ dom.scrollToElement(this.anchors[currentIndex].$refs[anchor], {
+ offset: 0,
+ animated: false
+ })
+ // #endif
+ },
+ getHeaderRect() {
+ // ������header slot������������������list���������������������������������������top������
+ return new Promise(resolve => {
+ dom.getComponentRect(this.$refs.header, res => {
+ resolve(res.size)
+ })
+ })
+ },
+ // scroll-view���������������
+ async scrollHandler(e) {
+ if (this.touching || this.scrolling) return
+ // ������������������������������������������������������������������������������
+ this.scrolling = true
+ uni.$u.sleep(10).then(() => {
+ this.scrolling = false
+ })
+ let scrollTop = 0
+ const len = this.children.length
+ let children = this.children
+ const anchors = this.anchors
+ // #ifdef APP-NVUE
+ // nvue���������������������������������������������������������
+ scrollTop = Math.abs(e.contentOffset.y)
+ // ������header slot���������������
+ const header = await this.getHeaderRect()
+ // item���top���������nvue������������������anchor���top������������nvue������index-item���top
+ let top = header.height
+ // ������list������������������cell���top������������������header slot���������item���������height���������������������nvue������������������
+ children = this.children.map((item, index) => {
+ const child = {
+ height: item.height,
+ top
+ }
+ // ���������������������������item������������������
+ top += item.height + anchors[index].height
+ return child
+ })
+ // #endif
+ // #ifndef APP-NVUE
+ // ���nvue������detail���������������������
+ scrollTop = e.detail.scrollTop
+ // #endif
+ for (let i = 0; i < len; i++) {
+ const item = children[i],
+ nextItem = children[i + 1]
+ // ������������������������������������item���top���������������������������������������������
+ if (scrollTop <= children[0].top || scrollTop >= children[len - 1].top + children[len -
+ 1].height) {
+ this.activeIndex = -1
+ break
+ } else if (!nextItem) {
+ // ���������������������item���������������������������������������
+ this.activeIndex = len - 1
+ break
+ } else if (scrollTop > item.top && scrollTop < nextItem.top) {
+ this.activeIndex = i
+ break
+ }
+ }
+ },
+ },
+ }
+</script>
+
+<style lang="scss" scoped>
+ @import "../../libs/css/components.scss";
+
+ .u-index-list {
+
+ &__letter {
+ position: fixed;
+ right: 0;
+ text-align: center;
+ z-index: 3;
+ padding: 0 6px;
+
+ &__item {
+ width: 16px;
+ height: 16px;
+ border-radius: 100px;
+ margin: 1px 0;
+ @include flex;
+ align-items: center;
+ justify-content: center;
+
+ &--active {
+ background-color: $u-primary;
+ }
+
+ &__index {
+ font-size: 12px;
+ text-align: center;
+ line-height: 12px;
+ }
+ }
+ }
+
+ &__indicator {
+ width: 50px;
+ height: 50px;
+ border-radius: 100px 100px 0 100px;
+ text-align: center;
+ color: #ffffff;
+ background-color: #c9c9c9;
+ transform: rotate(-45deg);
+ @include flex;
+ justify-content: center;
+ align-items: center;
+
+ &__text {
+ font-size: 28px;
+ line-height: 28px;
+ font-weight: bold;
+ color: #fff;
+ transform: rotate(45deg);
+ text-align: center;
+ }
+ }
+ }
+</style>
--
Gitblit v1.8.0