一、有一个固定的文章列表需要展示出来。效果如下图,标题在左侧,内容在右侧
二、注意点:
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>