vue+element实现下拉菜单并带本地搜索功能示例详解

需求:

后台返回数组对像,前端组合成数组,根据name组合成一个个数组并把后台返回的值当成一个children推入数组,在数组中自定义属性备份数据防止搜索的时候改变原数组使得数组无法回退


这里是用的vuex存储,因为多个页面使用同一个接口;所以没必要重复请请求
src\store\module\metadata.js

/*
 * @Author: your name
 * @Date: 2021-09-02 15:46:45
 * @LastEditTime: 2021-09-16 17:39:53
 * @LastEditors: Please set LastEditors
 * @Description: 控制台-数据接入-悬浮菜单
 * @FilePath: \vue-ui\src\store\module\metadata.js
 */
/**
 * 数据资源管理悬浮菜单数据
 */

import { Loading, Message } from 'element-ui'
import { apiManager } from '@/plugins/ajax'

let loadingInstance
const state = {
    allList: [],
    navList: [],
    name: {}
}
const mutations = {
    SET_NAVLIST: (state, list) => {
        // 使用深拷贝,防止页面搜索时报错
        state.navList = list.map(item => {
            if (item.children) {
                item.backList = JSON.stringify(item.children)
            }
        })
    },
    SET_ALLLIST: (state, list) => {
        state.allList = list
    },
    SET_NAME: (state, obj) => {
        Object.assign(state.name, obj)
    }
}
const actions = {
    requestMetadata({ commit, state }, { name, navList }) {
        return new Promise(resolve => {
            const nameKey = Object.keys(state.name)
            if (nameKey.indexOf(name) !== -1) {
                //阻止重复请求
                resolve(state.name[name])
            } else {
                loadingInstance = Loading.service()
                state.name[name] = name
                apiManager
                    .post('/metadata/tableInfo/query')
                    .then(res => {
                        commit('SET_ALLLIST', res.data)
                        for (const i in res.data) {
                            const item = navList.find(v => v.name === i) //把传入的name和请回来的key(name)匹配放入
                            if (item) {
                                item.children = res.data[i] //把请求回来的每个对象下的数组放入对应的Item.children中
                                item.navSearch = ''
                                item.backList = [] //建立备份,在搜索的时候防止改变原数组
                            }
                        }
                        commit('SET_NAVLIST', navList)
                        commit('SET_NAME', { [name]: navList })
                        resolve(navList)
                        loadingInstance.close()
                    })
                    .catch(err => {
                        resolve([])
                        loadingInstance.close()
                        Message.error(err)
                    })
            }
        })
    }
}

export default {
    namespaced: true,
    state,
    mutations,
    actions
}

页面父组件使用子组件
src\views\console\dataAccessManage\dataResourceTable\FileXs.vue

 <transition name="component-fade" mode="out-in">
   <floating-menu v-show="isCollapse" :newList='navList' @getDatails='getDatails' />
