vue antd的menu组件使用
vue antd的menu组件使用实现效果记录实现的主要几步1、数据处理2、布局3、功能实现,搜索标题则当前菜单高亮,右侧则显示对应的内容用到menu菜单时,需要注意它的api右侧显示content内容实现效果注:我这里的输入框,搜索的时候是只支持搜索标题,支持模糊搜索记录实现的主要几步1、数据处理在写静态页面的时候需要写假数据,会与后台沟通,这个地方菜单后期会返回什么样的数据结构,有的后台会以前
vue antd的menu组件使用
实现效果
注:我这里的输入框,搜索的时候是只支持搜索标题,支持模糊搜索
记录实现的主要几步
1、数据处理
在写静态页面的时候需要写假数据,会与后台沟通,这个地方菜单后期会返回什么样的数据结构,有的后台会以前端为准,你想要什么样的数据结构就给你什么样的结构,但这里后台按照他自己的来,直接给前端返回了一个扁平化的数据结构,意思是要自己处理成自己要的结构,没办法,你只得自己处理数据了。
沟通后,后台后面会返回下面这样的数据结构
data() {
return {
// 后台后面会返回的数据结构
list: [
{
id: 1,
parentId: 0,
fileType: 'dir',
fileName: '文件夹1'
},
{
id: 2,
parentId: 1,
fileType: 'dir',
fileName: 'api'
},
{
id: 5,
parentId: 1,
fileType: 'dir',
fileName: '文件夹2'
},
{
id: 3,
parentId: 2,
fileType: 'file',
fileName: '获取视频抽帧结果',
fileContent:
'### 引用 Blockquotes\n\n> 引用文本 Blockquotes\n\n引用的行内混合 Blockquotes\n\n> 引用:如果想要插入空白换行`即<br />标签`,在插入处先键入两个以上的空格然后回车即可,[普通链接](https://www.mdeditor.com/)。'
},
{
id: 6,
parentId: 2,
fileType: 'file',
fileName: '根据租户和客户获取物联网产品列表',
fileContent:
'# 技术文档一级标题名称过长是否影响右边导航展示\n## 服务发布\n### 服务api\n#### 未公开api\n# 根据租户和客户\n###### 获取物联网产品\n\n1. 开发者可以管理的部分主要分为 showcore 轮播图、\n2. 桌面推荐、\n3. 应用模板(适用于带屏设备上的内容展示)和\n4. app 轮播图和内容推荐(适用于控制app上的内容展示)。\n5. 开发者可以根据自身的需求在相应位置进行配置,并通过接入接口(link)来实现前端展示。[百度](https://www.xfyun.cn/?ch=bd05&renqun_youhua=478960&bd_vid=11991992860660649978)![车辆违停](https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=724715456,995074424&fm=15&gp=0.jpg)\n6. ![0NL~UOVXQEBWDKMRXU.png](http://10.40.204.55:80/group1/M00/00/19/CijMN1_sHmuAVP0aAAGeIkymU_g515.png)'
},
{
id: 4,
parentId: 0,
fileType: 'dir',
fileName: '文件夹2'
},
{
id: 7,
parentId: 4,
fileType: 'file',
fileName: '文件',
fileContent: '我是文件'
}
],
apilist:[]//这里存放处理后的数据
selectedKey: [],//展开的api
openKeys: [0] /*当前展开的菜单*/,
fileType值为dir代表是文件夹,而fileType值为file代表是文件夹下面的子文件,只有值为file时filecontent才会有内容.
这个地方所以要处理成三级菜单的才能符合需求。
鉴于我原生的不是很好,所以网上搜索了下参考了网上的写法
// 将后台返回的扁平化数据处理成树形结构
toTree(data) {
let result = []
if (!Array.isArray(data)) {
return result
}
data.forEach((item) => {
delete item.children
})
let map = {}
data.forEach((item) => {
map[item.id] = item
})
data.forEach((item) => {
let parent = map[item.parentId]
if (parent) {
;(parent.children || (parent.children = [])).push(item)
} else {
result.push(item)
}
})
this.apilist = result
}
这里是封装的一个方法,等到获取接口数据后直接调用这个方法将获取到的值传递过去,最后处理完后将值赋值给apilist这个数组
2、布局
数据处理好了,这个时候就可以布局了
这里用的antd 的menu菜单这个组件
<a-menu
style="width: 214px"
:default-open-keys="['1']"
:open-keys.sync="openKeys"
:mode="mode"
@openChange="onOpenChange"
:defaultSelectedKeys="defaultSelectedKeys"
v-model="selectedKey"
>
<template v-for="item in apilist">
<!-- 第一层 -->
<template v-if="item.children">
<a-sub-menu :key="item.id">
<span slot="title"
><span>{{ item.fileName }}</span></span
>
<template v-for="subitem in item.children">
<!-- 第二层 -->
<template v-if="subitem.children">
<a-sub-menu :key="subitem.id" :title="subitem.fileName">
<template v-for="sub3 in subitem.children">
<!-- 第三层 -->
<template v-if="sub3.children">
<!-- <a-menu-item :key="sub3.id" @click="setKey(sub3)">
{{ sub3.fileName }}
</a-menu-item> -->
<a-sub-menu :key="sub3.id" :title="sub3.fileName">
<template v-for="sub4 in sub3.children">
<a-menu-item
:key="sub4.id"
@click="setKey(sub4)"
>
{{ sub4.fileName }}
</a-menu-item>
</template>
</a-sub-menu>
</template>
<!-- 第三层 -->
<template v-else>
<a-menu-item :key="sub3.id" @click="setKey(sub3)">
{{ sub3.fileName }}
</a-menu-item>
</template>
</template>
</a-sub-menu>
</template>
<!-- 第二层 -->
<template v-else>
<a-menu-item :key="subitem.id" @click="setKey(subitem)">
{{ subitem.fileName }}
</a-menu-item>
</template>
</template>
</a-sub-menu>
</template>
<!-- 第一层 -->
<template v-else>
<a-menu-item
:key="item.id"
@click="setKey(item)"
:class="item.fileType == 'file' ? 'actstyle' : ''"
>
{{ item.fileName }}
</a-menu-item>
</template>
</template>
</a-menu>
不会布局的童鞋,可以仔细看下这个注释,每次遍历第一层的时候都会判断有没有children,有就怎样,没有就怎样,如果有就遍历它并判断它还有咩有children属性,有就再接着遍历和判断,每次key绑定时要注意要绑定当前数据的id
3、功能实现,搜索标题则当前菜单高亮,右侧则显示对应的内容
每次点击菜单时,判断它是dir还是file,因为dir是没有content值的,
如果是file就将直接赋值到页面上,并将当前的菜单高亮,这里的selectedkey就是当前高亮的值的id
setKey(item) {
if (item.fileType == 'file') {
let activeid = item.id
this.editorValue = item.fileContent
this.filename = item.fileName
this.list.forEach((item, index) => {
if (item.id == activeid) {
this.selectedKey = [activeid]
}
})
this.findParent(item.id)
} else if (item.fileType == 'dir' && item.children) {
if (item.children[0].children) {
this.editorValue = item.children[0].children[0].fileContent
this.filename = item.children[0].children[0].fileName
this.selectedKey = [item.children[0].children[0].id]
this.openKeys=[]
this.findParent(item.children[0].children[0].id)
} else {
this.editorValue = item.children[0].fileContent
this.filename = item.children[0].fileName
this.selectedKey = [item.children[0].id]
this.openKeys=[]
this.findParent(item.children[0].id)
}
}else {
this.editorValue = item.fileContent
this.filename = item.fileName
this.selectedKey = [item.id]
this.findParent(item.id)
}
},
如果是dir,还要判断它有没有children,没有就取children的值,有就取children的children的值
这里封装的findparent方法,是为了在搜索菜单的时候不仅当前菜单要高亮,同时它的前面的父级都要展开,否则搜索到了三级菜单时,没有展开前面的菜单,你就看不见它了
// 根据元素ID遍历树形结构,查找到所有父元素ID,目的为了展开
findParent(idx) {
let pid = []
this.list.forEach((item) => {
if (idx === item['id']) {
pid = item['parentId']
this.findParent(pid)
this.openKeys.push(pid)
}
})
},
用到menu菜单时,需要注意它的api
高亮的api selectedKey: []
展开的api openKeys: [0] 当前展开的菜单
这两个api绑定的一般都是它的id
右侧显示content内容
这里我用到的是mavon-editor,可以自行搜索下它的使用方法,这里就不做介绍了, “mavon-editor”: “^2.9.1”,这里我用的是这个版本的。
<mavon-editor
v-model="editorValue"
:toolbarsFlag="false"
:editable="true"
:subfield="false"
:defaultOpen="'preview'"
class="mavon_editor"
:toolbars="toolbar_settings"
:navigation="true"
/>
更多推荐
所有评论(0)