From f26f29d84e0a68831a6af14dab3eec5500496d2e Mon Sep 17 00:00:00 2001 From: spring <2396852758@qq.com> Date: 星期三, 28 五月 2025 16:48:52 +0800 Subject: [PATCH] 初始化项目 --- uview-ui/components/u-tabs/u-tabs.vue | 369 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 369 insertions(+), 0 deletions(-) diff --git a/uview-ui/components/u-tabs/u-tabs.vue b/uview-ui/components/u-tabs/u-tabs.vue new file mode 100644 index 0000000..8762e98 --- /dev/null +++ b/uview-ui/components/u-tabs/u-tabs.vue @@ -0,0 +1,369 @@ +<template> + <view class="u-tabs" :style="{ + background: bgColor + }"> + <!-- $u.getRect()瀵圭粍浠舵牴鑺傜偣鏃犳晥锛屽洜涓哄啓浜�.in(this)锛屾晠杩欓噷鑾峰彇鍐呭眰鎺ョ偣灏哄 --> + <view :id="id"> + <scroll-view scroll-x class="u-scroll-view" :scroll-left="scrollLeft" scroll-with-animation> + <view class="u-scroll-box" :class="{'u-tabs-scorll-flex': !isScroll}"> + <view class="u-tab-item u-line-1" :id="'u-tab-item-' + index" v-for="(item, index) in list" :key="index" @tap="clickTab(index)" + :style="[tabItemStyle(index)]"> + <u-badge :count="item[count] || item['count'] || 0" :offset="offset" size="mini"></u-badge> + {{ item[name] || item['name']}} + </view> + <view v-if="showBar" class="u-tab-bar" :style="[tabBarStyle]"></view> + </view> + </scroll-view> + </view> + </view> +</template> + +<script> + /** + * tabs 鏍囩 + * @description 璇ョ粍浠讹紝鏄竴涓猼abs鏍囩缁勪欢锛屽湪鏍囩澶氱殑鏃跺�欙紝鍙互閰嶇疆涓哄乏鍙虫粦鍔紝鏍囩灏戠殑鏃跺�欙紝鍙互绂佹婊戝姩銆� 璇ョ粍浠剁殑涓�涓壒鐐规槸閰嶇疆涓烘粴鍔ㄦā寮忔椂锛屾縺娲荤殑tab浼氳嚜鍔ㄧЩ鍔ㄥ埌缁勪欢鐨勪腑闂翠綅缃�� + * @tutorial https://www.uviewui.com/components/tabs.html + * @property {Boolean} is-scroll tabs鏄惁鍙互宸﹀彸鎷栧姩锛堥粯璁rue锛� + * @property {Array} list 鏍囩鏁扮粍锛屽厓绱犱负瀵硅薄锛屽[{name: '鎺ㄨ崘'}] + * @property {String Number} current 鎸囧畾鍝釜tab涓烘縺娲荤姸鎬侊紙榛樿0锛� + * @property {String Number} height 瀵艰埅鏍忕殑楂樺害锛屽崟浣峳px锛堥粯璁�80锛� + * @property {String Number} font-size tab鏂囧瓧澶у皬锛屽崟浣峳px锛堥粯璁�30锛� + * @property {String Number} duration 婊戝潡绉诲姩涓�娆℃墍闇�鐨勬椂闂达紝鍗曚綅绉掞紙榛樿0.5锛� + * @property {String} active-color 婊戝潡鍜屾縺娲籺ab鏂囧瓧鐨勯鑹诧紙榛樿#497bff锛� + * @property {String} inactive-color tabs鏂囧瓧棰滆壊锛堥粯璁�#303133锛� + * @property {String Number} bar-width 婊戝潡瀹藉害锛屽崟浣峳px锛堥粯璁�40锛� + * @property {Object} active-item-style 娲诲姩tabs item鐨勬牱寮忥紝瀵硅薄褰㈠紡 + * @property {Object} bar-style 搴曢儴婊戝潡鐨勬牱寮忥紝瀵硅薄褰㈠紡 + * @property {Boolean} show-bar 鏄惁鏄剧ず搴曢儴鐨勬粦鍧楋紙榛樿true锛� + * @property {String Number} bar-height 婊戝潡楂樺害锛屽崟浣峳px锛堥粯璁�6锛� + * @property {String Number} item-width 鏍囩鐨勫搴︼紙榛樿auto锛� + * @property {String Number} gutter 鍗曚釜tab鏍囩鐨勫乏鍙冲唴杈硅窛涔嬪拰锛屽崟浣峳px锛堥粯璁�40锛� + * @property {String} bg-color tabs瀵艰埅鏍忕殑鑳屾櫙棰滆壊锛堥粯璁�#ffffff锛� + * @property {String} name 缁勪欢鍐呴儴璇诲彇鐨刲ist鍙傛暟涓殑灞炴�у悕锛坱ab鍚嶇О锛夛紝瑙佸畼缃戣鏄庯紙榛樿name锛� + * @property {String} count 缁勪欢鍐呴儴璇诲彇鐨刲ist鍙傛暟涓殑灞炴�у悕锛坆adge寰芥爣鏁帮級锛屽悓name灞炴�х殑浣跨敤锛岃瀹樼綉璇存槑锛堥粯璁ount锛� + * @property {Array} offset 璁剧疆badge寰芥爣鏁扮殑浣嶇疆鍋忕Щ锛屾牸寮忎负 [x, y]锛屼篃鍗宠缃殑涓簍op鍜宺ight鐨勫�硷紝鍗曚綅rpx锛堥粯璁5, 20]锛� + * @property {Boolean} bold 婵�娲婚�夐」鐨勫瓧浣撴槸鍚﹀姞绮楋紙榛樿true锛� + * @event {Function} change 鐐瑰嚮鏍囩鏃惰Е鍙� + * @example <u-tabs ref="tabs" :list="list" :is-scroll="false"></u-tabs> + */ + export default { + name: "u-tabs", + props: { + // 瀵艰埅鑿滃崟鏄惁闇�瑕佹粴鍔紝濡傚彧鏈�2鎴栬��3涓殑鏃跺�欙紝灏变笉闇�瑕佹粴鍔ㄤ簡锛屾鏃朵娇鐢╢lex骞冲垎tab鐨勫搴� + isScroll: { + type: Boolean, + default: true + }, + //闇�寰幆鐨勬爣绛惧垪琛� + list: { + type: Array, + default () { + return []; + } + }, + // 褰撳墠娲诲姩tab鐨勭储寮� + current: { + type: [Number, String], + default: 0 + }, + // 瀵艰埅鏍忕殑楂樺害鍜岃楂� + height: { + type: [String, Number], + default: 80 + }, + // 瀛椾綋澶у皬 + fontSize: { + type: [String, Number], + default: 30 + }, + // 杩囨浮鍔ㄧ敾鏃堕暱, 鍗曚綅ms + duration: { + type: [String, Number], + default: 0.5 + }, + // 閫変腑椤圭殑涓婚棰滆壊 + activeColor: { + type: String, + default: '#497bff' + }, + // 鏈�変腑椤圭殑棰滆壊 + inactiveColor: { + type: String, + default: '#303133' + }, + // 鑿滃崟搴曢儴绉诲姩鐨刡ar鐨勫搴︼紝鍗曚綅rpx + barWidth: { + type: [String, Number], + default: 40 + }, + // 绉诲姩bar鐨勯珮搴� + barHeight: { + type: [String, Number], + default: 6 + }, + // 鍗曚釜tab鐨勫乏鎴栨湁鍐呰竟璺濓紙宸﹀彸鐩稿悓锛� + gutter: { + type: [String, Number], + default: 30 + }, + // 瀵艰埅鏍忕殑鑳屾櫙棰滆壊 + bgColor: { + type: String, + default: '#ffffff' + }, + // 璇诲彇浼犲叆鐨勬暟缁勫璞$殑灞炴��(tab鍚嶇О) + name: { + type: String, + default: 'name' + }, + // 璇诲彇浼犲叆鐨勬暟缁勫璞$殑灞炴��(寰芥爣鏁�) + count: { + type: String, + default: 'count' + }, + // 寰芥爣鏁颁綅缃亸绉� + offset: { + type: Array, + default: () => { + return [5, 20] + } + }, + // 娲诲姩tab瀛椾綋鏄惁鍔犵矖 + bold: { + type: Boolean, + default: true + }, + // 褰撳墠娲诲姩tab item鐨勬牱寮� + activeItemStyle: { + type: Object, + default() { + return {} + } + }, + // 鏄惁鏄剧ず搴曢儴鐨勬粦鍧� + showBar: { + type: Boolean, + default: true + }, + // 搴曢儴婊戝潡鐨勮嚜瀹氫箟鏍峰紡 + barStyle: { + type: Object, + default() { + return {} + } + }, + // 鏍囩鐨勫搴� + itemWidth: { + type: [Number, String], + default: 'auto' + } + }, + data() { + return { + scrollLeft: 0, // 婊氬姩scroll-view鐨勫乏杈规粴鍔ㄨ窛绂� + tabQueryInfo: [], // 瀛樻斁瀵箃ab鑿滃崟鏌ヨ鍚庣殑鑺傜偣淇℃伅 + componentWidth: 0, // 灞忓箷瀹藉害锛屽崟浣嶄负px + scrollBarLeft: 0, // 绉诲姩bar闇�瑕侀�氳繃translateX()绉诲姩鐨勮窛绂� + parentLeft: 0, // 鐖跺厓绱�(tabs缁勪欢)鍒板睆骞曞乏杈圭殑璺濈 + id: this.$u.guid(), // id鍊� + currentIndex: this.current, + barFirstTimeMove: true, // 婊戝潡绗竴娆$Щ鍔ㄦ椂(椤甸潰鍒氱敓鎴愭椂)锛屾棤闇�鍔ㄧ敾锛屽惁鍒欑粰浜烘�紓鐨勬劅瑙� + }; + }, + watch: { + // 鐩戝惉tab鐨勫彉鍖栵紝閲嶆柊璁$畻tab鑿滃崟鐨勫竷灞�淇℃伅锛屽洜涓哄疄闄呬娇鐢ㄤ腑鑿滃崟鍙兘鏄�氳繃 + // 鍚庡彴鑾峰彇鐨勶紙濡傛柊闂籥pp椤堕儴鐨勮彍鍗曪級锛岃幏鍙栬繑鍥為渶瑕佷竴瀹氭椂闂达紝鎵�浠ist鍙樺寲鏃讹紝閲嶆柊鑾峰彇甯冨眬淇℃伅 + list(n, o) { + // list鍙樺姩鏃讹紝閲嶅埗鍐呴儴绱㈠紩锛屽惁鍒欏彲鑳藉鑷磋秴鍑烘暟缁勮竟鐣岀殑鎯呭喌 + if(n.length !== o.length) this.currentIndex = 0; + // 鐢�$nextTick绛夊緟瑙嗗浘鏇存柊瀹屾瘯鍚庡啀璁$畻tab鐨勫眬閮ㄤ俊鎭紝鍚﹀垯鍙兘鍥犱负tab杩樻病鐢熸垚灏辫幏鍙栵紝灏变細鏈夐棶棰� + this.$nextTick(() => { + this.init(); + }); + }, + current: { + immediate: true, + handler(nVal, oVal) { + // 瑙嗗浘鏇存柊鍚庡啀鎵ц绉诲姩鎿嶄綔 + this.$nextTick(() => { + this.currentIndex = nVal; + this.scrollByIndex(); + }); + } + }, + }, + computed: { + // 绉诲姩bar鐨勬牱寮� + tabBarStyle() { + let style = { + width: this.barWidth + 'rpx', + transform: `translate(${this.scrollBarLeft}px, -100%)`, + // 婊戝潡鍦ㄩ〉闈㈡覆鏌撳悗绗竴娆℃粦鍔ㄦ椂锛屾棤闇�鍔ㄧ敾鏁堟灉 + 'transition-duration': `${this.barFirstTimeMove ? 0 : this.duration }s`, + 'background-color': this.activeColor, + height: this.barHeight + 'rpx', + opacity: this.barFirstTimeMove ? 0 : 1, + // 璁剧疆涓�涓緢澶х殑鍊硷紝瀹冧細鑷姩鍙栬兘鐢ㄧ殑鏈�澶у�硷紝涓嶇敤楂樺害鐨勪竴鍗婏紝鏄洜涓洪珮搴﹀彲鑳芥槸鍗曟暟锛屼細鏈夊皬鏁板嚭鐜� + 'border-radius': `${this.barHeight / 2}px` + }; + Object.assign(style, this.barStyle); + return style; + }, + // tab鐨勬牱寮� + tabItemStyle() { + return (index) => { + let style = { + height: this.height + 'rpx', + 'line-height': this.height + 'rpx', + 'font-size': this.fontSize + 'rpx', + 'transition-duration': `${this.duration}s`, + padding: this.isScroll ? `0 ${this.gutter}rpx` : '', + flex: this.isScroll ? 'auto' : '1', + width: this.$u.addUnit(this.itemWidth) + }; + // 瀛椾綋鍔犵矖 + if (index == this.currentIndex && this.bold) style.fontWeight = 'bold'; + if (index == this.currentIndex) { + style.color = this.activeColor; + // 缁欓�変腑鐨則ab item娣诲姞澶栭儴鑷畾涔夌殑鏍峰紡 + style = Object.assign(style, this.activeItemStyle); + } else { + style.color = this.inactiveColor; + } + return style; + } + } + }, + methods: { + // 璁剧疆涓�涓猧nit鏂规硶锛屾柟渚垮澶勮皟鐢� + async init() { + // 鑾峰彇tabs缁勪欢鐨勫昂瀵镐俊鎭� + let tabRect = await this.$uGetRect('#' + this.id); + // tabs缁勪欢璺濈灞忓箷宸﹁竟鐨勫搴� + this.parentLeft = tabRect.left; + // tabs缁勪欢鐨勫搴� + this.componentWidth = tabRect.width; + this.getTabRect(); + }, + // 鐐瑰嚮鏌愪竴涓猼ab鑿滃崟 + clickTab(index) { + // 鐐瑰嚮褰撳墠娲诲姩tab锛屼笉瑙﹀彂浜嬩欢 + if(index == this.currentIndex) return ; + // 鍙戦�佷簨浠剁粰鐖剁粍浠� + this.$emit('change', index); + }, + // 鏌ヨtab鐨勫竷灞�淇℃伅 + getTabRect() { + // 鍒涘缓鑺傜偣鏌ヨ + let query = uni.createSelectorQuery().in(this); + // 鍘嗛亶鎵�鏈塼ab锛岃繖閲屾槸鎵ц浜嗘煡璇紝鏈�缁堜娇鐢╡xec()浼氫竴娆℃�ц繑鍥炴煡璇㈢殑鏁扮粍缁撴灉 + for (let i = 0; i < this.list.length; i++) { + // 鍙size鍜宺ect涓や釜鍙傛暟 + query.select(`#u-tab-item-${i}`).fields({ + size: true, + rect: true + }); + } + // 鎵ц鏌ヨ锛屼竴娆℃�ц幏鍙栧涓粨鏋� + query.exec( + function(res) { + this.tabQueryInfo = res; + // 鍒濆鍖栨粴鍔ㄦ潯鍜岀Щ鍔╞ar鐨勪綅缃� + this.scrollByIndex(); + }.bind(this) + ); + }, + // 婊氬姩scroll-view锛岃娲诲姩鐨則ab澶勪簬灞忓箷鐨勪腑闂翠綅缃� + scrollByIndex() { + // 褰撳墠娲诲姩tab鐨勫竷灞�淇℃伅锛屾湁tab鑿滃崟鐨剋idth鍜宭eft(涓哄厓绱犲乏杈圭晫鍒扮埗鍏冪礌宸﹁竟鐣岀殑璺濈)绛変俊鎭� + let tabInfo = this.tabQueryInfo[this.currentIndex]; + if (!tabInfo) return; + // 娲诲姩tab鐨勫搴� + let tabWidth = tabInfo.width; + // 娲诲姩item鐨勫乏杈瑰埌tabs缁勪欢宸﹁竟鐨勮窛绂伙紝鐢╥tem鐨刲eft鍑忓幓tabs鐨刲eft + let offsetLeft = tabInfo.left - this.parentLeft; + // 灏嗘椿鍔ㄧ殑tabs-item绉诲姩鍒板睆骞曟涓棿锛屽疄闄呬笂鏄scroll-view鐨勭Щ鍔� + let scrollLeft = offsetLeft - (this.componentWidth - tabWidth) / 2; + this.scrollLeft = scrollLeft < 0 ? 0 : scrollLeft; + // 褰撳墠娲诲姩item鐨勪腑鐐圭偣鍒板乏杈圭殑璺濈鍑忓幓婊戝潡瀹藉害鐨勪竴鍗婏紝鍗冲彲寰楀埌婊戝潡鎵�闇�鐨勭Щ鍔ㄨ窛绂� + let left = tabInfo.left + tabInfo.width / 2 - this.parentLeft; + // 璁$畻褰撳墠娲昏穬item鍒扮粍浠跺乏杈圭殑璺濈 + this.scrollBarLeft = left - uni.upx2px(this.barWidth) / 2; + // 绗竴娆$Щ鍔ㄦ粦鍧楃殑鏃跺�欙紝barFirstTimeMove涓簍rue锛屾斁鍒板欢鏃朵腑灏嗗叾璁剧疆false + // 寤舵椂鏄洜涓簊crollBarLeft浣滅敤浜巆omputed璁$畻鏃讹紝闇�瑕佷竴涓繃绋嬮渶锛屽惁鍒欏鑷村嚭閿� + if(this.barFirstTimeMove == true) { + setTimeout(() => { + this.barFirstTimeMove = false; + }, 100) + } + } + }, + mounted() { + this.init(); + } + }; +</script> + +<style lang="scss" scoped> + @import "../../libs/css/style.components.scss"; + + view, + scroll-view { + box-sizing: border-box; + } + + /* #ifndef APP-NVUE */ + ::-webkit-scrollbar, + ::-webkit-scrollbar, + ::-webkit-scrollbar { + display: none; + width: 0 !important; + height: 0 !important; + -webkit-appearance: none; + background: transparent; + } + /* #endif */ + + .u-scroll-box { + position: relative; + /* #ifdef MP-TOUTIAO */ + white-space: nowrap; + /* #endif */ + } + + /* #ifdef H5 */ + // 閫氳繃鏍峰紡绌块�忥紝闅愯棌H5涓嬶紝scroll-view涓嬬殑婊氬姩鏉� + scroll-view ::v-deep ::-webkit-scrollbar { + display: none; + width: 0 !important; + height: 0 !important; + -webkit-appearance: none; + background: transparent; + } + /* #endif */ + + .u-scroll-view { + width: 100%; + white-space: nowrap; + position: relative; + } + + .u-tab-item { + position: relative; + /* #ifndef APP-NVUE */ + display: inline-block; + /* #endif */ + text-align: center; + transition-property: background-color, color; + } + + .u-tab-bar { + position: absolute; + bottom: 0; + } + + .u-tabs-scorll-flex { + @include vue-flex; + justify-content: space-between; + } +</style> -- Gitblit v1.9.3