这个功能的话实现起来比较简单,但是很多时候都要使用,在实际开发中,毕竟有时候每个对象的名字属性是独一无二的。运行效果如图所示:
那么这个效果是怎么实现的?由于源码比较长,我就先发针对这个功能的后面再发源码,(使用的框架是uview)
1、首先,需要在页面中定义一个数组来存储已有的对象,例如:
data() {
return {
itemList: [
{ name: '对象1', image: 'image1.jpg' },
{ name: '对象2', image: 'image2.jpg' },
{ name: '对象3', image: 'image3.jpg' },
{ name: '对象4', image: 'image4.jpg' },
{ name: '对象5', image: 'image5.jpg' }
],
newName: ''
}
}
2、然后,在页面中添加一个输入框和按钮,用于输入新对象的名字和触发新增操作:
<view>
<input v-model="newName" placeholder="请输入新对象名字" />
<button @click="addItem">新增</button>
</view>
3、接下来,可以在methods里定义一个方法来处理新增操作,并添加名字重复性检查:
methods: {
addItem() {
if (this.newName === '') {
// 名字为空,给出提示
uni.showToast({
title: '请填写名字',
icon: 'none'
});
return;
}
// 查找是否有重复的名字
const duplicate = this.itemList.some(item => item.name === this.newName);
if (duplicate) {
// 名字重复,给出提示
uni.showToast({
title: '名字重复,请重新输入',
icon: 'none'
});
return;
}
// 名字不重复,创建新对象并插入数组
const newItem = {
name: this.newName,
image: 'newimage.jpg'
};
this.itemList.push(newItem);
// 清空输入框内容
this.newName = '';
// 给出新增成功提示
uni.showToast({
title: '新增成功'
});
}
}
当然以上的代码仅仅用于演示思路和实现方法,有些参数需要根据自己的实际需求进行更改。
源码重要部分:
源码:
<template>
<view class="content">
<view @click="consoles" class="samsung">
<image src="/static/Tall-Book-Images/exitright.png" mode="aspectFit" style="width: 50rpx; height: 50rpx; ">
</image>
</view>
<view class="tilte">
<view class="title-top">分类管理</view>
<view class="title-bottom">长按拖动分类可排序,轻触你添加的分类可编辑。</view>
</view>
<view class="Classify">
<view :class="[showCode ? 'Expenditurelv':'Expenditure']" @click="expendituer()">支出</view>
<view :class="[showCodeR ? 'ExpenditureH':'Expenditure']" @click="ExpenditureH()">入账</view>
<view :class="[showCodeL ? 'ExpenditureL': 'Expenditure']" @click="ExpenditureL()">不计入收支</view>
</view>
<view class="box" v-show="showCode">
<view v-for="(item,index) in classify" :key="index">
<view class="box-mini" v-if="index<= 19">
<view class="img-box">
<image :src="item.imgs" mode="aspectFit" style="width: 50rpx; height: 50rpx;">
</image>
</view>
<view style="font-size: 28rpx;">{{item.name}}</view>
</view>
<view v-else class="box-mini" @click="deletes(index)">
<view class="img-box">
<image :src="item.imgs" mode="aspectFit" style="width: 50rpx; height: 50rpx;">
</image>
</view>
<view style="font-size: 28rpx;">{{item.name}}</view>
<view style="color: #cccccc;">轻触编辑</view>
</view>
</view>
<view class="box-mini" :style="styleactive" @click="last"> <!-- 添加-->
<view class="img-boxone">
<image src="/static/Tall-Book-Images/tianjia.png" mode="aspectFit"
style="width: 80rpx; height: 80rpx;">
</image>
</view>
<view style="font-size: 28rpx;">添加</view>
</view>
</view>
<view class="box" v-show="showCodeR">
<view v-for="(item,index) in classifyH" :key="index">
<view class="box-mini" v-if="index<= 19">
<view class="img-boxH">
<image :src="item.imgs" mode="aspectFit" style="width: 50rpx; height: 50rpx;">
</image>
</view>
<view style="font-size: 28rpx;">{{item.name}}</view>
</view>
<view v-else class="box-mini" @click="deletes(index)">
<view class="img-boxH">
<image :src="item.imgs" mode="aspectFit" style="width: 50rpx; height: 50rpx;">
</image>
</view>
<view style="font-size: 28rpx;">{{item.name}}</view>
<view style="color: #cccccc;">轻触编辑</view>
</view>
</view>
<view class="box-mini" :style="styleactive" @click="last"> <!-- 添加-->
<view class="img-boxone">
<image src="/static/Tall-Book-Images/tianjia.png" mode="aspectFit"
style="width: 80rpx; height: 80rpx;">
</image>
</view>
<view style="font-size: 28rpx;">添加</view>
</view>
</view>
<view class="box" v-show="showCodeL">
<view v-for="(item,index) in classifyL" :key="index">
<view class="box-mini" v-if="index<= 19">
<view class="img-boxL">
<image :src="item.imgs" mode="aspectFit" style="width: 50rpx; height: 50rpx;">
</image>
</view>
<view style="font-size: 28rpx;">{{item.name}}</view>
</view>
<view v-else class="box-mini" @click="deletes(index)">
<view class="img-boxL">
<image :src="item.imgs" mode="aspectFit" style="width: 50rpx; height: 50rpx;">
</image>
</view>
<view style="font-size: 28rpx;">{{item.name}}</view>
<view style="color: #cccccc;">轻触编辑</view>
</view>
</view>
<view class="box-mini" :style="styleactive" @click="last"> <!-- 添加-->
<view class="img-boxone">
<image src="/static/Tall-Book-Images/tianjia.png" mode="aspectFit"
style="width: 80rpx; height: 80rpx;">
</image>
</view>
<view style="font-size: 28rpx;">添加</view>
</view>
</view>
<view style="display: flex; justify-content: space-evenly; align-items: center;">
<view>{{showCode}}</view>
<view>{{showCodeR}}</view>
<view>{{showCodeL}}</view>
</view>
<u-popup :show="showaddition" mode="bottom" @close="close" @open="openss" round="10">
<view style="width: 100%; height: 650rpx; ">
<view class="top">
<view class="window" @click="close()">
<image src="/static/Tall-Book-Images/exitright.png" mode="aspectFit"
style="width: 40rpx; height: 40rpx;"></image>
</view>
<view
style=" font-size: 20px; text-align: center; line-height: 80rpx; width: 220rpx; height: 80rpx; position: absolute;top: 0; left: 0; right: 0; bottom: 0; margin: auto;">
添加分类
</view>
</view>
<view class="center">
<uni-easyinputs v-model="value" maxlength="4" @input="input"
placeholder="不能与已有类型名重复"></uni-easyinputs>
<view class="hint" :style="{color: isimit ? '#c90003' : '#c9c9c9'}">
{{showCharacterCount}}
</view>
</view>
<view class="bottom">
<button class="comfors" :style="active" @click="comfors">确定</button>
</view>
</view>
</u-popup>
<u-popup :show="showdelete" mode="bottom" @close="close" round="10"> <!--轻触编辑窗口-->
<view class="delete-box">
<view class="delete" @click="objectdelete">删除</view>
<view class="modification" @click="modification">修改</view>
<view class="cancel" @click="cancel">取消</view>
</view>
</u-popup>
<u-popup :show="ShowdeleteEmphasize" mode="bottom" @close="close" round="10"><!--强调是否确认窗口-->
<view class="delete-box">
<view class="delete-text">删除后。“私消”分类下的内容将归类为“其他”分类</view>
<view class="delete-Emphasize" @click="Emphasize">删除</view>
<view class="cancel" @click="cancel">取消</view>
</view>
</u-popup>
</view>
</template>
<script>
export default {
// computed:{
// showCodes(newVal){
// this.showCode = newVal
// }
// },
data() {
return {
styleactive: { //添加
background: '',
},
active: {
background: ' #f2f2f2',
color: '#d4d4d4'
},
value: '', //输入框的值
isimit: false, //是否超过了最大限制标志位
// activeindex: -1,
showaddition: false, //点开添加
showdelete: false, //删除弹窗
showCode: false, //支出分类
showCodeR: false, //入账分类
showCodeL: false, //不计入收支
deleteobj: -1, //删除索引用来确定删除操作的下标将index赋值给它
ShowdeleteEmphasize: false, //强调是否删除窗口
transfer: false, //判断是不是从删除弹窗中修改页面传送到添加弹窗修改名字的
classify: [{
name: '餐饮',
imgs: '/static/Tall-Book-Images/cy1.png'
},
{
name: '交通',
imgs: '/static/Tall-Book-Images/jt1.png'
},
{
name: '服饰',
imgs: '/static/Tall-Book-Images/yf1.png'
},
{
name: '购物',
imgs: '/static/Tall-Book-Images/gw1.png'
},
{
name: '服务',
imgs: '/static/Tall-Book-Images/sd1.png'
},
{
name: '教育',
imgs: '/static/Tall-Book-Images/jy1.png'
},
{
name: '娱乐',
imgs: '/static/Tall-Book-Images/ht1.png'
},
{
name: '运动',
imgs: '/static/Tall-Book-Images/lq1.png'
},
{
name: '生活缴费',
imgs: '/static/Tall-Book-Images/fz1.png'
},
{
name: '旅行',
imgs: '/static/Tall-Book-Images/lx1.png'
},
{
name: '宠物',
imgs: '/static/Tall-Book-Images/cw1.png'
},
{
name: '医疗',
imgs: '/static/Tall-Book-Images/yl1.png'
},
{
name: '保险',
imgs: '/static/Tall-Book-Images/bx1s.png'
},
{
name: '公益',
imgs: '/static/Tall-Book-Images/xin1.png'
},
{
name: '发红包',
imgs: '/static/Tall-Book-Images/hb1.png'
},
{
name: '转账',
imgs: '/static/Tall-Book-Images/zz1.png'
},
{
name: '亲属卡',
imgs: '/static/Tall-Book-Images/yhk1.png'
},
{
name: '其他人情',
imgs: '/static/Tall-Book-Images/qtrq1.png'
},
{
name: '其他',
imgs: '/static/Tall-Book-Images/qt1.png'
},
{
name: '退还',
imgs: '/static/Tall-Book-Images/thsh1.png'
}
],
classifyH: [{
name: '餐饮',
imgs: '/static/Tall-Book-Images/cy1.png'
},
{
name: '交通',
imgs: '/static/Tall-Book-Images/jt1.png'
},
{
name: '服饰',
imgs: '/static/Tall-Book-Images/yf1.png'
},
{
name: '购物',
imgs: '/static/Tall-Book-Images/gw1.png'
},
{
name: '服务',
imgs: '/static/Tall-Book-Images/sd1.png'
},
{
name: '教育',
imgs: '/static/Tall-Book-Images/jy1.png'
},
{
name: '娱乐',
imgs: '/static/Tall-Book-Images/ht1.png'
},
{
name: '运动',
imgs: '/static/Tall-Book-Images/lq1.png'
},
{
name: '生活缴费',
imgs: '/static/Tall-Book-Images/fz1.png'
},
{
name: '旅行',
imgs: '/static/Tall-Book-Images/lx1.png'
},
{
name: '宠物',
imgs: '/static/Tall-Book-Images/cw1.png'
},
{
name: '医疗',
imgs: '/static/Tall-Book-Images/yl1.png'
},
{
name: '保险',
imgs: '/static/Tall-Book-Images/bx1s.png'
},
{
name: '公益',
imgs: '/static/Tall-Book-Images/xin1.png'
},
{
name: '发红包',
imgs: '/static/Tall-Book-Images/hb1.png'
},
{
name: '转账',
imgs: '/static/Tall-Book-Images/zz1.png'
},
{
name: '亲属卡',
imgs: '/static/Tall-Book-Images/yhk1.png'
},
{
name: '其他人情',
imgs: '/static/Tall-Book-Images/qtrq1.png'
},
{
name: '其他',
imgs: '/static/Tall-Book-Images/qt1.png'
},
{
name: '退还',
imgs: '/static/Tall-Book-Images/thsh1.png'
}
],
classifyL: [{
name: '餐饮',
imgs: '/static/Tall-Book-Images/cy1.png'
},
{
name: '交通',
imgs: '/static/Tall-Book-Images/jt1.png'
},
{
name: '服饰',
imgs: '/static/Tall-Book-Images/yf1.png'
},
{
name: '购物',
imgs: '/static/Tall-Book-Images/gw1.png'
},
{
name: '服务',
imgs: '/static/Tall-Book-Images/sd1.png'
},
{
name: '教育',
imgs: '/static/Tall-Book-Images/jy1.png'
},
{
name: '娱乐',
imgs: '/static/Tall-Book-Images/ht1.png'
},
{
name: '运动',
imgs: '/static/Tall-Book-Images/lq1.png'
},
{
name: '生活缴费',
imgs: '/static/Tall-Book-Images/fz1.png'
},
{
name: '旅行',
imgs: '/static/Tall-Book-Images/lx1.png'
},
{
name: '宠物',
imgs: '/static/Tall-Book-Images/cw1.png'
},
{
name: '医疗',
imgs: '/static/Tall-Book-Images/yl1.png'
},
{
name: '保险',
imgs: '/static/Tall-Book-Images/bx1s.png'
},
{
name: '公益',
imgs: '/static/Tall-Book-Images/xin1.png'
},
{
name: '发红包',
imgs: '/static/Tall-Book-Images/hb1.png'
},
{
name: '转账',
imgs: '/static/Tall-Book-Images/zz1.png'
},
{
name: '亲属卡',
imgs: '/static/Tall-Book-Images/yhk1.png'
},
{
name: '其他人情',
imgs: '/static/Tall-Book-Images/qtrq1.png'
},
{
name: '其他',
imgs: '/static/Tall-Book-Images/qt1.png'
},
{
name: '退还',
imgs: '/static/Tall-Book-Images/thsh1.png'
}
],
}
},
computed: {
showCharacterCount() { //添加中备注字数限制
const count = this.value.length;
this.isimit = count > 3
return `${count}/${4}`
},
},
methods: {
input(e) {
console.log('输入内容:', e);
// console.log('this.index.lenth', this.value.length)
this.value = e
if (this.value) {
this.active.background = '#3eb575'
this.active.color = '#ffffff'
} else {
this.active.background = '#f2f2f2'
this.active.color = '#d4d4d4'
}
},
consoles() {
console.log('consoles')
this.$emit('close')
},
expendituer() { //点击支出
this.showCode = true;
this.showCodeL = false;
this.showCodeR = false;
},
ExpenditureH() { //点击入账
this.showCode = false;
this.showCodeR = true;
this.showCodeL = false;
},
ExpenditureL() { //点击不计入收支
this.showCode = false;
this.showCodeR = false;
this.showCodeL = true;
},
close() {
this.showaddition = false //关闭添加分类弹窗
this.showdelete = false //关闭删除弹窗
this.ShowdeleteEmphasize = false //关闭强调删除窗口
},
openss() {
//弹出层退出
},
last() { //添加功能
this.styleactive.background = "#dfdfdf"
this.showaddition = true //打开弹窗
setTimeout(() => {
this.styleactive.background = "#ffffff" //样式改变后立马还原
}, 150)
},
comfors() {
if (this.transfer) {//判断是不是修改内容弹窗过来的,过来的就只改名字
if(this.showCode)
{
if (this.value) {
this.active.background = "#33955f"
setTimeout(() => {
this.active.background = "#3eb575"
}, 150)
// this.classify[this.deleteobj].name = this.value //将新改的名字传入新增的对象
const duplicate = this.classify.some(item => item.name === this.value) //查询是否有重复的名字
if(duplicate){
uni.showToast({
title:'名字重复,请重新输入',
icon:'none'
});
return;
}else{
this.classify[this.deleteobj].name = this.value //将新改的名字传入新增的对象
}
this.showaddition = false //关闭添加弹窗
this.transfer = false //关闭判断
}
} else if(this.showCodeR){
if (this.value) {
this.active.background = "#33955f"
setTimeout(() => {
this.active.background = "#3eb575"
}, 150)
this.classifyH[this.deleteobj].name = this.value //将新改的名字传入新增的对象
this.showaddition = false //关闭添加弹窗
this.transfer = false //关闭判断
}
} else if(this.showCodeL){
if (this.value) {
this.active.background = "#33955f"
setTimeout(() => {
this.active.background = "#3eb575"
}, 150)
this.classifyL[this.deleteobj].name = this.value //将新改的名字传入新增的对象
this.showaddition = false //关闭添加弹窗
this.transfer = false //关闭判断
}
}
} else {
if (this.value) {
this.active.background = "#33955f"
setTimeout(() => {
this.active.background = "#3eb575"
}, 150)
const newItem = {
name: this.value,
// class: 'Clicre', //背景绿色样式
img: '/static/Tall-Book-Images/hb.png',
imgs: '/static/Tall-Book-Images/hb1.png',
}
if (this.showCode) { //支出添加新数组
const duplicate = this.classify.some(item => item.name === this.value)//查询是否有重复名字
if(duplicate){//如果重复
uni.showToast({
title:'名字重复,请重新输入',
icon:'none'
});
return;
}else{
this.classify.push(newItem)//插入数组
console.log('classify', this.classify)
this.$emit('updateList', newItem)//把数据传给父页面
this.showaddition = false//关闭弹窗
}
} else if (this.showCodeR) { //入账添加新数组
const duplicateone = this.classifyH.some(item => item.name === this.value)//查询是否有重复名字
if(duplicateone){//如果重复
uni.showToast({
title:'名字重复,请重新输入',
icon:'none'
});
return;
}else{
this.classifyH.push(newItem)
this.$emit('updateListOne',newItem)
this.showaddition = false//关闭弹窗
}
} else if (this.showCodeL) { //不计入收支新数组
const duplicatetwo = this.classifyL.some(item => item.name === this.value)//查询是否有重复名字
if(duplicatetwo){//如果重复
uni.showToast({
title:'名字重复,请重新输入',
icon:'none'
});
return;
}else{
this.classifyL.push(newItem)
this.$emit('updateListTwo', newItem)
this.showaddition = false//关闭弹窗
}
}
}
}
},
deletes(index) { //删除功能
this.deleteobj = index
this.showdelete = true
console.log('deleteobj', this.deleteobj)
},
objectdelete() { //确认删除?
this.showdelete = false //关闭删除弹窗
this.ShowdeleteEmphasize = true //开启强调弹窗
},
Emphasize() { //在次强调
if(this.showCode)
{
this.classify.splice(this.deleteobj,1)
}else if(this.showCodeR)
{
this.classifyH.splice(this.deleteobj,1)
}else if(this.showCodeL){
this.classifyL.splice(this.deleteobj,1)
}
// this.classify.splice(this.deleteobj, 1) //删除操作
this.ShowdeleteEmphasize = false //关闭强调弹窗
},
cancel() { //关闭删除弹窗
this.showdelete = false
this.ShowdeleteEmphasize = false
},
modification() { //修改内容
this.showdelete = false //关闭删除弹窗
this.showaddition = true //开启添加弹窗
this.transfer = true
}
}
}
</script>
<style lang="scss" scoped>
.Classify {
width: 100%;
display: flex;
height: 120rpx;
margin-top: 10rpx;
padding-left: 30rpx;
padding-right: 30rpx;
align-items: center;
margin-bottom: -12rpx;
justify-content: flex-start;
}
.content {
position: relative;
width: 100%;
height: 100%;
}
.samsung {
position: absolute;
width: auto;
height: auto;
top: 40rpx;
left: 30rpx;
}
.tilte {
display: flex;
flex-flow: column wrap;
justify-content: center;
align-items: center;
white-space: pre-wrap; //换行保留空格
width: 90%;
height: 350rpx;
margin: 100rpx auto 0;
// background-color: #c9c9c9;
}
.title-top {
font-size: 42rpx;
font-weight: bold;
margin-bottom: 40rpx;
}
.title-bottom {
font-size: 34rpx;
text-align: center;
letter-spacing: 0.1em;
line-height: 1.5em;
}
.Expenditurelv {
width: auto;
height: 60rpx;
color: #3eb575;
font-size: 32rpx;
text-align: center;
line-height: 60rpx;
margin-left: 20rpx;
border-radius: 10rpx;
background-color: #ebf7f1;
padding: 0rpx 20rpx 0rpx 20rpx;
}
.ExpenditureH {
width: auto;
height: 60rpx;
color: #f5c53a;
font-size: 32rpx;
text-align: center;
line-height: 60rpx;
margin-left: 20rpx;
border-radius: 10rpx;
background-color: #fdf8eb;
padding: 0rpx 20rpx 0rpx 20rpx;
}
.ExpenditureL {
width: auto;
height: 60rpx;
color: #8c8bc3;
font-size: 32rpx;
text-align: center;
line-height: 60rpx;
margin-left: 20rpx;
border-radius: 10rpx;
background-color: #f1f3f6;
padding: 0rpx 20rpx 0rpx 20rpx;
}
.Expenditure {
width: auto;
height: 60rpx;
color: #7d7d7d;
font-size: 32rpx;
text-align: center;
line-height: 60rpx;
margin-left: 20rpx;
border-radius: 10rpx;
background-color: #fafafa;
padding: 0rpx 20rpx 0rpx 20rpx;
}
.box {
width: 100%;
height: 500px;
margin-top: 50rpx;
display: flex;
flex-wrap: wrap;
overflow-y: auto;
}
.box-mini {
display: flex;
width: 120rpx;
height: 172rpx;
align-items: center;
flex-flow: column wrap;
justify-content: space-evenly;
margin: 0 0rpx 20rpx 52rpx;
}
.activebox {
background-color: #d4d4d4;
}
.img-box {
width: 80rpx;
height: 80rpx;
display: flex;
background: #3eb575;
border-radius: 50%;
justify-content: center;
align-items: center;
}
.img-boxH {
width: 80rpx;
height: 80rpx;
display: flex;
background: #f0b73a;
border-radius: 50%;
justify-content: center;
align-items: center;
}
.img-boxL {
width: 80rpx;
height: 80rpx;
display: flex;
background: #7888aa;
border-radius: 50%;
justify-content: center;
align-items: center;
}
.img-boxone {
width: 80rpx;
height: 80rpx;
display: flex;
border-radius: 50%;
justify-content: center;
align-items: center;
}
.top {
position: relative;
width: 100%;
height: 30%;
}
.center {
width: 100%;
height: 30%;
display: flex;
padding: 0 30rpx 0 30rpx;
justify-content: center;
align-items: center;
}
.hint {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
right: 35px;
width: 80rpx;
height: 80rpx;
}
.bottom {
width: 100%;
height: 40%;
position: relative;
}
.window {
width: 100rpx;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
}
.comfors {
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
position: absolute;
width: 380rpx;
height: 100rpx;
border-radius: 10rpx;
background-color: #f2f2f2;
display: flex;
justify-content: center;
align-items: center;
color: #d4d4d4;
}
.delete-box {
width: 100%;
display: flex;
height: 400rpx;
border-radius: 20px;
flex-flow: column wrap;
background-color: #fafafa;
}
.delete-text {
width: 100%;
height: 35%;
display: flex;
color: #c7c7c2;
font-size: 28rpx;
align-items: center;
justify-content: center;
border-bottom: 1rpx solid #eaeaea;
}
.delete {
width: 100%;
height: 38%;
display: flex;
color: #fa519a;
font-size: 36rpx;
align-items: center;
justify-content: center;
border-bottom: 1rpx solid #dddddd;
}
.delete-Emphasize {
width: 100%;
height: 35%;
display: flex;
color: #fa519a;
font-size: 36rpx;
align-items: center;
justify-content: center;
border-bottom: 20rpx solid #eaeaea;
}
.modification {
width: 100%;
height: 35%;
display: flex;
font-size: 36rpx;
align-items: center;
justify-content: center;
border-bottom: 20rpx solid #eaeaea;
}
.cancel {
width: 100%;
height: 25%;
display: flex;
font-size: 36rpx;
align-items: center;
justify-content: center;
}
</style>