使用其所有属性复制元素 - 更新

时间:2015-03-18 11:55:30

标签: javascript jquery event-delegation

更新4 嗨@Paul。我想我知道发生了什么,我只是不知道如何解决它。 我在touchstart中的警报导致应用程序停止,当我点击OK时,touchend事件已经过去了。我删除了touchstart Alert并且touchend警报工作,istouch值为" true"。 我添加了一些警报,看看它失败的地方,发现math.abs(e.pageX)不是一个数字 - 警报显示NaN。此外,$ snd.data(' tx')显示为" Undefined"。因为这个vx也被报道为NaN。 ds的值显示数值。

所以,我认为问题是$ snd在.on(touchstart ...)中定义,并且不能从.on(touchend ...)中引用。这可能是变量的范围问题吗?至少复制到搜索结果页面的原始术语和搜索结果显示相同的症状,因此触发了onclick处理程序,这是一个很好的进展。下面是点击处理程序的当前版本,你能让我知道我应该改变什么,我对js很新,这对我来说真的很有挑战性。再次感谢。

$(".wrapper")  //i'm attaching all event handlers to body, so everything with .spanish class will have them attached
        .on("click", ".spanish", function(e) {
            e.preventDefault();
        })
        .on("touchstart", ".spanish", function(e) {
            if (istouch) {
                var $snd = $(this);
                $snd.data({
                    tstart: new Date().getTime(),
                    tx: e.pageX,
                    ty: e.pageY
                });
            }
        })
        .on("touchend", ".spanish", function(e) {
            if (istouch) {
                alert("touchend detected istouch val = " + istouch); // shows istouch = true
                var $snd = $(this);
                var snd = this;
                var ds = $snd.data('tstart');
                alert("ds = " + ds); // shows a numeric value
                if (!ds) {
                    return;
                }
                alert("math.abs e.pagex = " + Math.abs(e.pageX)); // shows NaN
                alert("$snd.data('tx') = " + $snd.data('tx')); // shows "undefined"
                var vx = Math.abs(e.pageX - $snd.data('tx'));
                alert("vx = " + vx); // shows NaN
                var vy = Math.abs(e.pageY - $snd.data('ty'));
                Math.abs(e.pageY - $snd.data('ty'));
                alert("vx= "+ vx +" vy= " + vy + " ds = " + ds);
                if (vx < 20 && vy < 20 && new Date().getTime() - ds < 400) {
                    alert("tap detected and about to call playstop");
                    playstop.apply(snd, [e]);
                    $snd.data({
                        tstart: null,
                        tx: null,
                        ty: null
                    });
                }
            }
        });
    });

更新3 嗨@Paul,我对您的代码做了一些小改动,我将点击处理程序应用到了.wrapper div而不是Body,因为那里有一个主页,链接停止了工作当我应用您的更新时,主页链接现在可以正常工作。 每个英语短语都可以翻译成1,2或3个西班牙语短语,所有西班牙语短语都包含在任何给定英语div的单个.wrapper div中。

以下是一个示例,显示3个英语div及其西班牙语翻译。我总共有800多个英语短语。当用户搜索这些短语时,完整的英语&#39; div,包括wrapper div,应该被复制到搜索结果页面,看起来它正在被正确复制。

<div class="english">
      How old are you?
   <div class="wrapper">
       <a class="formal spanish" data-ignore="true" href="ageHowOldF.mp3">F: Cuántos años tiene?</a>
       <a class="informal spanish" data-ignore="true" href="ageHowOldI.mp3">I: Cuántos años tienes?</a>
   </div> <!-- End .wrapper -->
</div> <!-- End English -->

<div class="english">
       When were you born?
    <div class="wrapper">
        <a class="formal spanish" data-ignore="true" href="ageWhenBornF.mp3">F: Cuando nació?</a>
        <a class="informal spanish" data-ignore="true" href="ageWhenBornI.mp3">I: Cuando naciste?</a>
    </div> <!-- End .wrapper -->
</div> <!-- End English -->     

<div class="english">
       How old was he?
    <div class="wrapper">
        <a class="spanish" data-ignore="true" href="ageHowOldMale.mp3">Cuántos años ten&iacute;a &eacute;l?</a>
    </div> <!-- End .wrapper -->
</div> <!-- End English -->

更新2 @Paul,如我在回复下方的评论中所述,请参阅下面的完整文档准备脚本以及您的更改和searchApp脚本,该脚本将所选元素匹配/复制到空div。

