uniapp中使用Tag标签和input输入框连用,tag进行标签选择,使用input能够创建标签(uview)

前言

最近写uniapp,遇到了产品的提的需求,需要做一个tag+input连用的功能,点击Tag进行选择,使用input可以进行tag的修改和创建,先来看看产品提的设计稿:
大概是一个这样的功能,我开始理解错了以为是在input中显示tag,类似element-ui中有的select选择器,但实际这只是进行tag和input的连用,看下面的设计稿应该能看懂逻辑

在这里插入图片描述

功能梳理

uniapp的组件库虽多,但或多或少都存在功能性局限或是兼容性的问题。我这里使用的是Uview-ui,它也只提供了最普通的input和tag基础功能,这里主要的难点就是实现样式的定制,比如输入框,点击,获取焦点,校验问题等,都会呈现不同的样式。还有手写input校验等等,过程中需要考虑用户各种输入的情况和输入框与用户的交互效果:

组件抽离实现

这里的功能的我抽离成为了一个组件,所以我就直接把代码贴出来,需要的朋友可以直接使用或者进行定制。
注:初代功能实现,代码粗糙,互相交流学习,大佬勿喷

template

<u-popup  :show="label_popupShow" mode="bottom" :round="10">
		<view class="label_popup">
			<view class="label_popupTop">
				<view style="width:120rpx ;">
					<view class="label_popupDrop" @click="label_popupDrop">
						<image src="../../static/Vector.png"></image>
					</view>
				</view>
				
				<view class="label_popupTitle">标签</view>
				<view class="label_popupbtn" @click="saveTags">完成</view>
			</view>
			<view class="label_popupContant" >
				<view class="label_inputContant" :style="boxStyleDefault1">
					<u--input
					    placeholder="请输入内容"
					    border="surround"
						@blur="losefocusState"
						@focus="focusState"
					    v-model="labelInputvalue"
						@keyup.enter.native="deleteTags"
						@change="change"
					  ></u--input>
					  
				</view>
				<view class="infoText" v-if="isWarning">标签长度不能超过8</view>
				<view class="delete_contant">
					<text >已有标签</text>
					<image class="tagDelete_image" @click="tagDelete" src="@/static/notice/labeldelete.png" v-if="!tagClosable"> </image>
					<image class="tagDeleteBack_image" @click="tagDeleteBack" src="@/static/notice/labeldeleteBack.png" v-if="tagClosable"> </image>
				</view>
				 
				<view class="existing_label">
					<view class="u-page__tag-item" v-for="(item, index) in allTags" :key="index">
						<u-tag shape="circle"  :text="item.name" :plain="!item.checked"  :name="index"
							@click="TagClick" borderColor='#fff' color='black'  :closable='tagClosable'
							@close="closelabelTag">
						</u-tag>
					</view>
				</view>
			</view>
			
		</view>
	</u-popup>

script

