当前位置:网站首页>自定义插入页面标签以及实现类似通讯录的首字母搜索
自定义插入页面标签以及实现类似通讯录的首字母搜索
2022-07-01 18:45:00 【時間不夠以後】
- 自定义实现页面标注标签功能

<template>
<div>
<Icon type="ios-pricetags-outline" size="16" style="margin-right: 6px" />
<Tag v-for="(item, index) in allCaseTags" :key="index" :class="active === item ? 'active' : 'Classification'" @click.native="oncheckTag(item)">
<span
:contenteditable="item.tagId === ''"
v-html="item.tagName"
@keyup="keydown(item, index, $event)"
@blur="tagNameBlur(item, index, $event)"
style="border: none; outline: none; display: inline-block"
:ref="`tagName${index}`"
></span>
<Icon type="ios-close" v-if="active === item" style="margin-left: 4px" @click="delCurCaseTag(index)" />
</Tag>
<span class="tag-add" @click="addTags()" ref="addTagBtnRef">
<Icon type="icon-add" size="12" />
添加标签
</span>
<div class="popInput" :style="`left: ${left}px !important;`">
<ul class="tagUl" id="tagUl"></ul>
</div>
</div>
</template>
<script>
export default {
data() {
return {
allCaseTags: [{
tagName: '标签1', tagId: 1 }],
allProjectsTags: [
{
tagName: '标签1', tagId: 1, count: 1 },
{
tagName: '标签2', tagId: 2, count: 1 },
{
tagName: '标签3', tagId: 3, count: 1 },
{
tagName: '测试标签', tagId: 4, count: 1 },
{
tagName: 'vue', tagId: 5, count: 1 },
{
tagName: 'javascript', tagId: 6, count: 1 },
{
tagName: '前端', tagId: 7, count: 1 },
{
tagName: '后端', tagId: 8, count: 1 },
{
tagName: '测试', tagId: 9, count: 1 },
],
popDom: '',
active: {
},
left: 0,
}
},
mounted() {
var popDom = document.getElementById('tagUl')
this.popDom = popDom
popDom.addEventListener('click', this.onLiTag2Click, false)
window.addEventListener('click', (e) => this.onCancelCurrentTag(e))
},
methods: {
onLiTag2Click(e) {
console.log(e)
if (e.target.tagName.toLowerCase() === 'li') {
var len = this.allCaseTags.length
var _val = e.target.innerText
this.$refs[`tagName${
len - 1}`][0].innerText = _val
this.$set(this.allCaseTags[len - 1], 'tagName', _val)
this.popDom.innerHTML = []
}
},
addTags() {
const drag = this.$refs.addTagBtnRef
const canvasInfo = drag.getBoundingClientRect()
this.left = canvasInfo.left
this.allCaseTags.push({
caseId: this.id,
projectId: this.projectId,
tagName: '',
mapId: '',
tagId: '',
})
this.$nextTick(() => {
this.$refs[`tagName${
this.allCaseTags.length - 1}`][0].focus()
})
},
keydown(item, index, e) {
var _val = e.target.innerText.trim()
var _lis = []
if (_val) {
// TODO: 去重
const newArr = this.allProjectsTags.filter((item) => {
return !this.allCaseTags.some((ele) => ele.tagId === item.tagId)
})
newArr.forEach((str) => {
if (str.tagName.indexOf(_val) !== -1) {
// 匹配所有
// _lis.push('<li>' + str.tagName.replace(_val, '<font color=red>' + _val + '</font>') + '</li>')
_lis.push('<li>' + str.tagName + '</li>')
}
})
}
this.popDom.innerHTML = _lis.join('')
},
oncheckTag(item) {
this.active = item
},
// 用来监听鼠标点击非tag区域时,取消已选择的tag
onCancelCurrentTag() {
this.active = {
}
this.popDom.innerHTML = []
},
delCurCaseTag(index) {
this.allCaseTags.splice(index, 1)
this.onCancelCurrentTag()
},
tagNameBlur(item, index, event) {
var curText = event.target.innerText.replace(/[^\w\u4E00-\u9FA5]/g, '')
if (curText) {
this.$set(item, 'tagName', curText)
// 执行add操作
} else {
// 移除该tag
this.allCaseTags.splice(index, 1)
}
},
},
beforeDestroy() {
this.popDom.removeEventListener('click', this.onLiTag2Click, false)
window.removeEventListener('click', this.onCancelCurrentTag)
},
}
</script>
<style lang="less">
.active {
background: Var(--SubPrimary);
cursor: default;
}
.Classification {
background: Var(--TableHeader);
cursor: default;
}
.popInput {
position: fixed;
}
.tagUl {
// position: absolute;
list-style: none;
}
.tagUl li {
padding: 0 8px;
line-height: 28px;
background-color: Var(--Theme);
cursor: pointer;
&:hover {
background-color: Var(--SubSuccess);
}
}
</style>
- 实现A-Z的字母排序快速搜索(类似手机通讯录)

