Skip to content

fix(noticebar): children cannot update responsively in vertical mode #3251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: feat_v3.x
Choose a base branch
from
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
131 changes: 131 additions & 0 deletions src/packages/noticebar/__test__/noticebar.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react'
import { useState } from 'react'
import { render, fireEvent, waitFor, act } from '@testing-library/react'
import '@testing-library/jest-dom'
import { Fabulous } from '@nutui/icons-react'
Expand Down Expand Up @@ -220,3 +221,133 @@ test('vertical event test', async () => {
fireEvent.click(box)
await waitFor(() => expect(handleClick).toBeCalled())
})

test('vertical container height calculation with children', async () => {
const horseLamp1 = [
'NoticeBar 公告栏',
'Cascader 级联选择',
'DatePicker 日期选择器',
'CheckBox 复选按钮',
]
const height = 50
const { container } = render(
<NoticeBar direction="vertical" height={height} speed={10} duration={1000}>
{horseLamp1.map((item, index) => {
return (
<div
className="custom-item"
style={{ height: `${height}px`, lineHeight: `${height}px` }}
key={index}
>
{item}
</div>
)
})}
</NoticeBar>
)

await waitFor(
() => {
const wrapElement = container.querySelector('.nut-noticebar-box-wrap')
if (wrapElement) {
// 验证容器高度应该是 (childCount + 1) * height
// childCount = 4, height = 50, 所以期望高度是 (4 + 1) * 50 = 250px
const expectedHeight = `${(horseLamp1.length + 1) * height}px`
expect(wrapElement).toHaveStyle(`height: ${expectedHeight}`)
}
},
// 由于init中并不会立刻设置样式,所以需要等待一段时间
{ timeout: 3000 }
)
})

test('dynamic children update test', async () => {
let setList: any
const height = 40

const TestComponent = () => {
const [list, updateList] = useState(['原始项目1', '原始项目2', '原始项目3'])
setList = updateList

return (
<NoticeBar direction="vertical" height={height} speed={10} duration={500}>
{list.map((item, index) => (
<div
className="custom-item"
style={{ height: `${height}px`, lineHeight: `${height}px` }}
key={index}
>
{item}
</div>
))}
</NoticeBar>
)
}

const { container } = render(<TestComponent />)

// 等待初始渲染完成
await waitFor(() => {
const wrapElement = container.querySelector('.nut-noticebar-box-wrap')
expect(wrapElement).toHaveStyle('height: 160px') // (3 + 1) * 40

// 1. 初始时容器的垂直位移为0(显示第一项)
expect(wrapElement).toHaveStyle('transform: translate3D(0,0px,0)')

const items = container.querySelectorAll('.custom-item')
expect(items).toHaveLength(3)
expect(items[0]).toHaveTextContent('原始项目1')
})

// 等待轮播进行一段时间,确保当前不是第一项
await waitFor(
() => {
const wrapElement = container.querySelector('.nut-noticebar-box-wrap')
const transform = wrapElement
?.getAttribute('style')
?.match(/transform:\s*translate3D\(([^,]+),([^,]+),([^)]+)\)/)
const yOffset = transform ? transform[2].trim() : '0px'

// 验证已经轮播到非第一项(垂直偏移不为0)
expect(yOffset).not.toBe('0px')
},
{ timeout: 2000 }
) // 给足够时间让轮播发生

// 变更列表数据
act(() => {
setList(['新项目A', '新项目B', '新项目C', '新项目D'])
})

await waitFor(() => {
// 验证容器高度更新为新的计算值
const wrapElement = container.querySelector('.nut-noticebar-box-wrap')
expect(wrapElement).toHaveStyle('height: 200px') // (4 + 1) * 40

// 验证变更后重置回第一项:
// 1. 容器的垂直位移重置为0
expect(wrapElement).toHaveStyle('transform: translate3D(0,0px,0)')

// 2. 第一个子项没有额外的transform
const firstItem = container.querySelector(
'.custom-item:first-child'
) as HTMLElement
expect(firstItem.style.transform).toBe('')

// 验证元素结构更新:应该有4个项目
const items = container.querySelectorAll('.custom-item')
expect(items).toHaveLength(4)

// 验证当前显示的是新列表的第一项内容
expect(items[0]).toHaveTextContent('新项目A')
expect(items[1]).toHaveTextContent('新项目B')
expect(items[2]).toHaveTextContent('新项目C')
expect(items[3]).toHaveTextContent('新项目D')

// 验证样式更新:每个item的高度样式
items.forEach((item) => {
expect(item).toHaveStyle(`height: ${height}px`)
expect(item).toHaveStyle(`line-height: ${height}px`)
})
})
})
4 changes: 2 additions & 2 deletions src/packages/noticebar/demo.taro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const NoticeBarDemo = () => {
customeRight: '自定义右侧内容',
vertical: '垂直滚动',
complexAm: '纵向模式:自定义左侧图标',
customAm: '纵向模式:自定义滚动内容',
customAm: '纵向模式:自定义滚动内容,动态变更滚动内容',
customRightIcon: '纵向模式:自定义右侧图标',
},
'en-US': {
Expand All @@ -42,7 +42,7 @@ const NoticeBarDemo = () => {
customeRight: 'custom right content',
vertical: 'Vertical Scroll',
complexAm: 'Vertical Scroll Complex Animation',
customAm: 'Vertical Scroll Custom Style',
customAm: 'Vertical Scroll Custom Style,Dynamic Change Scroll Content',
customRightIcon: 'Vertical Scroll Custom Right Icon',
},
})
Expand Down
4 changes: 2 additions & 2 deletions src/packages/noticebar/demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const NoticeBarDemo = () => {
customeRight: '自定义右侧内容',
vertical: '垂直滚动',
complexAm: '纵向模式:自定义左侧图标',
customAm: '纵向模式:自定义滚动内容',
customAm: '纵向模式:自定义滚动内容,动态变更滚动内容',
customRightIcon: '纵向模式:自定义右侧图标',
},
'en-US': {
Expand All @@ -38,7 +38,7 @@ const NoticeBarDemo = () => {
customeRight: 'custom right content',
vertical: 'Vertical Scroll',
complexAm: 'Vertical Scroll Complex Animation',
customAm: 'Vertical Scroll Custom Style',
customAm: 'Vertical Scroll Custom Style,Dynamic Change Scroll Content',
customRightIcon: 'Vertical Scroll Custom Right Icon',
},
})
Expand Down
28 changes: 25 additions & 3 deletions src/packages/noticebar/demos/h5/demo10.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react'
import { NoticeBar } from '@nutui/nutui-react'
import React, { useState } from 'react'
import { Button, NoticeBar, Space } from '@nutui/nutui-react'

