HTML 元素(主要是文本)能否被选中,是由 user-select
css 属性控制的,若设置为 none
则不可选中,更多属性值参考 MDN.
HTML 页面的默认选中方式是行选择模式,即鼠标从按下到释放中间经过的所有行都会被选中。若要实现列选中模式或是任意选中模式,基本思路是:将表格所有单元格设置为不可选中,在鼠标经过时,将对应的单元格设置可选中,即可实现任意选择的模式。 以上思路有几点需要注意的:
- 浏览器适配:完整的设置不可选中的样式为:
-webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;
- 不可选中的元素:不一定是给单元格
td
设置不可选中,而应该给直接包裹文字的元素设置(如下例中是td
中 class 为cell
的div
)。 - 框选模式:该思路只能直线涂抹选中,即鼠标经过的 cell 会被选中。若想实现画对角线进行框选,还需要添加逻辑。
- 事件:会涉及的事件:
mousedown
,mousemove
,mouseup
。若使用 jquery 则可以很方便的进行事件注册和 DOM操作,若使用 vue 则可以通过自定义指令directives
得到需要操作的 DOM元素。
示例代码(Vue + elementUI):
const selectDisableStyle = `-webkit-user-select:none; -moz-user-select: none; -ms-user-select: none; user-select: none;`
...
directives: {
areaSelect: {
// 在需要自定义选择的元素上添加 v-areaSelect
inserted: (el, binding, vnode) => {
let randIds = new Map()
let mouseDownFlag = false
let mouseUpFlag = false
let cells = []
el.addEventListener('mousedown', function (event) {
mouseDownFlag = true
mouseUpFlag = false
cells = []
el.querySelectorAll('tr').forEach(tr => {
let row = tr.querySelectorAll('td div.cell')
row.length > 0 && cells.push(row)
})
cells.forEach((tdRow, idy) => {
tdRow.forEach((tdCol, idx) => {
const style = tdCol.getAttribute('style')
if (style.indexOf(selectDisableStyle) < 0) {
tdCol.setAttribute('style', style + selectDisableStyle)
}
// 若表格有 rowIndex ,cellIndex 则可不设 id
tdCol.setAttribute('id', `${
idy + 1}_${
idx + 1}`)
})
})
// 选中点击的 cell
removeStyle(event)
})
function mouseMove(evt) {
if (mouseUpFlag || !mouseDownFlag) {
return
}
// 缓存经过的 cell id
randIds.set(evt.target.id, evt.target.id)
// 选中
removeStyle(evt)
}
el.addEventListener('mousemove', mouseMove)
el.addEventListener('mouseup', function (evt)