这是文档就绪脚本:

 jQuery(function($){
            var highlight = 'yellow', origcolor = 'transparent', curSnd = null,
            istouch = !!('ontouchstart' in window) || !!('ontouchstart' in document.documentElement) || !!window.ontouchstart || (!!window.Touch && !!window.Touch.length) || !!window.onmsgesturechange || (window.DocumentTouch && window.document instanceof window.DocumentTouch);
        function playstop(e){
            alert("Start playstop");
            e.preventDefault();
            var $this = $(this);
            if(curSnd && curSnd.sound){
                if(this === curSnd.tag){
                    curSnd.sound.stop();
                    return;
                }
                curSnd.sound.stop();
            }
                    $this.stop(true, true).css({backgroundColor: highlight});
            var filename = this.href.substring(this.href.lastIndexOf('/')), myMedia = new Media(
                this.href, 
                function() {
                    myMedia && myMedia.release();
                    curSnd = myMedia = null;
                    $this.stop(true, true).animate({backgroundColor: origcolor}, 500);
                },
                function(e) {
                    myMedia && myMedia.release();
                    curSnd = myMedia = null;
                    $this.stop(true, true).animate({backgroundColor: origcolor}, 500);
                    window.console && console.log ("Audio play error - " + filename + "\ncode: " + e.code + "\nmessage: " + e.message);
                }
            );
            alert("Start playing sound")
            curSnd = {tag: this, sound: myMedia}; 
            curSnd.sound.play();
        } // End playstop
    $("body")  //i'm attaching all event handlers to body, so everything with .spanish class will have them attached
            .on("click", ".spanish", function(e) {
                e.preventDefault();
            })
            .on("touchstart", ".spanish", function(e) {
                if (istouch) {
                    var $snd = $(this);
                    $snd.data({
                        tstart: new Date().getTime(),
                        tx: e.pageX,
                        ty: e.pageY
                    });
                }
            })
            .on("touchend", ".spanish", function(e) {
                if (istouch) {
                    var $snd = $(this);
                    var snd = this;
                    var ds = $snd.data('tstart');
                    if (!ds) {
                        return;
                    }
                    var vx = Math.abs(e.pageX - $snd.data('tx'));
                    var vy = 'enter code here';
                    Math.abs(e.pageY - $snd.data('ty'));
                    if (vx < 20 && vy < 20 && new Date().getTime() - ds < 400) {
                        playstop.apply(snd, [e]);
                        $snd.data({
                            tstart: null,
                            tx: null,
                            ty: null
                        });
                    }
                }
            });
        });

</script>

这是搜索/复制脚本

function searchApp() {
    var $searchTerm = $(".searchField").val().toLowerCase(); // Convert search term to all lower case
    var $searchResults = "";
    document.getElementById("searchResultsDiv").innerHTML = "";
    $(".english").each(function () {
        if ($(this).text().toLowerCase().match($searchTerm)) { // If this specific '.english' class 
    $(this).clone(true, true).appendTo("#searchResultsDiv");
        }
    });
}; // /searchApp

更新

我认为我已经对导致我问题的区域进行了本地化 - 这是当我将一个元素复制到搜索结果页面中的空div时,当我点击时,原始元素中的事件监听器没有被触发搜索结果页面。

以下是正在复制的英语/西班牙语元素示例:

<div class="english">
    How old are you?
    <div class="wrapper">
        <a class="formal spanish" data-ignore="true" 
            href="ageHowOldF.mp3">F: Cuántos años tiene?</a>
        <a class="informal spanish" data-ignore="true"
            href="ageHowOldI.mp3">I: Cuántos años tienes?</a>
    </div> <!-- End .wrapper -->
</div> <!-- End English -->

这里是在原始元素与英文文本匹配时复制原始元素的代码:

if ($(this).text().toLowerCase().match($searchTerm)) {
    $(this).clone(true, true).appendTo("#searchResultsDiv");
}

英语/西班牙语短语正确显示在搜索结果页面上,但不响应点击。我向事件监听器添加了一条警告消息,当我点击搜索页面时这不会显示,但是当我点击原始页面时会显示。

我真的很感激您的任何建议。感谢。

END UPDATE

我有一个智能手机应用程序是一个会说英语/西班牙语的短语,当用户点击一个西班牙语短语时,jQuery播放一个短mp3文件并且这个工作正常,jQuery播放器在文档就绪时分配。我现在已经创建了一个搜索功能,可以将所有匹配的英语/西班牙语短语复制到搜索结果页面,这也可以正常工作。