需要安装插件,以便把汉字转化为拼音字母
npm install js-pinyinimport pinyin from 'js-pinyin'
<template>
<div>
<div
class="country"
ref="listview"
v-show="countryList.length > 0"
v-cloak
@scroll="setScrollY"
>
<ul class="country-list">
<li v-for="(group, index) in countryList" ref="listGroup" :key="index">
<h2 class="list-group-title">{
{
group.title }}</h2>
<ul>
<li v-for="(item, index) in group.items" :key="index" class="list-group-item">
<span class="name"> {
{
item.tagName }} </span>
<span> ( {
{
item.count }} ) </span>
</li>
</ul>
</li>
</ul>
<ul class="list-shortcut">
<li
@mouseover.stop.prevent="onMouseover(index)"
class="item"
v-for="(item, index) in shortcut"
:key="index"
>
{
{
item }}
</li>
</ul>
</div>
</div>
</template>
<script>
import pinyinUtil from 'js-pinyin'
export default {
data() {
return {
value1: true,
countryList: [],
shortcut: [],
phoneCode: '93',
touch: {
},
listHeight: [],
scrollY: -1,
currentIndex: 0,
}
},
created() {
// 获取列表
this.getCountryList()
},
computed: {
fixedTitle() {
return this.shortcut[this.currentIndex] ? this.shortcut[this.currentIndex] : 'A'
},
},
watch: {
scrollY(newY) {
var listHeight = this.listHeight
// 当滚动到顶部时, newY<=0
if (newY <= 0) {
this.currentIndex = 0
return
}
// 中间部分滚动
for (var i = 0; i < listHeight.length - 1; i++) {
var height1 = listHeight[i]
var height2 = listHeight[i + 1]
if (!height2 || (newY >= height1 && newY < height2)) {
this.currentIndex = i
return
}
}
// 滚动到底部且newY大于最后一个元素的上限
this.currentIndex = listHeight.length - 1
},
},
mounted() {
setTimeout(() => {
this.calculateTotalHeight()
}, 200)
},
methods: {
setScrollY() {
this.scrollY = this.$refs.listview.scrollTop
},
getCountryList() {
var res = [
{
tagName: 'qqs3', projectId: 1, tagId: 21, count: 3 },
{
tagName: 'qqs2', projectId: 1, tagId: 23, count: 1 },
{
tagName: 'qqs', projectId: 1, tagId: 24, count: 4 },
{
tagName: 'qqs4', projectId: 1, tagId: 36, count: 1 },
{
tagName: 'qqs5', projectId: 1, tagId: 37, count: 1 },
{
tagName: 'qqs6', projectId: 1, tagId: 38, count: 1 },
{
tagName: '1', projectId: 1, tagId: 39, count: -1 },
{
tagName: '数据1', projectId: 1, tagId: 40, count: 0 },
{
tagName: '测试2', projectId: 1, tagId: 41, count: 0 },
{
tagName: '标签1', projectId: 1, tagId: 69, count: 0 },
{
tagName: '1233', projectId: 1, tagId: 70, count: 0 },
{
tagName: 'aca', projectId: 1, tagId: 71, count: 1 },
{
tagName: 'aaa2', projectId: 1, tagId: 99, count: 1 },
{
tagName: 'bab', projectId: 1, tagId: 1, count: 1 },
{
tagName: 'bac', projectId: 1, tagId: 2, count: 1 },
{
tagName: 'bbb', projectId: 1, tagId: 3, count: 1 },
{
tagName: 'baa', projectId: 1, tagId: 4, count: 1 },
{
tagName: 'cac', projectId: 1, tagId: 5, count: 1 },
{
tagName: 'cab', projectId: 1, tagId: 6, count: 1 },
{
tagName: 'ccc', projectId: 1, tagId: 7, count: 1 },
{
tagName: 'ddd', projectId: 1, tagId: 8, count: 1 },
{
tagName: 'dad', projectId: 1, tagId: 9, count: 1 },
{
tagName: 'dav', projectId: 1, tagId: 10, count: 1 },
{
tagName: 'ee', projectId: 1, tagId: 11, count: 1 },
{
tagName: 'ear', projectId: 1, tagId: 12, count: 1 },
{
tagName: 'faf', projectId: 1, tagId: 13, count: 1 },
{
tagName: 'fac', projectId: 1, tagId: 14, count: 1 },
{
tagName: 'fad', projectId: 1, tagId: 15, count: 1 },
{
tagName: 'faa', projectId: 1, tagId: 16, count: 1 },
{
tagName: 'gac', projectId: 1, tagId: 17, count: 1 },
{
tagName: 'gab', projectId: 1, tagId: 18, count: 1 },
{
tagName: 'gar', projectId: 1, tagId: 19, count: 1 },
]
var map = {
}
res.forEach((item, index) => {
var key =
item.tagName.charCodeAt(0) > 255
? pinyinUtil.getCamelChars(item.tagName).slice(0, 1)
: item.tagName.slice(0, 1).toUpperCase()
if (/^[a-zA-Z]*$/.test(key)) {
if (!map[key]) {
this.shortcut.push(key)
map[key] = {
title: key,
items: [],
}
}
map[key].items.push(item)
} else {
if (!map['#']) {
this.shortcut.push('#')
map['#'] = {
title: '#',
items: [],
}
}
map['#'].items.push(item)
}
})
// 转为数组
var ret = []
for (var k in map) {
var val = map[k]
ret.push(val)
}
// 对首字母排序
ret.sort((a, b) => {
return a.title.charCodeAt(0) - b.title.charCodeAt(0)
})
this.shortcut.sort((a, b) => {
return a.charCodeAt(0) - b.charCodeAt(0)
})
// 对每个分组里面的数据进行排序
ret.map((v) => {
v.items.sort((a, b) => {
return a.tagName.localeCompare(b.tagName)
})
})
this.countryList = ret
},
onMouseover(index) {
this.touch.anchorIndex = index
this.scrollToIndex(index)
},
scrollToIndex(index) {
this.$refs.listview.scrollTo(0, this.listHeight[index])
},
calculateTotalHeight() {
var list = this.$refs.listGroup
var height = 0
this.listHeight.push(height)
if (list && list.length > 0) {
for (var i = 0; i < list.length; i++) {
var item = list[i]
height += item.clientHeight
this.listHeight.push(height)
}
}
},
},
}
</script>
<style scoped lang="less">
ul {
list-style: none;
}
.country {
position: fixed;
overflow-y: scroll;
overflow-x: hidden;
z-index: 3000;
width: 400px;
right: 0;
top: 50px;
bottom: 0;
}
/* 字母 */
.country-list h2 {
padding: 6px 16px;
color: Var(--LightDebug);
background: Var(--TableHeader);
line-height: 16px;
font: 500 14px/16px SFProText-Regular;
}
/* 数据list */
.country-list ul {
background: Var(--Theme);
padding: 0 16px;
}
.list-group-item {
padding: 8px 0 8px 20px;
border-bottom: 0.5px solid Var(--Divider);
&:hover {
cursor: pointer;
background: Var(--SubPrimary);
}
}
.country-list ul li:last-child {
border: none;
}
/* 搜索导航 */
.list-shortcut {
position: fixed;
z-index: 30;
right: 0;
padding-right: 8px;
top: 45%;
transform: translateY(-45%);
text-align: center;
background: Var(--Theme);
cursor: pointer;
}
.list-shortcut .item {
line-height: 16px;
color: Var(--SubContent);
font-size: 12px;
}
@media (min-width: 640px) {
.list-shortcut {
right: 8px;
}
.list-shortcut .item {
padding: 0 10px;
}
}
</style>
边栏推荐
- Collation of open source protocols of open source frameworks commonly used in Web Development
- EasyGBS网络不稳定情况下重复请求视频拉流问题的优化
- Oracle物理体系结构
- 奔赴山海之前,毕业季一定要做的那些事情
- torch. nn. functional. Interpolate function
- DTD建模
- IPv4 address, subnet mask, gateway
- The intelligent epidemic prevention system provides safety guarantee for the resumption of work and production at the construction site
- [English grammar] Unit1 articles, nouns, pronouns and numerals
- P2433 【深基1-2】小学数学 N 合一
猜你喜欢