<script>
	export default {
    
    
		name:"chooselabel",
		props: {
    
    
			show: {
    
    
				type:Boolean,
				default: false
			}
		},
		data(){
    
    
			return {
    
    
				isWarning:false,
				boxStyleDefault1:'',
				boxStyle:['',
				'background:linear-gradient(to right,rgba(253, 157, 157, 1), rgba(244, 53, 53, 1))',
				'background:linear-gradient(to right,rgba(93, 164, 247, 1), rgba(50, 133, 228, 1))'
				],
				// 标签弹窗是否弹出
				label_popupShow:false,
				// 标签弹窗的输入框数据
				labelInputvalue: '',
				// 存放所有的标签
				allTags:[
					// {
    
    
					// 	name:'# 红头文件',
					// 	checked: false
					// },
				],
				// 标签输入框是否聚焦
				isfocus:false,
				// 标签删除按钮是否出现
				tagClosable:false,
			}
		},
		computed: {
    
    
			focus() {
    
    
				return !this.isfocus?'':'border-image:linear-gradient(to right,rgba(93, 164, 247, 1), rgba(50, 133, 228, 1))1;'
			}
		},
		watch:{
    
    
			label_popupShow: function (newVal, oldVal) {
    
    
			      // console.log(newVal);
			      if(newVal){
    
    
					  console.log('获取')
					  this.getlocalTags()
				  }
			},
			show: function (newVal, oldVal) {
    
    
			      // console.log(newVal);
			      if(newVal){
    
    
					  this.label_popupShow = newVal
				  }
			},
			
		},
		methods:{
    
    
			// 删除单个标签触发的时间
			closelabelTag(e){
    
    
				console.log(e)
				console.log(list)
				let list = []
				list = uni.getStorageSync('userLabel')
				list.splice(e, 1)
				uni.setStorage({
    
    
					key:'userLabel',
					data:list
				})
				this.getlocalTags()
			},
			// 删除标签弹窗
			tagDelete(){
    
    
				this.tagClosable = true
			},
			tagDeleteBack() {
    
    
				this.tagClosable = false
			},
			getlocalTags(){
    
    
				
				let list = uni.getStorageSync('userLabel')
				console.log(list)
				if(list != '' || list.length == 0){
    
    
					this.allTags = []
					list.map((item, index) => {
    
    
						let a = {
    
    }
						console.log(item)
						a.name = '#' + ' ' +item
						a.checked = false
						this.allTags.push(a)
					})
				}else{
    
    
					console.log('第一次')
				}
				
				console.log(this.allTags)
			},
			// 标签保存
			saveTags(){
    
    
				if(this.labelInputvalue.length>8){
    
    
					this.boxStyleDefault1 = this.boxStyle[1]
					console.log('不通过')
				}else{
    
    
					console.log('通过啦啦')
					// 如果没有输入值点击保存 则直接关闭,不作处理
					if(this.labelInputvalue == ''){
    
    
						this.label_popupShow = false
						this.tagClosable = false
						this.$emit('closeLabel_popup','')
					}else {
    
    
						// 输入值点击保存 判断标签是否存在,不存在在走 新建标签的流程
						console.log('选择的标签是:',this.labelInputvalue)
						let isSame = 0
						this.allTags.map((item, index) => {
    
    
							item.name.slice(2) == this.labelInputvalue ? isSame++ : ''
						})
						// if isSame==0则标签不存在要新建标签
						if(isSame != 0) {
    
    
							//存在
							console.log('存在')
							this.label_popupShow = false
							this.tagClosable = false
							this.$emit('closeLabel_popup',this.labelInputvalue)
						}else {
    
    
							// 不存在
							
							console.log('不存在')
							let list = []
							list = uni.getStorageSync('userLabel')
							if(list == ''){
    
    
								list = []
								list.push(this.labelInputvalue)
								console.log(list)
								uni.setStorage({
    
    
									key:'userLabel',
									data:list
								})
								
							} else {
    
    
								list.push(this.labelInputvalue)
								uni.setStorage({
    
    
									key:'userLabel',
									data:list
								})
								// console.log(isSame)
							}
							this.label_popupShow = false
							this.tagClosable = false
							this.$emit('closeLabel_popup',this.labelInputvalue)
						}
					}
				}
			},
			TagClick(name) {
    
    
				this.allTags.map((item, index) => {
    
    
					item.checked = index === name ? true : false
					
				})
				this.labelInputvalue = this.allTags[name].name
				this.labelInputvalue= this.labelInputvalue.slice(2)
				
			},
			change(e){
    
    
				if(e.length>8){
    
    
					this.boxStyleDefault1 = this.boxStyle[1]
					this.isWarning = true
				}else {
    
    
					this.boxStyleDefault1 = this.boxStyle[2]
					this.isWarning = false
				}
			},
			// 输入框获取焦点
			focusState() {
    
    
				if(this.labelInputvalue.length>8){
    
    
					this.boxStyleDefault1 = this.boxStyle[1]
				}else{
    
    
					this.boxStyleDefault1 = this.boxStyle[2]
				}
				
			},
			// 输入框失去焦点
			losefocusState() {
    
    
				if(this.labelInputvalue.length>8){
    
    
					this.boxStyleDefault1 = this.boxStyle[1]
				}else{
    
    
					this.boxStyleDefault1 = this.boxStyle[0]
				}
				
			},
			// 标签弹出下拉隐藏按钮
			label_popupDrop(){
    
    
				this.label_popupShow = false
				this.tagClosable = false
				this.$emit('closeLabel_popup','')
				this.labelInputvalue = ''
				this.boxStyleDefault1 = this.boxStyle[0]
				this.isWarning = false
			},
		}
	}
</script>

CSS

