前端实现左右联动,置顶以及拖动小模块调整顺序

<template>
  <div class="editBox">
    <div class="left_tab" id="thescroll_tab">
      <div
        v-for="tab in thetabmodule"
        :key="tab.thename"
        :class="{ active: activeName === tab.thename }"
        class="tab-item"
        @click="handleTabClick(tab)"
        :data-tab="tab"
        :id="tab.thename+'left'"
      >
        <div class="theheaderclass" :data-tab="tab">
          <div class="left_text">{{ tab.label }}</div>
          <div class="number_text">{{ "(" + tab.datelength + ")" }}</div>
        </div>
      </div>
    </div>
    <div ref="rightBox" class="edit-cards" id="thescroll_container" @scroll="bindScrollEvent">
      <div
        v-if="
          currentArray[0].data.length ||
          collectArray[0].data.length ||
          thetabmodule.length
        "
      >
        <div>
          <div v-for="tab in currentArray" :key="tab.thename" id="currentuse">
            <div
              class="scroll_title"
              :class="{ activescrollTitle: activeName === tab.thename }"
            >
              <div
                class="smallbox"
                :class="{ activebox: activeName === tab.thename }"
              ></div>
              {{ tab.label }}
            </div>
            <div class="themodules_container">
              <SmallModule
                v-for="(item, index) in tab.data"
                :key="index"
                :moduleItem="item"
                @searchContent="searchContent"
              >
                <!-- <SmallModule v-for="(item, index) in tab.data" :key="index" :moduleItem="item"> -->
                <template v-slot:collect>
                  <div class="right_stare" v-if="item.iscollect == 1">
                    <i class="el-icon-star-on"></i>
                  </div>
                </template>
                <template v-slot:icon>
                  <img v-if="item.iconUrl" :src="item.iconUrl" alt="" />
                  <img v-else :src="theimage6" alt="" />
                </template>
                <template v-slot:theheader>
                  <!-- <div class="elliplice_1" v-if="item.type == 1">{{ item.name }}</div>
              <div class="elliplice_1" v-else>{{ item.customName }}</div> -->
                  <div
                    class="elliplice_1"
                    v-if="item.type == 1"
                    v-html="item.name"
                  ></div>
                  <div
                    class="elliplice_1"
                    v-else
                    v-html="item.customName"
                  ></div>
                </template>
              </SmallModule>
            </div>
          </div>
        </div>
        <div>
          <div v-for="tab in collectArray" :key="tab.thename" :id="tab.thename">
            <div class="thelinkbutton">
              <div
                class="scroll_title"
                :class="{ activescrollTitle: activeName === tab.thename }"
              >
                <div
                  class="smallbox"
                  :class="{ activebox: activeName === tab.thename }"
                ></div>
                {{ tab.label }}
              </div>
              <div class="linkbutton" @click="addlink">
                <i class="el-icon-plus"></i>
                <div class="linktext">{{ $t("addLink.addLinkBtn") }}</div>
              </div>
              <div class="linkTip">
                <!-- <div class="linkTip_content"> -->
                {{ $t("addLink.collectTip") }}
                <!-- </div> -->
              </div>
            </div>
            <transition-group class="themodules_container">
              <div
                v-for="(item, index) in tab.data"
                :key="index"
                :draggable="true"
                @dragstart="dragstart(item)"
                @dragenter="dragenter(item, $event)"
                @dragend="getDragend(tab.data, 'customer', $event)"
              >
                <SmallModule :moduleItem="item" @searchContent="searchContent">
                  <template v-slot:collect>
                    <div class="right_stare" v-if="item.iscollect == 1">
                      <i class="el-icon-star-on"></i>
                    </div>
                  </template>
                  <template v-slot:icon>
                    <img v-if="item.iconUrl" :src="item.iconUrl" alt="" />
                    <img v-else :src="theimage6" alt="" />
                  </template>
                  <template v-slot:theheader>
                    <!-- <div class="elliplice_1" v-if="item.type == 1">{{ item.name }}</div>
                <div class="elliplice_1" v-else>{{ item.customName }}</div> -->
                    <div
                      class="elliplice_1"
                      v-if="item.type == 1"
                      v-html="item.name"
                    ></div>
                    <div
                      class="elliplice_1"
                      v-else
                      v-html="item.customName"
                    ></div>
                  </template>
                </SmallModule>
              </div>
            </transition-group>
          </div>
        </div>
        <div v-for="tab in thetabmodule" :key="tab.thename" :id="tab.thename">
          <div
            class="scroll_title"
            :class="{ activescrollTitle: activeName === tab.thename }"
          >
            <div
              class="smallbox"
              :class="{ activebox: activeName === tab.thename }"
            ></div>
            {{ tab.label }}
          </div>
          <div class="themodules_container">
            <SmallModule
              v-for="(item, index) in tab.data"
              :key="index"
              :moduleItem="item"
              @searchContent="searchContent"
            >
              <template v-slot:collect>
                <div class="right_stare" v-if="item.iscollect == 1">
                  <i class="el-icon-star-on"></i>
                </div>
              </template>
              <template v-slot:icon>
                <img :src="item.iconUrl" alt="" />
              </template>
              <template v-slot:theheader>
                <div class="elliplice_1" v-html="item.name"></div>
              </template>
            </SmallModule>
          </div>
        </div>
        <div
          class="bottom_text"
          v-if="
            !searchvalue &&
            currentArray[0]?.data.length == firstcurrentList[0]?.data.length &&
            collectArray[0]?.data.length == firstcollectList[0]?.data.length
          "
        >
          {{ $t("addLink.tishiyu") }}
        </div>
      </div>
      <div class="theempty" v-show="showImg">
        <img src="@/assets/images/none.png" alt="" />
        <div class="img_text">未找到相关应用</div>
      </div>
    </div>
    <addLinkdialog
      :centerDialogVisible="centerDialogVisible"
      @closedialog="closedialog"
    />
  </div>
