quasarframework / quasar

Quasar Framework - Build high-performance VueJS user interfaces in record time
https://quasar.dev
MIT License
25.89k stars 3.51k forks source link

QDrawer with behavior="mobile" scrolls back to original position or as far as the new content will allow. #13475

Closed whoacowboy closed 2 years ago

whoacowboy commented 2 years ago

What happened?

I am using a QDrawer to filter content on my site. I am also using QInfiniteScroll to load more content when the user gets to the bottom of the page. When I scroll down to the bottom of the page everything works as expected and more content is loaded.

When I open the drawer and change the filters the content updates.

When I close the drawer, the page continually scrolls back down until the it gets to its previous position, loading new content on the way.

What did you expect to happen?

I would expect that the page would scroll to the top on new content and not continually try and scroll back to its previous position.

Reproduction URL

https://codepen.io/whoacowboy/full/oNEWVQw

How to reproduce?

  1. Go to the CodePen.
  2. Scroll down until until you are at blue 400 or so.
  3. Click the menu button.
  4. Click Change content menu item.

Flavour

Quasar CLI with Webpack (@quasar/cli | @quasar/app-webpack)

Areas

Components (quasar)

Platforms/Browsers

Firefox, Chrome, Safari

Quasar info output

Operating System - Darwin(21.1.0) - darwin/x64
NodeJs - 14.19.2

Global packages
  NPM - 6.14.17
  yarn - 1.22.19
  @quasar/cli - 1.3.2
  @quasar/icongenie - Not installed
  cordova - Not installed

Important local packages
  quasar - 2.7.0 -- Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
  @quasar/app-webpack - 3.5.2 -- Quasar Framework App CLI with Webpack
  @quasar/extras - 1.14.0 -- Quasar Framework fonts, icons and animations
  eslint-plugin-quasar - 1.1.0 -- Official ESLint plugin for Quasar
  vue - 3.2.33 -- The progressive JavaScript framework for building modern web UI.
  vue-router - 4.0.15
  pinia - Not installed
  vuex - 4.0.2 -- state management for Vue.js
  electron - Not installed
  electron-packager - Not installed
  electron-builder - Not installed
  @babel/core - 7.17.10 -- Babel compiler core.
  webpack - 5.72.1 -- Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.
  webpack-dev-server - 4.9.0 -- Serves a webpack app. Updates the browser on changes.
  workbox-webpack-plugin - Not installed
  register-service-worker - 1.7.2 -- Script for registering service worker, with hooks
  typescript - 4.5.5 -- TypeScript is a language for application scale JavaScript development
  @capacitor/core - Not installed
  @capacitor/cli - Not installed
  @capacitor/android - Not installed
  @capacitor/ios - Not installed

Quasar App Extensions
  @quasar/quasar-app-extension-dotenv - 1.1.0 -- Load .env variables into your quasar project
  quasar-app-extension-ide-helper - 1.0.0 -- Quasar framework extension which enables IDE features like autocomplete by generating helper files for IDE to index.
  @quasar/quasar-app-extension-testing-unit-jest - 2.2.5 -- A Quasar App Extension for running Jest tests

Relevant log output

No response

Additional context

On Chrome it keeps loading but on other browsers it scrolls back to the original position and loads one new set, but stops.

I looked into the code a little bit and it looks like it is happening in [prevent-scroll.js].(https://github.com/quasarframework/quasar/blob/dev/ui/src/utils/prevent-scroll.js)

It would be great if we could have a setting that allowed us scroll to top or back to original position.

I could live with just being able to disable it so I could manually scroll the page back up to the top.

pdanpdan commented 2 years ago

https://codepen.io/pdanpdan/pen/gOvXpBN?editors=0010

whoacowboy commented 2 years ago

Thank you. I have been hitting my head on that one. So i guess this is less a bug and more a feature request then.

pdanpdan commented 2 years ago

It is a problem, not a bug:) I mean it works as expected, but a method to queue something to execute when the body is scrollable would be nice. The change for body.style.top/left would be required anyway, but the timing for the final scroll when page is scrollable would be easier.

whoacowboy commented 2 years ago

Your solution worked really well though. I was stuck because I was trying to do everything with window.scrollTo I didn't think of using the position and scrollTo.

DerMrBacon commented 6 months ago

I have this problem too, that the page scrolls to initial position instead of staying in place, after closing the drawer it scrolls to this position. The codepen page is unfortunately not found 404.

whoacowboy commented 6 months ago

Hi @DerMrBacon,

I believe this was the entirety of the code that resolved the problem. If it doesn't work, let me know and I'll dig deeper.

This one cost me days of time on and off.

src/router/index.js

export default function ({ store } /* , ssrContext */) {
  // const store = useStore()
  const Router = createRouter({
    history: createWebHistory(),
    scrollBehavior(to, from, savedPosition) {
      window.scrollTo(0, 0)
      return { x: 0, y: 0, behavior: 'smooth' }
    },
    routes: makeRoutes({ store }),

    // Leave these as they are and change in quasar.conf.js instead!
    // quasar.conf.js -> build -> vueRouterMode
    // quasar.conf.js -> build -> publicPath
    mode: process.env.VUE_ROUTER_MODE,
    base: process.env.VUE_ROUTER_BASE,
  })

src/router/scrollBehavior.js

// - only available in html5 history mode
// - defaults to no scroll behavior
// - return false to prevent scroll
export default (to, from, savedPosition) => {
  if (savedPosition) {
    // savedPosition is only available for popstate navigations.
    return savedPosition
  } else {
    const position = {}
    // new navigation.
    // scroll to anchor by returning the selector
    if (to.hash) {
      position.selector = to.hash
    }
    // check if any matched route config has meta that requires scrolling to top
    if (to.matched.some((m) => m.meta.scrollToTop)) {
      // cords will be used if no selector is provided,
      // or if the selector didn't match any element.
      position.x = 0
      position.y = 0
    }
    // if the returned position is falsy or an empty object,
    // will retain current scroll position.
    return position
  }
}