当前位置:网站首页>自定义插入页面标签以及实现类似通讯录的首字母搜索
自定义插入页面标签以及实现类似通讯录的首字母搜索
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-pinyin
import 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>
边栏推荐
猜你喜欢
Summary of SQL query de duplication statistics methods
[Mori city] random talk on GIS data (I)
商业智能BI开发和报表开发有什么本质区别?
数字化转型企业成功的关键,用数据创造价值
Why has instagram changed from a content sharing platform to a marketing tool? How do independent sellers use this tool?
What is the essential difference between Bi development and report development?
Dom4j parsing XML, XPath retrieving XML
奔赴山海之前,毕业季一定要做的那些事情
Task: denial of service DOS
Regular expression =regex=regular expression
随机推荐
Interview questions for audio and video positions in Dachang -- today's headline
Compile ffmpeg source code with msys+vs2019 under win10
正则表达式=Regex=regular expression
Brpc understanding
Proxy in ES6
GetMessage底层机制分析
Opencv video quality detection -- sharpness detection
[to.Net] C set class source code analysis
采集抖音视频
面试题 16.16. 部分排序-双指针法
原生js打造日程表-支持鼠标滚轮滚动选择月份-可以移植到任何框架中
Contos 7 set up SFTP to create users, user groups, and delete users
Ffmpeg audio related commands
Solution and summary of Nacos startup failure
精耕渠道共謀發展 福昕攜手偉仕佳傑開展新產品培訓大會
【To .NET】C#集合类源码解析
Oracle物理体系结构
MySQl的基本使用
【英语语法】Unit1 冠词、名词、代词和数词
Regular expression =regex=regular expression