</template>
<script>
// import theimage6 from '@/assets/images/tubiao.jpg'
import SmallModule from "@/components/SmallModule.vue";
import addLinkdialog from "./addLinkdialog.vue";
import {
  getEnabledAppListAPI,
  recentlyAPI,
  collectListAPI,
  collectsortAPI,
} from "@/api/apply";
import theimage6 from "@/assets/images/default.png";

export default {
  components: {
    SmallModule,
    addLinkdialog,
  },
  props: {
    searchvalue: {
      type: String,
    },
  },
  data() {
    return {
      isempty: false,
      centerDialogVisible: false,
      theimage6: theimage6,
      thetabmodule: [],
      activeName:"", // 当前激活的标签名
      theStareList: [],
      //最近使用
      currentArray: [{ data: [] }],
      oldData: [],
      newData: [],
      dragStartId: "",
      dragEndId: "",
      //收藏
      collectArray: [{ data: [] }],
      firstcollectList: [],
      firstcurrentList: [],
      totalList: [],
      showImg: false,//展示未找到应用标志
    };
  },
  async activated() {
    if (this.searchvalue) {
      this.searchContent(this.searchvalue);
    } else {
      await this.getcollectList();
      await this.getEnableApply("");
    }
    // this.bindScrollEvent();
  },
  mounted(){
    window.addEventListener("beforeunload",()=>{ 
      localStorage.removeItem('activeName')
    });
  },
  methods: {
    closedialog(value) {
      if (value) {
        this.searchContent(this.searchvalue);
      }
      this.centerDialogVisible = false;
      // setTimeout(()=>{
      //   this.scrollToTop()
      // },20)
    },
    addlink() {
      this.centerDialogVisible = true;
    },
    dragstart(value) {
      this.oldData = value;
      this.dragStartId = value.collectId;
    },
    dragenter(value) {
      this.newData = value;
      this.dragEndId = value.collectId;
    },
    getDragend(listData) {
      if (this.dragStartId !== this.dragEndId) {
        let oldIndex = listData.indexOf(this.oldData);
        let newIndex = listData.indexOf(this.newData);
        let newItems = [...listData];
        // 删除之前DOM节点
        newItems.splice(oldIndex, 1);
        // 在拖拽结束目标位置增加新的DOM节点
        newItems.splice(newIndex, 0, this.oldData);
        // 每次拖拽结束后,将拖拽处理完成的数据,赋值原数组,使DOM视图更新,页面显示拖拽动画
        console.log("newItems", newItems);
        const idList = newItems.map((item) => item.collectId);
        this.collectArray = [
          {
            thename: this.$t("homeView.mycollect"),
            label: this.$t("homeView.mycollect"),
            data: newItems,
          },
        ];
        // {thename:'我的收藏',label:'我的收藏',data:collect.data.data?collect.data.data:[]}
        // 每次拖拽结束后调用接口时时保存数据
        collectsortAPI({ collectIds: idList }).then((res) => {
          console.log(res);
        });
      }
    },

    async getcurrentList() {
      const res = await recentlyAPI();
      // this.currentArray.push({thename:'最近使用',label:'最近使用',data:res.data.data?res.data.data:[]})
      let array2 = this.theStareList;
      let index = 0;
      const currently = [];
      this.currentArray = [];
      let length = "";
      //4A在更多应用页面最多为8个最近使用
      if (res.data.data.length < 8) {
        length = res.data.data.length;
      } else {
        length = 8;
      }
      for (let i = 0; i < length; i++) {
        // for (let i = 0; i < 8; i++) {
        let isContained = false;
        for (let j = 0; j < array2.length; j++) {
          if (
            res.data.data[i].name === array2[j].name &&
            res.data.data[i].id === array2[j].id
          ) {
            isContained = true;
            break;
          }
        }
        if (isContained) {
          res.data.data[i].iscollect = 1;
        } else {
          res.data.data[i].iscollect = 2;
        }
        index = index++;
        currently.push(res.data.data[i]);
      }
      this.currentArray.push({
        thename: this.$t("homeView.lastuse"),
        label: this.$t("homeView.lastuse"),
        data: currently,
      });
      this.firstcurrentList = this.currentArray;
    },
    // 收藏的数据
    async getcollectList() {
      const res = await collectListAPI();
      if (res) {
          res.data.data.forEach((item) => {
          item.iscollect = "1";
          // if(value){
          //   item.name = this.highlightKeyword(item.name, value);
          //   item.customName = this.highlightKeyword(item.customName, value);
          // }
        });
        this.theStareList = res.data.data;
        this.collectArray = [];
        this.collectArray.push({
          thename: this.$t("homeView.mycollect"),
          label: this.$t("homeView.mycollect"),
          data: res.data.data ? res.data.data : [],
        });
        this.firstcollectList = this.collectArray;
      }
    },
    highlightKeyword(text, keyword) {
      const highlightedKeyword = `<span style="color: #2D57F2;">${keyword}</span>`;
      const regex = new RegExp(keyword, "gi");
      return text.replace(regex, highlightedKeyword);
    },
    async getEnabledAppList(value) {
      const params = { appName: value };
      const res = await getEnabledAppListAPI(params);
      let array2 = this.theStareList || [];

      let instanceArray = res.data.data;
      let index = 0;
      this.thetabmodule = [];
      for (let key in instanceArray) {
        let array1 = instanceArray[key] || [];
        for (let i = 0; i < array1.length; i++) {
          let isContained = false;
          array1[i].name = this.highlightKeyword(array1[i].name, value);
          for (let j = 0; j < array2.length; j++) {
            if (array1[i].id === array2[j].id) {
              isContained = true;
              break;
            }
          }
          if (isContained) {
            array1[i].iscollect = 1;
          } else {
            array1[i].iscollect = 2;
          }
        }

        this.thetabmodule.push({
          thename: key || "",
          label: key || "",
          datelength: array1.length,
          data: array1,
        });
        index = index++;

        this.totalList = [];
        for (let k = 0; k < this.thetabmodule.length; k++) {
          this.totalList.push(this.thetabmodule[k].datelength);
        }
        const sum = this.totalList.reduce((accumulator, currentValue) => {
          return accumulator + currentValue;
        }, 0);
        this.$emit("appSum", sum);
      }
      this.activeName = localStorage.getItem('activeName')||this.thetabmodule[0]?.thename;
      if(this.collectArray[0].data.length == 0 && this.collectArray[0].data.length == 0 && this.thetabmodule.length == 0) {
        this.showImg = true
      } else {
        this.showImg = false
      }
    },
    async getEnableApply(value) {
      await Promise.all([
        this.getcurrentList(value),
        this.getEnabledAppList(value),
      ]);
    },

    async searchContent(value) {
      // console.log('firstcurrentList', this.firstcurrentList);

      if (!value) {
        await this.getcollectList();
        this.getEnableApply("");
      } else {
        let searchObj = this.searchvalue;
        let useArr = [...this.firstcurrentList];
        let collectArr = [...this.firstcollectList];
        let storeArr1 = [];
        let storeArr2 = [];
        this.currentArray = [];
        this.collectArray = [];
        //遍历最近使用,返回匹配item
        for (let i = 0; i < useArr.length; i++) {
          let data = useArr[i].data;
          for (let j = 0; j < data.length; j++) {
            if (data[j].customName) {
              let name = data[j].customName;
              if (name.indexOf(searchObj) != -1) {
                name = this.highlightKeyword(
                  data[j].customName,
                  this.searchvalue
                );
                storeArr1.push({ ...data[j], customName: name });
              }
            } else {
              let name = data[j].name;
              if (name.indexOf(searchObj) != -1) {
                name = this.highlightKeyword(data[j].name, this.searchvalue);

                storeArr1.push({ ...data[j], name: name });
              }
            }
          }
          // console.log('storeArr1', storeArr1)
          this.currentArray.push({
            thename: this.$t("homeView.lastuse"),
            label: this.$t("homeView.lastuse"),
            data: storeArr1,
          });
          // if(this.currentArray[0].data)
        }
        console.log("111", this.firstcollectList);

        this.collectArray = [];
        //遍历我的收藏
        for (let i = 0; i < collectArr.length; i++) {
          let data = collectArr[i].data;
          for (let j = 0; j < data.length; j++) {
            if (data[j].customName) {
              let name = data[j].customName;
              if (name.indexOf(searchObj) != -1) {
                name = this.highlightKeyword(
                  data[j].customName,
                  this.searchvalue
                );
                storeArr2.push({ ...data[j], customName: name });
              }
            } else {
              let name = data[j].name;
              if (name.indexOf(searchObj) != -1) {
                let name = data[j].name;
                if (name.indexOf(searchObj) != -1) {
                  name = this.highlightKeyword(data[j].name, this.searchvalue);
                  storeArr2.push({ ...data[j], name: name });
                }
              }
            }
          }
          console.log("storeArr2", storeArr2);

          this.collectArray.push({
            thename: this.$t("homeView.mycollect"),
            label: this.$t("homeView.mycollect"),
            data: storeArr2,
          });
        }

        //查询激活应用
        this.getEnabledAppList(this.searchvalue);
      }
    },
    // 根据右侧内容滚动,高亮侧边栏
    bindScrollEvent() {
      const editCards = document.querySelector(".edit-cards");
      const tabHeights = this.thetabmodule.map((tab) => {
        const card = document.getElementById(tab.thename);
        return {
          thename: tab.thename,
          offsetTop: card.offsetTop-editCards.offsetTop-30,  
        };
      });
      editCards.addEventListener("scroll", () => {
        const scrollPosition = editCards.scrollTop;
        tabHeights.forEach((item, index) => {
          if (editCards.scrollHeight - editCards.clientHeight === editCards.scrollTop||editCards.scrollHeight - editCards.clientHeight <= editCards.scrollTop) {
            return false
          }
          if (
            scrollPosition >= item.offsetTop && scrollPosition < tabHeights[index + 1].offsetTop
          ) {
             this.activeName = item.thename;
             localStorage.setItem('activeName',this.activeName)
             this.tabToTop(this.activeName)
          }
        });
      });
    },
    // 点击侧边栏,使得右侧内容滚动到对应为止
    scrollToTabContent(tabName) {
      const contentElement = document.getElementById(tabName);
      const tabContainer = document.getElementById("thescroll_container");
     
      if (contentElement && tabContainer) {
        // 计算contentElement相对于tabContainer的位置
        const offsetTop = contentElement.offsetTop - tabContainer.offsetTop;
        tabContainer.scrollTop = offsetTop;
      }
    },
  //  侧边栏滚动
    tabToTop(tabName) {
      const contentElement = document.getElementById(tabName+'left');
      const leftTab = document.getElementById("thescroll_tab");

      if (contentElement && leftTab) {
        const offsetTop = contentElement.offsetTop-leftTab.offsetTop
        // leftTab.scrollTop = offsetTop;
        leftTab.scrollTo(0, offsetTop);
      }
    },
     // 置顶
    scrollToTop() {
      const contentElement = document.getElementById("currentuse");
      const tabContainer = document.getElementById("thescroll_container");
      if (contentElement && tabContainer) {
        this.activeName=this.thetabmodule[0].thename
        localStorage.setItem('activeName',this.activeName)
        this.tabToTop(this.thetabmodule[0].thename)
        const offsetTop = contentElement.offsetTop - tabContainer.offsetTop;
        tabContainer.scrollTop = offsetTop;
      }
    },
    handleTabClick(tab) {
     //点击后切换样式
      this.activeName = tab.thename;
      localStorage.setItem('activeName',this.activeName)
      this.scrollToTabContent(tab.thename);
    },
  },
};
</script>
<style lang="scss" scoped>
.editBox {
  height: 100%;
  width: 100%;
  display: flex;
  overflow-y: auto;

  .left_tab {
    width: 205px;
    // border: 1px solid red;
    height: 100%;
    overflow: auto;
    scrollbar-width: none;
    // box-sizing: border-box;
    font-size: 14px;
    .active{
      background-color: #e2ebfc;
      color: #2d57f2;
      font-weight: 700;
      border-right: 3px solid #2d57f2;
      .theheaderclass{
        font-size: 16px;
      }
      
    }
   
  }
  .left_tab::-webkit-scrollbar{
    width: 0;
  }
  .left_tab::-webkit-scrollbar-thumb{
    background-color:transparent;
  }


}

