Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/packages/__VUE/popover/__tests__/popover.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,44 @@ test('Popover: target', async () => {
expect(popoverWrapper.attributes('style')).contain('top: 112px;')
expect(popoverWrapper.attributes('style')).contain('left: 150px;')
})

test('Popover: updates target position after scrolling', async () => {
const target = document.createElement('div')
target.id = 'popover-scroll-target'
let top = 100
target.getBoundingClientRect = () => ({
width: 300,
height: 40,
left: 0,
top,
right: 300,
bottom: top + 40,
x: 0,
y: top,
toJSON: () => ({})
}) as DOMRect
document.body.appendChild(target)

const wrapper = mount(
() => <Popover visible={true} targetId={target.id} list={list} duration={0} />,
{
global: {
stubs: {
teleport: true
}
}
}
)

await sleep(350)
const popover = wrapper.find('.nut-popover')
expect(popover.attributes('style')).toContain('top: 152px;')

top = 40
window.dispatchEvent(new Event('scroll'))
await nextTick()
expect(wrapper.find('.nut-popover').attributes('style')).toContain('top: 92px;')

wrapper.unmount()
target.remove()
})
29 changes: 28 additions & 1 deletion src/packages/__VUE/popover/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</Teleport>
</template>
<script lang="ts">
import { computed, watch, ref, PropType, CSSProperties, onMounted, nextTick } from 'vue'
import { computed, watch, ref, PropType, CSSProperties, onMounted, onUnmounted, nextTick } from 'vue'
import { createComponent, renderIcon } from '@/packages/utils/create'
import { useRect } from '@/packages/utils/useRect'
import NutPopup from '../popup/index.vue'
Expand Down Expand Up @@ -195,26 +195,53 @@ export default create({
}
}

let positionListenersBound = false
const updatePosition = () => {
if (props.visible) {
getContentWidth()
}
}
const bindPositionListeners = () => {
if (positionListenersBound) return
window.addEventListener('scroll', updatePosition, true)
window.addEventListener('resize', updatePosition)
positionListenersBound = true
}
const unbindPositionListeners = () => {
if (!positionListenersBound) return
window.removeEventListener('scroll', updatePosition, true)
window.removeEventListener('resize', updatePosition)
positionListenersBound = false
}

onMounted(() => {
setTimeout(() => {
getContentWidth()
}, 300)
if (props.visible) {
bindPositionListeners()
}
})

watch(
() => props.visible,
(value) => {
showPopup.value = value
if (value) {
bindPositionListeners()
window.addEventListener('touchstart', clickAway, true)
nextTick(() => {
getContentWidth()
})
} else {
unbindPositionListeners()
window.removeEventListener('touchstart', clickAway, true)
}
}
)
onUnmounted(() => {
unbindPositionListeners()
})
const update = (val: boolean) => {
emit('update', val)
emit('update:visible', val)
Expand Down
42 changes: 42 additions & 0 deletions src/packages/__VUE/tour/__tests__/tour.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { mount } from '@vue/test-utils'
import { StepOptions } from '../index.vue'
import { Tour } from '@nutui/nutui'
import { nextTick } from 'vue'

const steps1 = [
{
Expand Down Expand Up @@ -152,3 +153,44 @@ test('Tour: type=step', async () => {
const btn2 = wrapper.findAll('.nut-tour-content-bottom-operate-btn')
expect(btn2.length).toBe(2)
})

test('Tour: updates the mask position after scrolling', async () => {
const target = document.createElement('div')
target.id = 'tour-scroll-target'
let top = 100
target.getBoundingClientRect = () => ({
width: 100,
height: 20,
left: 10,
top,
right: 110,
bottom: top + 20,
x: 10,
y: top,
toJSON: () => ({})
}) as DOMRect
document.body.appendChild(target)

const wrapper = mount(
() => <Tour modelValue={true} type="tile" steps={[{ target: target.id }]} />,
{
global: {
stubs: {
teleport: true
}
}
}
)

await nextTick()
const mask = wrapper.find('.nut-tour-mask')
expect(mask.attributes('style')).toContain('top: 92px')

top = 40
window.dispatchEvent(new Event('scroll'))
await nextTick()
expect(mask.attributes('style')).toContain('top: 32px')

wrapper.unmount()
target.remove()
})
30 changes: 29 additions & 1 deletion src/packages/__VUE/tour/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
</div>
</template>
<script lang="ts">
import { computed, watch, ref, reactive, toRefs, PropType, nextTick, onMounted } from 'vue'
import { computed, watch, ref, reactive, toRefs, PropType, nextTick, onMounted, onUnmounted } from 'vue'
import { PopoverLocation, PopoverTheme } from '../popover/type'
import { createComponent } from '@/packages/utils/create'
import { useRect } from '@/packages/utils/useRect'
Expand Down Expand Up @@ -236,6 +236,25 @@ export default create({
maskRect.value = rect
}

const updatePosition = () => {
if (state.showTour) {
getRootPosition()
}
}
let positionListenersBound = false
const bindPositionListeners = () => {
if (positionListenersBound) return
window.addEventListener('scroll', updatePosition, true)
window.addEventListener('resize', updatePosition)
positionListenersBound = true
}
const unbindPositionListeners = () => {
if (!positionListenersBound) return
window.removeEventListener('scroll', updatePosition, true)
window.removeEventListener('resize', updatePosition)
positionListenersBound = false
}

const close = () => {
state.showTour = false
state.showPopup = false
Expand All @@ -250,12 +269,21 @@ export default create({
onMounted(() => {
state.active = 0
getRootPosition()
if (state.showTour) {
bindPositionListeners()
}
})
onUnmounted(() => {
unbindPositionListeners()
})
watch(
() => props.modelValue,
(val) => {
if (val) {
bindPositionListeners()
getRootPosition()
} else {
unbindPositionListeners()
}
state.active = 0
state.showTour = val
Expand Down