- I’m @shulandmimi
- I'm currently learning
Rust
,Typescript
and what interests me
shulandmimi / blog Goto Github PK
View Code? Open in Web Editor NEWshulan 的 博客 https://shulandmimi.github.io/blog/
shulan 的 博客 https://shulandmimi.github.io/blog/
偶然的,从网上看到一个这个面试题,从而引发了后面的一系列思考,在思考过程中产生出一些小想法,然后逐一解决。
首先,查询各种API,比较差异。
从中找出差异,然后查看能copy事件的API是如何完成的,当然,原生API除外
const newEl = el.cloneNode(bool);
bool 控制是否深度(克隆子级)clone
原生的copy后返回的newEl并不携带任何事件,只是有el的各种属性描述
const newEl = $(el).clone(bool)
bool 控制是否深入clone并且clone事件
jq的copy后返回一个jq包裹的元素,元素的dom存在事件
那么我们可以深入一下jq的源码操作,以下是查询源码后获得的消息
首先,写一个缓存存取
function cache() {
const map = new Map();
return {
add(k, v){
let arr = map.get(k);
Array.isArray(arr) ? arr.push(v) : arr = [v];
return map.set(k, b);
},
del(k){
return map.delete(k);
},
get(k) {
return map.get(k);
}
}
}
clone函数和on函数
const EventCache = cache();
function clone(DeepAndEventClone) {
const newEl = this.el;
if(DeepAndEventClone) {
const allEvent = EventCache.get(this.el);
if(allEvent && Array.isArray(allEvent)) {
for(let i = 0; i < allEvent.length; i ++>) {
const event = allEvent[i];
on(newEl, event.type, event.handler, event.options);
}
}
}
}
// 绑定事件,绑定事件时,根据DOM缓存元素
function on(target, type, handler, options) {
target.addEventListener(type, handler, options);
EventCache.add(target, {
type,
handler,
options
});
}
WeakMap做缓存
const cache = new WeakMap();
拦截addEventListener 和 removeEventListener
addEventListener 在拦截函数中保存事件
removeEventListener 在拦截函数中清除事件
// addEventListener
const addEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, handler, options){
const target = this;
const event = cache.get(target) || cache.set(target, {}).get(target);
const data = {
type,
handler,
options
}
if(typeof event === 'object' && event !== null && !Array.isArray(event)) {
const targetEvent = event[type] || (event[type] = []);
targetEvent.push(data);
}
return addEventListener.call(target, type, handler, options);
}
// removeEventListener
const removeEventListener = EventTarget.prototype.removeEventListener;
EventTarget.prototype.removeEventListener = function(type, handler, options) {
const target = this;
cache.delete(target);
return removeEventListener.call(target, type, handler, options);
}
PS: 一定要拦截EventTarget.prototype上addEventListener 和 removeEventListener, 其他地方的都是继承这里的
拦截cloneNode
拦截cloneNode并且在其中将句柄和缓存中的数据给copy出来的node
const EventList = `oncopy oncut onpaste onabort onblur oncancel oncanplay oncanplaythrough onchange onclick onclose oncontextmenu oncuechange ondblclick ondrag ondragend ondragenter ondragleave ondragover ondragstart ondrop ondurationchange onemptied onended onerror onfocus onformdata oninput oninvalid onkeydown onkeypress onkeyup onload onloadeddata onloadedmetadata onloadstart onmousedown onmouseenter onmouseleave onmousemove onmouseout onmouseover onmouseup onmousewheel onpause onplay onplaying onprogress onratechange onreset onresize onscroll onseeked onseeking onselect onstalled onsubmit onsuspend ontimeupdate ontoggle onvolumechange onwaiting onwheel onauxclick ongotpointercapture onlostpointercapture onpointerdown onpointermove onpointerup onpointercancel onpointerover onpointerout onpointerenter onpointerleave onselectstart onselectionchange onanimationend onanimationiteration onanimationstart ontransitionend onpointerrawupdate onbeforecopy onbeforecut onbeforepaste onsearch onfullscreenchange onfullscreenerror onwebkitfullscreenchange onwebkitfullscreenerror`.split(' ');
const cloneNode = Node.prototype.cloneNode;
Node.prototype.cloneNode = function(copyDeepAndEvent) {
const node = cloneNode.call(this, copyDeepAndEvent);
if(copyDeepAndEvent) {
const event = cache.get(this) || {};
// addEventListener 绑定的
for(let prop in event) {
const targetEvent = event[prop];
if(Array.isArray(targetEvent)) {
for(let i = 0; i < targetEvent.length; i ++) {
node.addEventListener(targetEvent[i].type, targetEvent[i].handler, targetEvent[i].options);
}
}
}
// 句柄
for(let i = 0; i < EventList.length; i ++ ){
if(typeof this[EventList[i]] === 'function') node[EventList[i]] = this[EventList[i]];
}
}
return node;
}
测试
const div1 = document.createElement('div');
const handler = function() {
console.log('event', '234');
}
div1.onclick = () => {
console.log('123');
};
div1.addEventListener('click', handler);
div1.style.cssText = `
width: 100px;
height: 100px;
background: red;
`;
document.body.appendChild(div1);
const div2 = div1.cloneNode(true);
document.body.appendChild(div2);
div2.removeEventListener('click', handler);
PS: 重写的代码必须放置在第一个addEventListener使用之前, 可以用一个立即执行函数使外界访问不到
const EventList = `oncopy oncut onpaste onabort onblur oncancel oncanplay oncanplaythrough onchange onclick onclose oncontextmenu oncuechange ondblclick ondrag ondragend ondragenter ondragleave ondragover ondragstart ondrop ondurationchange onemptied onended onerror onfocus onformdata oninput oninvalid onkeydown onkeypress onkeyup onload onloadeddata onloadedmetadata onloadstart onmousedown onmouseenter onmouseleave onmousemove onmouseout onmouseover onmouseup onmousewheel onpause onplay onplaying onprogress onratechange onreset onresize onscroll onseeked onseeking onselect onstalled onsubmit onsuspend ontimeupdate ontoggle onvolumechange onwaiting onwheel onauxclick ongotpointercapture onlostpointercapture onpointerdown onpointermove onpointerup onpointercancel onpointerover onpointerout onpointerenter onpointerleave onselectstart onselectionchange onanimationend onanimationiteration onanimationstart ontransitionend onpointerrawupdate onbeforecopy onbeforecut onbeforepaste onsearch onfullscreenchange onfullscreenerror onwebkitfullscreenchange onwebkitfullscreenerror`.split(' ');
const cache = new WeakMap();
const addEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, handler, options){
const target = this;
const event = cache.get(target) || cache.set(target, {}).get(target);
const data = {
type,
handler,
options
}
if(typeof event === 'object' && event !== null && !Array.isArray(event)) {
const targetEvent = event[type] || (event[type] = []);
targetEvent.push(data);
}
return addEventListener.call(target, type, handler, options);
}
const removeEventListener = EventTarget.prototype.removeEventListener;
EventTarget.prototype.removeEventListener = function(type, handler, options) {
const target = this;
cache.delete(target);
return removeEventListener.call(target, type, handler, options);
}
const cloneNode = Node.prototype.cloneNode;
Node.prototype.cloneNode = function(copyDeepAndEvent) {
const node = cloneNode.call(this, copyDeepAndEvent);
if(copyDeepAndEvent) {
const event = cache.get(this) || {};
// addEventListener 绑定的
for(let prop in event) {
const targetEvent = event[prop];
if(Array.isArray(targetEvent)) {
for(let i = 0; i < targetEvent.length; i ++) {
node.addEventListener(targetEvent[i].type, targetEvent[i].handler, targetEvent[i].options);
}
}
}
// 句柄
for(let i = 0; i < EventList.length; i ++ ){
if(typeof this[EventList[i]] === 'function') node[EventList[i]] = this[EventList[i]];
}
}
return node;
}
const div1 = document.createElement('div');
const handler = function() {
console.log('event', this);
}
div1.onclick = () => {
console.log('123');
};
div1.style.cssText = `
width: 100px;
height: 100px;
background: red;
`;
document.body.appendChild(div1);
const div2 = div1.cloneNode(true);
console.log(div2)
document.body.appendChild(div2);
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.