<style lang="scss" scoped> 
	.label_popup {
    
    
		height: 1040rpx;
		display: flex;
		flex-direction: column;
		align-items: center;
		.label_popupTop {
    
    
			margin-top: 20px;
			width: 640rpx;
			height: 56rpx;
			display: flex;
			flex-direction: row;
			justify-content: space-between;
			.label_popupDrop {
    
    
				 border-radius: 50%;
				 background-color:rgba(41, 41, 69, 0.05);
				 width: 48rpx;
				 height: 48rpx;
				 display: flex;
				 justify-content: center;
				 align-items: center;
				 image {
    
    
					 transform: rotate(90deg);
					 opacity: 0.7;
					 width: 5.5px;
					 height: 11px;
				 }
			}
			.label_popupTitle {
    
    
				font-family: 'PingFang SC';
				font-style: normal;
				font-weight: 500;
				font-size: 40rpx;
				line-height: 28px;
			}
			.label_popupbtn {
    
    
				background: linear-gradient(95.13deg, #5DA4F7 3.75%, #3285E4 95.95%);
				border-radius: 10px;
				width: 120rpx;
				height: 56rpx;
				display: flex;
				justify-content: center;
				align-items: center;
				color: #FFFFFF;
				font-family: 'PingFang SC';
				font-style: normal;
				font-weight: 500;
				font-size: 32rpx;
				line-height: 22px;
				letter-spacing: -0.2176px;
			}
		}
		.label_popupContant {
    
    
			width: 640rpx;
			.infoText{
    
    
				font-family: 'Inter';
				font-style: normal;
				font-weight: 400;
				font-size: 14px;
				line-height: 22px;
				color: #FF5252;
				margin-left: 5px;
			}
			.label_inputContant {
    
    
				width: 640rpx;
				border-radius: 4px;
				padding: 2rpx;
				background:linear-gradient(to right,rgba(220, 220, 220, 1), rgba(152, 152, 152, 1)) ;
				margin-top: 25px;
				display: flex;
				align-items: center;
				.labelTag {
    
    
					margin-left: 10px;
					
					border-radius: 5px;
				}
				/deep/.u-tag--mini {
    
    
					
					border: 1px dashed rgba(41, 41, 69, 0.6)!important;
				}
				/deep/.u-input--square {
    
    
					background: #fff!important;
					height: 60rpx;
				}
			}
		}
		.delete_contant {
    
    
			width: 640rpx;
			height: 42rpx;
			margin-top: 48px;
			display: flex;
			flex-direction: row;
			justify-content: space-between;
			align-items: center;
			text {
    
    
				font-family: 'PingFang SC';
				font-style: normal;
				font-weight: 400;
				font-size: 14px;
				line-height: 20px;
				color: rgba(41, 41, 69, 0.6);
			}
			.tagDelete_image {
    
    
				width: 42rpx;
				height: 42rpx;
			}
			.tagDeleteBack_image {
    
    
				width: 35rpx;
				height: 29.74rpx;
			}
		}
		.existing_label {
    
    
			width: 640rpx;
			margin-top: 10px;
			display: flex;
			flex-direction: row;
			justify-content: flex-start;
			align-content: space-between;
			flex-wrap: wrap;
			.u-page__tag-item {
    
    
				margin-top: 15px;
				// background: rgba(41, 41, 69, 0.05);
				margin-right: 10px;
			}
			// .u-page__tag-item:nth-child(3n){
    
    
			// 	margin-right: 0;
			// }
			.u-tag u-tag--circle u-tag--primary--plain u-tag--medium{
    
    
				margin-right: 0px!important;
			}
			/deep/{
    
    
				.u-tag--primary{
    
    
					border-radius: 50px;
					background-color:rgba(41, 41, 69, 0.05);
					border-color: #3285E4!important;
					// border-image:linear-gradient(to right,rgba(93, 164, 247, 1), rgba(50, 133, 228, 1))1!important;
				}
				.u-tag-wrapper {
    
    
					// background:  rgba(41, 41, 69, 0.05);
					border-radius: 50px;
				}
				.u-tag u-tag--circle u-tag--primary u-tag--medium {
    
    
					background-color:rgba(41, 41, 69, 0.05);
				}
				.u-tag--medium{
    
    
					padding: 0 15px;
					background:  rgba(41, 41, 69, 0.05);
				}
				.u-tag__close--medium{
    
    
					border: 1px solid rgba(122, 122, 140, 1);
					background:  #FFFFFF !important;
				}
				.u-tag__close{
    
    
					// background-color: #FFFFFF!important;
					top:12px;
					right: 18px;
				}
				.u-icon__icon{
    
    
					color:rgba(122, 122, 140, 1)!important;
				}
				// .u-tag u-tag--circle u-tag--primary--plain u-tag--medium {
    
    
				// 	background: red;
				// }
			}
		}
	}
</style>

猜你喜欢

转载自blog.csdn.net/weixin_45745641/article/details/128943297
今日推荐