树结构,遍历数组,展示内容

一、有一个固定的文章列表需要展示出来。效果如下图,标题在左侧,内容在右侧

二、注意点:

a.内容后台使用html格式返回,我这边展示假数据换成数据了
b.右下角有个分享链接的按钮,需要引入组件clipboard

c.后台返回的数据特殊,是根据数据是否有children,有的话才会展示出来

三、递归组件以及父页面代码展示

a.递归组件代码,helplist.vue
<template>
  <div class="helplist">
    <div
      v-if="model.isDisplay"
      :class="{
        selectColor: model.id == selectId,
        selectback: model.id == selectId,
        islevelOne: model.level == 1,
      }"
      :style="{ paddingLeft: model.level * 25 + 'px' }"
      class="helplist_label"
      @click.prevent="handleClick(model,getNextIcon(model))"
      @mouseenter="showcolor = true"
      @mouseleave="showcolor = false"
    >
      <span>
        <img
          class="helplist_label_icon"
          v-if="
            (model.selectIcon && showcolor) ||
            (model.selectIcon && model.id == selectId && model.level == 1)
          "
          :src="model.selectIcon"
          alt=""
        />
        <img
          class="helplist_label_icon"
          v-else-if="model.icon && model.level == 1"
          :src="model.icon"
          alt=""
        />
      </span>
      {{ model.label }}
    </div>
    <div
      v-show="reveal && model.isDisplay"
      :class="{ margin_L20: model.level != 1, margin_L30: model.level == 1 }"
    >
      <helplist
        v-for="item in model.children"
        @clickTitle="clickTitle"
        :key="item.id"
        :model="item"
        :selectId="selectId"
      />
    </div>
  </div>
</template>
<script>
export default {
  name: "helplist",
  data() {
    return {
      reveal: false,
      isFan: false,
      showcolor: false,
    };
  },
  props: ["model", "selectId"],
  components: {},
  computed: {
    isDispaly() {
      return this.model.children && this.model.children.length;
    },
  },
  created() {
    this.handleClick()
    },
  methods: {
    handleClick(model,flag) {
      if (model) {
        model.isshow = !model.isshow;
        if(!flag){
          this.clickTitle(model);
        }
      }
      if (this.isDispaly) {
        this.reveal = !this.reveal;
      }
      
    },
    clickTitle(val) {
      this.$emit("clickTitle", val);
    },
    getNextIcon(model) {
      if (!model.children || model.children.length == 0) {
        return false;
      }
      let flag = false;
      for (let i of model.children) {
        if (i.isDisplay) {
          flag = true;
        }
      }
      return flag
    },
  },
};
</script>

