首页 > 编程语言 >JavaScript 实现跨标签页移动元素效果

JavaScript 实现跨标签页移动元素效果

时间:2023-11-30 16:02:01浏览次数:32  
标签:元素 标签 JavaScript param let 坐标 data block 页面

该方案可实现跨浏览器容器进行拖动

1.入口文件 index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>index.html</title>
  <!-- 页面样式 -->
  <link rel="stylesheet" href="./index.css">
</head>
<body>
  <!-- 可移动的元素 -->
  <div id="block" class="block" style="left: 0px; top: 0px;"></div>
  <!-- 初始化操作按钮 -->
  <div id="init-btn" class="init-btn">
    <span>初始化</span>
  </div>
  <!-- 处理交互逻辑 -->
  <script src="./index.js"></script>
</body>
</html>

2.index.css

html, body {
  position: relative;
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  user-select: none;
}

html {
  font-size: 16px;
  line-height: 1;
}

body {
  background-color: #EDF2F7;
}

.block {
  display: block;
  position: absolute;
  width: 300px;
  height: 200px;
  border-radius: 8px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.07),
    0 2px 4px rgba(0,0,0,0.07),
    0 4px 8px rgba(0,0,0,0.07),
    0 8px 16px rgba(0,0,0,0.07),
    0 16px 32px rgba(0,0,0,0.07),
    0 32px 64px rgba(0,0,0,0.07);
  background-color: #FFF;
  cursor: grab;
}

.init-btn {
  display: inline-block;
  margin: 10px;
  padding: 12px 16px;
  border: 1px solid #2196F3;
  border-radius: 8px;
  background-color: #FFF;
  color: #2196F3;
  font-size: 16px;
  text-align: center;
  cursor: pointer;
}

.init-btn:hover {
  border-color: #FFF;
  background-color: #2196F3;
  color: #FFF;
}

3.index.js

(function () {

  /**
   * @typedef  ChannelMessage
   * @property {string} type
   * @property {any}    data
   */

  /** 可移动元素 */
  let block = document.getElementById('block');

  /** 初始化按钮 */
  let btn = document.getElementById('init-btn');

  /** 跨标签通信广播 */
  let channel = new BroadcastChannel('DataTransfer');

  /** 页面相对于窗口边缘的水平距离 */
  let offsetX = 0;

  /** 页面相对于窗口边缘的垂直距离 */
  let offsetY = 0;

  /**
   * @description 转换坐标值
   * @param {'p2s'|'s2p'} type
   * @param {object} coords
   * @param {number} coords.x
   * @param {number} coords.y
   */
  function convertCoords(type, coords) {

    let { x, y } = coords;
    let { screenLeft, screenTop } = window;

    switch (type) {
      // 页面坐标 -> 屏幕坐标
      case 'p2s':
        return {
          x: x + screenLeft + offsetX,
          y: y + screenTop + offsetY,
        };
      // 屏幕坐标 -> 页面坐标
      case 's2p':
        return {
          x: x - screenLeft - offsetX,
          y: y - screenTop - offsetY,
        };
      default:
        console.error('转换失败:类型错误');
        return { x: 0, y: 0 };
    }

  }

  /**
   * @description 处理校准距离
   * @param {object} data
   * @param {number} data.x
   * @param {number} data.y
   */
  function handleAdjustOffset(data) {

    console.log('[AdjustOffset]', data);

    offsetX = data.x;
    offsetY = data.y;

    if (btn) {
      btn.remove();
    }

  }

  /**
   * @description 处理元素坐标更新
   * @param {object} data
   * @param {number} data.x 相对于屏幕的水平坐标
   * @param {number} data.y 相对于屏幕的垂直坐标
   */
  function handleUpdateCoords(data) {
    let { x, y } = convertCoords('s2p', data);
    block.style.left = x + 'px';
    block.style.top = y + 'px';
  }

  /** 初始化元素坐标 */
  function initElementCoords() {

    /** 元素宽度 */
    let elementW = block.clientWidth;

    /** 元素高度 */
    let elementH = block.clientHeight;

    /** 页面宽度 */
    let windowW = window.innerWidth;

    /** 页面高度 */
    let windowH = window.innerHeight;

    // 将元素移动到页面中心
    block.style.left = Math.round(windowW / 2 - elementW / 2) + 'px';
    block.style.top = Math.round(windowH / 2 - elementH / 2) + 'px';

  }

  /**
   * @description 解析广播消息
   * @param   {MessageEvent<ChannelMessage>} event
   * @returns {ChannelMessage}
   */
  function parseChannelMessage(event) {

    let data = event.data;

    if (data && data.type) {
      return data;
    } else {
      return {
        type: '',
        data: null,
      };
    }

  }

  // 处理元素拖拽
  block.addEventListener('mousedown', function (downEvent) {

    /** 元素相对于屏幕的坐标 */
    let elementCoords = convertCoords('p2s', {
      x: parseInt(block.style.left),
      y: parseInt(block.style.top),
    });

    /** 元素起始水平坐标 */
    let elementX = elementCoords.x;

    /** 元素起始垂直坐标 */
    let elementY = elementCoords.y;

    /** 鼠标起始水平坐标 */
    let cursorX = downEvent.screenX;

    /** 鼠标起始垂直坐标 */
    let cursorY = downEvent.screenY;

    /**
     * @description 处理鼠标移动
     * @param {MouseEvent} moveEvent
     */
    let handleMove = function (moveEvent) {

      let newX = elementX + (moveEvent.screenX - cursorX);
      let newY = elementY + (moveEvent.screenY - cursorY);

      let coords = { x: newX, y: newY };

      // 更新当前页面元素坐标
      handleUpdateCoords(coords);

      // 通知其他页面
      channel.postMessage({
        type: 'UpdateCoords',
        data: coords,
      });

    };

    let handleUp = function () {
      window.removeEventListener('mousemove', handleMove);
      window.removeEventListener('mouseup', handleUp);
    };

    window.addEventListener('mousemove', handleMove);
    window.addEventListener('mouseup', handleUp);

  });

  // 处理按钮点击
  btn.addEventListener('click', function (ev) {

    let { pageX, pageY, screenX, screenY } = ev;

    let offsetX = 0, offsetY = 0;
    let relativeX = screenX - window.screenLeft;
    let relativeY = screenY - window.screenTop;

    while (relativeX > pageX) {
      offsetX++;
      relativeX--;
    }

    while (relativeY > pageY) {
      offsetY++;
      relativeY--;
    }

    // 更新当前页面数据
    handleAdjustOffset({
      x: offsetX,
      y: offsetY,
    });

    // 通知其他页面更新数据
    channel.postMessage({
      type: 'AdjustOffset',
      data: { x: offsetX, y: offsetY },
    });

    // 获取元素相对于屏幕的坐标,用于同步其他页面
    let coords = convertCoords('p2s', {
      x: parseInt(block.style.left),
      y: parseInt(block.style.top),
    });

    // 更新当前页面元素的坐标
    handleUpdateCoords(coords);

    // 通知其他页面更新元素坐标
    channel.postMessage({
      type: 'UpdateCoords',
      data: coords,
    });

  });

  // 处理广播消息
  channel.addEventListener('message', function (ev) {

    let { data, type } = parseChannelMessage(ev);

    switch (type) {
      case 'AdjustOffset':
        handleAdjustOffset(data);
        break;
      case 'UpdateCoords':
        handleUpdateCoords(data);
        break;
      default:
        break;
    }

  });

  initElementCoords();

})();

