# 标签编辑
考虑编程实现以下功能:
> 在界面设计中设计标签编辑组件需要一次性录入多个标签,但是手工录入或者导入的数据可能不一致,需要进行容错设计。
* [ ] 批量添加(编辑)标签Tags,两个标签之间使用分隔符分隔,系统转换为数组。
* [ ] 支持多种分隔符号,例如英文和中文的逗号,分号,|等都要兼容(容错)
* [ ] 多次输入的数据拼接成一个数组。
测试数据:计算机,电脑,,程序;数据;| 测试
以上解析为:计算机,电脑,程序数据,测试
# 参考设计
* [ ] 根据给定的字符串解析标签数组
* [ ] 合并两个标签数组
* [ ] 去重
使用的效果如图所示:
![](https://box.kancloud.cn/4561cdd87f9af5bc057b41516e6e86a6_406x108.png)
```
<template>
<view class="tagController">
<view class="tagContainer">
<view :class="computedClass" :key="index" v-for="(tagText,index) in tagList">
<text @tap="tapTag" :data-text="tagText">{{tagText}}</text>
<text v-if="isShowDelIcon" class="tagDelIcon" @tap="delTag" :data-text="tagText">x</text>
</view>
<view class="tagInput" v-if="isShowAdd">
<input type="text" v-model="tagString" placeholder="新增标签(组)" @blur="createTags" :class="computedClass" />
</view>
</view>
</view>
</template>
<script>
export default {
name: 'ts-tags',
model: {
prop: 'value',
event: 'input'
},
props: {
enableDel: {
type: [Boolean],
defalut: false
},
enableAdd: {
type: [Boolean],
defalut: false
},
value: {
type: [Array, String],
defalut() {
return []
}
},
size: { //标签大小 normal, small, large
type: String,
default: 'small'
},
type: { //标签类型default、primary、success、warning、error
type: String,
default: 'default'
},
disabled: { //是否为禁用状态
type: [String, Boolean],
defalut: false
},
inverted: { //是否为空心
type: [String, Boolean],
defalut: false
},
circle: { //是否为圆角
type: [String, Boolean],
defalut: false
},
dashed: { //是否为虚线框
type: [String, Boolean],
defalut: false
},
mark: { //是否为标记样式
type: [String, Boolean],
defalut: false
}
},
data() {
return {
tagString: '',
tagList: (typeof(this.value) === 'string' ? this.value.split(',') : this.value) || [],
isShowDelIcon: this.enableDel || false,
isShowAdd: this.enableAdd || false,
}
},
created() {
},
watch: {
value(newValue, oldValue) {
if (typeof(newValue) === 'string') {
this.tagList = newValue.split(',')
}
this.tagList = newValue || [];
}
},
computed: {
computedClass() {
let classArr = ['ts-tag'];
if (this.disabled === true || this.disabled === 'true') {
classArr.push('ts-tag--disabled');
}
if (this.inverted === true || this.inverted === 'true') {
classArr.push('ts-tag--inverted');
}
if (this.circle === true || this.circle === 'true') {
classArr.push('ts-tag--circle');
}
if (this.mark === true || this.mark === 'true') {
classArr.push('ts-tag--mark');
}
if (this.dashed === true || this.dashed === 'true') {
classArr.push('ts-tag--dashed');
}
classArr.push('ts-tag--' + this.size);
classArr.push('ts-tag--' + this.type);
// console.log(classArr);
return classArr;
},
},
methods: {
createTags: function() {
let tempTagArr = []
if (this.tagString.length > 0) {
let newTagList = this.tagString.split(/,|,|;|;/)
for (let i = 0; i < newTagList.length; i++) {
let newTag = newTagList[i].trim()
if (newTag !== '' && this.tagList.indexOf(newTag) < 0) {
tempTagArr.push(newTag)
}
}
}
this.tagString = ''
this.tagList.splice(this.tagList.length, 0, ...tempTagArr)
this.$emit('add', {
currentTag: tempTagArr,
allTags: this.tagList
})
// console.log(this.value);
this.$emit('input', this.tagList)
},
delTag: function(e) {
let delTagText = e.currentTarget.dataset.text
let delTagIndex = this.tagList.indexOf(delTagText)
this.tagList.splice(delTagIndex, 1)
this.$emit("delete", {
currentTag: delTagText,
allTags: this.tagList
})
this.$emit('input', this.tagList)
},
tapTag: function(e) {
let selTagText = e.currentTarget.dataset.text
this.$emit("click", selTagText)
}
}
}
</script>
<style lang="scss" scoped>
@import '../../variables.scss';
$tag-pd:0upx 10upx;
$tag-small-pd:0upx 5upx;
.tagController {
padding: 10upx 0upx;
display: flex;
flex-direction: column;
}
.tagContainer {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.tagDelIcon {
padding-left: 20upx;
}
.tagInput {}
.tagInput input {
width: 200upx;
}
@mixin tag-disabled {
opacity: 0.5;
}
.ts-tag {
box-sizing: border-box;
justify-content: center;
align-items: center;
padding: $tag-pd;
margin: 5upx;
background-color: $uni-bg-color-grey;
border: 1upx solid $uni-bg-color-grey;
color: $uni-text-color;
font-size: $uni-font-size-base;
border-radius: $uni-border-radius-base;
font-weight: normal;
&--circle {
border-radius: 20upx;
}
&--mark {
border-radius: 0 30upx 30upx 0
}
&--dashed {
border: 1upx dashed;
}
&--disabled {
@include tag-disabled;
}
&--normal {}
&--mini {
padding: $tag-small-pd;
font-size: $ts-font-size-xs;
}
&--small {
padding: $tag-small-pd;
font-size: $uni-font-size-sm;
}
&--large {
padding: $tag-pd;
font-size: $uni-font-size-lg;
}
&--default {}
&--primary {
color: $uni-text-color-inverse;
background-color: $uni-color-primary;
border: 1upx solid $uni-color-primary;
&.ts-tag--inverted {
color: $uni-color-primary;
background-color: $uni-bg-color;
border: 1upx solid $uni-color-primary;
}
}
&--success {
color: $uni-text-color-inverse;
background-color: $uni-color-success;
border: 1upx solid $uni-color-success;
&.ts-tag--inverted {
color: $uni-color-success;
background-color: $uni-bg-color;
border: 1px solid $uni-color-success;
}
&.ts-tag--dashed {
border: 1upx dashed;
}
}
&--warning {
color: $uni-text-color-inverse;
background-color: $uni-color-warning;
border: 1upx solid $uni-color-warning;
&.ts-tag--inverted {
color: $uni-color-warning;
background-color: $uni-bg-color;
border: 1upx solid $uni-color-warning;
}
&.ts-tag--dashed {
border: 1upx dashed;
}
}
&--error {
color: $uni-text-color-inverse;
background-color: $uni-color-error;
border: 1upx solid $uni-color-error;
&.ts-tag--inverted {
color: $uni-color-error;
background-color: $uni-bg-color;
border: 1upx solid $uni-color-error;
}
&.ts-tag--dashed {
border: 1upx dashed;
}
}
&--inverted {
color: $uni-text-color;
background-color: $uni-bg-color;
border: 1upx solid $uni-bg-color-grey;
}
}
</style>
```
- 内容介绍
- EcmaScript基础
- 快速入门
- 常量与变量
- 字符串
- 函数的基本概念
- 条件判断
- 数组
- 循环
- while循环
- for循环
- 函数基础
- 对象
- 对象的方法
- 函数
- 变量作用域
- 箭头函数
- 闭包
- 高阶函数
- map/reduce
- filter
- sort
- Promise
- 基本对象
- Arguments 对象
- 剩余参数
- Map和Set
- Json基础
- RegExp
- Date
- async
- callback
- promise基础
- promise-api
- promise链
- async-await
- 项目实践
- 标签系统
- 远程API请求
- 面向对象编程
- 创建对象
- 原型继承
- 项目实践
- Classes
- 构造函数
- extends
- static
- 项目实践
- 模块
- import
- export
- 项目实践
- 第三方扩展库
- immutable
- Vue快速入门
- 理解MVVM
- Vue中的MVVM模型
- Webpack+Vue快速入门
- 模板语法
- 计算属性和侦听器
- Class 与 Style 绑定
- 条件渲染
- 列表渲染
- 事件处理
- 表单输入绑定
- 组件基础
- 组件注册
- Prop
- 自定义事件
- 插槽
- 混入
- 过滤器
- 项目实践
- 标签编辑
- 移动客户端开发
- uni-app基础
- 快速入门程序
- 单页程序
- 底部Tab导航
- Vue语法基础
- 模版语法
- 计算属性与侦听器
- Class与Style绑定
- 样式与布局
- Box模型
- Flex布局
- 内置指令
- 基本指令
- v-model与表单
- 条件渲染指令
- 列表渲染指令v-for
- 事件与自定义属性
- 生命周期
- 项目实践
- 学生实验
- 贝店商品列表
- 加载更多数据
- 详情页面
- 自定义组件
- 内置组件
- 表单组件
- 技术专题
- 状态管理vuex
- Flyio
- Mockjs
- SCSS
- 条件编译
- 常用功能实现
- 上拉加载更多数据
- 数据加载综合案例
- Teaset UI组件库
- Teaset设计
- Teaset使用基础
- ts-tag
- ts-badge
- ts-button
- ta-banner
- ts-list
- ts-icon
- ts-load-more
- ts-segmented-control
- 代码模版
- 项目实践
- 标签组件
- 失物招领客户端原型
- 发布页面
- 检索页面
- 详情页面
- 服务端开发技术
- 服务端开发环境配置
- Koajs快速入门
- 快速入门
- 常用Koa中间件介绍
- 文件上传
- RestfulApi
- 一个复杂的RESTful例子
- 使用Mockjs生成模拟数据
- Thinkjs快速入门
- MVC模式
- Thinkjs介绍
- 快速入门
- RESTful服务
- RBAC案例
- 关联模型
- 应用开发框架
- 服务端开发
- PC端管理界面开发
- 移动端开发
- 项目实践
- 失物招领项目
- 移动客户端UI设计
- 服务端设计
- 数据库设计
- Event(事件)
- 客户端设计
- 事件列表页面
- 发布页面
- 事件详情页面
- API设计
- image
- event
- 微信公众号开发
- ui设计规范