simker

Life is too short, just make it.


  • 首页

  • 归档

  • 分类

  • 标签

  • 关于

  • 音乐

  • 搜索

使用JavaScript监听Dom节点变化

发表于 2020-03-15 更新于 2021-01-13 分类于 JavaScript , Webdom 阅读次数: Disqus:
本文字数: 3.4k 阅读时长 ≈ 3 分钟

最近接触 webdom 比较多,于此记录下部分 JavaScript 观察(或者说监听) Webdom 的姿势

我们最近在开发一个在线原型编辑,用户可以在我们的编辑器上编辑一些产品原型类似的东西,相似的产品有 墨刀 ,但是我们的方向主要是图文。

里面涉及到很多 Dom 的监听与变化,事件主要在上一篇文章说过,这次说说 Dom 的变化方面。

比较主要的就是一些 Dom 标签的添加与移除,有一块比较特殊的:

某个 element , 当这个元素被移除的时候,释放另外一个 element 的状态

看起来好像不是很麻烦,只要在移除的地方释放就完事了。类似于这样的:

1
2
3
4
5
6
7
8
9
const trigger = document.querySelector('.someTrigger'),
remove = document.querySelector('.someRemove'),
release = document.querySelector('.someRelease');

trigger.addEventListener('click', function() {
remove.remove();
release.setAttribute('some_state', 'release');
...other code
}, false);

后面我发现,这个状态简直有毒,因为业务的相关性太大,居然有十几个场景要设置的,而且有时候添加 Dom 节点也会涉及到。当然了,这不能难到我,我把代码修改了。变成了这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const trigger1 = document.querySelector('.someTrigger'),
remove = document.querySelector('.someRemove'),
release = document.querySelector('.someRelease')
//...others;

trigger1.addEventListener('click', beTrigger, false);
trigger2.addEventListener('click', beTrigger, false);
trigger3.addEventListener('dblclick', beTrigger, false);
trigger4.addEventListener('scroll', beTrigger, false);
trigger5.addEventListener('focus', otherTrigger, false);

function beTrigger() {
remove.remove();
release.setAttribute('some_state', 'release');
// ...other code
}

function otherTrigger() {
const child = document.createElement('div');
trigger.appendChild(child);
release.setAttribute('some_state', 'other');
// ...other code
}

这种处理方式很好,我提交代码进行了测试,没问题。于此我就下班了。

下班的路上,我还是对提交的代码很不安,虽然代码看起来什么问题,也能够处理业务,但是每一次有一个场景要触发,我就得添加一条 someElement.addEventListener('someEvent', otherFunction, true|false),重复写这个对我这样有代码强迫的人很难受。

回家后我发现基本都是 Dom 节点在新增或者移除而触发的。

可不可以监听容器下的 Dom 节点的变化呢?

答案是可以的。

我认为这个应该也是类似于事件处理的一类,于是我发现了 DOMNodeRemoved 和 DOMNodeInserted,它们被归类在了 Mutation Events里面,但是已经被 Web 标准废弃了,替代它的是 MutationObserver。

看了它的示例,我用 React 改写成了如下代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import React from 'react';
import { Button, Right } from 'anypath';

let observer = null, content;

class ObserveDom extends React.Component {
constructor(props) {
super(props);
this.addElement = this.addElement.bind(this);
}

componentDidMount () {
observer = new MutationObserver(this.observerCallBack);
this.initContent();
observer.observe(content, { childList: true });
}

componentWillUnmount() {
observer.disconnect();
observer = null;
}

observerCallBack (mutationsList, observer) {
Object.keys(mutationsList).map(function (index) {
const item = mutationsList[index];
switch (item.type) {
case 'childList':
console.info(item);
console.info('childList has been modified');
// ...other code
break;
default:
break;
}
})
}

initContent() {
if (content instanceof Element == false) content = document.getElementById('content');
}

addElement() {
const child = document.createElement('div');
Object.keys(itemStyle).map(function (item) {
child.style[item] = itemStyle[item];
});
child.innerHTML = 'Item';
content.appendChild(child);
// ...other code
}

render() {
return <div id='content'>
<header>
<title>ObserveDom</title>
<Right>
<Button onClick={this.addElement}>Add Element</Button>
<Button onClick={this.addElement}>Remove Element</Button>
</Right>
</header>
</div>
}
}

const itemStyle = {// ...anyStyle}

export default ObserveDom;

你甚至可以用这个 MutationObserver 给观察对象一个钩子,类似生命周期那样的(不过不是很有必要),这里我使用了 class 没有用 hooks ,因为用前者比较对生命周期划分的比较清晰,容易理解(当然用 hooks 也可以实现)。

Cai xian 微信支付

微信支付

Cai xian 支付宝

支付宝

# notes
JavaScript handle Event
浅谈前后端请求加密与签名
Cai xian

Cai xian

A super nice guy!
24 日志
12 分类
15 标签
© 2019 – 2021 Cai xian | 70k | 1:04
由 Hexo 强力驱动 v3.9.0
|
主题 – NexT.Pisces v7.3.0
|