Detect click on the inner text of the element without wrapping the text in a second element

后端 未结 5 712
星月不相逢
星月不相逢 2020-12-19 21:07

I have a Div which is as big as half of my page using CSS:

CLICK ON THIS TEXT

I am trying to wr

相关标签:
5条回答
  • 2020-12-19 21:17

    Since we cannot listen for events directly on the textNodes themselves, we have to take a more creative path to solving the problem. One thing we can do is look at the coordinates of the click event, and see if it overlaps with a textNode.

    First, we'll need a small helper method to help us track whether a set of coordinates exists within a set of constraints. This will make it easier for us to arbitrarily determine if a set of x/y values are within the a set of dimensions:

    function isInside ( x, y, rect ) {
        return x >= rect.left  && y >= rect.top
            && x <= rect.right && y <= rect.bottom;
    }
    

    This is fairly basic. The x and y values will be numbers, and the rect reference will be an object with at least four properties holding the absolute pixel values representing four corners of a rectangle.

    Next, we need a function for cycling through all childNodes that are textNodes, and determining whether a click event took place above one of them:

    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;
    }
    

    With all of this in place, we can now quickly determine if a textNode was directly below the clicked region, and get the value of that node:

    element.addEventListener( "click", function ( event ) {
        if ( event.srcElement === this ) {
            var clickedNode = textNodeFromPoint( this, event.clientX, event.clientY );
            if ( clickedNode ) {
                alert( "You clicked: " + clickedNode.nodeValue );
            }
        }
    });
    

    Note that the initial condition if ( event.srcElement ) === this allows us to ignore click events originating from nested elements, such as an image or a span tag. Clicks that happen over textNodes will show the parent element as the srcElement, and as such those are the only ones we're concerned with.

    You can see the results here: http://jsfiddle.net/jonathansampson/ug3w2xLc/

    0 讨论(0)
  • 2020-12-19 21:25

    Quick win would be to have

    <div id="bigdiv">
        <span id="text">TEXT HERE</span>
    </div>
    
    Script:
    $('#text').on('click', function() {
       .....
    });
    
    0 讨论(0)
  • 2020-12-19 21:25

    If you want to go straight through HTML, you can use

    <div id="bigdiv" onclick="myFunction();">
    

    and then simply apply the function afterwards in JS:

    function myFunction(){
        //...
    }
    

    EDIT: sorry, if you want the text to be affected, put in <p> around the text or <span> ie.

    <div id="bigdiv">
        <p onclick="myFuncion();"> TEXT </p>
    </div>
    
    0 讨论(0)
  • 2020-12-19 21:29

    Let's alter the content dinamically - I will make the clicking on lala available:

    <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');
        });
    

    See a working example here: http://jsfiddle.net/atrifan/5qc27f9c/

    P.S: sorry for the namings and stuff I am a little bit tired.

    Are you able to do this, is this what you are looking for?

    What the code does: It's making only the text inside the div although the div could have other divs as well, makes only the text that has no HTML container like a div a span a p an a or something like that and alters it adding it in a span and making it available for clicking.

    0 讨论(0)
  • 2020-12-19 21:41

    EDIT - Solution without adding wrapping element
    Doing this without a wrapping element is quite a hassle. I managed to get it to work, however this will only work for one liners that are centered vertically AND horizontally.

    To see the HTML and CSS that goes along with this, see the 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!');
    });
    

    Also, this code can be optimized, since the same calculcation is done multiple times, but I thought that leaving the calculcations there better illustrated what was going on.

    Solution by adding a wrapping element

    If you put a span around the text, then you can add an onClick event handler to the span.

    <div id="bigdiv">
         <span>CLICK ON THIS TEXT</span>
    </div>
    

    jQuery code

    jQuery('#bigdiv span').click(function() {
        jquery(this).remove();
    });
    
    0 讨论(0)
提交回复
热议问题