const Demo9 = () => {
const horseLamp3 = [
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

修复组件名称不一致

组件名称为 Demo9 但文件名为 demo10.tsx,这会造成混淆。

应用此修改来修复命名不一致:

-const Demo9 = () => {
+const Demo10 = () => {
-export default Demo9
+export default Demo10
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const Demo9 = () => {
const Demo10 = () => {
// ...rest of the component implementation...
}
export default Demo10
🤖 Prompt for AI Agents
In src/packages/noticebar/demos/h5/demo10.tsx at line 4, the component is named
Demo9 which is inconsistent with the file name demo10.tsx. Rename the component
from Demo9 to Demo10 to ensure the component name matches the file name and
avoid confusion.

Expand All @@ -9,6 +9,8 @@ const Demo9 = () => {
'CheckBox 复选按钮',
]

const [list, setList] = useState(horseLamp3)

return (
<>
<NoticeBar
Expand All @@ -21,7 +23,7 @@ const Demo9 = () => {
console.log('close')
}}
>
{horseLamp3.map((item, index) => {
{list.map((item, index) => {
return (
<div
className="custom-item"
Expand All @@ -36,6 +38,26 @@ const Demo9 = () => {
)
})}
</NoticeBar>

<Space style={{ marginTop: '10px' }}>
<Button
size="small"
onClick={() => {
setList((prev) => [...prev, `${prev.length + 1}`])
}}
>
添加最后一项
</Button>

<Button
size="small"
onClick={() => {
setList((prev) => prev.slice(0, -1))
}}
>
删除最后一项
</Button>
</Space>
</>
)
}
Expand Down
28 changes: 25 additions & 3 deletions src/packages/noticebar/demos/taro/demo10.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react'
import { NoticeBar } from '@nutui/nutui-react-taro'
import React, { useState } from 'react'
import { Button, NoticeBar, Space } from '@nutui/nutui-react-taro'

const Demo10 = () => {
const horseLamp3 = [
Expand All @@ -9,6 +9,8 @@ const Demo10 = () => {
'CheckBox 复选按钮',
]

const [list, setList] = useState(horseLamp3)

return (
<>
<NoticeBar
Expand All @@ -21,7 +23,7 @@ const Demo10 = () => {
console.log('close')
}}
>
{horseLamp3.map((item, index) => {
{list.map((item, index) => {
return (
<div
className="custom-item"
Expand All @@ -36,6 +38,26 @@ const Demo10 = () => {
)
})}
</NoticeBar>

<Space style={{ marginTop: '10px' }}>
<Button
size="small"
onClick={() => {
setList((prev) => [...prev, `${prev.length + 1}`])
}}
>
添加最后一项
</Button>

<Button
size="small"
onClick={() => {
setList((prev) => prev.slice(0, -1))
}}
>
删除最后一项
</Button>
</Space>
</>
)
}
Expand Down
2 changes: 1 addition & 1 deletion src/packages/noticebar/doc.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Add Right mode to set more custom content.

:::

### Vertical Scroll Custom Style
### Vertical Scroll Custom Style, Dynamic Content Updates

:::demo

Expand Down
2 changes: 1 addition & 1 deletion src/packages/noticebar/doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ import { NoticeBar } from '@nutui/nutui-react'

:::

### 纵向模式:自定义右侧图标
### 纵向模式:自定义右侧图标,动态变更滚动内容

:::demo

Expand Down
2 changes: 1 addition & 1 deletion src/packages/noticebar/doc.taro.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ import { NoticeBar } from '@nutui/nutui-react-taro'

:::

### 纵向模式:自定义右侧图标
### 纵向模式:自定义右侧图标,动态变更滚动内容

:::demo

Expand Down
2 changes: 1 addition & 1 deletion src/packages/noticebar/doc.zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ import { NoticeBar } from '@nutui/nutui-react'

:::

### 縱嚮模式:自定義右側圖標
### 縱嚮模式:自定義右側圖標,動態變更滾動內容

:::demo

Expand Down
Loading
Loading