English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Recientemente, el evento de tap ha traído problemas de diversa índole, uno de los cuales es que para resolver el problema de 'pantalla trasera' es necesario cambiar cada click original a tap, lo que nos hace abandonar a los usuarios de ie
Claro que se puede hacer compatible, pero nadie quiere tocar el código antiguo, por lo que hoy presentamos este objeto fastclick
Esto es el cuarto artículo reciente que habla sobre el evento de punto de tap, siempre hemos estado preocupados por resolver el problema de la 'pantalla trasera', por lo que hoy nuestro jefe propuso un repositorio fastclick, que finalmente resolvió nuestro problema
Y es que click no necesita ser reemplazado por tap, por lo que nuestro jefe me dijo con seriedad, ¡usenme! Ya he enviado todos los correos...
于是我下午就在看fastclick这个库,看看是不是能解决我们的问题,于是我们开始吧
读fastclick源码
尼玛使用太简单了,直接一句:
FastClick.attach(document.body);
于是所有的click响应速度直接提升,刚刚的!什么input获取焦点的问题也解决了!!!尼玛如果真的可以的话,原来改页面的同事肯定会啃了我
一步步来,我们跟进去,入口就是attach方法:
FastClick.attach = function(layer) { 'use strict'; return new FastClick(layer); };
这个兄弟不过实例化了下代码,所以我们还要看我们的构造函数:
function FastClick(layer) {
'use strict';
var oldOnClick, self = this;
this.trackingClick = false;
this.trackingClickStart = 0;
this.targetElement = null;
this.touchStartX = 0;
this.touchStartY = 0;
this.lastTouchIdentifier = 0;
this.touchBoundary = 10;
this.layer = layer;
if (!layer || !layer.nodeType) {
throw new TypeError('Layer must be a document node');
}
this.onClick = function() { return FastClick.prototype.onClick.apply(self, arguments); };
this.onMouse = function() { return FastClick.prototype.onMouse.apply(self, arguments); };
this.onTouchStart = function() { return FastClick.prototype.onTouchStart.apply(self, arguments); };
this.onTouchMove = function() { return FastClick.prototype.onTouchMove.apply(self, arguments); };
this.onTouchEnd = function() { return FastClick.prototype.onTouchEnd.apply(self, arguments); };
this.onTouchCancel = function() { return FastClick.prototype.onTouchCancel.apply(self, arguments); };
if (FastClick.notNeeded(layer)) {
return;
}
if (this.deviceIsAndroid) {
layer.addEventListener('mouseover', this.onMouse, true);
layer.addEventListener('mousedown', this.onMouse, true);
layer.addEventListener('mouseup', this.onMouse, true);
}
layer.addEventListener('click', this.onClick, true);
layer.addEventListener('touchstart', this.onTouchStart, false);
layer.addEventListener('touchmove', this.onTouchMove, false);
layer.addEventListener('touchend', this.onTouchEnd, false);
layer.addEventListener('touchcancel', this.onTouchCancel, false);
if (!Event.prototype.stopImmediatePropagation) {
layer.removeEventListener = function(type, callback, capture) {
var rmv = Node.prototype.removeEventListener;
if (type === 'click') {
rmv.call(layer, type, callback.hijacked || callback, capture);
}
rmv.call(layer, type, callback, capture);
}
};
layer.addEventListener = function(type, callback, capture) {
var adv = Node.prototype.addEventListener;
if (type === 'click') {
adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
if (!event.propagationStopped) {
callback(event);
}
}), capture);
}
adv.call(layer, type, callback, capture);
}
};
}
if (typeof layer.onclick === 'function') {
oldOnClick = layer.onclick;
layer.addEventListener('click', function(event) {
oldOnClick(event);
}, false);
layer.onclick = null;
}
}
Mire este código, no sé qué hacen muchos atributos aquí......así que lo ignoré.
if (!layer || !layer.nodeType) { throw new TypeError('Layer must be a document node'); }
Debemos ingresar un nodo a la función constructora, de lo contrario se producirá un problema.
Luego, este tipo registra algunos eventos básicos del ratón en sus métodos de propiedad, lo que hace específicamente lo hablaremos más tarde.
Hay un método notNeeded en la parte posterior:
FastClick.notNeeded = function(layer) {
'use strict';
var metaViewport;
if (typeof window.ontouchstart === 'undefined') {
return true;
}
if ((/Chrome\/[0-9]+/).test(navigator.userAgent)) {
if (FastClick.prototype.deviceIsAndroid) {
if (metaViewport && metaViewport.content.indexOf('user-scalable=no') !== -1) {
return true;
}
}
return true;
}
}
if (layer.style.msTouchAction === 'none') {
return true;
}
return false;
};
Este método se utiliza para determinar si es necesario usar fastclick, el significado de los comentarios no es muy claro, veamos el código.
Primera frase:
if (typeof window.ontouchstart === 'undefined') { return true; }
Si no se admite el evento touchstart, devuelve true
PS: La sensación actual es que fastclick también debe ser simulado por eventos de toque, pero no tiene problemas de punto de toque.
Después, también se juzgaron algunos problemas de android, no me interesa aquí, la intención debe ser que solo se puede admitir toque para admitir, por lo que regresamos al código principal.
En el código principal, vemos que si el navegador no admite eventos de toque o otros problemas, salta directamente.
Luego hay una propiedad deviceIsAndroid, vamos a verla (de hecho, no hace falta verlo para saber que es para determinar si es un dispositivo Android)
FastClick.prototype.deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0;
Vincular eventos
Bueno, este tipo comienza a registrar eventos, hasta ahora no se ha notado nada extraño
if (this.deviceIsAndroid) {
layer.addEventListener('mouseover', this.onMouse, true);
layer.addEventListener('mousedown', this.onMouse, true);
layer.addEventListener('mouseup', this.onMouse, true);
}
layer.addEventListener('click', this.onClick, true);
layer.addEventListener('touchstart', this.onTouchStart, false);
layer.addEventListener('touchmove', this.onTouchMove, false);
layer.addEventListener('touchend', this.onTouchEnd, false);
layer.addEventListener('touchcancel', this.onTouchCancel, false);
Las funciones de eventos específicas se han sobrescrito anteriormente, por ahora no nos preocupamos por ellas y continuemos viendo hacia adelante primero (de hecho, este tipo tiene muchos eventos vinculados)
stopImmediatePropagation
Se ha agregado una propiedad adicional:
Evitar la propagación del evento actual y evitar la ejecución continua de todas las funciones de manejo de eventos del mismo tipo en el elemento actual del evento.
Si un elemento tiene múltiples funciones de escucha de eventos del mismo tipo, cuando se desencadena ese tipo de evento, múltiples funciones de escucha se ejecutarán sucesivamente en orden. Si alguna función de escucha ejecuta el método event.stopImmediatePropagation(), además de evitar la propagación del evento (el efecto del método event.stopPropagation), también se evitará la ejecución de las demás funciones de escucha del mismo tipo que están vinculadas al elemento.
<html>
<head>
<style>
p { altura: 30px; width: 150px; background-color: #ccf; }
div {height: 30px; width: 150px; background-color: #cfc; }
</style>
</head>
<body>
<div>
<p>paragraph</p>
</div>
<script>
document.querySelector("p").addEventListener("click", function(event)
{
alert("Soy la primera función de escucha ligada al elemento p");
}, false);
document.querySelector("p").addEventListener("click", function(event)
{
alert("Soy la segunda función de escucha ligada al elemento p");
event.stopImmediatePropagation();
//Ejecute el método stopImmediatePropagation, impida que el evento clic se propague y impida la ejecución de otros listeners de eventos clic ligados al elemento p.
}, false);
document.querySelector("p").addEventListener("click", function(event)
{
alert("Soy la tercera función de escucha ligada al elemento p");
//Esta función de escucha se coloca después de la anterior función, y esta función no se ejecutará.
}, false);
document.querySelector("div").addEventListener("click", function(event)
{
alert("Soy el elemento div, soy el elemento superior del elemento p");
//El evento de clic del elemento p no se propagará hacia arriba, y esta función no se ejecutará.
}, false);
</script>
</body>
</html>
if (!Event.prototype.stopImmediatePropagation) {
layer.removeEventListener = function(type, callback, capture) {
var rmv = Node.prototype.removeEventListener;
if (type === 'click') {
rmv.call(layer, type, callback.hijacked || callback, capture);
}
rmv.call(layer, type, callback, capture);
}
};
layer.addEventListener = function(type, callback, capture) {
var adv = Node.prototype.addEventListener;
if (type === 'click') {
adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
if (!event.propagationStopped) {
callback(event);
}
}), capture);
}
adv.call(layer, type, callback, capture);
}
};
}
Luego, ese individuo redefinió el método de eventos de registro e inicio de sesión.
Primero veamos el registro de eventos, donde se utiliza addEventListener de Node, ¿qué es Node?]}
Por lo tanto, Node es una propiedad del sistema, que representa nuestro nodo, por lo que aquí se ha rewritten el evento de anulación
Aquí, descubrimos que realmente solo se ha tratado de manera especial el evento click
adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) { if (!event.propagationStopped) { callback(event); } }), capture);
Entre ellos, hay un hijacked que no sé qué hace, parece ser que se refiere a si se ha modificado en el medio
Luego aquí se ha rewritten, hijacked parece ser un método, que existe para evitar que se registren múltiples eventos en un mismo dom y se ejecuten múltiples veces
Anular y registrar son bastante similares, así que no nos preocupamos por eso, hasta este punto hemos sobrescrito el registro y anulación de eventos del elemento dom que nos pasaron, parece bastante impresionante, lo que significa que en el futuro, el elemento dom llamará al evento click usando el nuestro, por supuesto, esto es solo mi juicio temporal, específicamente, aún hay que seguir leyendo, y creo que mi juicio actual no es confiable, así que continuemos
Podemos anular eventos usando addEventListener o dom.onclick=function(){}; por lo tanto, aquí hay el siguiente código:
if (typeof layer.onclick === 'function') { oldOnClick = layer.onclick; layer.addEventListener('click', function(event) { oldOnClick(event); }, false); layer.onclick = null; }
Aquí, su flujo principal parece haber terminado, lo que significa que toda su lógica está aquí, ya sea la entrada o la salida debería ser el registro de eventos, así que escribamos un código para ver
punto de entrada
<input type="button" value="addevent">
<input type="button" value="addevent1">
$('#addEvent').click(function () {
var dom = $('#addEvent1')[0]
dom.addEventListener('click', function () {
alert('')
var s = '';
)
});
Vamos a ver qué hacemos después de hacer clic en este punto de ruptura, ahora haremos clic en el botón1asignará eventos a los botones2Registrar eventos:
Sin embargo, es una lástima que no podamos probar en computadoras, lo que dificulta nuestra lectura del código, después de probar en teléfonos, descubrimos que los botones2La respuesta es rápida, pero aquí no se puede ver el problema
Finalmente, alertó de !Event.prototype.stopImmediatePropagation y descubrió que en teléfonos y computadoras son todos false, por lo que lo que hicimos arriba es temporalmente inútil
FastClick.prototype.onClick = function (event) {
'use strict';
var permitted;
alert('¡Por fin entré aquí!');
if (this.trackingClick) {
this.targetElement = null;
this.trackingClick = false;
return true;
}
if (event.target.type === 'submit' && event.detail === 0) {
return true;
}
permitted = this.onMouse(event);
if (!permitted) {
this.targetElement = null;
}
return permitted;
};
Finalmente, entramos, ahora necesitamos saber qué es trackingClick
/** * ¿Se está rastreado actualmente un click? * @type Boolean */ this.trackingClick = false;
Inicialmente, esta propiedad era false, pero aquí se estableció en true y se salió directamente, lo que indica que se terminó de绑定事件,dejemos esto por ahora, haremos otras cosas,
porque, creo que el punto principal debería estar en los eventos de toque
PS: Hasta aquí, descubrimos que esta biblioteca no debería solo acelerar el click, sino también todas las respuestas
He registrado cosas en varios eventos y he encontrado que en todos los lugares con click solo se ejecutan touchstart y touchend, por lo que hasta aquí, creo que mi punto de vista está bien establecido
él usa eventos de toque para simular un click, por lo que solo seguimos esto:
FastClick.prototype.onTouchStart = function (event) {
'use strict';
var targetElement, touch, selection;
log('touchstart');
if (event.targetTouches.length > 1) {
return true;
}
targetElement = this.getTargetElementFromEventTarget(event.target);
touch = event.targetTouches[0];
if (this.deviceIsIOS) {
selection = window.getSelection();
if (selection.rangeCount && !selection.isCollapsed) {
return true;
}
if (!this.deviceIsIOS4) {
if (touch.identifier === this.lastTouchIdentifier) {
event.preventDefault();
return false;
}
this.lastTouchIdentifier = touch.identifier;
this.updateScrollParent(targetElement);
}
}
this.trackingClick = true;
this.trackingClickStart = event.timeStamp;
this.targetElement = targetElement;
this.touchStartX = touch.pageX;
this.touchStartY = touch.pageY;
if ((event.timeStamp - this.lastClickTime) < 200) {
event.preventDefault();
}
return true;
};
Se utilizó un método:
FastClick.prototype.getTargetElementFromEventTarget = function (eventTarget) { 'use strict'; if (eventTarget.nodeType === Node.TEXT_NODE) { return eventTarget.parentNode; } return eventTarget; };
Es obtener el elemento actual de touchstart
Luego registró la información del ratón, principalmente en el momento del touchend, según x, y para determinar si es un click
Es en el caso de iOS donde se hicieron algunas cosas, aquí lo salté
Luego aquí se registraron algunas cosas y salió, sin nada especial, ahora entramos en nuestra salida touchend
FastClick.prototype.onTouchEnd = function (event) {
'use strict';
var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
log('touchend');
if (!this.trackingClick) {}}
return true;
}
if ((event.timeStamp - this.lastClickTime) < 200) {
this.cancelNextClick = true;
return true;
}
this.lastClickTime = event.timeStamp;
trackingClickStart = this.trackingClickStart;
this.trackingClick = false;
this.trackingClickStart = 0;
if (this.deviceIsIOSWithBadTarget) {
touch = event.changedTouches[0];
targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;
targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;
}
targetTagName = targetElement.tagName.toLowerCase();
if (targetTagName === 'label') {
forElement = this.findControl(targetElement);
if (forElement) {
this.focus(targetElement);
if (this.deviceIsAndroid) {
return false;
}
targetElement = forElement;
}
} else if (this.needsFocus(targetElement)) {
if ((event.timeStamp - trackingClickStart) > 100 || (this.deviceIsIOS && window.top !== window && targetTagName === 'input')) {
this.targetElement = null;
return false;
}
this.focus(targetElement);
if (!this.deviceIsIOS4 || targetTagName !== 'select') {
this.targetElement = null;
event.preventDefault();
}
return false;
}
if (this.deviceIsIOS && !this.deviceIsIOS4) {
scrollParent = targetElement.fastClickScrollParent;
if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {}}
return true;
}
}
if (!this.needsClick(targetElement)) {
event.preventDefault();
this.sendClick(targetElement, event);
}
return false;
};
Este tipo ha hecho muchas cosas
Aquí corrigo un error, ahora también se ejecutan esos onclick... tal vez mi pantalla ha cambiado (deslizar)
if ((event.timeStamp - this.lastClickTime) < 200) { this.cancelNextClick = true; return true; }
Este código es muy clave, nuestra primera clic ejecutará la lógica a continuación, si se hace clic continuamente, directamente se acabó, la lógica a continuación no se ejecuta...
No se ejecuta, ¿entonces qué más ha hecho este tipo?
De hecho, no hay lógica aquí, significa que si el clic es demasiado rápido, los dos clics solo se ejecutarán una vez, este umbral es200ms, por ahora parece estar bien
Bueno, continuemos, me di cuenta de que llegó otro punto clave
Porque no podemos hacer que el input obtenga el foco con el evento tap, pero fastclick sí puede, aquí tal vez es una clave, veamos algunas funciones relacionadas con obtener el foco
FastClick.prototype.focus = function (targetElement) {
'use strict';
var length;
if (this.deviceIsIOS && targetElement.setSelectionRange) {
length = targetElement.value.length;
targetElement.setSelectionRange(length, length);
}
targetElement.focus();
}
};
setSelectionRange es nuestra clave, tal vez así es como obtiene el foco... Debo probarlo más tarde, deje que se maneje en la próxima vez
Luego, si el intervalo de tiempo es demasiado largo, el código no considera que la operación sea del mismo elemento DOM
Finalmente llegó la clave de esta vez: sendClick, ya sea touchend o onMouse, todos se concentran aquí
FastClick.prototype.sendClick = function (targetElement, event) {
'use strict';
var clickEvent, touch;
// En algunos dispositivos Android, activeElement necesita estar desenfocado de lo contrario el clic sintético no tendrá efecto (#24)
if (document.activeElement && document.activeElement !== targetElement) {
document.activeElement.blur();
}
touch = event.changedTouches[0];
// Synthesise a click event, with an extra attribute so it can be tracked
clickEvent = document.createEvent('MouseEvents');
clickEvent.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
clickEvent.forwardedTouchEvent = true;
targetElement.dispatchEvent(clickEvent);
};
Creó un evento de ratón y luego desencadenó el evento dispatchEvent (este es similar a fireEvent)
//El documento tiene un evento personalizado ondataavailable asociado
document.addEventListener('ondataavailable', function (event) {
alert(event.eventType);
}, false);
var obj = document.getElementById("obj");
//El elemento obj tiene un evento click asociado
obj.addEventListener('click', function (event) {
alert(event.eventType);
}, false);
//调用document对象的 createEvent 方法得到一个event的对象实例。
var event = document.createEvent('HTMLEvents');
// initEvent接受3个参数:
// 事件类型,是否冒泡,是否阻止浏览器的默认行为
event.initEvent("ondataavailable", true, true);
event.eventType = 'message';
//触发document上绑定的自定义事件ondataavailable
document.dispatchEvent(event);
var event1 = document.createEvent('HTMLEvents');
event1.initEvent("click", true, true);
event1.eventType = 'message';
//触发obj元素上绑定click事件
document.getElementById("test").onclick = function () {
obj.dispatchEvent(event1);
};
至此,我们就知道了,我们为dom先绑定了鼠标事件,然后touchend时候触发了,而至于为什么本身注册的click未触发就要回到上面代码了
解决“点透”(成果)
有了这个思路,我们来试试我们抽象出来的代码:
!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<style>
#list { display: block; position: absolute; top: 100px; left: 10px; width: 200px; height: 100px; }
div { display: block; border: 1px solid black; height: 300px; width: 100%; }
#input { width: 80px; height: 200px; display: block; }
</style>
</head>
<body>
<div>
</div>
<div>
<div>
<input type="text" />
</div>
</div>
<script type="text/javascript">
var el = null;
function getEvent(el, e, type) {
e = e.changedTouches[0];
var event = document.createEvent('MouseEvents');
event.initMouseEvent(type, true, true, window, 1, e.screenX, e.screenY, e.clientX, e.clientY, false, false, false, false, 0, null);
event.forwardedTouchEvent = true;
return event;
}
list.addEventListener('touchstart', function (e) {
var firstTouch = e.touches[0]
el = firstTouch.target;
t1 = e.timeStamp;
)
list.addEventListener('touchend', function (e) {
e.preventDefault();
var event = getEvent(el, e, 'click');
el.dispatchEvent(event);
)
var list = document.getElementById('list');
list.addEventListener('click', function (e) {
list.style.display = 'none';
setTimeout(function () {
list.style.display = '';
}, 1000);
)
</script>
</body>
</html>
De esta manera, no se produce la transparencia, porque todos los eventos de touch de Zepto están vinculados al documento, por lo que e.preventDefault(); es inútil
El resultado es que aquí estamos directamente en el DOM, e.preventDefault();
Funciona, no dispara el evento predeterminado del navegador, por lo tanto, no existe el problema de transparencia, y así concluye el evento de transparencia...
Imagen que ayuda a entender
El código se escribió en la empresa, no sé dónde está la imagen en casa, por favor, todos la miran
¿Por qué Zepto tiene el problema de transparencia?/¿Cómo resuelve fastclick el problema de transparencia?
Al principio, le dije al jefe que Zepto no maneja bien los eventos de tap, y ha causado muchos problemas
Porque el evento está vinculado al documento, primero touchstart y luego touchend, se determina si este DOM tiene un evento de tap registrado según el parámetro de evento de touchstart
Entonces, aquí viene el problema, en Zepto touchend hay un parámetro de evento, llamamos a event.preventDefault(), aquí ya estamos en el nivel más alto, este código no sirve para nada
Pero la solución de fastclick es muy ingeniosa, esta biblioteca dispara directamente el evento de click en el DOM en el momento del touchend y reemplaza el tiempo de disparo original
Lo que significa que originalmente tenía que350-4El código ejecutado en 00ms se movió repentinamente a50-100ms, y aunque aquí se utiliza el evento touch, el evento touch está vinculado a un DOM específico en lugar de al documento
Por lo tanto, e.preventDefault() es efectivo, podemos evitar la propagación y también evitar el evento predeterminado del navegador, esta es la esencia de fastclick, ¡no puede decirse que no sea alta!
El código de fastclick es verdaderamente revelador, hoy he aprendido mucho, aquí lo registro
Anotaciones posteriores
La declaración anterior tiene un problema, aquí está la corrección:
Primero, volvamos al esquema original de Zepto y veamos cuáles son sus problemas:
Debido a que el estándar de JavaScript no admite eventos de tap, Zepto tap se simula mediante touchstart y touchend. Zepto binda eventos de touch al documento en el momento de la inicialización, y al hacer clic, según el parámetro event, obtiene el elemento actual y guarda la posición del ratón al hacer clic y al soltar. Según el rango de movimiento del ratón del elemento actual, se determina si es un evento de clic, y si lo es, se dispara el evento de tap registrado.
Luego FastClick maneja de manera similar a Zepto, pero también tiene diferencias
FastClick es绑定到您传递的 elemento (generalmente document.body)
② Después de touchstart y touchend (se obtiene manualmente el elemento actual de clic), si es un evento de clase clic, se desencadena manualmente el evento clic del elemento DOM
Por lo tanto, el evento de clic se desencadena en touchend, y la velocidad de respuesta aumenta, el desencadenamiento es similar al tap de Zepto
Bien, ¿por qué el código básicamente idéntico, Zepto lo hace transparente mientras que FastClick no?
La razón es que hay un setTimeout en el código de Zepto, y ni siquiera si se ejecuta e.preventDefault() dentro de este código no será útil
Esta es la diferencia fundamental, porque setTimeout tiene una prioridad más baja
Con un temporizador, cuando el código ejecuta setTimeout, se colocará este código al final del motor de JS
Y nuestro código detectará inmediatamente e.preventDefault, una vez que se añada setTimeout, e.preventDefault no tendrá efecto, esta es la razón fundamental de la transparencia de Zepto
Conclusión
Aunque, esta vez he seguido muchos caminos sinuosos, pero finalmente he resuelto el problema
Declaración: Este artículo se ha obtenido de la red, el copyright pertenece al propietario original, el contenido se ha contribuido y cargado de manera autónoma por los usuarios de Internet, este sitio web no posee los derechos de propiedad, no se ha realizado un procesamiento editorial humano y no asume la responsabilidad de las responsabilidades legales relacionadas. Si encuentra contenido sospechoso de copyright, por favor envíe un correo electrónico a: notice#w proporcionando evidencia relevante, una vez que se verifique, este sitio eliminará inmediatamente el contenido sospechoso de infracción.3Declaración: El contenido de este artículo se obtiene de la red, el copyright pertenece al propietario original, el contenido se contribuye y carga de manera autónoma por los usuarios de Internet, este sitio web no posee los derechos de propiedad, no se ha realizado un procesamiento editorial humano y no asume la responsabilidad de las responsabilidades legales relacionadas. Si encuentra contenido sospechoso de copyright, por favor envíe un correo electrónico a: notice#w proporcionando evidencia relevante, una vez que se verifique, este sitio eliminará inmediatamente el contenido sospechoso de infracción.