mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-28 05:39:34 +08:00
feat: support mobile layout adaptation
This commit is contained in:
@@ -1,13 +1,11 @@
|
||||
<template>
|
||||
<div :class="prefixCls" v-if="getShowSearch" @click="handleSearch">
|
||||
<div :class="prefixCls" v-if="getShowSearch" @click.stop="handleSearch">
|
||||
<Tooltip>
|
||||
<template #title> {{ t('component.app.search') }} </template>
|
||||
<SearchOutlined />
|
||||
</Tooltip>
|
||||
|
||||
<transition name="zoom-fade" mode="out-in">
|
||||
<AppSearchModal @close="handleClose" v-if="showModal" />
|
||||
</transition>
|
||||
<AppSearchModal @close="handleClose" :visible="showModal" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
|
@@ -1,48 +1,58 @@
|
||||
<template>
|
||||
<div :class="prefixCls" @click.stop>
|
||||
<ClickOutSide @clickOutside="handleClose">
|
||||
<div :class="`${prefixCls}-content`">
|
||||
<a-input
|
||||
:class="`${prefixCls}-input`"
|
||||
:placeholder="t('component.app.search')"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
</a-input>
|
||||
<div :class="`${prefixCls}-not-data`" v-show="getIsNotData">
|
||||
{{ t('component.app.searchNotData') }}
|
||||
</div>
|
||||
<ul :class="`${prefixCls}-list`" v-show="!getIsNotData" ref="scrollWrap">
|
||||
<li
|
||||
:ref="setRefs(index)"
|
||||
v-for="(item, index) in searchResult"
|
||||
:key="item.path"
|
||||
:data-index="index"
|
||||
@mouseenter="handleMouseenter"
|
||||
@click="handleEnter"
|
||||
:class="[
|
||||
`${prefixCls}-list__item`,
|
||||
{
|
||||
[`${prefixCls}-list__item--active`]: activeIndex === index,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<div :class="`${prefixCls}-list__item-icon`">
|
||||
<g-icon :icon="item.icon || 'mdi:form-select'" :size="20" />
|
||||
<Teleport to="body">
|
||||
<transition name="zoom-fade" mode="out-in">
|
||||
<div :class="getClass" @click.stop v-if="visible">
|
||||
<ClickOutSide @clickOutside="handleClose">
|
||||
<div :class="`${prefixCls}-content`">
|
||||
<div :class="`${prefixCls}-input__wrapper`">
|
||||
<a-input
|
||||
:class="`${prefixCls}-input`"
|
||||
:placeholder="t('component.app.search')"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
</a-input>
|
||||
<span :class="`${prefixCls}-cancel`" @click="handleClose">{{
|
||||
t('component.app.cancel')
|
||||
}}</span>
|
||||
</div>
|
||||
<div :class="`${prefixCls}-list__item-text`">{{ item.name }}</div>
|
||||
<div :class="`${prefixCls}-list__item-enter`">
|
||||
<g-icon icon="ant-design:enter-outlined" :size="20" />
|
||||
|
||||
<div :class="`${prefixCls}-not-data`" v-show="getIsNotData">
|
||||
{{ t('component.app.searchNotData') }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<AppSearchFooter />
|
||||
<ul :class="`${prefixCls}-list`" v-show="!getIsNotData" ref="scrollWrap">
|
||||
<li
|
||||
:ref="setRefs(index)"
|
||||
v-for="(item, index) in searchResult"
|
||||
:key="item.path"
|
||||
:data-index="index"
|
||||
@mouseenter="handleMouseenter"
|
||||
@click="handleEnter"
|
||||
:class="[
|
||||
`${prefixCls}-list__item`,
|
||||
{
|
||||
[`${prefixCls}-list__item--active`]: activeIndex === index,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<div :class="`${prefixCls}-list__item-icon`">
|
||||
<g-icon :icon="item.icon || 'mdi:form-select'" :size="20" />
|
||||
</div>
|
||||
<div :class="`${prefixCls}-list__item-text`">{{ item.name }}</div>
|
||||
<div :class="`${prefixCls}-list__item-enter`">
|
||||
<g-icon icon="ant-design:enter-outlined" :size="20" />
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<AppSearchFooter />
|
||||
</div>
|
||||
</ClickOutSide>
|
||||
</div>
|
||||
</ClickOutSide>
|
||||
</div>
|
||||
</transition>
|
||||
</Teleport>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, unref, ref } from 'vue';
|
||||
@@ -54,15 +64,20 @@
|
||||
import AppSearchFooter from './AppSearchFooter.vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { ClickOutSide } from '/@/components/ClickOutSide';
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
export default defineComponent({
|
||||
name: 'AppSearchModal',
|
||||
components: { SearchOutlined, ClickOutSide, AppSearchFooter },
|
||||
emits: ['close'],
|
||||
props: {
|
||||
visible: Boolean,
|
||||
},
|
||||
setup(_, { emit }) {
|
||||
const scrollWrap = ref<ElRef>(null);
|
||||
const { prefixCls } = useDesign('app-search-modal');
|
||||
const { t } = useI18n();
|
||||
const [refs, setRefs] = useRefs();
|
||||
const { getIsMobile } = useAppInject();
|
||||
|
||||
const {
|
||||
handleSearch,
|
||||
@@ -77,9 +92,19 @@
|
||||
return !keyword || unref(searchResult).length === 0;
|
||||
});
|
||||
|
||||
const getClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}--mobile`]: unref(getIsMobile),
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
return {
|
||||
t,
|
||||
prefixCls,
|
||||
getClass,
|
||||
handleSearch,
|
||||
searchResult,
|
||||
activeIndex,
|
||||
@@ -98,12 +123,12 @@
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-app-search-modal';
|
||||
|
||||
@footer-prefix-cls: ~'@{namespace}-app-search-footer';
|
||||
.@{prefix-cls} {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
z-index: 800;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -113,6 +138,43 @@
|
||||
justify-content: center;
|
||||
// backdrop-filter: blur(2px);
|
||||
|
||||
&--mobile {
|
||||
padding: 0;
|
||||
|
||||
> div {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.@{prefix-cls}-input {
|
||||
width: calc(100% - 38px);
|
||||
}
|
||||
|
||||
.@{prefix-cls}-cancel {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.@{prefix-cls}-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.@{footer-prefix-cls} {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.@{prefix-cls}-list {
|
||||
height: calc(100% - 80px);
|
||||
max-height: unset;
|
||||
|
||||
&__item {
|
||||
&-enter {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
position: relative;
|
||||
width: 532px;
|
||||
@@ -124,10 +186,16 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&-input__wrapper {
|
||||
display: flex;
|
||||
padding: 14px 14px 0 14px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-input {
|
||||
width: calc(100% - 28px);
|
||||
width: 100%;
|
||||
height: 56px;
|
||||
margin: 14px 14px 0 14px;
|
||||
font-size: 1.5em;
|
||||
color: #1c1e21;
|
||||
|
||||
@@ -136,6 +204,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-cancel {
|
||||
display: none;
|
||||
font-size: 1em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
&-not-data {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
Reference in New Issue
Block a user