m0_65749592 2023-08-25 17:26 采纳率: 35.5%
浏览 5

一个标签功能 , 我想实现这个标签可以拖拽功能 需要加什么呀

一个标签功能 , 我想实现这个标签可以拖拽功能 需要加什么呀 下面贴下全代码

img

<template>
  <div>
    <div class="tags">
      <!-- 左箭头 -->
      <div
        class="arrow arrow_left"
        v-show="arrowVisible"
        @click="handleClickToLeft"
      >
        <i class="el-icon-arrow-left"></i>
      </div>
      <!-- 标签内容 -->
      <div class="tags_content" ref="box">
        <span ref="tags">
          <el-tag
            v-for="(tag, index) in tags"
            :key="tag.name + index"
            :class="[active == index ? 'active top_tags' : 'top_tags']"
            effect="dark"
            :closable="tag.name != 'Dashboard'"
            @close="handleClose(index, tag)"
            @click="clickTag(index, tag)"
            @contextmenu.native.prevent="handleClickContextMenu(index, tag)"
          >
            {{ tag.title || '首页' }}
          </el-tag>
        </span>
      </div>
      <!-- 右箭头 -->
      <div
        class="arrow arrow_right"
        v-show="arrowVisible"
        @click="handleClickToRight"
      >
        <i class="el-icon-arrow-right"></i>
      </div>
    </div>
    <!-- 右键菜单 -->
    <ul
      v-show="contextMenu.isShow"
      :style="{ left: contextMenu.menuLeft, top: '96px' }"
      class="el-dropdown-menu el-popper"
      x-placement="bottom-end"
    >
      <li
        v-if="this.active == this.contextMenu.index"
        class="el-dropdown-menu__item"
        @click="refresh"
      >
        刷新
      </li>
      <li class="el-dropdown-menu__item" @click="closeRightTag">
        关闭右侧
      </li>
      <li class="el-dropdown-menu__item" @click="closeOtherTag">
        关闭其它
      </li>
      <div x-arrow="" class="popper__arrow" style="left: 44px;"></div>
    </ul>
  </div>
</template>

<script>
  import Sortable from 'sortablejs';
