Skip to content

Commit fbdd2a6

Browse files
authored
feat(keepAlive activate): set autofocus on activate in QField/QForm; restore scroll on activate in QScrollArea (#12087)
* feat(keepAlive activate): set autofocus on activate in QField/QForm; restore scroll on activate in QScrollArea * chore(QScrollArea): add test case for keepAlive * chore(keep-alive): add test case for events order * chore(keep-alive): small tweaks for QScrollArea test
1 parent 090ab40 commit fbdd2a6

File tree

8 files changed

+142
-48
lines changed

8 files changed

+142
-48
lines changed

ui/dev/src/pages/components/scroll-area.vue

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,46 +8,50 @@
88

99
<div style="height: 200px;" />
1010

11-
<q-scroll-area
12-
v-if="!darkVariant"
13-
ref="scroll"
14-
style="width: 400px; height: 500px;"
15-
class="bg-yellow"
16-
:visible="alwaysVisible"
17-
:bar-style="customBarStyle"
18-
:vertical-bar-style="customVBarStyle"
19-
:horizontal-bar-style="customHBarStyle"
20-
:thumbStyle="customThumbStyle"
21-
:vertical-thumb-style="customVThumbStyle"
22-
:horizontal-thumb-style="customHThumbStyle"
23-
:tabindex="focusable === true ? 0 : void 0"
24-
>
25-
<div :class="{ 'flex no-wrap' : horizontal }">
26-
<div style="margin-top: 150px" />
27-
<div style="margin-bottom: 25px" :style="horizontal ? 'width: 160px' : ''" v-for="n in number" :key="n">
28-
{{ n }} Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
29-
<q-btn label="Click" color="primary" />
11+
<keep-alive>
12+
<q-scroll-area
13+
v-if="!darkVariant"
14+
key="scl"
15+
ref="scroll"
16+
style="width: 400px; height: 500px;"
17+
class="bg-yellow"
18+
:visible="alwaysVisible"
19+
:bar-style="customBarStyle"
20+
:vertical-bar-style="customVBarStyle"
21+
:horizontal-bar-style="customHBarStyle"
22+
:thumbStyle="customThumbStyle"
23+
:vertical-thumb-style="customVThumbStyle"
24+
:horizontal-thumb-style="customHThumbStyle"
25+
:tabindex="focusable === true ? 0 : void 0"
26+
>
27+
<div :class="{ 'flex no-wrap' : horizontal }">
28+
<div style="margin-top: 150px" />
29+
<div style="margin-bottom: 25px" :style="horizontal ? 'width: 160px' : ''" v-for="n in number" :key="n">
30+
{{ n }} Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
31+
<q-btn label="Click" color="primary" />
32+
</div>
3033
</div>
31-
</div>
32-
</q-scroll-area>
34+
</q-scroll-area>
3335

34-
<q-scroll-area
35-
v-else
36-
ref="scroll"
37-
style="width: 400px; height: 500px;"
38-
class="bg-dark text-white q-mt-lg"
39-
:visible="alwaysVisible"
40-
dark
41-
:tabindex="focusable === true ? 0 : void 0"
42-
>
43-
<div :class="{ 'flex no-wrap' : horizontal }">
44-
<div style="margin-top: 150px" />
45-
<div style="margin-bottom: 25px" :style="horizontal ? 'width: 160px' : ''" v-for="n in number" :key="n">
46-
{{ n }} Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
47-
<q-btn label="Click" color="primary" />
36+
<q-scroll-area
37+
v-else
38+
key="scd"
39+
ref="scroll"
40+
style="width: 400px; height: 500px;"
41+
class="bg-dark text-white"
42+
:visible="alwaysVisible"
43+
dark
44+
:tabindex="focusable === true ? 0 : void 0"
45+
>
46+
<div :class="{ 'flex no-wrap' : horizontal }">
47+
<div style="margin-top: 150px" />
48+
<div style="margin-bottom: 25px" :style="horizontal ? 'width: 160px' : ''" v-for="n in number" :key="n">
49+
{{ n }} Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
50+
<q-btn label="Click" color="primary" />
51+
</div>
4852
</div>
49-
</div>
50-
</q-scroll-area>
53+
</q-scroll-area>
54+
</keep-alive>
5155

5256
<br>
5357
<q-btn @click="number--">
@@ -162,7 +166,8 @@ export default {
162166
backgroundColor: '#888',
163167
borderRadius: '7px',
164168
borderStyle: 'solid',
165-
borderColor: 'transparent'
169+
borderColor: 'transparent',
170+
backgroundClip: 'content-box'
166171
}
167172
: null
168173
},