我遇到的问题是,当用户点击搜索结果页面上的任何西班牙语短语时,应用程序会调用系统声音播放器(我认为)而不是jQuery声音播放器和系统声音播放器显示一个音频控制栏,我不希望用户看到它。

我已经尝试了我能想到的一切,基本上遵循两种方法:

  1. 复制元素的所有属性
  2. 将onclick事件分配给搜索结果页面中的父元素
  3. 这些方法都没有解决这个问题 - 至少我所知道的没有解决这个问题。

    我对js / jQuery很新,所以请原谅我,如果我错过了一些非常明显的东西。

    请在下面找到:

    1. 英语/西班牙语元素示例,有几百个 完全是这些。如果是,则将它们复制到搜索结果页面 搜索匹配英语短语/单词
    2. 将点击处理程序分配给的文档就绪脚本 西班牙语短语
    3. 查找匹配元素并将其复制到的搜索功能 搜索结果页
    4. 示例英语/西班牙语元素

      <div class="english">
          How old are you?
          <div class="wrapper">
              <a class="formal spanish" data-ignore="true" 
                  href="ageHowOldF.mp3">F: Cuántos años tiene?</a>
              <a class="informal spanish" data-ignore="true"
                  href="ageHowOldI.mp3">I: Cuántos años tienes?</a>
          </div> <!-- End .wrapper -->
      </div> <!-- End English -->
      

      文档就绪脚本

      这也可以改变背景颜色,检查水龙头和滑动等等。

      jQuery(function($) {
          var highlight = 'yellow',
              origcolor = 'transparent',
              curSnd = null,
              istouch = !!('ontouchstart' in window) || !!('ontouchstart' in document.documentElement) || !!window.ontouchstart || (!!window.Touch && !!window.Touch.length) || !!window.onmsgesturechange || (window.DocumentTouch && window.document instanceof window.DocumentTouch);
      
          function playstop(e) {
                  e.preventDefault();
                  var $this = $(this);
                  if (curSnd && curSnd.sound) {
                      if (this === curSnd.tag) {
                          curSnd.sound.stop();
                          return;
                      }
                      curSnd.sound.stop();
                  }
                  $this.stop(true, true).css({
                      backgroundColor: highlight
                  });
                  var filename = this.href.substring(this.href.lastIndexOf('/')),
                      myMedia = new Media(
                          this.href,
                          function() {
                              myMedia && myMedia.release();
                              curSnd = myMedia = null;
                              $this.stop(true, true).animate({
                                  backgroundColor: origcolor
                              }, 500);
                          },
                          function(e) {
                              myMedia && myMedia.release();
                              curSnd = myMedia = null;
                              $this.stop(true, true).animate({
                                  backgroundColor: origcolor
                              }, 500);
                              window.console && console.log("Audio play error - " + filename + "\ncode: " + e.code + "\nmessage: " + e.message);
                          }
                      );
                  curSnd = {
                      tag: this,
                      sound: myMedia
                  };
                  curSnd.sound.play();
              } // End playstop
          $('.spanish').click(function(e) {
              e.preventDefault();
          }).each(function(i, snd) {
              if (istouch) {
                  var $snd = $(snd);
                  snd.addEventListener('touchstart', function(e) {
                      $snd.data({
                          tstart: new Date().getTime(),
                          tx: e.pageX,
                          ty: e.pageY
                      });
                  }, false);
                  snd.addEventListener('touchend', function(e) {
                      var ds = $snd.data('tstart');
                      if (!ds) {
                          return;
                      }
                      var vx = Math.abs(e.pageX - $snd.data('tx')),
                          vy = `enter code here`
                      Math.abs(e.pageY - $snd.data('ty'));
                      if (vx < 20 && vy < 20 && new Date().getTime() - ds < 400) {
                          playstop.apply(snd, [e]);
                          $snd.data({
                              tstart: null,
                              tx: null,
                              ty: null
                          });
                      }
                  }, false);
              }
          });
      });
      

      搜索功能

      function searchApp() {
          // Convert search term to all lower case
          var $searchTerm = $(".searchField").val().toLowerCase();
          var $searchResults = "";
          document.getElementById("searchResultsDiv").innerHTML = "";
          $(".english").each(function() {
              // If this specific '.english' class 
              if ($(this).text().toLowerCase().match($searchTerm)) {
                  // Append all HTML contents of '.english' div into $searchResults variable 
                  $searchResults += $(this)[0].outerHTML;
              }
          });
          // Within searchResultsDiv tag, write $searchResults variable to HTML
          $("#searchResultsDiv").html($searchResults);
      }; // /searchApp
      

      更新5 我将警报更改为console.log。第一项测试是点击搜索结果页面上已存在的西班牙语短语。以下是控制台日志

      touchstart $snd = [object Object] index.html:67
      touchend detected istouch val = true index.html:72
      touchend ds = 1427885920974 index.html:76
      pageX in touchend = undefined index.html:77
      touchend math.abs e.pagex = NaN index.html:82
      touchend $snd.data('tx') = undefined index.html:83
      touchend vx = NaN index.html:85
      touchend vx= NaN vy= NaN ds = 1427885920974 
      

      第二项测试是点击其中一个创建的西班牙元素。这是日志

      touchstart $snd = [object Object] index.html:67
      touchend detected istouch val = true index.html:72
      touchend ds = 1427885920974 index.html:76
      pageX in touchend = undefined index.html:77
      touchend math.abs e.pagex = NaN index.html:82
      touchend $snd.data('tx') = undefined index.html:83
      touchend vx = NaN index.html:85
      touchend vx= NaN vy= NaN ds = 1427885920974 
      

      这些都没有发出声音。下面是touchstart和touchend处理程序脚本,显示我添加console.log语句的位置。

      .on("touchstart", ".spanish", function(e) {
          if (istouch) {
          $snd = $(this);
          $snd.data({
               tstart: new Date().getTime(),
               tx: e.pageX,
               ty: e.pageY
                      });
          console.log("touchstart $snd = " + $snd);
              }
          })
      
       .on("touchend", ".spanish", function(e) {
           if (istouch) {
          console.log("touchend detected istouch val = " + istouch);
               var $snd = $(this);
               var snd = this;
               var ds = $snd.data('tstart');
          console.log("touchend ds = " + ds); 
          console.log("pageX in touchend = " + $snd.data('tx'));
          if (!ds) {
                          return;
                      }
      console.log("touchend math.abs e.pagex = " + Math.abs(e.pageX)); 
          console.log("touchend $snd.data('tx') = " + $snd.data('tx'));
               var vx = Math.abs(e.pageX - $snd.data('tx'));
          console.log("touchend vx = " + vx); 
               var vy = Math.abs(e.pageY - $snd.data('ty'));
               Math.abs(e.pageY - $snd.data('ty'));
          console.log("touchend vx= "+ vx +" vy= " + vy + " ds = " + ds);
               if (vx < 20 && vy < 20 && new Date().getTime() - ds < 400) {
          console.log("touchend tap detected and about to call playstop");
               playstop.apply(snd, [e]);
               $snd.data({
                     tstart: null,
                     tx: null,
                     ty: null
                          });
                      }
                  }
              });
          });
      