</transition>
data() {
      return {
          navList: [
              {
                  imgSrc: require('./../../../../../public/images/m6.png'),
                  name: 'ftp',
                  typeName: 'FTP服务器',
                  children: [],
                  total: 0
              },
              {
                  imgSrc: require('./../../../../../public/images/m5.png'),
                  name: 'txt',
                  typeName: '文件服务器',
                  children: [],
                  total: 0
              }
          ],

   },
  async mounted() {
    const param = {
        name: 'fileXs',
        navList: this.navList
    }
    // 请求vuex
    this.navlist = await this.$store.dispatch('metadata/requestMetadata', param)
},

子组件
src\views\console\dataAccessManage\components\floatingMenu.vue

<!--
 * @Author: your name
 * @Date: 2021-09-02 14:01:58
 * @LastEditTime: 2021-09-16 17:43:10
 * @LastEditors: Please set LastEditors
 * @Description: 数据资源表中悬浮菜单
 * @FilePath: \vue-ui\src\views\console\dataAccessManage\components\floatingMenu.vue
-->
<template>
    <div class="data-sheet-main__nav" v-if="sjktcList.length || newList.length">
        <div>
            <div class="nav__item" v-for="(item,index) in sjktcList" :key="'info2-' + index">
                <div class="item_name sjk_name" :class="{ sjk_active: sjkActive == index }" @click="sjktcShow(item.type,index)">{{item.typeName}}</div>
            </div>
        </div>
        <!-- file -->
        <el-collapse class="nav__item" v-model="activeNames">
            <el-collapse-item class="item_name" :title="item.typeName" :name="item.typeName" v-for="(item,index) in newList" :key="index">
                <ul class="nav__item__list">
                    <li class="list__li">
                        <el-input v-input-val-bg v-model="item.navSearch" @input="handleNavSearch(item)" prefix-icon="el-icon-search" size="mini" placeholder="请输入关键字" clearable></el-input>
                    </li>
                    <li v-for="(key,i) in item.children" :key="i" :class="{ 'list__li--active': key.id == dbId }" class="list__li" @click="getDatails(key,item)">
                        <span :title="key.name" class="list--title">{{key.name}}</span>
                        <span class="list--count">{{key.total || 0}}</span>
                    </li>
                    <li class="no-data" v-if="!item.children.length">暂无数据</li>
                </ul>
            </el-collapse-item>
        </el-collapse>
    </div>
</template>
<script>
import { debounce } from '@/utils'
export default {
    name: 'floatingMenu',
    props: {
        sjktcList: {
            type: Array,
            default: () => []
        },
        newList: {
            type: Array,
            default: () => []
        }
    },
    components: {},
    data() {
        return {
            sjkActive: 0,
            navSearch: '',
            navChildData: [],
            dbId: '',
            activeNames: []
        }
    },
    mounted() {
    },
    methods: {
        // 点击列表中的内容
        getDatails(args, db) {
            this.dbId = args.id
            this.$emit('getDatails', { args, db })
        },
        // eslint-disable-next-line space-before-function-paren
        handleNavSearch: debounce(function (obj) {
            this.$forceUpdate()//防止input框赋值失败
            const currlist = JSON.parse(obj.backList)
            if (obj.navSearch == '') {
                obj.children = currlist
            } else {
                obj.children = currlist.filter(item => {
                    return item.name.toLowerCase().indexOf(obj.navSearch.toLowerCase()) != -1
                })
            }
        }, 100),
        sjktcShow(type, i) {
            this.sjkActive = i
            this.$emit('sjktcShow', [type])
        }
    },
    watch: {
        newList: {
            deep: true,
            handler(list) {
                if (list) {
                    // 默认激活显示展开list下的0个菜单
                    for (let i = 0; i < list.length; i++) {
                        const item = list[i]
                        if (!this.dbId && item.children.length) {
                            this.activeNames = item.typeName
                            this.getDatails(item.children[0], item)//默认请求第一条数据内容
                        }
                    }
                }
            }
        }
    }
}
</script>
<style lang='scss' scoped>
.data-sheet-main__nav {
    width: 180px;
    position: absolute;
    top: 0px;
    left: -190px;
    z-index: 100;
    background: #fff;
    border: 1px solid #6579fe;
    padding-top: 10px;
    .sjk_active {
        color: $theme !important;
    }
    .nav__item {
        position: relative;
        margin-bottom: 15px;

        .item_name {
            width: 100%;
            display: inline-block;
            padding-left: 17px;
            font-size: 14px;
            line-height: 24px;
            color: rgba(0, 0, 0, 0.85);
            /deep/.el-collapse-item__header {
                font-weight: bold;
                border-bottom: none;
                position: relative;
                padding-left: 15px;
                .el-collapse-item__arrow {
                    position: absolute;
                    left: 0;
                    transform: rotate(270deg);
                }
                .el-collapse-item__arrow.is-active {
                    transform: rotate(90deg);
                }
            }

            &:hover {
                cursor: pointer;
            }
        }
        .no-data {
            text-align: center;
            color: #999;
            padding: 10px 0;
            width: 100%;
        }
        img {
            width: 100%;
            height: 50px;
        }
        .nav__item--total {
            position: absolute;
            display: block;
            width: 30px;
            height: 30px;
            background: #fff;
            border: 1px solid #ccc;
            border-radius: 50%;
            line-height: 30px;
            border: 1px solid #71b1ec;
            box-shadow: 0 3px 6px #156d90;
            text-align: center;
            color: #fd0b0b;
            font-size: 16px; /*no*/
            top: 0;
            right: 0;
            transform: translate(25%, -20%);
        }
        .nav__item__list {
            display: flex;
            max-height: 246px;
            overflow-y: auto;
            flex-wrap: wrap;

            .list__li {
                width: 100%;
                margin-top: 5px;
                line-height: 30px;
                padding: 0 6px 0 17px;
                position: relative;
                cursor: pointer;
                color: #333;
                &:hover {
                    color: $blue;
                }
                .list--title {
                    width: 90px;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    white-space: nowrap;
                    float: left;
                    &:hover {
                        color: #409eff;
                    }
                }
                .list--count {
                    color: #46a0fc;
                    float: right;
                }
            }
            .list__li--active {
                color: $blue;
            }
        }
    }
    /deep/.el-collapse {
        border-top: none;
    }
}
.data-sheet-main__list {
    flex: 1;
    margin-left: 20px;
    .list-header {
        flex-direction: column;

        .order {
            text-align: right;
            a {
                background: #6579fe;
                font-family: PingFangSC-Regular;
                font-size: 12px;
                line-height: 22px;
                color: #ffffff;
                padding: 6px;
                border-radius: 4px;
            }
        }
    }
    .handler--fixed-right {
        padding: 25px 10px;
    }
    .nodata {
        text-align: center;
        font-size: 16px;
    }
}
</style>

到此这篇关于vue+element实现下拉菜单并带本地搜索功能的文章就介绍到这了,更多相关vue element下拉菜单搜索内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Vue+Element UI 树形控件整合下拉功能菜单(tree + dropdown +input)

    这篇博客主要介绍树形控件的两个小小的功能: 下拉菜单 输入过滤框 以CSS样式为主,也会涉及到Vue组件和element组件的使用. 对于没有层级的数据,我们可以使用表格或卡片来展示.要展示或建立层级关系,就一定会用到树形组件了. 使用Vue + Element UI,构建出最基本的树如下图所示: 现在我们就要在这个基础上进行改造,使页面更加符合我们的交互场景. 下拉菜单 将下拉菜单嵌到树节点中,使操作更加简便.紧凑. 效果演示 效果如图: 图示1:悬浮在树节点状态 图示2:点击三个点图标状态

  • vue+Element中table表格实现可编辑(select下拉框)

    最近在工作中遇到一个问题,需要在表格中实现数据可编辑状态,具体情况是需要在单元格里加入下拉框:并且每个下拉框的数组数据是不一样的,具体是根据当前行前面数据的id查询而来,前面的是数据是动态生成的,后面的下拉框数据也是根据id动态生成的,内容不同:有点类似于树形二级状态,后面的下拉框数据来源并没有在前面内容里,而是另外一个接口查询,具体操作如下: HTML代码: 1.在处理人列加入一个下拉框模板,其中v-model必须要scope.row.proJbruserValue来绑定,意思是这个值绑定到当

  • vue+element搭建后台小总结 el-dropdown下拉功能

    本文实例为大家分享了el-dropdown下拉功能的具体代码,供大家参考,具体内容如下 功能:点击el-dropdown 下拉 下拉的数据 从后台获取 遍历到界面上 且多个el-dropdown下拉 共用 一个 @command 事件  @command="handleCommand" 上代码部分  html //全部城市 下拉 //handleCommand下拉事件 all_city点击后显示在上面的数据 item.label下拉的数据 :command点击传的值 用flag来区分同

  • Vue + Element-ui的下拉框el-select获取额外参数详解

    直接上代码吧~ <el-table-column label="用户类型" width="180"> <template slot-scope="scope"> <el-select v-model="scope.row.roleID" placeholder="请选择" @change="changeRole($event,scope)"> <

  • vue+element实现下拉菜单并带本地搜索功能示例详解

    需求: 后台返回数组对像,前端组合成数组,根据name组合成一个个数组并把后台返回的值当成一个children推入数组,在数组中自定义属性备份数据防止搜索的时候改变原数组使得数组无法回退 这里是用的vuex存储,因为多个页面使用同一个接口;所以没必要重复请请求 src\store\module\metadata.js /* * @Author: your name * @Date: 2021-09-02 15:46:45 * @LastEditTime: 2021-09-16 17:39:53

  • Vue实现自定义下拉菜单功能

    先看例子,后面有对用到的知识点的总结 效果图: 实现代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>组件练习</title> <link rel="stylesheet" type="text/css" href="component.c

  • Element Dropdown下拉菜单的使用方法

    组件- 下拉菜单 基础用法 <el-dropdown> <span class="el-dropdown-link"> 下拉菜单<i class="el-icon-arrow-down el-icon--right"></i> </span> <el-dropdown-menu slot="dropdown"> <el-dropdown-item>黄金糕</

  • Android开发之无痕过渡下拉刷新控件的实现思路详解

    相信大家已经对下拉刷新熟悉得不能再熟悉了,市面上的下拉刷新琳琅满目,然而有很多在我看来略有缺陷,接下来我将说明一下存在的缺陷问题,然后提供一种思路来解决这一缺陷,废话不多说!往下看嘞! 1.市面一些下拉刷新控件普遍缺陷演示 以直播吧APP为例: 第1种情况: 滑动控件在初始的0位置时,手势往下滑动然后再往上滑动,可以看到滑动到初始位置时滑动控件不能滑动. 原因: 下拉刷新控件响应了触摸事件,后续的一系列事件都由它来处理,当滑动控件到顶端的时候,滑动事件都被下拉刷新控件消费掉了,传递不到它的子控件

  • Springboot Vue实现单点登陆功能示例详解

    目录 正文 简单上个图 先分析下登陆要做啥 怎么落实? 上代码 接口: token生成部分 刷新token 验证token 正文 登陆是系统最基础的功能之一.这么长时间了,一直在写业务,这个基础功能反而没怎么好好研究,都忘差不多了.今天没事儿就来撸一下. 以目前在接触和学习的一个开源系统为例,来分析一下登陆该怎么做.代码的话我就直接CV了. 简单上个图 (有水印.因为穷所以没开会员) 先分析下登陆要做啥 首先,搞清楚要做什么. 登陆了,系统就知道这是谁,他有什么权限,可以给他开放些什么业务功能,

  • vue+three.js实现炫酷的3D登陆页面示例详解

    目录 前言: Three.js的基础知识 关于场景 关于光源 关于相机(重要) 关于渲染器 完善效果 创建一个左上角的地球 使地球自转 创建星星 使星星运动 创建云以及运动轨迹 使云运动 完成three.js有关效果 结语 前言: 大家好,我是xx传媒严导(xx这两个字请自行脑补) . 该篇文章用到的主要技术:vue3.three.js 我们先看看成品效果: 高清大图预览(会有些慢): 座机小图预览: 废话不多说,直接进入正题 Three.js的基础知识 想象一下,在一个虚拟的3D世界中都需要什

  • Java Swing组件下拉菜单控件JComboBox用法示例

    本文实例讲述了Java Swing组件下拉菜单控件JComboBox用法.分享给大家供大家参考,具体如下: JComboBox是Swing中的下拉菜单控件.它永远只能选中一个项目,然而比单选按钮节省空间.如果使用setEditable设置为true则内部选项的文本可以编辑,因此这种组件被称为组合框.注意,对选项的编辑只会影响当前项,而不会改变列表内容.可以使用addItem方法来添加选项列表,或者使用insertItemAt在任何位置插入选项:然而如果有大量选项需要添加,这种方法是非常笨重的,可

  • vue中Axios的封装和API接口的管理示例详解

    目录 一.axios的封装 安装 引入 环境的切换 设置请求超时 post请求头的设置 请求拦截 响应的拦截 封装get方法和post方法 axios的封装基本就完成了,下面再简单说下api的统一管理. 2018.8.14更新 我们所要的说的axios的封装和api接口的统一管理,其实主要目的就是在帮助我们简化代码和利于后期的更新维护. 一.axios的封装 在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js

  • Vue使用axios发送请求并实现简单封装的示例详解

    目录 一.安装axios 二.简单使用 1.配置 2.发送请求 三.封装使用 1.创建js封装类 2.配置 3.发送请求 一.安装axios npm install axios --save 二.简单使用 1.配置 main.js中加入如下内容 // 引入axios --------------------------------------------------- import axios from 'axios' Vue.prototype.$axios = axios Vue.proto

  • jQuery实现带动画效果的多级下拉菜单代码

    本文实例讲述了jQuery实现带动画效果的多级下拉菜单代码.分享给大家供大家参考.具体如下: 这是一款基于jQuery实现的多级下拉菜单,带动画效果,所有的元素以ul li ul li ul li的循环格式嵌套 如果没有下级分类 就用li a结束嵌套,代码内不用toggle()的原因是为了在收缩菜单的时候同时也将该菜单的下级菜单以后的所有元素都隐藏. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/jquery-animate-style-dow

随机推荐