思路
考虑到是移动端的滑动选中功能,所以刚开始的思路是直接使用移动端自带的选中功能。但是和产品沟通需求后,很明显不是他想要的效果,是实现一个类似微信图文识别选中文本的功能。
初始思路是:
- 使用 touch 的事件监听滑动
- 通过当前位置获取对应元素,给对应元素添加上样式
- 需要获取文本时,遍历元素来获取
但是在实现的时候还有一些细节需要考虑,比如如何取消选中。
实现
<template>
<div class="copy-div">
<!-- selectstart return false 阻止默认的选中事件-->
<div class="copy-text" @selectstart="()=>{return false}">
<span v-for="(item, index) in content" class="text-span" :key="index" :id="index"
@touchstart="highlight" @touchmove="highlight"
@touchend="highlight">{{ item }}</span>
</div>
</div>
</template>
<script>
// 用于记录当前元素的更改时间
const updateObj = {};
export default {
props: {},
data() {
return {
copyText: '',
content: 'hello 欢迎来到我的世界!!!!'
};
},
computed: {},
created() {
},
mounted() {
},
methods: {
// 标识高亮
highlight(e) {
let currentTime = new Date().getTime();
// 获取当前位置元素
let element = document.elementFromPoint(e.changedTouches[0].pageX, e.changedTouches[0].pageY);
if (element) {
let classList = element.classList || [];
let id = element.id;
let updTime = updateObj[id] || 0;
let className = '';
// 要确保选中的是目标元素
// touch 事件可能多次触发,如果修改时间距离当前事件100ms之后才允许再次修改
if (classList.contains('text-span') && currentTime - updTime > 800) {
// 取消选中
if (classList.contains('highlight-wrap')) {
className = 'text-span';
} else {
// 选中
className = 'text-span highlight-wrap';
}
element.setAttribute('class', className);
}
// 更新当前元素的修改事件
updateObj[id] = currentTime;
}
this.$nextTick(() => {
this.getSelectText();
});
},
// 全选/取消全选
// state true 取消全选,false全选
selectAll(state) {
let dom = document.getElementsByClassName('copy-text')[0];
let elements = dom.children;
let currentTime = new Date().getTime();
if (elements) {
elements.forEach(el => {
el.setAttribute('class', state ? 'text-span' : 'text-span highlight-wrap');
updateObj[el.id] = currentTime;
});
}
this.getSelectText();
},
// 获取选中的内容
getSelectText() {
let dom = document.getElementsByClassName('copy-text')[0];
let elements = dom.children;
this.copyText = '';
if (elements) {
elements.forEach(el => {
if (el.classList.contains('highlight-wrap')) {
this.copyText += el.innerHTML;
}
});
}
},
},
};
</script>
<style lang="less" scoped>
.copy-div {
// 阻止默认选中事件
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
.copy-text {
font-size: 14px;
font-weight: 400;
color: rgba(31, 34, 38, 0.8);
line-height: 26px;
}
}
// 选中样式
.highlight-wrap {
background: #B3D7FF;
}
</style>
遗留问题
虽然基本的实现了完整的功能,但是还有一些问题:
- 滑动过快时,可能可能有一些元素应该选中,但实际上并未选中
- 频繁遍历元素
如果大家有什么好的方案欢迎讨论。