优化
This commit is contained in:
@@ -302,6 +302,7 @@
|
||||
"useMediaQuery": true,
|
||||
"useMemoize": true,
|
||||
"useMemory": true,
|
||||
"useMobileTable": true,
|
||||
"useModel": true,
|
||||
"useMounted": true,
|
||||
"useMouse": true,
|
||||
|
||||
2
auto-imports.d.ts
vendored
2
auto-imports.d.ts
vendored
@@ -336,6 +336,7 @@ declare global {
|
||||
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
|
||||
const useMemoize: typeof import('@vueuse/core')['useMemoize']
|
||||
const useMemory: typeof import('@vueuse/core')['useMemory']
|
||||
const useMobileTable: typeof import('./src/composables/useMobileTable.js')['useMobileTable']
|
||||
const useModel: typeof import('vue')['useModel']
|
||||
const useMounted: typeof import('@vueuse/core')['useMounted']
|
||||
const useMouse: typeof import('@vueuse/core')['useMouse']
|
||||
@@ -747,6 +748,7 @@ declare module 'vue' {
|
||||
readonly useMediaQuery: UnwrapRef<typeof import('@vueuse/core')['useMediaQuery']>
|
||||
readonly useMemoize: UnwrapRef<typeof import('@vueuse/core')['useMemoize']>
|
||||
readonly useMemory: UnwrapRef<typeof import('@vueuse/core')['useMemory']>
|
||||
readonly useMobileTable: UnwrapRef<typeof import('./src/composables/useMobileTable.js')['useMobileTable']>
|
||||
readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
|
||||
readonly useMounted: UnwrapRef<typeof import('@vueuse/core')['useMounted']>
|
||||
readonly useMouse: UnwrapRef<typeof import('@vueuse/core')['useMouse']>
|
||||
|
||||
1
components.d.ts
vendored
1
components.d.ts
vendored
@@ -80,6 +80,7 @@ declare module 'vue' {
|
||||
ProductCard: typeof import('./src/components/product/ProductCard.vue')['default']
|
||||
ProductDocumentationDialog: typeof import('./src/components/admin/ProductDocumentationDialog.vue')['default']
|
||||
ProductFormDialog: typeof import('./src/components/admin/ProductFormDialog.vue')['default']
|
||||
ResponsiveActionColumn: typeof import('./src/components/common/ResponsiveActionColumn.vue')['default']
|
||||
RichTextEditor: typeof import('./src/components/common/RichTextEditor.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
|
||||
@@ -396,6 +396,138 @@
|
||||
.filter-buttons {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* ===== 移动端表格优化 ===== */
|
||||
/* 表格容器允许横向滚动 */
|
||||
.table-wrapper {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
/* 隐藏滚动条但保持滚动功能 */
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
/* 移除固定列效果 - 通过覆盖 Element Plus 的固定列样式 */
|
||||
.list-page-container .el-table .el-table__fixed,
|
||||
.list-page-container .el-table .el-table__fixed-right {
|
||||
position: static !important;
|
||||
box-shadow: none !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
/* 固定列的表头和表体都改为静态定位 */
|
||||
.list-page-container .el-table .el-table__fixed-header-wrapper,
|
||||
.list-page-container .el-table .el-table__fixed-body-wrapper,
|
||||
.list-page-container .el-table .el-table__fixed-footer-wrapper {
|
||||
position: static !important;
|
||||
}
|
||||
|
||||
/* 表格单元格在移动端优化 */
|
||||
.list-page-container .el-table th,
|
||||
.list-page-container .el-table td {
|
||||
padding: 12px 8px !important;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* 操作按钮组在移动端改为紧凑布局 */
|
||||
.list-page-container .el-table .el-table__cell .flex.gap-2,
|
||||
.list-page-container .el-table .el-table__cell .flex.items-center,
|
||||
.list-page-container .el-table .el-table__cell .flex.space-x-2 {
|
||||
flex-wrap: wrap;
|
||||
gap: 6px !important;
|
||||
}
|
||||
|
||||
/* 操作按钮在移动端缩小 */
|
||||
.list-page-container .el-table .el-button--small {
|
||||
padding: 6px 10px;
|
||||
font-size: 12px;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
/* 表格列宽度优化 - 允许更灵活的宽度 */
|
||||
.list-page-container .el-table .el-table__cell {
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
/* 操作列宽度自适应,不设置最小宽度 */
|
||||
.list-page-container .el-table .el-table__cell[data-label="操作"],
|
||||
.list-page-container .el-table th:last-child,
|
||||
.list-page-container .el-table td:last-child {
|
||||
min-width: auto !important;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
/* 隐藏部分次要列在移动端 - 通过类名控制 */
|
||||
.list-page-container .el-table .el-table__cell.hidden-mobile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 操作按钮在移动端自动换行,避免溢出 */
|
||||
.list-page-container .el-table .el-table__cell .el-button + .el-button {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/* 表格在移动端允许横向滚动 */
|
||||
.list-page-container .el-table {
|
||||
min-width: 600px;
|
||||
}
|
||||
|
||||
/* 操作列在移动端不设置最小宽度,允许换行 */
|
||||
.list-page-container .el-table .el-table__cell[data-label="操作"] {
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* 操作按钮组在移动端更紧凑 */
|
||||
.list-page-container .el-table .el-table__cell .flex {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
/* 下拉菜单按钮在移动端优化 */
|
||||
.list-page-container .el-table .el-dropdown .el-button {
|
||||
padding: 6px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 超小屏幕进一步优化 */
|
||||
@media (max-width: 480px) {
|
||||
.list-page-container {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.list-page-header {
|
||||
padding: 16px 12px 12px;
|
||||
}
|
||||
|
||||
.list-page-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.list-page-filters {
|
||||
padding: 16px 12px;
|
||||
}
|
||||
|
||||
.list-page-table {
|
||||
padding: 0 12px 12px;
|
||||
}
|
||||
|
||||
/* 表格单元格进一步缩小 */
|
||||
.list-page-container .el-table th,
|
||||
.list-page-container .el-table td {
|
||||
padding: 10px 6px !important;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 操作按钮更紧凑 */
|
||||
.list-page-container .el-table .el-button--small {
|
||||
padding: 4px 8px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* 操作按钮组更紧凑 */
|
||||
.list-page-container .el-table .el-table__cell .flex.gap-2,
|
||||
.list-page-container .el-table .el-table__cell .flex.items-center {
|
||||
gap: 4px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 动画效果 */
|
||||
|
||||
@@ -316,7 +316,6 @@ import RichTextEditor from '@/components/common/RichTextEditor.vue'
|
||||
import { Rank, Search } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
|
||||
@@ -47,9 +47,9 @@ import { onMounted, onUnmounted, ref } from 'vue'
|
||||
})
|
||||
|
||||
// 固定配置
|
||||
const FETCH_PAGE_SIZE = 5// 每次获取的记录数
|
||||
const BASE_EMIT_INTERVAL = 4700// 基础5秒,避免弹幕重叠
|
||||
const RANDOM_EMIT_RANGE = 1000 // 0-1秒随机范围
|
||||
const FETCH_PAGE_SIZE = 8// 每次获取的记录数
|
||||
const BASE_EMIT_INTERVAL = 5500// 基础5秒,避免弹幕重叠
|
||||
const RANDOM_EMIT_RANGE = 2000 // 0-1秒随机范围
|
||||
|
||||
const enabled = ref(true)
|
||||
const danmakuWrapper = ref(null)
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useMobileTable } from '@/composables/useMobileTable'
|
||||
import { watch, nextTick, onMounted } from 'vue'
|
||||
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
@@ -48,6 +51,23 @@ defineProps({
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
// 移动端表格优化
|
||||
const { isMobile, removeFixedColumns } = useMobileTable()
|
||||
|
||||
// 监听表格内容变化,重新应用优化
|
||||
watch(() => isMobile.value, () => {
|
||||
nextTick(() => {
|
||||
removeFixedColumns()
|
||||
})
|
||||
})
|
||||
|
||||
// 在组件挂载后应用优化
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
removeFixedColumns()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
143
src/components/common/ResponsiveActionColumn.vue
Normal file
143
src/components/common/ResponsiveActionColumn.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<div class="responsive-action-column">
|
||||
<!-- 桌面端:显示所有按钮 -->
|
||||
<div v-if="!isMobile" class="action-buttons-desktop">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<!-- 移动端:主要操作按钮 + 更多操作下拉菜单 -->
|
||||
<div v-else class="action-buttons-mobile">
|
||||
<!-- 主要操作按钮(最多显示2个) -->
|
||||
<template v-for="(action, index) in primaryActions" :key="index">
|
||||
<el-button
|
||||
:type="action.type || 'default'"
|
||||
:size="action.size || 'small'"
|
||||
@click="action.handler"
|
||||
>
|
||||
{{ action.label }}
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 更多操作下拉菜单 -->
|
||||
<el-dropdown v-if="moreActions.length > 0" @command="handleCommand" trigger="click">
|
||||
<el-button type="info" size="small">
|
||||
更多
|
||||
<el-icon class="el-icon--right">
|
||||
<ArrowDown />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
v-for="(action, index) in moreActions"
|
||||
:key="index"
|
||||
:command="action"
|
||||
>
|
||||
<el-icon v-if="action.icon" class="dropdown-item-icon">
|
||||
<component :is="action.icon" />
|
||||
</el-icon>
|
||||
{{ action.label }}
|
||||
</el-dropdown-item>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, useSlots } from 'vue'
|
||||
import { useMobileTable } from '@/composables/useMobileTable'
|
||||
import { ArrowDown } from '@element-plus/icons-vue'
|
||||
|
||||
const props = defineProps({
|
||||
// 主要操作按钮数量(移动端显示)
|
||||
primaryCount: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
// 操作按钮配置(如果使用配置方式)
|
||||
actions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
const { isMobile } = useMobileTable()
|
||||
const slots = useSlots()
|
||||
|
||||
// 从插槽中提取按钮信息(如果使用插槽方式)
|
||||
const extractActionsFromSlots = () => {
|
||||
if (!slots.default) return []
|
||||
|
||||
const actions = []
|
||||
// 这里需要从插槽中解析按钮,但 Vue 3 的插槽是渲染函数,比较难解析
|
||||
// 所以建议使用 actions prop 方式
|
||||
return actions
|
||||
}
|
||||
|
||||
// 计算主要操作和更多操作
|
||||
const primaryActions = computed(() => {
|
||||
if (props.actions.length > 0) {
|
||||
return props.actions.slice(0, props.primaryCount)
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
const moreActions = computed(() => {
|
||||
if (props.actions.length > 0) {
|
||||
return props.actions.slice(props.primaryCount)
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
// 处理下拉菜单命令
|
||||
const handleCommand = (action) => {
|
||||
if (action && action.handler) {
|
||||
action.handler()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.responsive-action-column {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.action-buttons-desktop {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.action-buttons-mobile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.dropdown-item-icon {
|
||||
margin-right: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 移动端按钮更紧凑 */
|
||||
@media (max-width: 768px) {
|
||||
.action-buttons-mobile .el-button {
|
||||
padding: 6px 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.action-buttons-mobile .el-button {
|
||||
padding: 4px 8px;
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
101
src/composables/useMobileTable.js
Normal file
101
src/composables/useMobileTable.js
Normal file
@@ -0,0 +1,101 @@
|
||||
import { ref, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
|
||||
/**
|
||||
* 移动端表格优化 composable
|
||||
* 用于在移动端移除表格固定列,优化显示效果
|
||||
*/
|
||||
export function useMobileTable() {
|
||||
const isMobile = ref(false)
|
||||
const isTablet = ref(false)
|
||||
|
||||
// 检测屏幕尺寸
|
||||
const checkScreenSize = () => {
|
||||
if (typeof window === 'undefined') return
|
||||
const width = window.innerWidth
|
||||
isMobile.value = width < 768
|
||||
isTablet.value = width >= 768 && width < 1024
|
||||
}
|
||||
|
||||
// 移除表格固定列
|
||||
const removeFixedColumns = () => {
|
||||
if (typeof window === 'undefined') return
|
||||
|
||||
// 只在移动端执行
|
||||
if (!isMobile.value) {
|
||||
// 桌面端恢复固定列样式
|
||||
const tables = document.querySelectorAll('.list-page-container .el-table')
|
||||
tables.forEach((table) => {
|
||||
const fixedElements = table.querySelectorAll('.el-table__fixed, .el-table__fixed-right')
|
||||
fixedElements.forEach((el) => {
|
||||
el.style.position = ''
|
||||
el.style.boxShadow = ''
|
||||
el.style.backgroundColor = ''
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 使用 nextTick 确保 DOM 已更新
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
const tables = document.querySelectorAll('.list-page-container .el-table')
|
||||
tables.forEach((table) => {
|
||||
// 移除固定列元素
|
||||
const fixedElements = table.querySelectorAll('.el-table__fixed, .el-table__fixed-right')
|
||||
fixedElements.forEach((el) => {
|
||||
el.style.position = 'static'
|
||||
el.style.boxShadow = 'none'
|
||||
el.style.backgroundColor = 'transparent'
|
||||
el.style.zIndex = 'auto'
|
||||
})
|
||||
|
||||
// 移除固定列的表头、表体、表尾包装器
|
||||
const fixedWrappers = table.querySelectorAll(
|
||||
'.el-table__fixed-header-wrapper, .el-table__fixed-body-wrapper, .el-table__fixed-footer-wrapper'
|
||||
)
|
||||
fixedWrappers.forEach((el) => {
|
||||
el.style.position = 'static'
|
||||
})
|
||||
|
||||
// 移除固定列的遮罩层
|
||||
const fixedPatch = table.querySelectorAll('.el-table__fixed-right-patch, .el-table__fixed-patch')
|
||||
fixedPatch.forEach((el) => {
|
||||
el.style.display = 'none'
|
||||
})
|
||||
})
|
||||
}, 150)
|
||||
})
|
||||
}
|
||||
|
||||
// 监听窗口大小变化
|
||||
const handleResize = () => {
|
||||
const wasMobile = isMobile.value
|
||||
checkScreenSize()
|
||||
// 如果移动状态发生变化,重新应用优化
|
||||
if (wasMobile !== isMobile.value) {
|
||||
removeFixedColumns()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
checkScreenSize()
|
||||
if (typeof window !== 'undefined') {
|
||||
window.addEventListener('resize', handleResize)
|
||||
// 初始移除固定列
|
||||
removeFixedColumns()
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
isMobile,
|
||||
isTablet,
|
||||
removeFixedColumns
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user