Копирование элемента со всеми его атрибутами - Обновление
ОБНОВЛЕНИЕ 4 Привет @Paul. Я думаю, что знаю, что происходит, я просто не знаю, как это исправить. Оповещение, которое было у меня в touchstart, приводило к остановке приложения, и когда я нажимал ОК, событие 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 испанские фразы, все испанские фразы содержатся в одном.wrapper div для любого данного английского div.
Ниже приведен пример, показывающий 3 английских дива с их переводом на испанский. У меня 800+ английских фраз в целом. Когда пользователь ищет эти фразы, полный "английский" 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ía é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");
}
Английские / испанские фразы правильно отображаются на странице результатов поиска, но не реагируют на нажатие. Я добавил предупреждающее сообщение в прослушиватель событий, и оно не отображается, когда я нажимаю на страницу поиска, но отображается, когда я нажимаю на исходную страницу.
Буду очень признателен за любые ваши предложения. Благодарю.
КОНЕЦ ОБНОВЛЕНИЯ
У меня есть приложение для смартфона, которое является разговорным английским / испанским разговорником, когда пользователь нажимает на испанскую фразу, воспроизводится короткий mp3-файл. jQuery
и это работает правильно, проигрыватель jQuery назначен в готовом документе. Теперь я создал функцию поиска, которая копирует все соответствующие фразы на английском и испанском языках на страницу результатов поиска, и это также работает правильно.
Проблема, с которой я сталкиваюсь, заключается в том, что когда пользователь нажимает любую из фраз на испанском языке на странице результатов поиска, приложение вызывает системный проигрыватель звука (я думаю), а не jQuery
звуковой проигрыватель и системный звуковой проигрыватель отображают панель управления звуком, которую я не хочу, чтобы мои пользователи видели.
Я перепробовал все, что мог придумать, в основном следуя двум подходам:
- Скопируйте все атрибуты элемента
- Назначить событие onclick родительскому элементу на странице результатов поиска
Ни один из этих подходов не исправляет это - по крайней мере, я ничего не знаю об этом.
Я довольно новичок в js/jQuery, поэтому, пожалуйста, прости меня, если я пропустил что-то ослепительно очевидное.
Пожалуйста, посмотрите ниже:
- Образец английского / испанского элемента, всего их несколько сотен. Они копируются на страницу результатов поиска, если поиск соответствует английской фразе / слову
- Скрипт готового документа, который назначает обработчик клика для испанских фраз
- Функция поиска, которая находит и копирует соответствующие элементы на страницу результатов поиска
ОБРАЗЕЦ Английский / Испанский элемент
<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 ответ
Основная проблема в вашем коде заключается в том, что вы добавляете обработчики событий в один набор объектов, а не повторно добавляете их в клонированные. Выделение событий будет более подходящим для вас. Измени свой ${'.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
функция может связывать некоторые события (touchstart
, touchend
а также click
В его случае) к текущим существующим элементам и тем, которые будут созданы в будущем, например, в процессе клонирования элементов - это, вероятно, будет лучшим решением для вас.
Узнайте больше об этом здесь: http://api.jquery.com/on/