feat: #8655 added button for scrolling up #1523

Merged
provira merged 34 commits from 8655-scrollUpButton into dev 2025-04-15 11:26:07 +00:00
3 changed files with 69 additions and 50 deletions
Showing only changes of commit 4db882cc03 - Show all commits

View File

@ -39,7 +39,7 @@ quasar.iconMapFn = (iconName) => {
<template>
<RouterView />
<VnScroll />
<VnScroll mode="window" />
</template>
<style lang="scss">

View File

@ -32,6 +32,7 @@ import VnTableOrder from 'src/components/VnTable/VnOrder.vue';
import VnTableFilter from './VnTableFilter.vue';
import { getColAlign } from 'src/composables/getColAlign';
import RightMenu from '../common/RightMenu.vue';
import VnScroll from '../common/VnScroll.vue'
const arrayData = useArrayData(useAttrs()['data-key']);
const $props = defineProps({
@ -166,13 +167,13 @@ const tableRef = ref();
const params = ref(useFilterParams($attrs['data-key']).params);
const orders = ref(useFilterParams($attrs['data-key']).orders);
const app = inject('app');
const vnScrollRef = ref(null);
const editingRow = ref(null);
const editingField = ref(null);
const isTableMode = computed(() => mode.value == TABLE_MODE);
const selectRegex = /select/;
const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
const showButton = ref(false);
const tableModes = [
{
icon: 'view_column',
@ -187,21 +188,17 @@ const tableModes = [
disable: $props.disableOption?.card,
},
];
const scrollToTop = () => {
if (tableRef.value) {
const virtualScrollContainer = tableRef.value.$el.querySelector('.q-table__middle');
if (isTableMode) {
virtualScrollContainer.scrollTo({ top: 0, behavior: 'smooth' });
showButton.value = false;
const onVirtualScroll = ({ to }) => {
const virtualScrollContainer = tableRef.value?.$el?.querySelector('.q-table__middle');
if (virtualScrollContainer) {
Outdated
Review

Esta parte es necesaria? Con el codigo que hay dentro de VnScroll no funciona?

Esta parte es necesaria? Con el codigo que hay dentro de VnScroll no funciona?
virtualScrollContainer.dispatchEvent(new CustomEvent('scroll'));
if (vnScrollRef.value) {
vnScrollRef.value.updateScrollContainer(virtualScrollContainer);
}
}
};
const onVirtualScroll = ({ index }) => {
showButton.value = index !== 0;
handleScroll();
};
onBeforeMount(() => {
const urlParams = route.query[$props.searchUrl];
hasParams.value = urlParams && Object.keys(urlParams).length !== 0;
@ -234,16 +231,6 @@ onUnmounted(async () => {
if ($props.isEditable) document.removeEventListener('click', clickHandler);
});
watch(
mode,
(newMode) => {
if (newMode === CARD_MODE) {
showButton.value = false;
}
},
{ immediate: true }
);
watch(
() => $props.columns,
(value) => splitColumns(value),
@ -653,16 +640,6 @@ const rowCtrlClickFunction = computed(() => {
});
</script>
<template>
<QBtn
v-show="showButton"
round
color="primary"
icon="arrow_upward"
class="scroll-to-top"
@click="scrollToTop"
>
<QTooltip>{{ $t('globals.scrollToTop') }}</QTooltip>
</QBtn>
<RightMenu v-if="$props.rightSearch" :overlay="overlay">
<template #right-panel>
<VnTableFilter
@ -1110,6 +1087,12 @@ const rowCtrlClickFunction = computed(() => {
</template>
</FormModelPopup>
</QDialog>
<VnScroll
ref="vnScrollRef"
v-if="isTableMode"
:scroll-target="tableRef?.$el?.querySelector('.q-table__middle')"
mode="table"
/>
</template>
<i18n>
en:
@ -1317,11 +1300,4 @@ es:
label.header-filter > .q-field__inner > .q-field__control {
padding: inherit;
}
.scroll-to-top {
position: fixed;
top: 70px;
left: 50%;
z-index: 1000;
}
</style>

View File

@ -1,8 +1,9 @@
<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
const props = defineProps({
scrollTarget: { type: [String, Object], default: 'window' } // Puede ser un selector o un ref
scrollTarget: { type: [String, Object], default: 'window' },
mode: { type: String, default: 'window' }
});
const scrollPosition = ref(0);
@ -10,7 +11,11 @@ const showButton = ref(false);
let scrollContainer = null;
const onScroll = () => {
scrollPosition.value = scrollContainer.scrollTop || window.scrollY;
if (!scrollContainer) return;
scrollPosition.value =
props.mode === 'table'
? scrollContainer.scrollTop
: window.scrollY;
};
watch(scrollPosition, (newValue) => {
@ -18,41 +23,79 @@ watch(scrollPosition, (newValue) => {
});
const scrollToTop = () => {
scrollContainer.scrollTo({ top: 0, behavior: 'smooth' });
if (scrollContainer) {
scrollContainer.scrollTo({ top: 0, behavior: 'smooth' });
}
};
onMounted(() => {
scrollContainer = props.scrollTarget === 'window' ? window : document.querySelector(props.scrollTarget);
const updateScrollContainer = (container) => {
if (container) {
if (scrollContainer) {
scrollContainer.removeEventListener('scroll', onScroll);
}
scrollContainer = container;
scrollContainer.addEventListener('scroll', onScroll);
onScroll();
}
};
defineExpose({
updateScrollContainer
});
const initScrollContainer = async () => {
Review

Yo esto lo simplificaria a:

const initScrollContainer = async () => {
await nextTick();
let scrollContainer  = window;
    if (props.target) {
        if (typeof props.scrollTarget === 'object') {
            scrollContainer = props.scrollTarget;
        } else {
            scrollContainer = document.querySelector(props.scrollTarget);
        }
    }

    if (!scrollContainer) return
        scrollContainer.addEventListener('scroll', onScroll);    
};
Yo esto lo simplificaria a: ``` const initScrollContainer = async () => { await nextTick(); let scrollContainer = window; if (props.target) { if (typeof props.scrollTarget === 'object') { scrollContainer = props.scrollTarget; } else { scrollContainer = document.querySelector(props.scrollTarget); } } if (!scrollContainer) return scrollContainer.addEventListener('scroll', onScroll); }; ```
Review

Se carga el window scroll. Esta solución funciona y reduce el codigo innecesario, además se puede prescindir de la prop mode (ya no es necesaria):

const initScrollContainer = async () => {
    await nextTick();

    if (typeof props.scrollTarget === 'object') {
        scrollContainer = props.scrollTarget;
    } else {
        scrollContainer = window;
    }

    if (!scrollContainer) return
        scrollContainer.addEventListener('scroll', onScroll);    
};

Se carga el window scroll. Esta solución funciona y reduce el codigo innecesario, además se puede prescindir de la prop mode (ya no es necesaria): ``` const initScrollContainer = async () => { await nextTick(); if (typeof props.scrollTarget === 'object') { scrollContainer = props.scrollTarget; } else { scrollContainer = window; } if (!scrollContainer) return scrollContainer.addEventListener('scroll', onScroll); }; ```
await nextTick();
if (props.mode === 'table') {
if (typeof props.scrollTarget === 'object') {
scrollContainer = props.scrollTarget;
} else {
scrollContainer = document.querySelector(props.scrollTarget);
}
if (!scrollContainer && props.scrollTarget !== 'window') {
setTimeout(initScrollContainer, 100);
return;
}
} else {
scrollContainer = window;
}
if (scrollContainer) {
scrollContainer.addEventListener('scroll', onScroll);
onScroll();
}
};
onMounted(() => {
initScrollContainer();
});
onUnmounted(() => {
if (scrollContainer) {
scrollContainer.removeEventListener('scroll', onScroll);
scrollContainer = null;
}
});
</script>
<template>
provira marked this conversation as resolved
Review

Si lo visualizas desde el movil no se queda en el centro
image

Si lo visualizas desde el movil no se queda en el centro ![image](/attachments/4194e3b9-925f-4dd5-93fe-d2c20f4e402d)
<QBtn
<QIcon
pablone marked this conversation as resolved Outdated

Te falta el efecto de hover al poner el ratón sobre el icono (poner el cursor como pointer y un pequeño degrado en el color). valora poner un QBtn y lo pondria un poco más grande size="md"

Te falta el efecto de hover al poner el ratón sobre el icono (poner el cursor como pointer y un pequeño degrado en el color). valora poner un `QBtn` y lo pondria un poco más grande `size="md"`

Con un QBtn se ve muy pequeño el icono con respecto al tamaño del botón

Con un QBtn se ve muy pequeño el icono con respecto al tamaño del botón
v-if="showButton"
round
color="primary"
icon="arrow_upward"
name="keyboard_arrow_up"
class="scroll-to-top"
@click="scrollToTop"
>
<QTooltip>{{ $t('globals.scrollToTop') }}</QTooltip>
</QBtn>
</QIcon>
</template>
<style scoped>
.scroll-to-top {
position: fixed;
top: 70px;
font-size: 50px;
left: 50%;
z-index: 1000;
}