标签:元素,标签,JavaScript,param,let,坐标,data,block,页面
From: https://blog.51cto.com/u_16173094/8632074

相关文章

  • 82. 删除排序链表中的重复元素 II
    82.删除排序链表中的重复元素II2021年3月25日​数据量300,数据大小[-200,200]​题意很简单,就考验你指针的使用。​两种方法桶排序暴力法思路很简单,加个100的偏移量,然后全都存下来,再倒着存进链表里返回即可。classSolution{public:ListNode*deleteDuplicates(......
  • 83. 删除排序链表中的重复元素
    83.删除排序链表中的重复元素2021年3月26日删除排序链表中的重复元素II的简化版,while套while就行为了时间,指针都不删除吗?classSolution{public:ListNode*deleteDuplicates(ListNode*head){ListNode*p=head;while(p&&p->next){w......
  • JavaScript 防抖和节流
    JavaScript防抖和节流防抖以下js类库实现方法:lodash.debounceunderscore-debounce最初接触实现一个防抖函数的需求,是在前端封装React组件的过程中,当时是要实现一个搜索下拉框,根据输入提示搜索内容。根据<input>的input事件来监听用户输入,并调用后端接口传递输入信息......
  • javascript运行时报"未定义"错误怎么办
    https://www.php.cn/faq/508703.htmlJavascript是一种非常流行的编程语言,它广泛地应用于网页开发、动态效果实现、数据处理等领域。然而,Javascript也存在一些常见的错误,在开发的过程中需要我们注意和处理。其中之一的运行时错误:""未定义,下面就来详细介绍如何解决这一问题。什么......
  • 调用BarTender打印标签
    1privateBarTender.ApplicationbtAPP;2privateBarTender.FormatbtFormat;3//初始化对象4btAPP=newBarTender.Application();56try7{8btFormat=btApp.Form......
  • 让多媒体元素在既定容器中自由布局
    一功能可添加时间、日期、星期、字幕、图片、视频和背景音乐。可修改布局大小。画布及元素的个别属性(如x,y,width,height,fontsize)将会通过一定比例进行缩放,以此达到接近实际所看到的效果。可通过拖拽修改元素位置、添加新元素;可对元素进行收缩以改变其尺寸等属性。支持修改时间......
  • day1数组理论基础,704. 二分查找,27. 移除元素
    数组理论基础,704.二分查找,27.移除元素1数组理论基础1.1数组概念定义:存放在连续内存空间上的相同类型数据的集合。特点:1.数组中数据类型相同2.数组所占空间连续1.2数组创建2704.二分查找给定一个n个元素有序的(升序)整型数组nums和一个目标值target,写一个函数......
  • 自定义标签
    1.在应用(如:app01)下创建文件夹templatetags再创建一个py文件,编写自定义标签(如:mytag) 2.编写自定义标签fromdjangoimporttemplateregister=template.Library()@register.filter(name="cut")defcut(value,arg):returnvalue.replace(arg,"")@register.filt......
  • Ant-Design modal对话框未打开时,无法通过uesRef获取modal内部元素DOM节点
    为什么要记录下来呢?因为我在网上和chatGpt上没有搜到合适的解决方案。在CDNS上看到个和我遇到问题一样的,居然要收费才能看,所以自己记下来。当然肯定还有其他的好方案,欢迎大家留言。需求:使用antdV/g6画关系图,类似于企查查上面的那样:点击按钮打开Modal框,把数据渲染到Modal框的div......
  • 给定两个列表,找出他们相同的元素和不同的元素
    list1=[11,22,33,11]list2=[11,22,89,45]A=set(list1)#先去重B=set(list2)print(A&B)#相同的元素print(A^B)#不同的元素 ......