ui/dev/src/pages/web-tests/panel-keep-alive.vue

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373

7474
<script>
7575
import { h } from 'vue'
76+
import { QInput, QForm } from 'quasar'
7677
7778
export default {
7879
components: {
@@ -83,6 +84,12 @@ export default {
8384
name: String
8485
},
8586
87+
data () {
88+
return {
89+
text: 'input text sample'
90+
}
91+
},
92+
8693
created () {
8794
this.log('created')
8895
},
@@ -95,12 +102,20 @@ export default {
95102
this.log('mounted')
96103
},
97104
105+
activated () {
106+
this.log('activated')
107+
},
108+
109+
deactivated () {
110+
this.log('deactivated')
111+
},
112+
98113
beforeUnmount () {
99114
this.log('beforeUnmount')
100115
},
101116
102117
unmounted () {
103-
this.log('destroyed')
118+
this.log('unmounted')
104119
},
105120
106121
methods: {
@@ -110,7 +125,24 @@ export default {
110125
},
111126
112127
render () {
113-
return h('div', [ 'keep alive test ' + this.name ])
128+
return h('div', () => ([
129+
'keep alive test ' + this.name,
130+
h(QForm, {
131+
autofocus: true
132+
}, () => ([
133+
h(QInput, {
134+
class: 'q-my-md',
135+
style: 'max-width: 300px',
136+
modelValue: this.text,
137+
// autofocus: true,
138+
outlined: true,
139+
label: 'Input with autofocus',
140+
'onUpdate:model-value': val => {
141+
this.text = val
142+
}
143+
})
144+
]))
145+
]))
114146
}
115147
}
116148
},

ui/src/components/form/QForm.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { h, ref, onMounted, getCurrentInstance, nextTick, provide } from 'vue'
1+
import { h, ref, onActivated, onDeactivated, onMounted, getCurrentInstance, nextTick, provide } from 'vue'
22

33
import { createComponent } from '../../utils/private/create.js'
44
import { stopAndPrevent } from '../../utils/event.js'
@@ -161,6 +161,16 @@ export default createComponent({
161161
}
162162
})
163163

164+
let shouldActivate = false
165+
166+
onDeactivated(() => {
167+
shouldActivate = true
168+
})
169+
170+
onActivated(() => {
171+
shouldActivate === true && props.autofocus === true && focus()
172+
})
173+
164174
onMounted(() => {
165175
props.autofocus === true && focus()
166176
})