import tags from 'element-resize-detector';
export default {
  data() {
    return {
      // 是否有箭头
      arrowVisible: true,
      // 点击次数
      num: 0,
      active: 0,
      tags: [
       {name: 'AgencyConfig', path: '/AgencyConfig', title: '代理配置'    } ,//   上面25行用title
      ],
      // 右键的元素
      contextMenu: {
        index: 0,
        tag: {},
        menuLeft: 0,
        isShow: false
      }
    };
  },
  watch: {
    $route() {
      this.getThisPage();
    },
    tags() {
      this.listenFun(this.$refs.tags, "tags");
    }
  },
  mounted() {
    this.listenFun(this.$refs.box, "box");
    var that = this;
    document.addEventListener("click", function(e) {
      that.contextMenu.isShow = false;
    });

  },
  methods: {
    // 监听可视区域宽,浏览器窗口大小改变执行
    listenFun(monitor, dom) {
      let boxWidth = this.$refs.box.offsetWidth,
        tagsWidth = this.$refs.tags.offsetWidth,
        erd = tags();
      erd.listenTo(monitor, ele => {
        this.$nextTick(() => {
          if (this.$refs.box && this.$refs.box.style) {
            if ((dom == "box" && ele.offsetWidth >= tagsWidth) || (dom == "tags" && ele.offsetWidth <= boxWidth)) {
                this.arrowVisible = false;
                this.$refs.box.style.paddingLeft = "1px";
                this.$refs.box.style.paddingRight = "16px";
                this.$refs.box.style.transform = "TranslateX(0px)";
                this.num = 0;
            } else {
                this.arrowVisible = true;
                this.$refs.box.style.paddingLeft = "56px";
                this.$refs.box.style.paddingRight = "56px";
            }
          }
        });
      });
    },
    // 判断当前页
    getThisPage() {
      let currentPgae = this.$route;
      console.log('`````````',currentPgae)
      // 判断tags里是否有当前页面
      var index = this.tags.findIndex(tag => tag.name == currentPgae.name);
      if (index === -1) {
        this.tags.push({
          name: currentPgae.name,
          path: currentPgae.path,
          title: currentPgae.meta.title
        });
      }
      // 当前选择页
      this.active = this.tags.findIndex(tag => tag.name == currentPgae.name);

    },
    // 关闭标签
    handleClose(index, tag) {
      this.tags.splice(this.tags.indexOf(tag), 1);
      if (index - 1 === 0) {
        this.$router.push('/dashboard');
      } else if (index == this.tags.length) {
        this.active = index - 1;
        this.$router.push(this.tags[index - 1].path);
      } else {
        this.$router.push(this.tags[index].path);
      }
    },
    // 点击标签
    clickTag(index, tag) {
      this.active = index;
      if (this.active === 0) {
        this.$router.push('/dashboard')
      } else {
       this.$router.push(tag.path);
      }
    },

    // 左侧按钮
    handleClickToLeft() {
      if (this.num > 0) {
        this.num--;
        this.$refs.box.style.transform = `TranslateX(-${this.num * 200}px)`;
      }
    },
    // 右侧按钮
    handleClickToRight() {
      // 最后一个标签右测距离浏览器左侧距离
      let lastChild = document
        .querySelectorAll(".top_tags")
        [this.tags.length - 1].getBoundingClientRect().right;
      // 可视窗口的宽
      let bodyWidth = document.body.offsetWidth;
      // 右侧箭头48+右侧边距16
      if (bodyWidth - lastChild <= 64) {
        this.num++;
        this.$refs.box.style.transform = `TranslateX(-${this.num * 200}px)`;
      }
    },
    // 右键
    handleClickContextMenu(index, tag) {
      this.contextMenu.isShow = true;
      this.contextMenu.index = index;
      this.contextMenu.tag = tag;
      let isTag = document
        .querySelectorAll(".top_tags")
        [index].getBoundingClientRect();
      this.contextMenu.menuLeft = isTag.left - 48 + isTag.width / 2 + "px";
    },
    // 刷新
    refresh() {
      this.$router.go(0);
    },

    // 关闭其他
    closeOtherTag() {
      let tagsLin = this.tags.length,
        { index, tag, menuLeft } = this.contextMenu;
      if (index !== 0) {
        this.tags = [
          {
            path: "/dashboard",
            name: "Dashboard"
          },
          {
            name: tag.name,
            path: tag.path,
            title: tag.title
          }
        ];
      } else {
        this.tags = [
          {
            path: "/dashboard",
            name: "Dashboard"
          }
        ];
      }
      this.active = index;
      if (this.active === 0) {
        this.$router.push('/dashboard');
      } else {
        this.$router.push(tag.path);
      }

    },
    // 关闭右侧
    closeRightTag() {
      let tagsLin = this.tags.length,
        { index, tag, menuLeft } = this.contextMenu;
      this.tags.splice(index + 1, tagsLin - index);
      this.active = index;
      if (this.active === 0) {
        this.$router.push('/dashboard');
      } else {
        this.$router.push(tag.path);

      }
    }
  },
  created() {
    // 监听页面刷新
    window.addEventListener("beforeunload", e => {
      localStorage.setItem(
        "tagInfo",
        JSON.stringify({
          active: this.active,
          tags: this.tags
        })
      );
    });
    let tagInfo = localStorage.getItem("tagInfo")
      ? JSON.parse(localStorage.getItem("tagInfo"))
      : {
          active: 0,
          tags: [
            {
              path: "/dashboard",
              name: "Dashboard"
            }
          ]
        };
    this.active = tagInfo.active;
    this.tags = tagInfo.tags;

  }
};
</script>


 <style  lang="scss" scoped>

 ::v-deep.el-tag--dark {
  border-color: transparent;
}
 ::v-deep.el-tag--dark .el-tag__close {
  color: #6b6b6b; //叉叉本身的颜色
  font-size: 16px;
}
 ::v-deep.el-tag--dark .el-tag__close:hover {
  background: #5f5f5f; // 鼠标放到 叉掉标签 显示的颜色
}
.tags {
  position: relative;
  overflow: hidden;
  .arrow {
    width: 30px;
    text-align: center;
    cursor: pointer;
    background: #ffffff; // 箭头颜色
    position: absolute;
    z-index: 1;
    &_left {
      left: 0;
      top: 0;
    }
    &_right {
      right: 0;
      top: 0;
    }
  }
  &_content {
    transition: 0.3s;
    white-space: nowrap;
     //padding: 0 16px;
  }

  .top_tags {
    margin-right: 8px; // 右边距
    cursor: pointer;
    background: #9793aa; // 其他标签颜色
    font-size: 13px; // 字体大小
    font-weight: 500; // 字体粗细
    color: #ffffff; // 文字颜色
  }
  .top_tags:hover,
  .active,
  .arrow:hover {
    background: #7f6b5f; // 点击页面颜色

  }
}
</style>



  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-08-25 23:32
    关注

    【以下回答由 GPT 生成】

    要在Vue.js中实现拖拽标签的功能,可以使用HTML5中的Drag and Drop API。下面是具体的解决方案:

    1. 首先,在每个标签元素上添加draggable="true"属性,以使其可以拖拽。
    <span
      ref="tags"
      v-for="(tag, index) in tags"
      :key="tag.name + index"
      :class="[active === index ? 'active top_tags' : 'top_tags']"
      effect="dark"
      :closable="tag.name !== 'Dashboard'"
      @close="handleClose(index, tag)"
      @click="clickTag(index, tag)"
      @contextmenu.native.prevent="handleClickContextMenu(index, tag)"
      draggable="true"
    >
      {{ tag.title || '首页' }}
    </span>
    
    1. 接下来,添加拖拽事件处理函数。在Vue组件的created生命周期钩子函数中,为所有的标签元素绑定拖拽事件:
    created() {
      const tagsElement = this.$refs.tags;
      Array.from(tagsElement).forEach((element) => {
        element.addEventListener('dragstart', this.handleDragStart);
        element.addEventListener('dragover', this.handleDragOver);
        element.addEventListener('dragend', this.handleDragEnd);
      });
    },
    
    1. 在Vue组件的methods属性中,定义handleDragStart(event)handleDragOver(event)handleDragEnd(event)这三个拖拽事件的处理函数。这些处理函数将标签的索引信息存储在拖拽事件的DataTransfer对象中,并在需要时进行相关的处理。
    methods: {
      handleDragStart(event) {
        // 存储标签的索引信息到拖拽事件的DataTransfer对象中
        const tagIndex = Array.from(this.$refs.tags).indexOf(event.target);
        event.dataTransfer.setData('text/plain', tagIndex.toString());
      },
      handleDragOver(event) {
        // 阻止默认的拖拽行为
        event.preventDefault();
      },
      handleDragEnd(event) {
        // 从拖拽事件的DataTransfer对象中获取标签的索引信息
        const tagIndex = parseInt(event.dataTransfer.getData('text/plain'));
        // 处理标签的拖拽结束逻辑
        // ...
      },
    }
    
    1. 最后,在handleDragEnd(event)处理函数中,根据标签的拖拽结束位置和起始位置进行相关的交换操作。可以使用Vue的$set方法来更新标签列表的顺序,确保视图正确地更新。
    handleDragEnd(event) {
      // 从拖拽事件的DataTransfer对象中获取标签的索引信息
      const tagIndex = parseInt(event.dataTransfer.getData('text/plain'));
      // 获取拖拽结束位置的索引
      const targetIndex = Array.from(this.$refs.tags).indexOf(event.target);
    
      // 判断是否发生了位置交换
      if (tagIndex !== targetIndex) {
        // 更新标签列表的顺序
        this.$set(this.tags, tagIndex, this.tags.splice(targetIndex, 1, this.tags[tagIndex])[0]);
      }
    },
    

    这样,就可以在Vue.js中实现可拖拽的标签功能了。

    请注意,以上代码仅提供了一个大致的实现思路,具体的交互和样式细节可能需要根据实际需求进行调整和完善。



    【相关推荐】



    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    评论

报告相同问题?

问题事件

  • 创建了问题 8月25日

悬赏问题

  • ¥30 模拟电路 logisim
  • ¥15 PVE8.2.7无法成功使用a5000的vGPU,什么原因
  • ¥15 is not in the mmseg::model registry。报错,模型注册表找不到自定义模块。
  • ¥15 安装quartus II18.1时弹出此error,怎么解决?
  • ¥15 keil官网下载psn序列号在哪
  • ¥15 想用adb命令做一个通话软件,播放录音
  • ¥30 Pytorch深度学习服务器跑不通问题解决?
  • ¥15 部分客户订单定位有误的问题
  • ¥15 如何在maya程序中利用python编写领子和褶裥的模型的方法
  • ¥15 Bug traq 数据包 大概什么价