检测点击元素的内部文本,而不将文本包装在第二个元素中
Detect click on the inner text of the element without wrapping the text in a second element
我有一个div,它和我使用CSS:的页面的一半一样大
<div id="bigdiv">
CLICK ON THIS TEXT
</div>
我正在尝试编写一个javascript或jquery代码,它检测文本上的点击,而不是元素的其余部分。有办法做到这一点吗?
由于我们无法直接在textNodes上侦听事件,因此我们必须采取更具创造性的方法来解决问题。我们可以做的一件事是查看点击事件的坐标,看看它是否与textNode重叠。
首先,我们需要一个小的辅助方法来帮助我们跟踪一组约束中是否存在一组坐标。这将使我们更容易任意确定一组x/y值是否在一组维度内:
function isInside ( x, y, rect ) {
return x >= rect.left && y >= rect.top
&& x <= rect.right && y <= rect.bottom;
}
这是相当基本的。x
和y
值将是数字,而rect
引用将是具有至少四个属性的对象,这些属性保持表示矩形四个角的绝对像素值。
接下来,我们需要一个函数来循环遍历所有作为文本节点的子节点,并确定点击事件是否发生在其中一个子节点之上:
function textNodeFromPoint( element, x, y ) {
var node, nodes = element.childNodes, range = document.createRange();
for ( var i = 0; node = nodes[i], i < nodes.length; i++ ) {
if ( node.nodeType !== 3 ) continue;
range.selectNodeContents(node);
if ( isInside( x, y, range.getBoundingClientRect() ) ) {
return node;
}
}
return false;
}
有了所有这些,我们现在可以快速确定textNode是否在点击区域的正下方,并获得该节点的值:
element.addEventListener( "click", function ( event ) {
if ( event.srcElement === this ) {
var clickedNode = textNodeFromPoint( this, event.clientX, event.clientY );
if ( clickedNode ) {
alert( "You clicked: " + clickedNode.nodeValue );
}
}
});
请注意,初始条件if ( event.srcElement ) === this
允许我们忽略源自嵌套元素(如图像或span标记)的单击事件。单击textNodes会将父元素显示为srcElement
,因此这些是我们唯一关心的元素。
您可以在此处看到结果:http://jsfiddle.net/jonathansampson/ug3w2xLc/
快速获胜将是拥有
<div id="bigdiv">
<span id="text">TEXT HERE</span>
</div>
Script:
$('#text').on('click', function() {
.....
});
让我们日常更改内容-我会让点击lala可用:
<div id="gig">
<div id="smthing">one</div>lala
<div id="else"></div>
</div>
Script:
var htmlText = $('#gig').text(); //the big divs text
var children = $('#gig').children(); //get dom elements so they can be ignored later
$.each(children, function (index, child) {
var txt = $(child).text().trim();
if (txt != '') { //if a child has text in him
htmlText = htmlText.replace(txt, 'xxx'); //replace it in the big text with xxx
}
});
htmlText = htmlText.split("xxx"); //split for xxx make it arrat
var counter = 0; //the part when the text is added
$.each(htmlText, function (i, el) {
htmlText[i] = el.trim();
if (htmlText[i] != "") { //if there is something here than it's my text
htmlText[i] = '<span id="text">' + htmlText[i] + '</span>'; //replace it with a HTML element personalized
counter++; //mark that you have replaced the text
} else { // if there is nothing at this point it means that I have a DOM element here
htmlText[i] = $(children[i - counter])[0].outerHTML; //add the DOM element
}
});
if (children.length >= htmlText.length) { //you might have the case when not all the HTML children were added back
for (var i = htmlText.length - 1; i < children.length; i++) {
htmlText[i + 1] = $(children[i])[0].outerHTML; //add them
}
}
htmlText = htmlText.join(""); //form a HTML markup from the altered stuff
$('#gig').html(htmlText); // replace the content of the big div
$('#text').on('click', function (data) { //add click support
alert('ok');
});
请参阅此处的工作示例:http://jsfiddle.net/atrifan/5qc27f9c/
对不起,我有点累了。
你能做到这一点吗?这就是你想要的吗?
代码的作用:它只生成div中的文本,尽管div也可以有其他div,只生成没有像div这样的HTML容器的文本,并将其添加到span中,使其可用于单击。
EDIT-不添加包装元素的解决方案
在没有包装元素的情况下进行此操作相当麻烦。我设法让它工作起来,但这将只适用于垂直和水平居中的一个行。
要查看附带的HTML和CSS,请参阅jsFiddle:http://jsfiddle.net/v8jbsu3m/3/
jQuery('#bigDiv').click(function(e) {
// Get the x and y offest from the window
margin_top = jQuery(this).offset().top;
margin_left = jQuery(this).offset().left;
// Get the dimensions of the element.
height = jQuery(this).height();
width = jQuery(this).width();
// Retrieve the font_size and remove the px addition
font_size = parseInt(jQuery(this).css('font-size').replace('px', ''));
// Retrieve the position of the click
click_x = e.pageX;
click_y = e.pageY;
// These variables will be used to validate the end result
var in_text_y = false;
var in_text_x = false;
// Determine the click relative to the clicked element
relative_x = click_x - margin_left;
relative_y = click_y - margin_top;
// Determine whether the y-coordinate of the click was in the text
if (relative_y >= (parseFloat(height) / 2) - (parseFloat(font_size) / 2) &&
relative_y <= (parseFloat(height) / 2) + (parseFloat(font_size) / 2))
in_text_y = true;
// This piece of code copies the string and places it in a invisible div
// If this div has the same font styling and no paddings etc... it can
// be used to get the width of the text
text = jQuery(this).text();
text_width = jQuery('#widthTester').html(text).width();
// Determine whether the x-coordinate of the click was in the text
if (relative_x >= (parseFloat(width) / 2) - (parseFloat(text_width) / 2) &&
relative_x < (parseFloat(width) / 2) + (parseFloat(text_width) / 2))
in_text_x = true;
// If the x and y coordinates were both in the text then take action
if (in_text_x && in_text_y)
alert('You clicked the text!');
});
此外,这段代码可以进行优化,因为相同的计算可以多次进行,但我认为将计算留在那里可以更好地说明正在发生的事情
添加包装元素的解决方案
如果在文本周围放置一个跨度,则可以向该跨度添加onClick事件处理程序。
<div id="bigdiv">
<span>CLICK ON THIS TEXT</span>
</div>
jQuery代码
jQuery('#bigdiv span').click(function() {
jquery(this).remove();
});
如果您想直接浏览HTML,可以使用
<div id="bigdiv" onclick="myFunction();">
然后在JS:中简单地应用该函数
function myFunction(){
//...
}
编辑:对不起,如果你想让文本受到影响,请在文本周围放<p>
或<span>
,即
<div id="bigdiv">
<p onclick="myFuncion();"> TEXT </p>
</div>
- 如何在浏览器中选择所有*renderable*文本元素
- 如何使用RaphaelJS将文本元素约束在正方形中
- 使用d3.js删除svg文本元素
- 替换动态生成的文本元素
- Protractor测试:如何设置登录表单中文本元素的值
- 如何获取与提交表单上所选复选框相同行的文本元素
- SVG文本锚点设置使文本元素移动
- Svg文本元素被另一个Svg元素重叠
- Imacros替换文本元素
- Windows 8 上的 Safari 5 反转 SVG 上的所有文本元素
- 运行 PHP 代码以根据文本元素的值从数据库中获取值
- 我想要输入文本元素中的实时更改事件
- 如何使用 jQuery 忽略文本元素上的特定字符
- RaphaelJS中的文本元素不会在触摸设备上拖动
- d3 - 旋转数组中的文本元素
- 如何通过单击复选框将文本元素从输入复制到另一个输入
- .text() 给出元素中的所有文本元素
- 在函数内调用对象文本元素
- 移动文本元素与弧拉斐尔JS
- 编辑文本元素时,将重置后端用户设置