通过MutationObserver监听DOM元素,做一个位置随指定元素位置变化而变化的气泡 | ResizeObserver监听元素大小

-

最近需要把时间轴修改成自己想要的样子,需要在时间轴的当前时间条上设置一个气泡,但是没有这个api,于是想到一个办法,通过监听 时间条dom元素,获取时间条的位置,然后创建一个元素当做气泡,这个气泡的位置会随着时间条的位置变化而变化;

1、需要用到MutationObserver 来监听时间条dom元素,

2、用DOM.getBoundingClientRect()方法监听dom相对于窗口的位置;

3、根据时间条的位置,给创建的气泡元素设置位置,从而达到给时间条加气泡的效果;

4、为了简化一些,我用了一个div当做时间条,设置一个定时器让它持续移动。可以模拟出来拖动时间条的场景。

上代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>observer</title>
<style>
.wrap{
  width:400px;
  height:400px;
  position: relative;
  margin-left:200px;
}
.box{
  width: 300px;
  height:300px;
  position: absolute;
  top:0;
  left:0;
  background:cadetblue;
  clip-path: polygon(15px 0, calc(100% - 15px) 0, 100% 15px,  100% calc(100% - 15px), calc(100% - 15px) 100%, 15px 100%, 0 calc(100% - 15px), 0 15px)
}
.pop{
  position: fixed;
  border:1px solid black;
  border-radius:4px;
  padding: 4px;
  box-shadow: 0px 0px 4px 2px black inset;
  user-select: none;
}
</style>
</head>
<body>
<div class="wrap">
  <div class="box"></div>
</div>


<script>
let box = document.querySelector(".box");
let add = 1;
setInterval(() => {
  let left = parseInt(getComputedStyle(box).left);
  console.log(left);
  if(left > 300 ){
    add = -1;
  }
  if (left < 0){
    add = 1;
  }
  box.style.left = `${left + add}px`
}, 1000);

// 观察者的选项(要观察哪些突变)
var config = { attributes: true, childList: false, subtree: false };// 只监听属性发生变化
 
 // 当观察到突变时执行的回调函数
 var callback = function(mutationsList) {
   console.log(mutationsList, 'mutationsList');
     mutationsList.forEach(function(item,index){
         if (item.type == 'childList') {
            console.log('有节点发生改变');
         } else if (item.type == 'attributes') {
            let targetleft = item.target.getBoundingClientRect().left;
            console.log(targetleft,'targetleft');
            let date = new Date();
            changePop(item.target, `
              <div>${date.getYear()}年${date.getMonth() + 1}月${date.getDay()}</div>
              <span>${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}</span>
            `)
         } else if (item.type == 'subtree') {
            console.log('subtree有变化');
         }
     });
 };

 // 创建一个链接到回调函数的观察者实例
 var observer = new MutationObserver(callback);

 // 开始观察已配置突变的目标节点
 observer.observe(box, config);

 // 停止观察
 //observer.disconnect();

function changePop(parent,innerHTML){
  let pop = null;
  if(!document.querySelector('.pop')){
    pop = document.createElement('div');
    pop.classList.add('pop')
    document.body.appendChild(pop);
  } else {
    pop = document.querySelector('.pop');
  }
  let position = parent.getBoundingClientRect();
  pop.style.left = `${position.left}px`;
  pop.style.top = `${position.bottom}px`;
  pop.innerHTML = innerHTML;
}
</script>
</body>
</html>

效果:气泡位置会跟着时间条的位置变化而变化

 下面简单说一下ResizeObserver API的使用,这个方法是监听元素的大小改变,不用通过window.resize来监听窗口改变来达到目的,有些时候只监听window.resize也是达不到目的的,因为我们可能用js来改变某一个元素的宽高,所以用ResizeObserver方法来监听会更加方便,不过这个API目前是实验阶段,在chrome浏览器已经支持

文档地址:https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserver

 

<textarea id="main"></textarea>
<script>


// javascript

let mainEl = document.querySelector('#main')
const resizeObserver = new ResizeObserver(entries => {
  console.log(entries, 'entries');
  for (let entry of entries) {
    console.log(entry.contentRect, 'contentRect');
    entry.target.style.borderRadius = Math.max(0, 250 - entry.contentRect.width) + 'px';
  }
});
resizeObserver.observe(mainEl);

// 取消某个元素监听
//resizeObserver.unobserve(mainEl)

// 取消全部元素监听
//resizeObserver.disconnect()

 

 

 

 拖动富文本框,监听到实时的大小。

 

 

-

posted @ 2021-10-30 16:44  古墩古墩  Views(1792)  Comments(0Edit  收藏  举报