mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
fix: avoid many scrollTo calls for n components
Thank you @vbelolapotkov for pointing out the flaws here: https://github.com/Human-Connection/Human-Connection/pull/1756#discussion_r329361572 So here is my attempt to fix it: * Install `vue-scrollto` which relies on `requestAnimationFrame` - apparently this is better on Safari and IE? 🤔 - Mocking out entire modules is easier in jest: https://jestjs.io/docs/en/bypassing-module-mocks * Require `checkAnchor` to be implemented on the component
This commit is contained in:
parent
2c705a8680
commit
9da40c4895
@ -10,7 +10,7 @@
|
||||
</ds-card>
|
||||
</div>
|
||||
<div v-else :class="{ comment: true, 'disabled-content': comment.deleted || comment.disabled }">
|
||||
<ds-card :id="`commentId-${comment.id}`">
|
||||
<ds-card :id="anchor">
|
||||
<ds-space margin-bottom="small" margin-top="small">
|
||||
<hc-user :user="author" :date-time="comment.createdAt" />
|
||||
<!-- Content Menu (can open Modals) -->
|
||||
@ -111,6 +111,9 @@ export default {
|
||||
user: 'auth/user',
|
||||
isModerator: 'auth/isModerator',
|
||||
}),
|
||||
anchor() {
|
||||
return `commentId-${this.comment.id}`
|
||||
},
|
||||
displaysComment() {
|
||||
return !this.unavailable || this.isModerator
|
||||
},
|
||||
@ -144,6 +147,9 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
checkAnchor(anchor) {
|
||||
return `#${this.anchor}` === anchor
|
||||
},
|
||||
isAuthor(id) {
|
||||
return this.user.id === id
|
||||
},
|
||||
|
||||
@ -41,6 +41,9 @@ export default {
|
||||
post: { type: Object, default: () => {} },
|
||||
},
|
||||
methods: {
|
||||
checkAnchor(anchor) {
|
||||
return anchor === '#comments'
|
||||
},
|
||||
updateCommentList(updatedComment) {
|
||||
this.post.comments = this.post.comments.map(comment => {
|
||||
return comment.id === updatedComment.id ? updatedComment : comment
|
||||
|
||||
@ -1,32 +1,20 @@
|
||||
export function scrollToAnchor(anchor) {
|
||||
if (!anchor) return
|
||||
if (!window || !document) {
|
||||
return
|
||||
}
|
||||
const container = document.querySelector(anchor)
|
||||
if (container) {
|
||||
const { top } = container.getBoundingClientRect()
|
||||
setTimeout(() => {
|
||||
// we have to set a small timeout to ensure this part comes after nuxt
|
||||
// scrollBehaviour: https://nuxtjs.org/api/configuration-router/#scrollbehavior
|
||||
window.scroll({
|
||||
top,
|
||||
left: 0,
|
||||
behavior: 'smooth',
|
||||
})
|
||||
}, 250)
|
||||
}
|
||||
}
|
||||
import { scrollTo } from 'vue-scrollto'
|
||||
|
||||
export default {
|
||||
watch: {
|
||||
$route(to, from) {
|
||||
const anchor = to && to.hash
|
||||
scrollToAnchor(anchor)
|
||||
if (!this.checkAnchor(anchor)) return
|
||||
setTimeout(() => {
|
||||
scrollTo(anchor, 1000)
|
||||
}, 250)
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const anchor = this.$route && this.$route.hash
|
||||
scrollToAnchor(anchor)
|
||||
if (!this.checkAnchor(anchor)) return
|
||||
setTimeout(() => {
|
||||
scrollTo(anchor, 1000)
|
||||
}, 250)
|
||||
},
|
||||
}
|
||||
|
||||
47
webapp/mixins/scrollToAnchor.spec.js
Normal file
47
webapp/mixins/scrollToAnchor.spec.js
Normal file
@ -0,0 +1,47 @@
|
||||
import { scrollTo } from 'vue-scrollto'
|
||||
import scrollToAnchor from './scrollToAnchor'
|
||||
jest.mock('vue-scrollto')
|
||||
|
||||
let component
|
||||
|
||||
describe('scrollToAnchor', () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers()
|
||||
scrollTo.mockClear()
|
||||
})
|
||||
|
||||
describe('scrollToAnchor', () => {
|
||||
const action = hash => {
|
||||
let {
|
||||
watch: { $route },
|
||||
} = scrollToAnchor
|
||||
$route.bind(component)({ hash })
|
||||
jest.runAllTimers()
|
||||
}
|
||||
|
||||
describe('given anchor `commentId-4711`', () => {
|
||||
beforeEach(() => {
|
||||
component = {
|
||||
anchor: 'commentId-4711',
|
||||
checkAnchor(anchor) {
|
||||
return this.anchor === anchor
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
describe('$route.hash === anchor', () => {
|
||||
it('calls window.scroll', () => {
|
||||
action('commentId-4711')
|
||||
expect(scrollTo).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('$route.hash !== anchor', () => {
|
||||
it('skips window.scroll', () => {
|
||||
action('commentId-4712')
|
||||
expect(scrollTo).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -83,6 +83,7 @@
|
||||
"vue-count-to": "~1.0.13",
|
||||
"vue-infinite-scroll": "^2.0.2",
|
||||
"vue-izitoast": "^1.2.1",
|
||||
"vue-scrollto": "^2.17.1",
|
||||
"vue-sweetalert-icons": "~4.2.0",
|
||||
"vuex-i18n": "~1.13.1",
|
||||
"xregexp": "^4.2.4",
|
||||
|
||||
@ -4235,6 +4235,11 @@ bcrypt-pbkdf@^1.0.0:
|
||||
dependencies:
|
||||
tweetnacl "^0.14.3"
|
||||
|
||||
bezier-easing@2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/bezier-easing/-/bezier-easing-2.1.0.tgz#c04dfe8b926d6ecaca1813d69ff179b7c2025d86"
|
||||
integrity sha1-wE3+i5JtbsrKGBPWn/F5t8ICXYY=
|
||||
|
||||
bfj@^6.1.1:
|
||||
version "6.1.1"
|
||||
resolved "https://registry.yarnpkg.com/bfj/-/bfj-6.1.1.tgz#05a3b7784fbd72cfa3c22e56002ef99336516c48"
|
||||
@ -15315,6 +15320,13 @@ vue-router@~3.0.7:
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.7.tgz#b36ca107b4acb8ff5bc4ff824584059c23fcb87b"
|
||||
integrity sha512-utJ+QR3YlIC/6x6xq17UMXeAfxEvXA0VKD3PiSio7hBOZNusA1jXcbxZxVEfJunLp48oonjTepY8ORoIlRx/EQ==
|
||||
|
||||
vue-scrollto@^2.17.1:
|
||||
version "2.17.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-scrollto/-/vue-scrollto-2.17.1.tgz#cd62ee0b98cf7e2ba9fd94f029addcd093978a48"
|
||||
integrity sha512-uxOJXg6cZL88B+hTXRHDJMR+gHGiaS70ZTNk55fE5Z2TdwyIx9K/IHoNeTrtBrM6u3FASAIymKjZaQLmDf8Ykg==
|
||||
dependencies:
|
||||
bezier-easing "2.1.0"
|
||||
|
||||
vue-server-renderer@^2.6.10:
|
||||
version "2.6.10"
|
||||
resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.6.10.tgz#cb2558842ead360ae2ec1f3719b75564a805b375"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user