<style  scoped>
.helplist {
  height: 100%;
}
.helplist_label {
  cursor: pointer;
  text-align: left;
  line-height: 40px;
  padding: 20rpx 0;
  font-size: 16px;
  color: #333333;
}
.islevelOne {
  font-weight: bold;
}
.helplist_label:hover {
  color: #17908E;
  cursor: pointer;
  background-color: #f6f7f7;
  border-radius: 4px;
}
.selectColor {
  color: #17908E;
}
.selectback {
  background-color: #f6f7f7;
  border-radius: 4px;
}
.helplist_label_icon {
  width: 20px;
  height: 20px;
  vertical-align: middle;
}
.search-button {
  background-color: #eaf0f1;
  height: 40px;
  width: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.search-button:hover {
  color: #ffffff;
}
</style>
b.父页面home.vue,接口名称删除,自行修改
<template>
  <div class="home">
    <div class="help_left approval-scroll">
      <div v-for="(menu, index) in titleList" :key="menu.id">
        <helplist
          :model="menu"
          :index="index"
          @clickTitle="clickTitle"
          :selectId="selectId"
        ></helplist>
      </div>
    </div>
    <div class="help_right">
      <div style="height: calc(100% - 100px)">
        <div class="content_common">
          <div
            @scroll="onScroll"
            class="content_first approval-scroll"
            id="contents"
            ref="mainContent"
          >
            <div
              @click="jump(index)"
              class="subject-list-wrap-relot-const"
              v-for="(item, index) in content.children"
              :id="'floor' + index"
              :key="item"
            >
              <!-- <p class="subject_content" v-html="item.content"></p> -->
              {{ item.content }}
            </div>
          </div>
        </div>
      </div>
    </div>
    <div
      class="share_position copy-btn"
      :data-clipboard-text="copiedText"
      @click="copyToclipboard"
    >
      分享链接
    </div>
  </div>
</template>

<script>
import feedback from "@/components/feedback.vue";
import helplist from "@/components/helplist.vue";
import ClipboardJS from "clipboard";
import baseUrl from "@/api/request";

export default {
  name: "home",
  data() {
    return {
      titleList: [],
      isFan: false,
      content: "",
      searchText: null,
      inputFocus: false,
      moveIndex: "",
      navBarFixed: false,
      pageName: "",
      pageI: "",
      isStep: true,
      showhover: false, //默认不显示悬停
      sharehover: false,
      showwhite: false, //默认不显示白色搜索
      defaultProps: {
        children: "children",
        label: "label",
      },
      //登录
      Rid: "",
      copiedText: "",
      circleList: [
        {
          articleType: "2",
          children: [],
          content: "产品介绍content",
          createTime: "2021-12-20 16:37:52",
          icon: "https://v.lawbal.com:9393/26,28d978e8b2b620.svg",
          id: "649cce11_1901_4b48_a2a6_e9868b10dc87",
          isDeleted: 0,
          isDisplay: false,
          isdown: false,
          isshow: false,
          label: "产品介绍",
          level: 1,
          parentId: "",
          previousDis: null,
          selectIcon: "https://v.lawbal.com:9393/29,28dd06a65a9238.svg",
          sort: null,
          title: "产品介绍",
          updateTime: "2022-01-10 09:49:56",
        },
        {
          articleType: "2",
          children: [
            {
              articleType: "2",
              children: [
                {
                  articleType: "2",
                  children: [
                    {
                      articleType: "2",
                      children: [],
                      content: "2.content",
                      createTime: "2022-01-12 09:21:47",
                      icon: "",
                      id: "8a1eeb05_ba56_4171_ab2c_dd97a59387c1",
                      isDeleted: 0,
                      isDisplay: false,
                      isdown: false,
                      isshow: false,
                      label: "2.title",
                      level: 3,
                      parentId: "00128666_ecef_45d0_8312_08e3c1194ac0",
                      previousDis: null,
                      selectIcon: "",
                      sort: null,
                      title: "2.title",
                      updateTime: "2022-04-14 18:35:13",
                    },
                  ],
                  content: "",
                  createTime: "2022-01-12 09:19:09",
                  icon: "",
                  id: "00128666_ecef_45d0_8312_08e3c1194ac0",
                  isDeleted: 0,
                  isDisplay: true,
                  isdown: true,
                  isshow: false,
                  label: "1.title",
                  level: 2,
                  parentId: "0d452617_7482_48fd_a31b_fcc1eff8b155",
                  previousDis: null,
                  selectIcon: "",
                  sort: null,
                  title: "1.title",
                  updateTime: "2022-04-14 17:09:59",
                },
              ],
              content: "",
              createTime: "2022-01-12 09:19:09",
              icon: "",
              id: "00128666_ecef_45d0_8312_08e3c1194ac0",
              isDeleted: 0,
              isDisplay: true,
              isdown: true,
              isshow: false,
              label: "2.",
              level: 2,
              parentId: "0d452617_7482_48fd_a31b_fcc1eff8b155",
              previousDis: null,
              selectIcon: "",
              sort: null,
              title: "2.",
              updateTime: "2022-04-14 17:09:59",
            },
            {
              articleType: "2",
              children: [
                {
                  articleType: "2",
                  children: [
                    {
                      articleType: "2",
                      children: [],
                      content: "3.1正文content",
                      createTime: "2022-04-14 18:20:34",
                      icon: "",
                      id: "ddd1d8cb_eacc_4e58_afb8_65ad38288801",
                      isDeleted: 0,
                      isDisplay: false,
                      isdown: false,
                      isshow: false,
                      label: "3.1label",
                      level: 4,
                      parentId: "5f199fca_40e0_48a5_af29_6301951499c0",
                      previousDis: null,
                      selectIcon: "",
                      sort: null,
                      title: "3.1label",
                      updateTime: "2022-07-12 11:36:56",
                    },
                  ],
                  content: "3.1内容",
                  createTime: "2022-01-26 11:38:23",
                  icon: "",
                  id: "5f199fca_40e0_48a5_af29_6301951499c0",
                  isDeleted: 0,
                  isDisplay: true,
                  isdown: true,
                  isshow: false,
                  label: "3.1 title",
                  level: 3,
                  parentId: "94302c72_bce2_4c37_8376_c17f9343e1e8",
                  previousDis: null,
                  selectIcon: "",
                  sort: null,
                  title: "3.1 title",
                  updateTime: "2022-04-14 18:25:23",
                },
                {
                  articleType: "2",
                  children: [
                    {
                      articleType: "2",
                      children: [],
                      content: "3.2内容",
                      createTime: "2022-04-14 18:24:33",
                      icon: "",
                      id: "a94d3c2c_a7de_4bde_9c74_b1cf8ec789ef",
                      isDeleted: 0,
                      isDisplay: false,
                      isdown: false,
                      isshow: false,
                      label: "3.2title",
                      level: 4,
                      parentId: "91d5a9f3_211e_4735_aec4_91352eded115",
                      previousDis: null,
                      selectIcon: "",
                      sort: null,
                      title: "3.2title",
                      updateTime: "2022-04-14 18:24:52",
                    },
                  ],
                  content: "3.2content",
                  createTime: "2022-04-14 17:55:06",
                  icon: "",
                  id: "91d5a9f3_211e_4735_aec4_91352eded115",
                  isDeleted: 0,
                  isDisplay: true,
                  isdown: true,
                  isshow: false,
                  label: "3.2 title",
                  level: 3,
                  parentId: "94302c72_bce2_4c37_8376_c17f9343e1e8",
                  previousDis: null,
                  selectIcon: "",
                  sort: null,
                  title: "3.2 tilte",
                  updateTime: "2022-04-14 18:24:42",
                },
              ],
              content: "",
              createTime: "2022-01-26 11:36:29",
              icon: "",
              id: "94302c72_bce2_4c37_8376_c17f9343e1e8",
              isDeleted: 0,
              isDisplay: true,
              isdown: true,
              isshow: false,
              label: "3",
              level: 2,
              parentId: "0d452617_7482_48fd_a31b_fcc1eff8b155",
              previousDis: null,
              selectIcon: "",
              sort: null,
              title: "3",
              updateTime: "2022-04-14 18:36:18",
            },
          ],
          content: "",
          createTime: "2021-12-20 16:56:57",
          icon: "https://v.lawbal.com:9393/27,28dd1a444271ed.svg",
          id: "0d452617_7482_48fd_a31b_fcc1eff8b155",
          isDeleted: 0,
          isDisplay: true,
          isdown: true,
          isshow: false,
          label: "标题",
          level: 1,
          parentId: "",
          previousDis: null,
          selectIcon: "https://v.lawbal.com:9393/24,28dd1e866286be.svg",
          sort: null,
          title: "标题",
          updateTime: "2024-01-02 14:05:57",
        },
      ],
    };
  },
  props: [],
  computed: {},

  created() {
    this.gethelpList();
  },
  components: {
    helplist,
    feedback,
  },
  watch: {},
  mounted() {
    if (this.$route.query.id) {
      this.Rid = this.$route.query.id;
      localStorage.setItem("Rid", this.$route.query.id);
    }
  },
  destroyed() {},
  methods: {
    copyToclipboard() {
      let that = this;
      that.$message({
        message: "恭喜你,成功获取文章链接",
        type: "success",
      });
      var clipboard = new ClipboardJS(".copy-btn");
      clipboard.on("success", function (e) {
        console.info("Action:", e.action);
        e.clearSelection();
      });
      clipboard.on("error", function (e) {
        console.error("Action:", e.action);
      });
    },
    jump(index) {
      var items = document.querySelectorAll(".subject-list-wrap-relot-const");
      for (var i = 0; i < items.length; i++) {
        if (index === i) {
          items[i].scrollIntoView({
            block: "start", //默认跳转到顶部
            behavior: "smooth", //滚动的速度
          });
        }
      }
    },
    onScroll(e) {
      let scrollItems = document.querySelectorAll(
        ".subject-list-wrap-relot-const"
      );
      for (let i = scrollItems.length - 1; i >= 0; i--) {
        // 判断滚动条滚动距离是否大于当前滚动项可滚动距离
        let judge =
          e.target.scrollTop >=
          scrollItems[i].offsetTop - scrollItems[0].offsetTop;
        if (judge) {
          this.pageI = i;
          break;
        }
      }
    },
    gethelpList() {
      this.$http
        .get("/../", {})
        .then((res) => {
          console.log("titleList", res.page.list);
          if (res.page.list) {
            this.titleList = this.circleList; 
            this.titleList.isParent = this.circleList.length > 0 ? 1 : 0; 
            this.isChild(this.titleList);
            this.getLevel(this.titleList, 1);
            this.getFirstChild(this.titleList);
          }
        })
        .catch((msg) => {
          this.$message({
            message: msg,
            type: "error",
          });
        });
    },
    // 递归拿到第一篇文章
    getFirstChild(val) {
      let res = {};
      if (JSON.stringify(res) != "{}") {
        return; //如果res不再是空对象,退出递归
      } else {
        //遍历数组
        for (let i = 0; i < val.length; i++) {
          //如果当前的isleaf是true,说明是叶子节点,把当前对象赋值给res,并return,终止循环
          if (val[i].isDisplay) {
            res = val[i];
            //默认选中第一条数据
            this.clickTitle(res.children[0]);
            return;
          } else if (!val[i].children) {
            //如果chidren为空,则停止这次循环
            break;
          } else {
            //否则的话,递归当前节点的children
            this.getFirstChild(val[i].children);
          }
        }
      }
    },
    isChild(list) {
      for (let i of list) {
        // 默认无下级,未展开
        this.$set(i, "isdown", false);
        this.$set(i, "isshow", false);
        if (i.children && i.children.length > 0) {
          // 有下级,isdown,true
          // 未展开,isshow,false
          this.$set(i, "isdown", true);
          this.$set(i, "isshow", false);
          this.isChild(i.children);
        }
      }
    },
    //获取等级
    getLevel(list, count) {
      for (let i of list) {
        this.$set(i, "level", count);
        if (i.children && i.children.length > 0) {
          let counts = count + 1;
          this.getLevel(i.children, counts);
        }
      }
    },
    openFan() {
      this.isFan = true;
    },
    clickTitle(val) {
      debugger;
      if (this.$route.query.id) {
        let model = this.findPnodeId(this.circleList, this.Rid);
        localStorage.setItem("Rid", this.$route.query.id);
        this.content = model;
        this.selectId = model.id;
        this.$router.push({ query: {} }); //清空地址栏参数
      } else {
        this.content = val;
        this.selectId = val.id;
        this.Rid = val.id;
        localStorage.setItem("Rid", val.id);
        let text = "";
        text =
          "https://..." +
          (localStorage.getItem("userId") || this.$route.query.userId) +
          "&id=" +
          val.id;
        this.copiedText = text;
      }
    },

    handleFocus() {
      this.inputFocus = true;
    },
    //这里传入目录顺序
    handleClick(i) {
      let idIndex = "floor" + i;
      this.moveIndex = i;
      let anchorElement = document.getElementById(idIndex);
      if (anchorElement) {
        anchorElement.scrollIntoView();
      }
      // 点击的时候 滚动到对应的那个内容区
      // 1:获取点击的按钮对应页面的id
      let PageId = document.querySelector("#floor" + i);
      this.pageI = i;
      //设置滚动 并且带有丝滑的滚动事件
      window.scrollTo({
        top: PageId.offsetTop - 80,
        behavior: "smooth",
      });
    },
    //传入参数:需要遍历的json,需要匹配的id
    findPnodeId(data, id) {
      let result;
      for (var i = 0; i < data.length; i++) {
        if (data[i].id == id) {
          return data[i];
        } else if (data[i].children && data[i].children.length > 0) {
          result = this.findPnodeId(data[i].children, id);
          if (result) {
            return result;
          }
        }
      }
      return result;
    },
  },
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.content_first {
  width: 100%;
  height: calc(100% - 20px);
}
.home {
  display: flex;
  height: 100%;
  background: #ffffff;
  overflow: hidden;
  border-radius: 8px;
  -webkit-box-shadow: -1px 0 10px #bac7c8;
  box-shadow: -1px 0 10px #bac7c8;
}
.help_left {
  border-right: 1px solid #d6e3e4;
  padding: 20px;
  overflow-y: auto;
}
/* 滚动条样式 */
.approval-scroll {
  transition: all 0.5s;
  overflow: auto;
}
.approval-scroll::-webkit-scrollbar {
  width: 8px !important;
  height: 2px !important;
}
.approval-scroll::-webkit-scrollbar-thumb {
  border-radius: 10px !important;
  background: transparent !important;
}
.approval-scroll::-webkit-scrollbar-track {
  border-radius: 10px !important;
  background: transparent !important;
}

.approval-scroll:hover::-webkit-scrollbar-thumb {
  border-radius: 10px !important;
  background: #cccccc !important;
}
.approval-scroll:hover::-webkit-scrollbar-track {
  border-radius: 10px !important;
  background: transparent !important;
}
.help_right {
  -webkit-box-flex: 1;
  -ms-flex: 1;
  flex: 1;
  background: #fff;
  padding: 0 15px 0 20px;
  height: 100%;
}
.share_position_text {
  position: fixed;
  right: calc(5% + 60px);
  bottom: calc(10% + 70px);
  width: 50px;
  height: 50px;
  cursor: pointer;
  font-size: 15px;
  padding: 0px !important;
  border-radius: 8px !important;
  border: #ffffff !important;
  width: 80px;
  height: 40px;
  line-height: 40px;
  text-align: center;
  box-shadow: 0 1px 4px 0 rgb(0 0 0 / 10%) !important;
}
.share_position {
  position: fixed;
  right: 5%;
  bottom: calc(10% + 70px);
  width: 50px;
  height: 50px;
  cursor: pointer;
}
.help_position_text {
  position: fixed;
  right: calc(5% + 60px);
  bottom: 10%;
  font-size: 15px;
  padding: 0px !important;
  border-radius: 8px !important;
  border: #ffffff !important;
  width: 80px;
  height: 40px;
  line-height: 40px;
  text-align: center;
  box-shadow: 0 1px 4px 0 rgb(0 0 0 / 10%) !important;
}
.help_position {
  position: fixed;
  right: 5%;
  bottom: 10%;
  width: 50px;
  height: 50px;
  cursor: pointer;
}
.approvalpojo {
  padding: 5px 5px 5px 0;
  border-left: 1px dashed #e1e1e1;
  display: grid;
}
.approve_right {
  min-width: 45px;
  display: inline-block;
  margin-left: 15px;
  position: relative;
  color: #333333;
  padding-top: 12px;
}
.circle {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #e1e1e1;
  position: absolute;
  left: -19px;
  top: 17px;
}
.selectBack {
  background-color: #17908e;
}
.node {
  display: flex;
  flex: 1;
}
.approvalpojo_list {
  color: #666666;
  font-size: 14px;
  cursor: pointer;
}
.approvalpojo_list:hover {
  color: #17908e;
}

.search-input {
  display: flex;
  margin: 0 auto;
  overflow: hidden;
  padding: 30px 0;
  width: 33%;
  min-width: 350px;
  min-height: 50px;
  height: 50px;
  margin-right: 50px;
  position: relative;
}

.search-button {
  position: absolute;
  right: 8px;
  height: 36px;
  line-height: 36px;
  margin-top: 8px;
  width: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  border-radius: 20px;
}
.search-button:hover {
  background: #17908e;
  color: #fff;
}
.search-top {
  width: 100%;
  position: relative;
}
.search-input-input {
  border-radius: 40px;
  flex: 1;
  outline: none;
  padding: 0 20px;
  border-right: 0px solid #ffffff !important;
  border: 1px solid #d5d5d5;
  height: 50px;
  box-shadow: inset 0 1px 4px 0 rgb(0 0 0 / 10%);
  color: #4a4a4a;
  padding-left: 40px;
}
.title_first_div {
  margin-left: 50px;
  width: 10%;
  min-width: 150px;
}
.title_first_div > p {
  color: #999999;
  font-size: 14px;
  text-align: left;
}
.content_common {
  display: flex;
  height: 100%;
}
.selectColor {
  color: #17908e;
}
.icon {
  color: rgb(204, 204, 204);
}
.icon_hover {
  color: #ffffff;
}

/* 滚动条 */
.approval-scroll {
  transition: all 0.5s;
  overflow: auto;
}
.approval-scroll::-webkit-scrollbar {
  width: 8px !important;
  height: 2px !important;
}
.approval-scroll::-webkit-scrollbar-thumb {
  border-radius: 10px !important;
  background: transparent !important;
}
.approval-scroll::-webkit-scrollbar-track {
  border-radius: 10px !important;
  background: transparent !important;
}

.approval-scroll:hover::-webkit-scrollbar-thumb {
  border-radius: 10px !important;
  background: #cccccc !important;
}
.approval-scroll:hover::-webkit-scrollbar-track {
  border-radius: 10px !important;
  background: transparent !important;
}
.overflow_yy {
  height: 100%;
  overflow-y: scroll;
}
.icon:hover {
  color: #ffffff !important;
}
.subject_content >>> img {
  max-width: 100%;
  height: auto;
}

input::-webkit-input-placeholder {
  color: rgb(204, 204, 204);
}
input:focus::-webkit-input-placeholder {
  color: #a9a9a9;
}
/* Firefox < 19 */
input:-moz-placeholder {
  color: rgb(204, 204, 204);
}
input:focus:-moz-placeholder {
  color: #a9a9a9;
}
/* Firefox > 19 */
input::-moz-placeholder {
  color: rgb(204, 204, 204);
}
input:focus::-moz-placeholder {
  color: #a9a9a9;
}

/* Internet Explorer 10 */
input:-ms-input-placeholder {
  color: rgb(204, 204, 204);
}
input:focus:-ms-input-placeholder {
  color: #a9a9a9;
}
</style>
<style>
.el-input-group__append,
.el-input-group__prepend {
  background-color: #ffffff !important;
}
.draw_atooltip.is-light {
  font-size: 15px;
  padding: 0px !important;
  border-radius: 8px !important;
  border: #ffffff !important;
  width: 80px;
  height: 40px;
  line-height: 40px;
  text-align: center;
  box-shadow: 0 1px 4px 0 rgb(0 0 0 / 10%) !important;
}

.el-tooltip__popper[x-placement^="left"] .popper__arrow {
  border-left-color: transparent !important;
}

.el-popper[x-placement^="bottom"] .popper__arrow:after {
  margin-left: -6px;
  border-bottom-color: transparent !important;
  border-top-width: 0;
}

.el-popper[x-placement^="top"] .popper__arrow:after {
  margin-left: -6px;
  border-top-color: transparent !important;
  border-bottom-width: 0;
}

.el-tooltip__popper.is-light[x-placement^="bottom"] .popper__arrow:after {
  margin-left: -6px;
  border-bottom-color: transparent !important;
  border-top-width: 0;
}

.el-tooltip__popper.is-light[x-placement^="top"] .popper__arrow:after {
  margin-left: -6px;
  border-top-color: transparent !important;
  border-bottom-width: 0;
}

.el-tooltip__popper.is-light {
  @include themedColor("background-color", "primary-background-color");
}
</style>

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值