.edit-cards {
  width: 100%;
  height: 80vh;
  overflow-y: scroll;
  scrollbar-width: none;
}

.edit-cards::-webkit-scrollbar {
  width: 0;
}

.edit-cards::-webkit-scrollbar-thumb {
  background-color: transparent;
}

.el-tabs--left.el-tabs--card .el-tabs__nav {
  border: none;
}

.edit-cards {
  height: 100%;
  // overflow: hidden;
  padding: 0 20px;
  // margin-top: -30px;

  .scroll_title {
    font-size: 18px;
    font-weight: 700;
    margin-top: 20px;
    display: flex;
    align-items: center;
    white-space: nowrap;
  }

  .themodules_container {
    width: 100%;
    display: grid;
    grid-template-columns: repeat(4, minmax(185px, 1fr));
    // grid-template-columns: repeat(4, 1fr);
    gap: 16px;
    // min-width: 80vw;
  }
}

.activescrollTitle {
  color: #454ec8;
}

.smallbox {
  width: 10px;
  height: 10px;
  background-color: #7f4ee8;
  margin-right: 20px;
}

.activebox {
  background-color: #454ec8;
}

.sort-move {
  transition: transform 1s;
}

.thelinkbutton {
  display: flex;
  align-items: center;

  .linkbutton {
    margin-top: 20px;
    height: 20px;
    margin-left: 10px;
    font-size: 12px;
    display: flex;
    align-items: center;
    padding: 3px 7px 3px 3px;
    background-color: #2d57f2;
    text-align: center;
    color: #fff;
    border-radius: 6px;
    cursor: pointer;
    width: fit-content !important;
    white-space: nowrap;
    /* 防止文本换行 */
    overflow: hidden;
    /* 隐藏溢出内容 */
    text-overflow: ellipsis;
    /* 溢出文本显示省略号 */

    .linktext {
      width: fit-content;
    }
  }

  .linkTip {
    flex: 1;
    height: 20px;
    padding-top: 26px;
    // width: fit-content;
    // .linkTip_content {
    margin-left: 8px;
    font-size: 12px;
    font-weight: 400;
    color: #86909c;
    white-space: nowrap;
    /* 防止文本换行 */
    overflow: hidden;
    /* 隐藏溢出内容 */
    text-overflow: ellipsis;
    // overflow: hidden;
    // text-overflow: ellipsis;
    // }
  }
}