ui/src/components/infinite-scroll/QInfiniteScroll.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ export default createComponent({
4141
const rootRef = ref(null)
4242

4343
let index = props.initialIndex || 0
44-
let scrollPos = false
4544
let localScrollTarget, poll
4645

4746
const classes = computed(() =>
@@ -180,8 +179,10 @@ export default createComponent({
180179
watch(() => props.scrollTarget, updateScrollTarget)
181180
watch(() => props.debounce, setDebounce)
182181

182+
let scrollPos = false
183+
183184
onActivated(() => {
184-
if (localScrollTarget && scrollPos !== false) {
185+
if (scrollPos !== false && localScrollTarget) {
185186
setVerticalScrollPosition(localScrollTarget, scrollPos)
186187
}
187188
})

ui/src/components/scroll-area/QScrollArea.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { h, ref, computed, withDirectives, onBeforeUnmount, getCurrentInstance } from 'vue'
1+
import { h, ref, computed, withDirectives, onActivated, onDeactivated, onBeforeUnmount, getCurrentInstance } from 'vue'
22

33
import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
44

@@ -380,6 +380,26 @@ export default createComponent({
380380
}
381381
})
382382

383+
let scrollPosition = null
384+
385+
onDeactivated(() => {
386+
scrollPosition = {
387+
top: scroll.vertical.position.value,
388+
left: scroll.horizontal.position.value
389+
}
390+
})
391+
392+
onActivated(() => {
393+
if (scrollPosition === null) { return }
394+
395+
const scrollTarget = targetRef.value
396+
397+
if (scrollTarget !== null) {
398+
setHorizontalScrollPosition(scrollTarget, scrollPosition.left)
399+
setVerticalScrollPosition(scrollTarget, scrollPosition.top)
400+
}
401+
})
402+
383403
onBeforeUnmount(emitScroll.cancel)
384404

385405
return () => {

ui/src/components/tabs/QTabs.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { h, ref, computed, watch, nextTick, onBeforeUnmount, onActivated, getCurrentInstance, provide } from 'vue'
1+
import { h, ref, computed, watch, nextTick, onBeforeUnmount, onActivated, onDeactivated, getCurrentInstance, provide } from 'vue'
22

33
import QIcon from '../icon/QIcon.js'
44
import QResizeObserver from '../resize-observer/QResizeObserver.js'
@@ -568,7 +568,15 @@ export default createComponent({
568568
unwatchRoute !== void 0 && unwatchRoute()
569569
})
570570

571-
onActivated(recalculateScroll)
571+
let shouldActivate = false
572+
573+
onDeactivated(() => {
574+
shouldActivate = true
575+
})
576+
577+
onActivated(() => {
578+
shouldActivate === true && recalculateScroll()
579+
})
572580

573581
return () => {
574582
const child = [

ui/src/components/virtual-scroll/use-virtual-scroll.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { h, ref, computed, watch, onActivated, onBeforeMount, onBeforeUnmount, nextTick, getCurrentInstance } from 'vue'
1+
import { h, ref, computed, watch, onActivated, onDeactivated, onBeforeMount, onBeforeUnmount, nextTick, getCurrentInstance } from 'vue'
22

33
import debounce from '../../utils/debounce.js'
44
import { noop } from '../../utils/event.js'
@@ -691,7 +691,15 @@ export function useVirtualScroll ({
691691
setVirtualScrollSize()
692692
})
693693

694+
let shouldActivate = false
695+
696+
onDeactivated(() => {
697+
shouldActivate = true
698+
})
699+
694700
onActivated(() => {
701+
if (shouldActivate !== true) { return }
702+
695703
const scrollEl = getVirtualScrollTarget()
696704

697705
if (prevScrollStart !== void 0 && scrollEl !== void 0 && scrollEl !== null && scrollEl.nodeType !== 8) {

ui/src/composables/private/use-field.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { h, ref, computed, watch, Transition, nextTick, onBeforeUnmount, onMounted, getCurrentInstance } from 'vue'
1+
import { h, ref, computed, watch, Transition, nextTick, onActivated, onDeactivated, onBeforeUnmount, onMounted, getCurrentInstance } from 'vue'
22

33
import { isRuntimeSsrPreHydration } from '../../plugins/Platform.js'
44

@@ -532,6 +532,16 @@ export default function (state) {
532532
// expose public methods
533533
Object.assign(proxy, { focus, blur })
534534

535+
let shouldActivate = false
536+
537+
onDeactivated(() => {
538+
shouldActivate = true
539+
})
540+
541+
onActivated(() => {
542+
shouldActivate === true && props.autofocus === true && proxy.focus()
543+
})
544+
535545
onMounted(() => {
536546
if (isRuntimeSsrPreHydration.value === true && props.for === void 0) {
537547
state.targetUid.value = getTargetUid()

0 commit comments

Comments
 (0)