mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 21:50:28 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			159 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			159 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
Vue.component("combo-box", {
 | 
						||
	props: ["name", "title", "placeholder", "size", "v-items", "v-value"],
 | 
						||
	data: function () {
 | 
						||
		let items = this.vItems
 | 
						||
		if (items == null || !(items instanceof Array)) {
 | 
						||
			items = []
 | 
						||
		}
 | 
						||
 | 
						||
		// 自动使用ID作为值
 | 
						||
		items.forEach(function (v) {
 | 
						||
			if (v.value == null) {
 | 
						||
				v.value = v.id
 | 
						||
			}
 | 
						||
		})
 | 
						||
 | 
						||
		// 当前选中项
 | 
						||
		let selectedItem = null
 | 
						||
		if (this.vValue != null) {
 | 
						||
			let that = this
 | 
						||
			items.forEach(function (v) {
 | 
						||
				if (v.value == that.vValue) {
 | 
						||
					selectedItem = v
 | 
						||
				}
 | 
						||
			})
 | 
						||
		}
 | 
						||
 | 
						||
		return {
 | 
						||
			allItems: items,
 | 
						||
			items: items.$copy(),
 | 
						||
			selectedItem: selectedItem,
 | 
						||
			keyword: "",
 | 
						||
			visible: false,
 | 
						||
			hideTimer: null,
 | 
						||
			hoverIndex: 0
 | 
						||
		}
 | 
						||
	},
 | 
						||
	methods: {
 | 
						||
		reset: function () {
 | 
						||
			this.selectedItem = null
 | 
						||
			this.change()
 | 
						||
			this.hoverIndex = 0
 | 
						||
 | 
						||
			let that = this
 | 
						||
			setTimeout(function () {
 | 
						||
				if (that.$refs.searchBox) {
 | 
						||
					that.$refs.searchBox.focus()
 | 
						||
				}
 | 
						||
			})
 | 
						||
		},
 | 
						||
		changeKeyword: function () {
 | 
						||
			this.hoverIndex = 0
 | 
						||
			let keyword = this.keyword
 | 
						||
			if (keyword.length == 0) {
 | 
						||
				this.items = this.allItems.$copy()
 | 
						||
				return
 | 
						||
			}
 | 
						||
			this.items = this.allItems.$copy().filter(function (v) {
 | 
						||
				return teaweb.match(v.name, keyword)
 | 
						||
			})
 | 
						||
		},
 | 
						||
		selectItem: function (item) {
 | 
						||
			this.selectedItem = item
 | 
						||
			this.change()
 | 
						||
			this.hoverIndex = 0
 | 
						||
			this.keyword = ""
 | 
						||
			this.changeKeyword()
 | 
						||
		},
 | 
						||
		confirm: function () {
 | 
						||
			if (this.items.length > this.hoverIndex) {
 | 
						||
				this.selectItem(this.items[this.hoverIndex])
 | 
						||
			}
 | 
						||
		},
 | 
						||
		show: function () {
 | 
						||
			this.visible = true
 | 
						||
 | 
						||
			// 不要重置hoverIndex,以便焦点可以在输入框和可选项之间切换
 | 
						||
		},
 | 
						||
		hide: function () {
 | 
						||
			let that = this
 | 
						||
			this.hideTimer = setTimeout(function () {
 | 
						||
				that.visible = false
 | 
						||
			}, 500)
 | 
						||
		},
 | 
						||
		downItem: function () {
 | 
						||
			this.hoverIndex++
 | 
						||
			if (this.hoverIndex > this.items.length - 1) {
 | 
						||
				this.hoverIndex = 0
 | 
						||
			}
 | 
						||
			this.focusItem()
 | 
						||
		},
 | 
						||
		upItem: function () {
 | 
						||
			this.hoverIndex--
 | 
						||
			if (this.hoverIndex < 0) {
 | 
						||
				this.hoverIndex = 0
 | 
						||
			}
 | 
						||
			this.focusItem()
 | 
						||
		},
 | 
						||
		focusItem: function () {
 | 
						||
			if (this.hoverIndex < this.items.length) {
 | 
						||
				this.$refs.itemRef[this.hoverIndex].focus()
 | 
						||
				let that = this
 | 
						||
				setTimeout(function () {
 | 
						||
					that.$refs.searchBox.focus()
 | 
						||
					if (that.hideTimer != null) {
 | 
						||
						clearTimeout(that.hideTimer)
 | 
						||
						that.hideTimer = null
 | 
						||
					}
 | 
						||
				})
 | 
						||
			}
 | 
						||
		},
 | 
						||
		change: function () {
 | 
						||
			this.$emit("change", this.selectedItem)
 | 
						||
 | 
						||
			let that = this
 | 
						||
			setTimeout(function () {
 | 
						||
				if (that.$refs.selectedLabel != null) {
 | 
						||
					that.$refs.selectedLabel.focus()
 | 
						||
				}
 | 
						||
			})
 | 
						||
		},
 | 
						||
		submitForm: function (event) {
 | 
						||
			if (event.target.tagName != "A") {
 | 
						||
				return
 | 
						||
			}
 | 
						||
			let parentBox = this.$refs.selectedLabel.parentNode
 | 
						||
			while (true) {
 | 
						||
				parentBox = parentBox.parentNode
 | 
						||
				if (parentBox == null || parentBox.tagName == "BODY") {
 | 
						||
					return
 | 
						||
				}
 | 
						||
				if (parentBox.tagName == "FORM") {
 | 
						||
					parentBox.submit()
 | 
						||
					break
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
	},
 | 
						||
	template: `<div style="display: inline; z-index: 10; background: white">
 | 
						||
	<!-- 搜索框 -->
 | 
						||
	<div v-if="selectedItem == null">
 | 
						||
		<input type="text" v-model="keyword" :placeholder="placeholder" :size="size" style="width: 11em" @input="changeKeyword" @focus="show" @blur="hide" @keyup.enter="confirm()" @keypress.enter.prevent="1" ref="searchBox" @keyup.down="downItem" @keyup.up="upItem"/>
 | 
						||
	</div>
 | 
						||
	
 | 
						||
	<!-- 当前选中 -->
 | 
						||
	<div v-if="selectedItem != null">
 | 
						||
		<input type="hidden" :name="name" :value="selectedItem.value"/>
 | 
						||
		<a href="" class="ui label basic" style="line-height: 1.4; font-weight: normal; font-size: 1em" ref="selectedLabel" @click.prevent="submitForm"><span>{{title}}:{{selectedItem.name}}</span>
 | 
						||
			<span title="清除" @click.prevent="reset"><i class="icon remove small"></i></span>
 | 
						||
		</a>
 | 
						||
	</div>
 | 
						||
	
 | 
						||
	<!-- 菜单 -->
 | 
						||
	<div v-if="selectedItem == null && items.length > 0 && visible">
 | 
						||
		<div class="ui menu vertical small narrow-scrollbar" style="width: 11em; max-height: 17em; overflow-y: auto; position: absolute; border: rgba(129, 177, 210, 0.81) 1px solid; border-top: 0; z-index: 100">
 | 
						||
			<a href="" v-for="(item, index) in items" ref="itemRef" class="item" :class="{active: index == hoverIndex, blue: index == hoverIndex}" @click.prevent="selectItem(item)" style="line-height: 1.4">{{item.name}}</a>
 | 
						||
		</div>
 | 
						||
	</div>
 | 
						||
</div>`
 | 
						||
}) |