.theheaderclass {
  display: flex;
  height: 48px;
  width: 100%;
  align-items: center;
  font-size: 14px;
  font-family: "Noto Sans", sans-serif;
  cursor: pointer;

  .left_text {
    line-height: 48px;
    max-width: 100px;
    margin-left: 25px;
    white-space: nowrap;
    /* 强制文本不换行 */
    overflow: hidden;
    /* 隐藏溢出内容 */
    text-overflow: ellipsis;
    /* 溢出部分显示省略号 */
  }

  .number_text {
    line-height: 48px;
  }
}

.clicked_tab {
  background-color: #e2e9fd;
  color: #2d57f2;
  font-size: 16px;
  border-radius: 10px 0 0 10px;
  border-right: 1px solid #2d57f2;
  font-weight: 700;
}

.bottom_text {
  text-align: center;
  line-height: 50px;
  color: #676f7a;
  font-weight: 600;
  margin-top: -10px;
  margin-bottom: 30px;
}

.theempty {
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
    img {
      margin-left: -12%;
    }

  .img_text {
    color: var(---Text-4, #4e5969);
    font-family: PingFang SC;
    font-size: 12px;
    font-style: normal;
    font-weight: 400;
    margin-top: 10px;
    margin-left: -12.5%
  }
}

.elliplice_1 {
  min-width: 120px;
  margin-left: -3px;
}
// .scrollable-tabs{
//   height: 100px;
//   overflow-y:scroll ;
// }

// .scrollable-tab-pane {
//     overflow-y: auto;
//     max-height: 300px; /* 根据需要设置每个标签页内容的最大高度,超出则滚动 */
// }

</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

捂風鋔笶_小欣同學

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值