GB28181之SIP协议

商业智能BI开发和报表开发有什么本质区别?
![pickle. Load error [attributeerror: can't get attribute 'volatile' on < module '\u main']](/img/98/c4df0747856eda262b82942eedad8f.png)
pickle. Load error [attributeerror: can't get attribute 'volatile' on < module '\u main']

奔赴山海之前,毕业季一定要做的那些事情

Uni app wechat applet one click login to obtain permission function

原生js打造日程表-支持鼠标滚轮滚动选择月份-可以移植到任何框架中

Dom4j parsing XML, XPath retrieving XML

EasyGBS网络不稳定情况下重复请求视频拉流问题的优化

Salesmartly has some tricks for Facebook chat!

Solidity - contract structure - error - ^0.8.4 NEW
随机推荐
Ffmpeg error code
Ffmpeg audio related commands
微信公众号开发相关流程及功能介绍
Wireshark packet analysis TCP, FTP
Dom4j parsing XML, XPath retrieving XML
[info() method in org.slf4j.logger]
Basic knowledge of audio coding and decoding
Enabling "new Chinese enterprises", SAP process automation landing in China
What must be done in graduation season before going to Shanhai
商业智能BI开发和报表开发有什么本质区别?
面试题 16.16. 部分排序-双指针法
音频编解码基础知识
P2433 【深基1-2】小学数学 N 合一
Introduction and installation of crunch, and making password dictionary with crunch
AAAI2020: Real-time Scene Text Detection with Differentiable Binarization
【To .NET】C#集合类源码解析
Extensive reading of the paper [film: visual reasoning with a general condition layer]
After studying 11 kinds of real-time chat software, I found that they all have these functions
ffmpeg常用命令(二)
Solidity - contract structure - error - ^0.8.4 NEW