From d1448cb0ef10f358bb7bddb4e1ec268515e0b787 Mon Sep 17 00:00:00 2001 From: gaoluyang <2820782392@qq.com> Date: 星期二, 15 七月 2025 11:46:57 +0800 Subject: [PATCH] 项目初始化 --- 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 + // 灏嗚嚜瀹氫箟鑺傜偣璁剧疆鎴愯櫄鎷熺殑锛屾洿鍔犳帴杩慥ue缁勪欢鐨勮〃鐜帮紝鑳芥洿濂界殑浣跨敤flex灞炴�� + options: { + virtualHost: true + }, + // #endif + data() { + return { + // 褰撳墠姝e湪琚�変腑鐨勫瓧姣嶇储寮� + activeIndex: -1, + touchmoveIndex: 1, + // 绱㈠紩瀛楁瘝鐨勪俊鎭� + letterInfo: { + height: 0, + itemHeight: 0, + top: 0 + }, + // 璁剧疆瀛楁瘝鎸囩ず鍣ㄧ殑楂樺害锛屽悗闈负浜嗚鎸囩ず鍣ㄨ窡闅忓瓧姣嶏紝骞跺皢灏栬閮ㄥ垎鎸囧悜瀛楁瘝鐨勪腑閮紝闇�瑕佷緷璧栨鍊� + indicatorHeight: 50, + // 瀛楁瘝鏀惧ぇ鎸囩ず鍣ㄧ殑top鍊硷紝涓轰簡璁╁叾鎸囧悜褰撳墠婵�娲荤殑瀛楁瘝 + // indicatorTop: 0 + // 褰撳墠鏄惁姝e湪琚Е鎽哥姸鎬� + touching: false, + // 婊氬姩鏉¢《閮╰op鍊� + 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锛屽苟灏唗his.scrollViewHeight璁剧疆涓簃axHeight + //瑙e喅褰搖-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) { + // 寤舵椂涓�瀹氭椂闂村悗鍐嶉殣钘忔寚绀哄櫒锛屼负浜嗚鐢ㄦ埛鐪嬬殑鏇寸洿瑙傦紝鍚屾椂涔熸槸涓轰簡娑堥櫎蹇�熷垏鎹-transition鐨剆how甯︽潵鐨勫奖鍝� + uni.$u.sleep(300).then(() => { + this.touching = false + }) + }, + // 鑾峰彇绱㈠紩鍒楄〃鐨勫昂瀵镐互鍙婂崟涓瓧绗︾殑灏哄淇℃伅 + getIndexListLetterRect() { + return new Promise(resolve => { + // 寤舵椂涓�瀹氭椂闂达紝浠ヨ幏鍙杁om灏哄 + // #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涓紝涓哄師鐢熷鑸爮锛屽叾楂樺害涓嶇畻鍦╳indowHeight鍐咃紝杩欓噷璁剧疆涓鸿礋鍊硷紝鍚庨潰鐩稿姞鏃跺彉鎴愬噺鍘诲叾楂樺害鐨勪竴鍗� + customNavHeight = -(sys.statusBarHeight + 44) + // #endif + } else { + customNavHeight = uni.$u.getPx(this.customNavHeight) + } + this.letterInfo = { + height, + // 涓轰簡璁╁瓧姣嶅垪琛ㄥ灞忓箷缁濆灞呬腑锛岃鍏跺瀵艰埅鏍忚繘琛屼慨姝o紝涔熷嵆寰�涓婂亸绉诲鑸爮鐨勪竴鍗婇珮搴� + top: (windowHeight - height) / 2 + customNavHeight / 2, + itemHeight: Math.floor(height / this.uIndexList.length) + } + }) + }, + // 鑾峰彇褰撳墠琚Е鎽哥殑绱㈠紩瀛楁瘝 + getIndexListLetter(pageY) { + const { + top, + height, + itemHeight + } = this.letterInfo + // 瀵笻5鐨刾ageY杩涜淇锛岃繖鏄敱浜巙ni-app鑷綔澶氭儏鍦℉5涓皢瑙︽懜鐐圭殑鍧愭爣璺烪5鐨勫鑸爮缁撳悎瀵艰嚧鐨勯棶棰� + // #ifdef H5 + pageY += uni.$u.sys().windowTop + // #endif + // 瀵圭涓�鍜屾渶鍚庝竴涓瓧姣嶅仛杈圭晫澶勭悊锛屽洜涓虹敤鎴峰彲鑳藉湪瀛楁瘝鍒楄〃涓婅Е鎽稿埌涓ょ鐨勫敖澶村悗渚濈劧缁х画婊戝姩 + if (pageY < top) { + return 0 + } else if (pageY >= top + height) { + // 濡傛灉瓒呭嚭浜嗭紝鍙栨渶鍚庝竴涓瓧姣� + return this.uIndexList.length - 1 + } else { + // 灏嗚Е鎽哥偣鐨刌杞村亸绉诲�硷紝鍑忓幓绱㈠紩瀛楁瘝鐨則op鍊硷紝闄や互姣忎釜瀛楁瘝鐨勯珮搴︼紝鍗冲彲寰楀埌褰撳墠瑙︽懜鐐硅惤鍦ㄥ摢涓瓧姣嶄笂 + return Math.floor((pageY - top) / itemHeight); + } + }, + // 璁剧疆鍚勯」鐢辫Е鎽歌�屽鑷村彉鍖栫殑鍊� + setValueForTouch(currentIndex) { + // 濡傛灉鍋忕Щ閲忓お灏忥紝鍓嶅悗寰楀嚭鐨勪細鏄悓涓�涓储寮曞瓧姣嶏紝涓轰簡闃叉姈锛岃繘琛岃繑鍥� + if (currentIndex === this.activeIndex) return + this.activeIndex = currentIndex + // #ifndef APP-NVUE || MP-WEIXIN + // 鍦ㄩ潪nvue涓紝鐢变簬anchor鍜宨tem閮藉湪u-index-item涓紝鎵�浠ラ渶瑕佸index-item杩涜鍋忕Щ + this.scrollIntoView = `u-index-item-${this.uIndexList[currentIndex].charCodeAt(0)}` + // #endif + // #ifdef MP-WEIXIN + // 寰俊灏忕▼搴忎笅锛宻croll-view鐨剆croll-into-view灞炴�ф棤娉曞slot涓殑鍐呭鐨刬d鐢熸晥锛屽彧鑳介�氳繃璁剧疆scrollTop鐨勫舰寮忓幓绉诲姩婊氬姩鏉� + this.scrollTop = this.children[currentIndex].top + // #endif + // #ifdef APP-NVUE + // 鍦╪vue涓紝鐢变簬cell鍜宧eader涓哄悓绾у厓绱狅紝鎵�浠ュ疄闄呮槸闇�瑕佸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缁勪欢涓幏鍙栧厓绱犵殑灏哄鏄病鏈塼op鍊肩殑 + 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鐨則op鍊硷紝鍦╪vue涓嬶紝妯℃嫙鍑虹殑anchor鐨則op锛岀被浼奸潪nvue涓嬬殑index-item鐨則op + let top = header.height + // 鐢变簬list缁勪欢鏃犳硶鑾峰彇cell鐨則op鍊硷紝杩欓噷閫氳繃header slot鍜屽悇涓猧tem涔嬮棿鐨刪eight锛屾ā鎷熷嚭绫讳技闈瀗vue涓嬬殑浣嶇疆淇℃伅 + children = this.children.map((item, index) => { + const child = { + height: item.height, + top + } + // 杩涜绱姞锛岀粰涓嬩竴涓猧tem鎻愪緵璁$畻渚濇嵁 + top += item.height + anchors[index].height + return child + }) + // #endif + // #ifndef APP-NVUE + // 闈瀗vue閫氳繃detail鑾峰彇婊氬姩鏉′綅绉� + scrollTop = e.detail.scrollTop + // #endif + for (let i = 0; i < len; i++) { + const item = children[i], + nextItem = children[i + 1] + // 濡傛灉婊氬姩鏉¢珮搴﹀皬浜庣涓�涓猧tem鐨則op鍊硷紝姝ゆ椂鏃犻渶璁剧疆浠绘剰瀛楁瘝涓洪珮浜� + if (scrollTop <= children[0].top || scrollTop >= children[len - 1].top + children[len - + 1].height) { + this.activeIndex = -1 + break + } else if (!nextItem) { + // 褰撲笉瀛樺湪涓嬩竴涓猧tem鏃讹紝鎰忓懗鐫�鍘嗛亶鍒颁簡鏈�鍚庝竴涓� + 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.9.3