Skip to content
Merged
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
5 changes: 5 additions & 0 deletions packages/utils/src/popper/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -901,4 +901,9 @@ export class PopperJS {

return boundaries
}

// https://popper.js.org/docs/v2/lifecycle/#set-new-options
setOptions(options: PopperOptions) {
Object.assign(this._options, options)
}
}
18 changes: 17 additions & 1 deletion packages/vue-hooks/src/vue-popper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export const userPopper = (options: IPopperInputParams) => {
}
}

// 注意: 一直以来,state.showPopper 为false时,并未调用doDestory. 像popover只是依赖这个值来 给reference元素 v-show一下
// 注意: 一直以来,state.showPopper 为false时,并未调用doDestroy. 像popover只是依赖这个值来 给reference元素 v-show一下
watch(
() => state.showPopper,
(val) => {
Expand All @@ -236,6 +236,22 @@ export const userPopper = (options: IPopperInputParams) => {
}
)

watch(
() => props.placement,
(val?: string) => {
state.currentPlacement = val
state.popperJS?.setOptions({ placement: val })

if (props.disabled) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition props.disabled should be checked before setting state.currentPlacement and calling setOptions. This ensures that no unnecessary operations are performed when the popover is disabled.

return
}
if (val) {
nextTick(updatePopper)
}
props.trigger === 'manual' && emit('update:modelValue', val)
}
)

onBeforeUnmount(() => {
nextTick(() => {
doDestroy(true)
Expand Down
41 changes: 38 additions & 3 deletions packages/vue/src/popover/__tests__/popover.test.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import { mountPcMode as mount } from '@opentiny-internal/vue-test-utils'
import { describe, test, expect } from 'vitest'
import { describe, test, expect, afterEach } from 'vitest'
import Button from '@opentiny/vue-button'
import Popover from '@opentiny/vue-popover'
import { ref } from 'vue'

describe('PC Mode', () => {
document.body.innerHTML = `
<div>
<div id="app"></div>
</div>
`

let wrapper

afterEach(() => {
wrapper?.unmount()
})

// attrs
test('trigger 触发方式', async () => {
const wrapper = mount(
wrapper = mount(
() => (
<Popover placement="top-start" title="标题" width="200" trigger="hover" append-to-body content="这是一段内容">
{{
Expand All @@ -36,8 +44,35 @@ describe('PC Mode', () => {

test.todo('height 高度')

test.todo('placement 出现位置')
test('placement 出现位置', async () => {
wrapper = mount(() => (
<Popover placement="top-start" trigger="hover" content="这是一段内容">
{{
reference: () => <Button>悬浮我提示</Button>
}}
</Popover>
))

await wrapper.find('button').trigger('mouseenter')
expect(document.querySelector('.tiny-popover')!.getAttribute('x-placement')).toBe('top-start')
})

test('响应式 placement', async () => {
const placement = ref('bottom')
wrapper = mount(() => (
<Popover placement={placement.value} content="这是一段内容">
{{ reference: () => <Button>点击我</Button> }}
</Popover>
))

await wrapper.find('button').trigger('click')
expect(document.querySelector('.tiny-popover')!.getAttribute('x-placement')).toBe('bottom')
await wrapper.find('button').trigger('click')

placement.value = 'right'
await wrapper.find('button').trigger('click')
expect(document.querySelector('.tiny-popover')!.getAttribute('x-placement')).toBe('right')
})
test.todo('disabled 是否可用')

test.todo('modelValue 状态是否可见')
Expand Down