【更新】优化菜单搜索功能,感谢CcSimple兄弟送来的PR

pull/56/head
小诺 2022-11-03 21:28:12 +08:00 committed by 俞宝山
parent 887fa9d735
commit 362b538bae
8 changed files with 38 additions and 166 deletions

View File

@ -1,5 +1,4 @@
import { mapState, mapMutations } from 'vuex' import { mapState, mapMutations } from 'vuex'
import hotkeys from 'hotkeys-js' import hotkeys from 'hotkeys-js'
export default { export default {
@ -30,9 +29,7 @@ export default {
searchToggle: 'search/toggle', searchToggle: 'search/toggle',
searchSet: 'search/set' searchSet: 'search/set'
}), }),
/** // 接收点击搜索按钮
* 接收点击搜索按钮
*/
handleSearchClick() { handleSearchClick() {
this.searchToggle() this.searchToggle()
if (this.searchActive) { if (this.searchActive) {

View File

@ -6,8 +6,7 @@
class="search-box" class="search-box"
style="width: 100%" style="width: 100%"
allowClear allowClear
placeholder="搜索页面(支持拼音检索)" placeholder="搜索页面(支持拼音检索)"
size="large"
@change="querySearch" @change="querySearch"
> >
<template #prefix> <template #prefix>
@ -15,7 +14,7 @@
</template> </template>
</a-input> </a-input>
<a-card <a-card
:body-style="{ padding: '4px 0' }" :body-style="{ padding: '0 0' }"
hoverable hoverable
@mouseenter="onCardIn" @mouseenter="onCardIn"
@mouseleave="onCardOut" @mouseleave="onCardOut"
@ -23,13 +22,13 @@
@keypress.down="handleKeyDown" @keypress.down="handleKeyDown"
style="margin: 10px 0" style="margin: 10px 0"
> >
<div ref="cardList" class="search-card beauty-scroll" style=""> <div ref="cardList" class="search-card beauty-scroll">
<a-list size="small" :data-source="resultsList"> <a-list size="small" :data-source="resultsList">
<template #renderItem="{ item, index }"> <template #renderItem="{ item, index }">
<a-list-item <a-list-item
@click="handleSelect(item.fullPath)" @click="handleSelect(item.fullPath)"
@mouseover="onCardItemHover(index)" @mouseover="onCardItemHover(index)"
:class="{ active: index == cardIndex }" :class="{ active: index === cardIndex }"
style="padding-right: 10px" style="padding-right: 10px"
> >
<template #actions> <template #actions>
@ -42,7 +41,7 @@
<a>{{ item.name }}</a> <a>{{ item.name }}</a>
</template> </template>
<template #avatar> <template #avatar>
<a-avatar style="color: black; background-color: transparent" :type="item.icon"> <a-avatar style="color: var(--text-color); background-color: transparent" :type="item.icon">
<template #icon> <template #icon>
<component :is="item.icon" /> <component :is="item.icon" />
</template> </template>
@ -108,18 +107,14 @@
} }
}, },
methods: { methods: {
/** //
* @description 过滤选项 这个方法在每次输入框的值发生变化时会触发
*/
querySearch(e) { querySearch(e) {
let queryString = e.target.value || '' let queryString = e.target.value || ''
const results = queryString && this.fuse.search(queryString).map((e) => e.item) const results = queryString && this.fuse.search(queryString).map((e) => e.item)
this.searchText = queryString this.searchText = queryString
this.results = results this.results = results
}, },
/** //
* @description 聚焦输入框
*/
focus() { focus() {
this.searchText = '' this.searchText = ''
setTimeout(() => { setTimeout(() => {
@ -178,9 +173,7 @@
onCardItemHover(index) { onCardItemHover(index) {
this.cardIndex = index this.cardIndex = index
}, },
/** //
* @description 接收用户在下拉菜单中选中事件
*/
handleSelect(path) { handleSelect(path) {
// //
if (path === this.$route.path) { if (path === this.$route.path) {
@ -190,26 +183,20 @@
this.$router.push({ path }) this.$router.push({ path })
this.handleEsc() this.handleEsc()
}, },
/** //
* @augments 关闭输入框的下拉菜单
*/
closeSuggestion() { closeSuggestion() {
if (this.$refs.input.activated) { if (this.$refs.input.activated) {
this.results = [] this.results = []
this.$refs.input.activated = false this.$refs.input.activated = false
} }
}, },
/** //
* @augments 接收用户点击空白区域的关闭
*/
handlePanelClick(e) { handlePanelClick(e) {
if ('INPUT' != e.target.tagName) { if ('INPUT' !== e.target.tagName) {
this.handleEsc() this.handleEsc()
} }
}, },
/** //
* @augments 接收用户触发的关闭
*/
async handleEsc() { async handleEsc() {
this.closeSuggestion() this.closeSuggestion()
await this.$nextTick() await this.$nextTick()
@ -221,21 +208,23 @@
<style lang="less" scoped> <style lang="less" scoped>
/deep/ .ant-input { /deep/ .ant-input {
height: 48px; height: 35px;
} }
/deep/ .ant-input:not(:first-child) { /deep/ .ant-input:not(:first-child) {
padding-left: 10px; padding-left: 10px;
} }
/deep/ .ant-input-prefix { /deep/ .ant-input-prefix {
font-size: 24px; font-size: 20px;
}
/deep/ .ant-list-sm .ant-list-item {
padding: 4px 16px;
}
/deep/ .ant-list-item-meta {
align-items: center;
} }
.search-box { .search-box {
width: 100%; width: 100%;
} }
.beauty-scroll { .beauty-scroll {
scrollbar-color: var(--primary-color) var(--primary-2); scrollbar-color: var(--primary-color) var(--primary-2);
scrollbar-width: thin; scrollbar-width: thin;
@ -255,31 +244,22 @@
background: var(--primary-3); background: var(--primary-3);
} }
} }
.search-card { .search-card {
height: 220px; height: 220px;
overflow: hidden; overflow: hidden;
overflow-y: scroll; overflow-y: scroll;
} }
/deep/ .ant-list-item.active { /deep/ .ant-list-item.active {
background-color: var(--primary-1); background-color: var(--primary-1);
} }
.search-tips { .search-tips {
display: flex; display: flex;
border-top: 1px solid #f0f0f0; border-top: 1px solid var(--component-background);
padding-top: 6px; padding-top: 10px;
.tips { .tips {
margin-right: 10px; margin-right: 10px;
} }
.key { .key {
//display: flex;
//flex-direction: row;
//align-items: center;
//justify-content: center;
width: 30px; width: 30px;
height: 20px; height: 20px;
line-height: 20px; line-height: 20px;
@ -287,7 +267,6 @@
padding-bottom: 2px; padding-bottom: 2px;
margin: 0px 4px; margin: 0px 4px;
border-radius: 2px; border-radius: 2px;
background-color: white;
box-shadow: inset 0 -2px #cdcde6, inset 0 0 1px 1px #fff, 0 1px 2px 1px #1e235a66; box-shadow: inset 0 -2px #cdcde6, inset 0 0 1px 1px #fff, 0 1px 2px 1px #1e235a66;
font-weight: bold; font-weight: bold;
} }

View File

@ -45,7 +45,7 @@
.d2-panel-search-item__icon-box { .d2-panel-search-item__icon-box {
i { i {
font-size: 24px; font-size: 24px;
color: @primary-color; color: var(--primary-color);
} }
} }
} }

View File

@ -61,7 +61,7 @@
style="overflow: hidden" style="overflow: hidden"
destroyOnClose destroyOnClose
dialogClass="searchModal" dialogClass="searchModal"
:bodyStyle="{ maxHeight: '520px', overflow: 'auto', padding: '10px' }" :bodyStyle="{ maxHeight: '520px', overflow: 'auto', padding: '14px' }"
@cancel="searchPanelClose" @cancel="searchPanelClose"
> >
<panel-search ref="panelSearch" @close="searchPanelClose" /> <panel-search ref="panelSearch" @close="searchPanelClose" />

View File

@ -14,26 +14,15 @@ export default {
pool: [] pool: []
}, },
mutations: { mutations: {
/** // 切换激活状态
* @description 切换激活状态
* @param {Object} state state
*/
toggle(state) { toggle(state) {
state.active = !state.active state.active = !state.active
}, },
/** // 设置激活模式
* @description 设置激活模式
* @param {Object} state state
* @param {Boolean} active active
*/
set(state, active) { set(state, active) {
state.active = active state.active = active
}, },
/** // 初始化
* @description 初始化
* @param {Object} state state
* @param {Array} menu menu
*/
init(state, menu) { init(state, menu) {
const pool = [] const pool = []
const getFullName = function (meta) { const getFullName = function (meta) {
@ -48,10 +37,10 @@ export default {
} }
const push = function (menu) { const push = function (menu) {
menu.forEach((m) => { menu.forEach((m) => {
if ('menu' == m.meta.type) { if ('menu' === m.meta.type) {
if (m.children) { if (m.children) {
push(m.children) push(m.children)
} else { } else if (m.children === null){
pool.push({ pool.push({
icon: m.meta.icon, icon: m.meta.icon,
path: m.path, path: m.path,

View File

@ -183,14 +183,15 @@ a, button, input, textarea {
} }
.snowy-header-right { .snowy-header-right {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.snowy-header-logo { .snowy-header-logo {
height: 49px; height: 50px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
} }
.snowy-header-logo-primary-color { .snowy-header-logo-primary-color {

View File

@ -1,85 +0,0 @@
/**
* Copyright [2022] [https://www.xiaonuo.vip]
* Snowy采用APACHE LICENSE 2.0开源协议您在使用过程中需要注意以下几点
* 1.请不要删除和修改根目录下的LICENSE文件
* 2.请不要删除和修改Snowy源码头部的版权声明
* 3.本项目代码可免费商业使用商业使用请保留源码和相关描述文件的项目出处作者声明等
* 4.分发源码时候请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
import { mapState } from 'vuex'
import { DEVICE_TYPE, deviceEnquire } from '@/utils/device'
// const mixinsComputed = Vue.config.optionMergeStrategies.computed
// const mixinsMethods = Vue.config.optionMergeStrategies.methods
const mixin = {
computed: {
...mapState({
layoutMode: (state) => state.app.layout,
navTheme: (state) => state.app.theme,
primaryColor: (state) => state.app.color,
colorWeak: (state) => state.app.weak,
fixedHeader: (state) => state.app.fixedHeader,
fixSiderbar: (state) => state.app.fixSiderbar,
fixSidebar: (state) => state.app.fixSiderbar,
contentWidth: (state) => state.app.contentWidth,
autoHideHeader: (state) => state.app.autoHideHeader,
sidebarOpened: (state) => state.app.sidebar,
multiTab: (state) => state.app.multiTab
})
},
methods: {
isTopMenu() {
return this.layoutMode === 'topmenu'
},
isSideMenu() {
return !this.isTopMenu()
}
}
}
const mixinDevice = {
computed: {
...mapState({
device: (state) => state.app.device
})
},
methods: {
isMobile() {
return this.device === DEVICE_TYPE.MOBILE
},
isDesktop() {
return this.device === DEVICE_TYPE.DESKTOP
},
isTablet() {
return this.device === DEVICE_TYPE.TABLET
}
}
}
const AppDeviceEnquire = {
mounted() {
const { $store } = this
deviceEnquire((deviceType) => {
switch (deviceType) {
case DEVICE_TYPE.DESKTOP:
$store.commit('TOGGLE_DEVICE', 'desktop')
$store.dispatch('setSidebar', true)
break
case DEVICE_TYPE.TABLET:
$store.commit('TOGGLE_DEVICE', 'tablet')
$store.dispatch('setSidebar', false)
break
case DEVICE_TYPE.MOBILE:
default:
$store.commit('TOGGLE_DEVICE', 'mobile')
$store.dispatch('setSidebar', true)
break
}
})
}
}
export { mixin, AppDeviceEnquire, mixinDevice }

View File

@ -1,11 +1,6 @@
import pinyin from 'js-pinyin' import pinyin from 'js-pinyin'
import store from '@/store/index'
/** // 中文转拼音 传入仅首字母
* 中文转拼音
* @param first 仅首字母
* @returns {String}
*/
Object.defineProperty(String.prototype, 'toPinyin', { Object.defineProperty(String.prototype, 'toPinyin', {
writable: false, writable: false,
enumerable: false, enumerable: false,
@ -19,11 +14,7 @@ Object.defineProperty(String.prototype, 'toPinyin', {
} }
}) })
/** // 字符检索 传入检索值
* 字符检索
* @param input 检索值
* @returns {Boolean}
*/
Object.defineProperty(String.prototype, 'filter', { Object.defineProperty(String.prototype, 'filter', {
writable: false, writable: false,
enumerable: false, enumerable: false,