1 个答案:

答案 0 :(得分:1)

代码中的主要问题是您将事件处理程序添加到一组对象,而不是将它们重新添加到克隆的对象中。删除事件会更适合您。将您的${'.spanish') eventHandlers更改为:

$("body")  //i'm attaching all event handlers to body, so everything with .spanish class will have them attached
        .on("click", ".spanish", function(e) {
            e.preventDefault();
        })
        .on("touchstart", ".spanish", function(e) {
            if (istouch) {
                var $snd = $(this);
                $snd.data({
                    tstart: new Date().getTime(),
                    tx: e.pageX,
                    ty: e.pageY
                });
            }
        })
        .on("touchend", ".spanish", function(e) {
            if (istouch) {
                var $snd = $(this);
                var snd = this;
                var ds = $snd.data('tstart');
                if (!ds) {
                    return;
                }
                var vx = Math.abs(e.pageX - $snd.data('tx'));
                var vy = 'enter code here';
                Math.abs(e.pageY - $snd.data('ty'));
                if (vx < 20 && vy < 20 && new Date().getTime() - ds < 400) {
                    playstop.apply(snd, [e]);
                    $snd.data({
                        tstart: null,
                        tx: null,
                        ty: null
                    });
                }
            }
        });

基本上,我只是将你的函数分成两个独立的jquery事件委托函数。所有这些处理程序都将附加到.spanish容器中与选择器body匹配的所有内容。您可以对其进行修改以进行一些优化(如果您有一些div作为所有这些元素的包装器。)

jQuery $.on函数可以将一些事件(在他的案例中为touchstarttouchendclick)绑定到当前现有元素,以及将来创建的元素,例如,在克隆元素的过程中 - 它可能是最适合您的解决方案。

在此处详细了解:http://api.jquery.com/on/