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-dropdown/u-dropdown.vue | 298 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 298 insertions(+), 0 deletions(-) diff --git a/uview-ui/components/u-dropdown/u-dropdown.vue b/uview-ui/components/u-dropdown/u-dropdown.vue new file mode 100644 index 0000000..a665cc8 --- /dev/null +++ b/uview-ui/components/u-dropdown/u-dropdown.vue @@ -0,0 +1,298 @@ +<template> + <view class="u-dropdown"> + <view class="u-dropdown__menu" :style="{ + height: $u.addUnit(height) + }" :class="{ + 'u-border-bottom': borderBottom + }"> + <view class="u-dropdown__menu__item" v-for="(item, index) in menuList" :key="index" @tap.stop="menuClick(index)"> + <view class="u-flex"> + <text class="u-dropdown__menu__item__text" :style="{ + color: item.disabled ? '#c0c4cc' : (index === current || highlightIndex == index) ? activeColor : inactiveColor, + fontSize: $u.addUnit(titleSize) + }">{{item.title}}</text> + <view class="u-dropdown__menu__item__arrow" :class="{ + 'u-dropdown__menu__item__arrow--rotate': index === current + }"> + <u-icon :custom-style="{display: 'flex'}" :name="menuIcon" :size="$u.addUnit(menuIconSize)" :color="index === current || highlightIndex == index ? activeColor : '#c0c4cc'"></u-icon> + </view> + </view> + </view> + </view> + <view class="u-dropdown__content" :style="[contentStyle, { + transition: `opacity ${duration / 1000}s linear`, + top: $u.addUnit(height), + height: contentHeight + 'px' + }]" + @tap="maskClick" @touchmove.stop.prevent> + <view @tap.stop.prevent class="u-dropdown__content__popup" :style="[popupStyle]"> + <slot></slot> + </view> + <view class="u-dropdown__content__mask"></view> + </view> + </view> +</template> + +<script> + /** + * dropdown 涓嬫媺鑿滃崟 + * @description 璇ョ粍浠朵竴鑸敤浜庡悜涓嬪睍寮�鑿滃崟锛屽悓鏃跺彲鍒囨崲澶氫釜閫夐」鍗$殑鍦烘櫙 + * @tutorial http://uviewui.com/components/dropdown.html + * @property {String} active-color 鏍囬鍜岄�夐」鍗¢�変腑鐨勯鑹诧紙榛樿#497bff锛� + * @property {String} inactive-color 鏍囬鍜岄�夐」鍗℃湭閫変腑鐨勯鑹诧紙榛樿#606266锛� + * @property {Boolean} close-on-click-mask 鐐瑰嚮閬僵鏄惁鍏抽棴鑿滃崟锛堥粯璁rue锛� + * @property {Boolean} close-on-click-self 鐐瑰嚮褰撳墠婵�娲婚」鏍囬鏄惁鍏抽棴鑿滃崟锛堥粯璁rue锛� + * @property {String | Number} duration 閫夐」鍗″睍寮�鍜屾敹璧风殑杩囨浮鏃堕棿锛屽崟浣峬s锛堥粯璁�300锛� + * @property {String | Number} height 鏍囬鑿滃崟鐨勯珮搴︼紝鍗曚綅浠绘剰锛堥粯璁�80锛� + * @property {String | Number} border-radius 鑿滃崟灞曞紑鍐呭涓嬫柟鐨勫渾瑙掑�硷紝鍗曚綅浠绘剰锛堥粯璁�0锛� + * @property {Boolean} border-bottom 鏍囬鑿滃崟鏄惁鏄剧ず涓嬭竟妗嗭紙榛樿false锛� + * @property {String | Number} title-size 鏍囬鐨勫瓧浣撳ぇ灏忥紝鍗曚綅浠绘剰锛屾暟鍊奸粯璁や负rpx鍗曚綅锛堥粯璁�28锛� + * @event {Function} open 涓嬫媺鑿滃崟琚墦寮�鏃惰Е鍙� + * @event {Function} close 涓嬫媺鑿滃崟琚叧闂椂瑙﹀彂 + * @example <u-dropdown></u-dropdown> + */ + export default { + name: 'u-dropdown', + props: { + // 鑿滃崟鏍囬鍜岄�夐」鐨勬縺娲绘�侀鑹� + activeColor: { + type: String, + default: '#497bff' + }, + // 鑿滃崟鏍囬鍜岄�夐」鐨勬湭婵�娲绘�侀鑹� + inactiveColor: { + type: String, + default: '#606266' + }, + // 鐐瑰嚮閬僵鏄惁鍏抽棴鑿滃崟 + closeOnClickMask: { + type: Boolean, + default: true + }, + // 鐐瑰嚮褰撳墠婵�娲婚」鏍囬鏄惁鍏抽棴鑿滃崟 + closeOnClickSelf: { + type: Boolean, + default: true + }, + // 杩囨浮鏃堕棿 + duration: { + type: [Number, String], + default: 300 + }, + // 鏍囬鑿滃崟鐨勯珮搴︼紝鍗曚綅浠绘剰锛屾暟鍊奸粯璁や负rpx鍗曚綅 + height: { + type: [Number, String], + default: 80 + }, + // 鏄惁鏄剧ず涓嬭竟妗� + borderBottom: { + type: Boolean, + default: false + }, + // 鏍囬鐨勫瓧浣撳ぇ灏� + titleSize: { + type: [Number, String], + default: 28 + }, + // 涓嬫媺鍑烘潵鐨勫唴瀹归儴鍒嗙殑鍦嗚鍊� + borderRadius: { + type: [Number, String], + default: 0 + }, + // 鑿滃崟鍙充晶鐨刬con鍥炬爣 + menuIcon: { + type: String, + default: 'arrow-down' + }, + // 鑿滃崟鍙充晶鍥炬爣鐨勫ぇ灏� + menuIconSize: { + type: [Number, String], + default: 26 + } + }, + data() { + return { + showDropdown: true, // 鏄惁鎵撳紑涓嬫潵鑿滃崟, + menuList: [], // 鏄剧ず鐨勮彍鍗� + active: false, // 涓嬫媺鑿滃崟鐨勭姸鎬� + // 褰撳墠鏄鍑犱釜鑿滃崟澶勪簬婵�娲荤姸鎬侊紝灏忕▼搴忎腑姝ゅ涓嶈兘鍐欐垚false鎴栬��""锛屽惁鍒欏悗缁皢current璧嬪�间负0锛� + // 鏃犺兘鐨凾X娌℃湁浣跨敤===鑰屾槸浣跨敤==鍒ゆ柇锛屽鑷寸▼搴忚涓哄墠鍚庝簩鑰呮病鏈夊彉鍖栵紝浠庤�屼笉浼氳Е鍙戣鍥炬洿鏂� + current: 99999, + // 澶栧眰鍐呭鐨勬牱寮忥紝鍒濆鏃跺浜庡簳灞傦紝涓旈�忔槑 + contentStyle: { + zIndex: -1, + opacity: 0 + }, + // 璁╂煇涓彍鍗曚繚鎸侀珮浜殑鐘舵�� + highlightIndex: 99999, + contentHeight: 0 + } + }, + computed: { + // 涓嬫媺鍑烘潵閮ㄥ垎鐨勬牱寮� + popupStyle() { + let style = {}; + // 杩涜Y杞翠綅绉伙紝灞曞紑鐘舵�佹椂锛屾仮澶嶅師浣嶃�傛敹榻愮姸鎬佹椂锛屽線涓婁綅绉�100%锛岃繘琛岄殣钘� + style.transform = `translateY(${this.active ? 0 : '-100%'})` + style['transition-duration'] = this.duration / 1000 + 's'; + style.borderRadius = `0 0 ${this.$u.addUnit(this.borderRadius)} ${this.$u.addUnit(this.borderRadius)}`; + return style; + } + }, + created() { + // 寮曠敤鎵�鏈夊瓙缁勪欢(u-dropdown-item)鐨則his锛屼笉鑳藉湪data涓0鏄庡彉閲忥紝鍚﹀垯鍦ㄥ井淇″皬绋嬪簭浼氶�犳垚寰幆寮曠敤鑰屾姤閿� + this.children = []; + }, + mounted() { + this.getContentHeight(); + }, + methods: { + init() { + // 褰撴煇涓瓙缁勪欢鍐呭鍙樺寲鏃讹紝瑙﹀彂鐖剁粍浠剁殑init锛岀埗缁勪欢鍐嶈姣忎竴涓瓙缁勪欢閲嶆柊鍒濆鍖栦竴閬� + // 浠ヤ繚璇佹暟鎹殑姝g‘鎬� + this.menuList = []; + this.children.map(child => { + child.init(); + }) + }, + // 鐐瑰嚮鑿滃崟 + menuClick(index) { + // 鍒ゆ柇鏄惁琚鐢� + if (this.menuList[index].disabled) return; + // 濡傛灉鐐瑰嚮鏃剁殑绱㈠紩鍜屽綋鍓嶆縺娲婚」绱㈠紩鐩稿悓锛屾剰鍛崇潃鐐瑰嚮浜嗘縺娲婚」锛岄渶瑕佹敹璧蜂笅鎷夎彍鍗� + if (index === this.current && this.closeOnClickSelf) { + this.close(); + // 绛夊姩鐢荤粨鏉熷悗锛屽啀绉婚櫎涓嬫媺鑿滃崟涓殑鍐呭锛屽惁鍒欑洿鎺ョЩ闄わ紝涔熷氨娌℃湁涓嬫媺鑿滃崟鏀惰捣鐨勬晥鏋滀簡 + setTimeout(() => { + this.children[index].active = false; + }, this.duration) + return; + } + this.open(index); + }, + // 鎵撳紑涓嬫媺鑿滃崟 + open(index) { + // 閲嶇疆楂樹寒绱㈠紩锛屽惁鍒欎細閫犳垚澶氫釜鑿滃崟鍚屾椂楂樹寒 + // this.highlightIndex = 9999; + // 灞曞紑鏃讹紝璁剧疆涓嬫媺鍐呭鐨勬牱寮� + this.contentStyle = { + zIndex: 11, + } + // 鏍囪灞曞紑鐘舵�佷互鍙婂綋鍓嶅睍寮�椤圭殑绱㈠紩 + this.active = true; + this.current = index; + // 鍘嗛亶鎵�鏈夌殑瀛愬厓绱狅紝灏嗙储寮曞尮閰嶇殑椤规爣璁颁负婵�娲荤姸鎬侊紝鍥犱负瀛愬厓绱犳槸閫氳繃v-if鎺у埗鍒囨崲鐨� + // 涔嬫墍浠ヤ笉鏄洜display: none锛屾槸鍥犱负nvue娌℃湁display杩欎釜灞炴�� + this.children.map((val, idx) => { + val.active = index == idx ? true : false; + }) + this.$emit('open', this.current); + }, + // 璁剧疆涓嬫媺鑿滃崟澶勪簬鏀惰捣鐘舵�� + close() { + this.$emit('close', this.current); + // 璁剧疆涓烘敹璧风姸鎬侊紝鍚屾椂current褰掍綅锛岃缃负绌哄瓧绗︿覆 + this.active = false; + this.current = 99999; + // 涓嬫媺鍐呭鐨勬牱寮忚繘琛岃皟鏁达紝涓嶉�忔槑搴﹁缃负0 + this.contentStyle = { + zIndex: -1, + opacity: 0 + } + }, + // 鐐瑰嚮閬僵 + maskClick() { + // 濡傛灉涓嶅厑璁哥偣鍑婚伄缃╋紝鐩存帴杩斿洖 + if (!this.closeOnClickMask) return; + this.close(); + }, + // 澶栭儴鎵嬪姩璁剧疆鏌愪釜鑿滃崟楂樹寒 + highlight(index = undefined) { + this.highlightIndex = index !== undefined ? index : 99999; + }, + // 鑾峰彇涓嬫媺鑿滃崟鍐呭鐨勯珮搴� + getContentHeight() { + // 杩欓噷鐨勫師鐞嗕负锛屽洜涓篸ropdown缁勪欢鏄浉瀵瑰畾浣嶇殑锛屽畠鐨勪笅鎷夊嚭鏉ョ殑鍐呭锛屽繀椤荤粰瀹氫竴涓珮搴� + // 鎵嶈兘璁╅伄缃╁崰婊¤彍鍗曚竴涓嬶紝鐩村埌灞忓箷搴曢儴鐨勯珮搴� + // this.$u.sys()涓簎View灏佽鐨勮幏鍙栬澶囦俊鎭殑鏂规硶 + let windowHeight = this.$u.sys().windowHeight; + this.$uGetRect('.u-dropdown__menu').then(res => { + // 杩欓噷鑾峰彇鐨勬槸dropdown鐨勫昂瀵革紝鍦℉5涓婏紝uniapp鑾峰彇灏哄鏄湁bug鐨�(浠ュ墠鎻愬嚭淇杩囷紝鍚庢潵鍙堝嚭鐜颁簡姝ug锛岀洰鍓峢x2.8.11鐗堟湰) + // H5绔痓ug琛ㄧ幇涓哄厓绱犲昂瀵哥殑top鍊间负瀵艰埅鏍忓簳閮ㄥ埌鍒板厓绱犵殑涓婅竟娌跨殑璺濈锛屼絾鏄厓绱犵殑bottom鍊肩‘鏄鑸爮椤堕儴鍒板厓绱犲簳閮ㄧ殑璺濈 + // 浜岃�呮槸浜掔浉鐭涚浘鐨勶紝鏈川鍘熷洜鏄疕5绔鑸爮闈炲師鐢燂紝uni鐨勫紑鍙戣�呭ぇ鎰忛�犳垚 + // 杩欓噷鍙栬彍鍗曟爮鐨刡otton鍊煎悎鐞嗙殑锛屼笉鑳界敤res.top锛屽惁鍒欓〉闈細閫犳垚婊氬姩 + this.contentHeight = windowHeight - res.bottom; + }) + } + } + } +</script> + +<style scoped lang="scss"> + @import "../../libs/css/style.components.scss"; + + .u-dropdown { + flex: 1; + width: 100%; + position: relative; + + &__menu { + @include vue-flex; + position: relative; + z-index: 11; + height: 80rpx; + + &__item { + flex: 1; + @include vue-flex; + justify-content: center; + align-items: center; + + &__text { + font-size: 28rpx; + color: $u-content-color; + } + + &__arrow { + margin-left: 6rpx; + transition: transform .3s; + align-items: center; + @include vue-flex; + + &--rotate { + transform: rotate(180deg); + } + } + } + } + + &__content { + position: absolute; + z-index: 8; + width: 100%; + left: 0px; + bottom: 0; + overflow: hidden; + + + &__mask { + position: absolute; + z-index: 9; + background: rgba(0, 0, 0, .3); + width: 100%; + left: 0; + top: 0; + bottom: 0; + } + + &__popup { + position: relative; + z-index: 10; + transition: all 0.3s; + transform: translate3D(0, -100%, 0); + overflow: hidden; + } + } + + } +</style> -- Gitblit v1.9.3