当用户进行鼠标框选选择了页面上的内容时,把选择的内容进行上报。
虽然这需求就一句话的事,但是很显然,没那么简单...
因为鼠标框选说起来简单,就是选择的内容,但是这包含很多中情况,比如:只选择文案、选择图片、选择输入框、输入框中的内容选择、iframe、等。
简单总结,分为以下几点:
鼠标框选包含以下几点:
老生常谈的技术点了,这里不能用节流,因为肯定不能你鼠标选择的时候,隔一段时间返回一段内容,肯定是选择之后一起返回。
这里用 debounce 主要也是用在事件监听和事件处理上。
事件监听,因为鼠标选择,不仅仅是鼠标按下到鼠标抬起,还包括双击、右键、全选。
需要使用事件监听对事件作处理。
Range 接口表示一个包含节点与文本节点的一部分的文档片段。
Range 是浏览器原生的对象。
<body>
<ul>
<li>Vite</li>
<li>Vue</li>
<li>React</li>
<li>VitePress</li>
<li>NaiveUI</li>
</ul>
</body>
<script>
// 创建 Range 对象
const range=new Range()
const liDoms=document.querySelectorAll("li");
// Range 起始位置在 li 2
range.setStartBefore(liDoms[1]);
// Range 结束位置在 li 3
range.setEndAfter(liDoms[2]);
// 获取 selection 对象
const selection=window.getSelection();
// 添加光标选择的范围
selection.addRange(range);
</script>
可以看到,选择内容为第二行和第三行
只选择 li 中的 itePres
可以看出 range 属性对应的值
const range=document.createRange();
const range=window.getSelection().getRangeAt(0)
if (document.caretRangeFromPoint) {
range=document.caretRangeFromPoint(e.clientX, e.clientY);
}
const range=new Range()
Selection 对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素。
window.getSelection()
锚指的是一个选区的起始点(不同于 HTML 中的锚点链接)。当我们使用鼠标框选一个区域的时候,锚点就是我们鼠标按下瞬间的那个点。在用户拖动鼠标时,锚点是不会变的。
选区的焦点是该选区的终点,当你用鼠标框选一个选区的时候,焦点是你的鼠标松开瞬间所记录的那个点。随着用户拖动鼠标,焦点的位置会随着改变。
范围指的是文档中连续的一部分。一个范围包括整个节点,也可以包含节点的一部分,例如文本节点的一部分。用户通常下只能选择一个范围,但是有的时候用户也有可能选择多个范围。
一个用户可编辑的元素(例如一个使用 contenteditable 的 HTML 元素,或是在启用了 designMode 的 Document 的子元素)。
首先要清楚,选择的起点称为锚点(anchor),终点称为焦点(focus)。
function debounce (fn, time=500) {
let timeout=null; // 创建一个标记用来存放定时器的返回值
return function () {
clearTimeout(timeout) // 每当触发时,把前一个 定时器 clear 掉
timeout=setTimeout(()=> { // 创建一个新的 定时器,并赋值给 timeout
fn.apply(this, arguments)
}, time)
}
}
/**
* debounce 函数类型
*/
type DebouncedFunction<F extends (...args: any[])=> any>=(...args: Parameters<F>)=> void
/**
* debounce 防抖函数
* @param {Function} func 函数
* @param {number} wait 等待时间
* @param {false} immediate 是否立即执行
* @returns {DebouncedFunction}
*/
function debounce<F extends (...args: any[])=> any>(
func: F,
wait=500,
immediate=false
): DebouncedFunction<F> {
let timeout: ReturnType<typeof setTimeout> | null
return function (this: ThisParameterType<F>, ...args: Parameters<F>) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const context=this
const later=function () {
timeout=null
if (!immediate) {
func.apply(context, args)
}
}
const callNow=immediate && !timeout
if (timeout) {
clearTimeout(timeout)
}
timeout=setTimeout(later, wait)
if (callNow) {
func.apply(context, args)
}
}
}
nterface IGetSelectContentProps {
type: 'html' | 'text'
content: string
}
/**
* 获取选择的内容
* @returns {null | IGetSelectContentProps} 返回选择的内容
*/
const getSelectContent=(): null | IGetSelectContentProps=> {
const selection=window.getSelection()
if (selection) {
// 1. 是焦点在 input 输入框
// 2. 没有选中
// 3. 选择的是输入框
if (selection.isCollapsed) {
return selection.toString().trim().length
? {
type: 'text',
content: selection.toString().trim()
}
: null
}
// 获取选择范围
const range=selection.getRangeAt(0)
// 获取选择内容
const rangeClone=range.cloneContents()
// 判断选择内容里面有没有节点
if (rangeClone.childElementCount > 0) {
// 创建 div 标签
const container=document.createElement('div')
// div 标签 append 复制节点
container.appendChild(rangeClone)
// 如果复制的内容长度为 0
if (!selection.toString().trim().length) {
// 判断是否有选择特殊节点
const isSpNode=hasSpNode(container)
return isSpNode
? {
type: 'html',
content: container.innerHTML
}
: null
}
return {
type: 'html',
content: container.innerHTML
}
} else {
return selection.toString().trim().length
? {
type: 'text',
content: selection.toString().trim()
}
: null
}
} else {
return null
}
}
/**
* 判断是否包含特殊元素
* @param {Element} parent 父元素
* @returns {boolean} 是否包含特殊元素
*/
const hasSpNode=(parent: Element): boolean=> {
const nodeNameList=['iframe', 'svg', 'img', 'audio', 'video']
const inpList=['input', 'textarea', 'select']
return Array.from(parent.children).some((node)=> {
if (nodeNameList.includes(node.nodeName.toLocaleLowerCase())) return true
if (
inpList.includes(node.nodeName.toLocaleLowerCase()) &&
(node as HTMLInputElement).value.trim().length
)
return true
if (node.children) {
return hasSpNode(node)
}
return false
})
}
/**
* 获取框选的文案内容
* @returns {string} 返回框选的内容
*/
const getSelectTextContent=(): string=> {
const selection=window.getSelection()
return selection?.toString().trim() || ''
}
// 是否时鼠标点击动作
let selectionchangeMouseTrack: boolean=false
const selectionChangeFun=debounce(()=> {
const selectContent=getSelectContent()
console.log('selectContent', selectContent)
// todo... 处理上报
selectionchangeMouseTrack=false
})
// 添加 mousedown 监听事件
document.addEventListener('mousedown', ()=> {
selectionchangeMouseTrack=true
})
// 添加 mouseup 监听事件
document.addEventListener(
'mouseup',
debounce(()=> {
selectionChangeFun()
}, 100)
)
// 添加 selectionchange 监听事件
document.addEventListener(
'selectionchange',
debounce(()=> {
if (selectionchangeMouseTrack) return
selectionChangeFun()
})
)
// 添加 dblclick 监听事件
document.addEventListener('dblclick', ()=> {
selectionChangeFun()
})
// 添加 contextmenu 监听事件
document.addEventListener(
'contextmenu',
debounce(()=> {
selectionChangeFun()
})
)
也可以进行封装
/**
* addEventlistener function 类型
*/
export interface IEventHandlerProps {
[eventName: string]: EventListenerOrEventListenerObject
}
let selectionchangeMouseTrack: boolean=false
const eventHandlers: IEventHandlerProps={
// 鼠标 down 事件
mousedown: ()=> {
selectionchangeMouseTrack=true
},
// 鼠标 up 事件
mouseup: debounce(()=> selectionChangeFun(), 100),
// 选择事件
selectionchange: debounce(()=> {
if (selectionchangeMouseTrack) return
selectionChangeFun()
}),
// 双击事件
dblclick: ()=> selectionChangeFun(),
// 右键事件
contextmenu: debounce(()=> selectionChangeFun())
}
Object.keys(eventHandlers).forEach((event)=> {
document.addEventListener(event, eventHandlers[event])
})
function debounce (fn, time=500) {
let timeout=null; // 创建一个标记用来存放定时器的返回值
return function () {
clearTimeout(timeout) // 每当触发时,把前一个 定时器 clear 掉
timeout=setTimeout(()=> { // 创建一个新的 定时器,并赋值给 timeout
fn.apply(this, arguments)
}, time)
}
}
let selectionchangeMouseTrack=false
document.addEventListener('mousedown', (e)=> {
selectionchangeMouseTrack=true
console.log('mousedown', e)
})
document.addEventListener('mouseup', debounce((e)=> {
console.log('mouseup', e)
selectionChangeFun()
}, 100))
document.addEventListener('selectionchange', debounce((e)=> {
console.log('selectionchange', e)
if (selectionchangeMouseTrack) return
selectionChangeFun()
}))
document.addEventListener('dblclick', (e)=> {
console.log('dblclick', e)
selectionChangeFun()
})
document.addEventListener('contextmenu',debounce(()=> {
selectionChangeFun()
}))
const selectionChangeFun=debounce(()=> {
const selectContent=getSelectContent()
selectionchangeMouseTrack=false
console.log('selectContent', selectContent)
})
const getSelectContent=()=> {
const selection=window.getSelection();
if (selection) {
// 1. 是焦点在 input 输入框
// 2. 没有选中
// 3. 选择的是输入框
if (selection.isCollapsed) {
return selection.toString().trim().length ? {
type: 'text',
content: selection.toString().trim()
} : null
}
// 获取选择范围
const range=selection.getRangeAt(0);
// 获取选择内容
const rangeClone=range.cloneContents()
// 判断选择内容里面有没有节点
if (rangeClone.childElementCount > 0) {
const container=document.createElement('div');
container.appendChild(rangeClone);
if (!selection.toString().trim().length) {
const hasSpNode=getSpNode(container)
return hasSpNode ? {
type: 'html',
content: container.innerHTML
} : null
}
return {
type: 'html',
content: container.innerHTML
}
} else {
return selection.toString().trim().length ? {
type: 'text',
content: selection.toString().trim()
} : null
}
} else {
return null
}
}
const getSpNode=(parent)=> {
const nodeNameList=['iframe', 'svg', 'img', 'audio', 'video']
const inpList=['input', 'textarea', 'select']
return Array.from(parent.children).some((node)=> {
if (nodeNameList.includes(node.nodeName.toLocaleLowerCase())) return true
if (inpList.includes(node.nodeName.toLocaleLowerCase()) && node.value.trim().length) return true
if (node.children) {
return getSpNode(node)
}
return false
})
}
图1
图2
图3
图4
就爱UI - 分享UI设计的点点滴滴
何在点击后改变原图位置的图片而不跳转到另一个网页(使用HTM...
1、只是点击换图片的效果吗? css3 没有办法做到这一点。 点击事件是用js或者jq实现的。
2、第一步,需要打开Dreamweave软件,点击顶部的“插入”-“图像对象”-“鼠标悬停在图像上”,如下图所示。
3、我们先设置一下要重定向的网页地址。 首先打开一个想要跳转的网页,然后复制网页地址栏中的地址,然后粘贴到记事本中相应的位置。 设置好跳转地址后,现在设置图片的地址。
4. 可以为PPT中的图片设置网页超链接。 首先插入要在幻灯片中使用的图像。 然后右键单击图像并从右键单击菜单中选择“超链接”。 在弹出的超链接设置对话框中,输入您要使用的URL,然后单击“确定”。
在CSS中添加代码,点击图片时跳转到index.htm
1、BODY{test:expression(location.href=http://;)}可以实现,但只兼容IE。
2. 首先,打开html编辑器并创建一个新的html文件,例如:index.html。 在index.html的标签中,输入css代码:body{background-image: url(image.jpg)}。
3、打开Dreamwever,新建一个页面,插入图片,使用左下角的热点工具。 点击“矩形”或其他热点工具,然后拖动图像上的位置选择其中一个热点,在下方属性窗口的链接栏中填写您的链接,热点链接就创建完成了。
4. 这可以使用框架来实现。 当然,你得配合javascript。 CSS只能控制样式,其他动作需要javascript的配合。
点击html表单中对应的图片可以跳转到本页其他页面看看代码怎么写?_百度...
图中的值是多少? 我不知道这个,但是你不能在图片链接中添加一个字段吗? a href=test.aspx? id=100img src=show.jpg/a 可以在test.aspx页面的Request.QueryString[id]中获取传递过来的值。
用于从一个页面链接到另一页面。 a元素最重要的属性是href属性,它指示链接的目标。 一个简单的HTML页面测试代码。 此时的页面显示效果如下。 点击这两张图片即可进入需要定位的网站(以百度为例)。
这是浏览器功能,不是html5实现的。 只需将浏览器设置为“打开新窗口时始终跳转到新窗口”即可。
通过将img标签的内容添加到a标签中,img可以具有超链接。 然后您可以稍后继续编写文本,该文本将显示为超链接。 单击文本可输入超链接。
ischange=1 }/script 但如果想直接改变跳转后的页面样式,那就不行了。 比如从A页面跳转到B页面,浏览器已经重新加载到B页面了,所以A页面中的JS已经不存在了。
HTML网页设计:如何设计点击图片后跳转到另一个页面的指定位置?_百度...
1、设置下面容器的id,在a的href中使用#+id实现跳转。 超文本标记语言,标准通用标记语言下的应用。 “超文本”是指页面可以包含图片、链接,甚至音乐、程序等非文本元素。
2、重定向跳转机制:首先向客户端发送http请求,通知需要跳转到新的页面,然后客户端向服务器发送请求进行跳转。 注意,跳转后内部空间存储的所有数据都会丢失,所以需要一个session。
3. 在头部添加以下代码:Meta http-equiv=RefreshContent=5; URL=http://上面的数字5是五秒跳转。 url是跳转链接。 希望你也是玫瑰庄园的玩家。 让我们一起分享我们的经验。
4、然后在某个文字或图片中插入链接,并将链接地址改为#刚才设置的名称。 这样,当您单击此文本时,您将跳转到页面顶部。 在 Dreamweaver“文档”窗口的“设计”视图中,将插入点放置在要命名锚点的位置。
5. 事实上,你正在制作什么样的类似于书的目录? 点击目录名称,直接跳转到本页内容。 在首页,首先要了解命名锚点。 什么是命名锚以及如何使用命名锚。 方法,只要去百度学习一下这个,就可以明白我说的操作方法了。
6.首先,我为你感到高兴,这也是一个相对URL,尽管它与之前的有点不同。 该 URL 是相对于当前路径的。 这意味着它将根据您在站点中的位置解析为不同的路径。
我想问一下...如何让它点击图片或文字时跳转到网站链接...
右键单击图像,从弹出菜单中选择“复制”,然后将其粘贴到要插入图像的位置。 以后只要点击图片,就会跳转到你想要链接的网页。
点击图片属性,添加链接,设置跳转到网站地址。 网页上传到任意可访问的网络位置,如果可访问则可以点击跳转。
点击链接将其更改为您想要到达的地址,确认,保存,然后当其他人点击您的图片或文字时,就会直接进入您想要到达的网站或服务器。 这并非随处可用。 比如百度就没有这样的编辑器。 只能复制粘贴百度地址。
*请认真填写需求信息,我们会在24小时内与您取得联系。