demo地址:点击下载
其中封装了自定义指令及公共组件的左侧菜单,菜单效果为双击,可搜索子节点
用户需求,左侧菜单为一次加载出来;可以搜索树控件下所有的子菜单内容
1.左侧菜单可以自由拉宽缩小;右侧内容不变,本人用到的方法是右侧div中嵌入router-view才能做到不缩放
1.左侧菜单默认为200的宽;拉条为15的宽当小于200的时候右侧动态设置宽度,不让右侧空出来
```views views ? ? ? ? ? ?? ├─ AboutView.vue ? └─ HomeView.vue ??
``` ---
```components components ? ? ? ? ? ? └─ TreeCode ? ? ? ? ?? ? ?├─ index copy.vue ? ? ?├─ index.json ? ? ? ? ?└─ index.vue ? ? ??
``` ---
```drag-move drag-move ? ? ? ├─ index.js ? ? └─ index.scss ?
``` ---
上代码
router文件
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: HomeView,
redirect: '/AboutView',
children: [
{
path: 'AboutView',
name: 'AboutView',
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
}
]
}
]
const router = new VueRouter({
routes
})
export default router
HomeView.vue文件
<!--
* @Author: your name
* @Date: 2022-04-22 22:14:46
* @LastEditTime: 2022-04-23 14:05:33
* @LastEditors: Please set LastEditors
* @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
* @FilePath: \my-project\src\views\HomeView.vue
-->
<template>
<div class='only-container'>
<div class='only-left-sidebar'>
左侧栏
<tree-code style="width: 100%;height:380px" type="comCode" @node-click="nodeClick" />
</div>
<div class='only-resize' title='收缩侧边栏' v-drag-move='{setWidth:setWidth}'>?</div>
<div class='only-right'>
右侧{{rightWidth}}
<router-view :setWidth="rightWidth"></router-view>
</div>
</div>
</template>
<script>
import TreeCode from '@/components/TreeCode/index'
export default {
components: { TreeCode },
data () {
return {
dialogVisible: false,
rightWidth: 230
}
},
computed: {
},
mounted () {
// this.dragControllerDiv()
},
methods: {
setWidth (x) {
console.log('data中的设置', x);
this.rightWidth = x;
},
nodeClick (data) {
console.log('发送请求', data)
}
}
}
</script>
<style lang="scss" scoped>
</style>
AboutView.vue
<template>
<div class="content" v-bind:style="style">
子页面-{{style}}
</div>
</template>
<script>
export default {
name: 'AboutView',
props: {
setWidth: {
type: [String, Number],
default: 230
}
},
components: {},
data () {
return {
}
},
computed: {
style () {
return {
width: `calc(100vw - ${this.setWidth}px)`
}
}
},
beforeMount () { },
mounted () { },
methods: {},
watch: {}
}
</script>
<style lang='scss' scoped>
.content {
background: yellow;
height: 100%;
}
</style>
TreeCode.vue?左侧树控件
<!--树形侧边导航-->
<template>
<div v-if="state" class="tree-code" style="height:100%;">
<div v-loading="rootLoading" style="height: 100%;max-height: 100%;overflow-y: auto">
<div class="filter-content">
<el-input placeholder="输入关键字进行过滤" v-model="filterText">
</el-input>
<el-button icon="el-icon-search" circle @click="handleSearch"></el-button>
</div>
<el-tree ref="tree" :filter-node-method="filterNode" :props="props" :data="loadData" highlight-current node-key="code" size="medium" :expand-on-click-node="false" @node-click="handleNodeClick" @check-change="handleCheckChange" style="height: 100%;overflow: auto" />
</div>
</div>
</template>
<script>
import { list } from './index.json'
export default {
name: 'TreeCode',
props: {
type: {
type: String,
required: true,
default: null,
validator: function (value) {
// comCode:归属机构
// teamCode: 续保团队
return ['comCode', 'teamCode'].indexOf(value) !== -1
}
}
},
data () {
return {
filterText: '',
treeClickCount: 0, // 定义点击次数,默认0次
props: {
label: 'label',
isLeaf: 'leaf'
},
// 是否加载中
loading: false,
// 根节点加载
rootLoading: false,
// 状态
state: true,
loadData: []
}
},
mounted () {
// this.loadData = list
this.getlist()
},
methods: {
getlist () {
this.rootLoading = true
// 如果当前是请求接口那么这个方法写到then里面传入res
if (this.type == 'comCode') { //父组件判断请求哪个接口
this.loadData = this.getReturnNode(list)
console.log(' this.loadData', this.loadData);
this.rootLoading = false
}
},
getReturnNode (arr) {
// 循环遍历
for (let i = 0; i < arr.length; i++) {
arr[i].label = arr[i].text
arr[i].code = arr[i].id
// 如果数组中有children则继续递归
if (arr[i].children) {
this.getReturnNode(arr[i].children)
}
}
return arr
},
filterNode (value, data, node) {
if (!value) return true
let parentNode = node.parent;
let labels = [node.label];
let level = 1
while (level < node.level) {
labels = [...labels, parentNode.label]
parentNode = parentNode.parent
level++
}
return labels.some(label => label.indexOf(value) !== -1)
},
// 点击处理
handleNodeClick (data) {
// 记录点击次数
this.treeClickCount++
// 单次点击次数超过2次不作处理,直接返回,也可以拓展成多击事件
if (this.treeClickCount >= 2) {
return
}
// 计时器,计算300毫秒为单位,可自行修改
this.timer = window.setTimeout(() => {
if (this.treeClickCount == 1) {
// 把次数归零
this.treeClickCount = 0
// 单击事件处理
console.log('单击事件,可在此处理对应逻辑')
} else if (this.treeClickCount > 1) {
// 把次数归零
this.treeClickCount = 0
// 双击事件
console.log('双击事件,可在此处理对应逻辑')
this.$emit('node-click', data)
}
}, 300)
},
// 获取多选节点数组
handleCheckChange () {
this.$emit('check-change', this.$refs.tree.getCheckedNodes())
},
// 设置目前勾选的节点
setCheckedNodes (list) {
this.$refs.tree.setCheckedNodes(list)
},
// 重新加载
reload () {
console.log('重新加载');
// 父组件用法 window.location.reload()
this.state = false
this.$nextTick(() => (this.state = true))
},
// 点击搜索
handleSearch () {
this.$refs.tree.filter(this.filterText);
}
},
watch: {
// filterText (val) {//输入时搜索
// this.$refs.tree.filter(val);
// }
}
}
</script>
<style scoped>
.tree-code {
user-select: none;
}
.filter-content {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
控件下对应的本地json
{
"list": [
{
"id": 0,
"text": "广东电网",
"children": [
{
"id": "0-1",
"text": "员工宿舍"
},
{
"id": "0-2",
"text": "食堂",
"children": [
{
"id": "0-2-1",
"text": "球机1号"
},
{
"id": "0-2-2",
"text": "球机2号"
}
]
}
]
},
{
"id": 1,
"text": "广东电网2",
"children": [
{
"id": "1-1",
"text": "员工宿舍2"
},
{
"id": "1-2",
"text": "食堂2",
"children": [
{
"id": "1-2-1",
"text": "球机1号2"
},
{
"id": "1-2-2",
"text": "球机2号2"
}
]
}
]
}
]
}
drag-move.js自定义指令
/*
* @Author: your name
* @Date: 2022-04-23 12:09:47
* @LastEditTime: 2022-04-23 14:17:00
* @LastEditors: your name
* @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
* @FilePath: \my-project\src\directive\drag-move\index.js
*/
import './index.scss'
const dragMove = {
inserted: function (el, binding, vnode) {
const left = document.getElementsByClassName('only-left-sidebar')[0]
const right = document.getElementsByClassName('only-right')[0]
el.onmousedown = function (e) {
const startX = e.clientX
const resizeLeft = el.offsetLeft
const parent = document.getElementsByClassName('only-container')[0]
document.onmousemove = function (e) {
const moveX = e.clientX
let moveLen = resizeLeft + (moveX - startX)
const maxT = parent.clientWidth - el.offsetWidth // 容器宽度 - 左边区域的宽度 = 右边区域的宽度
moveLen = moveLen < 10 ? 10 : moveLen // 左边区域最小宽度为10px
moveLen = moveLen > (maxT - 150) ? maxT - 150 : moveLen // 右边区域最小宽度为150px
left.style.width = moveLen + 'px'
right.style.left = moveLen + 'px'
el.style.left = (moveLen - 5) + 'px'
if (moveX < 200) { //小于默认值的时候把多于的宽度分给右侧容器
binding.value.setWidth(moveX + 20)
}
};
document.onmouseup = function () {
// document.onmousemove = document.onmouseup = null;
document.onmousemove = null
document.onmouseup = null
};
};
}
}
const install = function (Vue) {
Vue.directive('drag-move', dragMove)
}
if (window.Vue) {
window['drag-move'] = dragMove
Vue.use(install) // eslint-disable-line
}
dragMove.install = install
export default {
install
}
对应的css
.only-container {
width: 100%;
height: 100vh;
display: flex;
}
/*左侧div样式*/
.only-left-sidebar {
// position: absolute;
width: 200px;
// left: 0;
// top: 55px;
// bottom: 0;
background: palevioletred;
}
/*拖拽区div样式*/
.only-resize {
cursor: col-resize;
position: absolute;
left: 200px;
top: calc(50% - 23px);
line-height: 80px;
text-align: center;
background: #ddd;
border-radius: 5px;
width: 10px;
z-index: 1;
}
/*拖拽区鼠标悬停样式*/
.only-resize:hover {
background: #ccc;
}
/*右侧div'样式*/
.only-right {
position: absolute;
left: 208px;
right: 0;
bottom: 0;
background: peru;
height: 100%;
// width: calc(100vw - 200px);
}
main.js文件
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import DragMove from '@/directive/drag-move'
Vue.config.productionTip = false
Vue.use(ElementUI)
Vue.use(DragMove)
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
|