Skip to content
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

两个ScrollView嵌套导致scrollTop不可控,外面滚动里面会不停render #7626

Closed
paulloo opened this issue Sep 16, 2020 · 14 comments
Assignees
Labels
F-react Framework - React question Further information is requested T-h5 Target - 编译到 H5 V-2 Version - 2.x
Projects

Comments

@paulloo
Copy link

paulloo commented Sep 16, 2020

相关平台

H5

复现仓库

https://gist.github.com/1c2f020ddbe986c56e0006a6615d9825
浏览器版本: Chrome 77.0.3865.120
使用框架: React

复现步骤

<ScrollView scrollY className='doc-body' scrollTop={scrollTop} onScroll={this.onScrollHandle.bind(this)} style={{position: 'absolute', left: 0, right: 0, top: 0, bottom: 0}}>
          <ScrollView scrollX scrollLeft={scrollLeft} style={{whiteSpace: 'nowrap', position: "fixed", top: 0, left: 0, right: 0, zIndex: 9099}}>
            横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动
          </ScrollView>
.........................
          </ScrollView>

1.两个ScrollView嵌套,外层监听onScroll事件 ,并设置外层scrollTop.
2.内部的ScrollView 设置scrollLeft

期望结果

内外层ScrollView互不影响

实际结果

外层scrollView 滚动,会不停render内部组件,并且会影响内部ScrollViewScrollLeft的定位

环境信息

Taro CLI 2.2.13 environment info:
    System:
      OS: Windows 10
    Binaries:
      Node: 10.16.3 - D:\nodejs\node.EXE
      Yarn: 1.22.4 - ~\AppData\Roaming\npm\yarn.CMD
      npm: 6.9.0 - D:\nodejs\npm.CMD
@taro-bot2 taro-bot2 bot added F-react Framework - React T-h5 Target - 编译到 H5 V-2 Version - 2.x labels Sep 16, 2020
@paulloo
Copy link
Author

paulloo commented Sep 16, 2020

@ZakaryCode 看了下 @tarojs/component/scroll-view/index.js ,debug看了下,一个页面创建了多个ScrollView 实例,当滚动其中一个ScrollView 其他实例都会render 是这个问题吗?

@paulloo
Copy link
Author

paulloo commented Sep 16, 2020

image

@ZakaryCode
Copy link
Contributor

根据提供的示例,你并没有监听内层ScrollView的变动,所以scrollLeft值是从外层onScrollHandle中同步变更的?

@ZakaryCode
Copy link
Contributor

方便的话补充下示例代码,以便调试。

@ZakaryCode ZakaryCode added the question Further information is requested label Sep 16, 2020
@paulloo
Copy link
Author

paulloo commented Sep 16, 2020

根据提供的示例,你并没有监听内层ScrollView的变动,所以scrollLeft值是从外层onScrollHandle中同步变更的?

import Taro from '@tarojs/taro'
import { View, Text, ScrollView } from '@tarojs/components'

import DocsHeader from '../../components/doc-header'

import TestScrollView from './testScrollView'

import './index.scss'

type Color = {
  name: string
  hex: string
}
type ColorData = {
  type: string
  data: Color[]
}

interface BasicColorState {
  colorData: ColorData[]
  scrollTop: number;
  scrollLeft: number;
}

export default class BasicColor extends Taro.Component<{}, BasicColorState> {
  public config: Taro.PageConfig = {
    navigationBarTitleText: 'Taro UI'
  }

  public constructor () {
    super()

    this.state = {
      colorData: [
        {
          type: '主色',
          data: [
            {
              name: '浅蓝色',
              hex: '#78A4FA'
            },
            {
              name: '品牌蓝',
              hex: '#6190E8'
            },
            {
              name: '深蓝色',
              hex: '#346FC2'
            }
          ]
        },
        {
          type: '辅助色',
          data: [
            {
              name: '蓝色 - Info',
              hex: '#78A4FA'
            },
            {
              name: '绿色 - Positive',
              hex: '#13CE66'
            },
            {
              name: '红色 - Negative',
              hex: '#FF4949'
            },
            {
              name: '黄色 - Warning',
              hex: '#FFC82C'
            }
          ]
        },
        {
          type: '中性色',
          data: [
            {
              name: '黑色 0',
              hex: '#333333'
            },
            {
              name: '黑色 1',
              hex: '#7F7F7F'
            },
            {
              name: '黑色 2',
              hex: '#B2B2B2'
            },
            {
              name: '灰色 0',
              hex: '#333333'
            },
            {
              name: '灰色 1',
              hex: '#666666'
            },
            {
              name: '灰色 2',
              hex: '#999999'
            },
            {
              name: '灰色 3',
              hex: '#CCCCCC'
            },
            {
              name: '灰色 4',
              hex: '#E5E5E5'
            },
            {
              name: '灰色 5',
              hex: '#F0F0F0'
            },
            {
              name: '灰色 6',
              hex: '#F7F7F7'
            }
          ]
        },
        {
          type: '其他色',
          data: [
            {
              name: '边框可选色',
              hex: '#C5D9E8'
            },
            {
              name: '背景色 0',
              hex: '#ECF5FD'
            },
            {
              name: '背景色 1',
              hex: '#FAFBFC'
            }
          ]
        }
      ],
      scrollTop: 0,
      scrollLeft: 100
    }
  }

  onScrollHandle(e) {
    this.setState({
      scrollTop: e.detail.scrollTop
    })
  }

  public render (): JSX.Element {
    const { colorData, scrollTop, scrollLeft } = this.state

    return (
      <View className='page'>
        {/* S Header */}
        <DocsHeader title='Color 颜色'></DocsHeader>
        {/* E Header */}

        {/* S Body */}
        <ScrollView scrollY className='doc-body' scrollTop={scrollTop} onScroll={this.onScrollHandle.bind(this)} style={{position: 'absolute', left: 0, right: 0, top: 0, bottom: 0}}>
          <ScrollView scrollX scrollLeft={scrollLeft} style={{whiteSpace: 'nowrap', position: "fixed", top: 0, left: 0, right: 0, zIndex: 9099}}>
            横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动
          </ScrollView>
          {colorData.map(item => (
            <View className='panel' key={item.type}>
              <View className='panel__title'>{item.type}</View>
              <View className='panel__content'>

                <View className='color-list'>
                  {item.data.map(color => (
                    <View className='color-item' key={color.hex}>
                      <View className='color-item__circle' style={`background: ${color.hex}`}>
                        <View className='inner-circle-1'></View>
                        <View className='inner-circle-2' style={`border-color: ${color.hex}`}></View>
                      </View>
                      <View className='color-item__info'>
                        <Text className='name'>{color.name}</Text>
                        <Text className='hex' selectable>{color.hex}</Text>
                      </View>
                    </View>
                  ))}
                </View>
              </View>
            </View>
          ))}
        </ScrollView>
        {/* E Body */}
      </View>
    )
  }
}

@ZakaryCode
Copy link
Contributor

根据提供的示例,你并没有监听内层ScrollView的变动,所以scrollLeft值是从外层onScrollHandle中同步变更的?

import Taro from '@tarojs/taro'
import { View, Text, ScrollView } from '@tarojs/components'

import DocsHeader from '../../components/doc-header'

import TestScrollView from './testScrollView'

import './index.scss'

type Color = {
  name: string
  hex: string
}
type ColorData = {
  type: string
  data: Color[]
}

interface BasicColorState {
  colorData: ColorData[]
  scrollTop: number;
  scrollLeft: number;
}

export default class BasicColor extends Taro.Component<{}, BasicColorState> {
  public config: Taro.PageConfig = {
    navigationBarTitleText: 'Taro UI'
  }

  public constructor () {
    super()

    this.state = {
      colorData: [
        {
          type: '主色',
          data: [
            {
              name: '浅蓝色',
              hex: '#78A4FA'
            },
            {
              name: '品牌蓝',
              hex: '#6190E8'
            },
            {
              name: '深蓝色',
              hex: '#346FC2'
            }
          ]
        },
        {
          type: '辅助色',
          data: [
            {
              name: '蓝色 - Info',
              hex: '#78A4FA'
            },
            {
              name: '绿色 - Positive',
              hex: '#13CE66'
            },
            {
              name: '红色 - Negative',
              hex: '#FF4949'
            },
            {
              name: '黄色 - Warning',
              hex: '#FFC82C'
            }
          ]
        },
        {
          type: '中性色',
          data: [
            {
              name: '黑色 0',
              hex: '#333333'
            },
            {
              name: '黑色 1',
              hex: '#7F7F7F'
            },
            {
              name: '黑色 2',
              hex: '#B2B2B2'
            },
            {
              name: '灰色 0',
              hex: '#333333'
            },
            {
              name: '灰色 1',
              hex: '#666666'
            },
            {
              name: '灰色 2',
              hex: '#999999'
            },
            {
              name: '灰色 3',
              hex: '#CCCCCC'
            },
            {
              name: '灰色 4',
              hex: '#E5E5E5'
            },
            {
              name: '灰色 5',
              hex: '#F0F0F0'
            },
            {
              name: '灰色 6',
              hex: '#F7F7F7'
            }
          ]
        },
        {
          type: '其他色',
          data: [
            {
              name: '边框可选色',
              hex: '#C5D9E8'
            },
            {
              name: '背景色 0',
              hex: '#ECF5FD'
            },
            {
              name: '背景色 1',
              hex: '#FAFBFC'
            }
          ]
        }
      ],
      scrollTop: 0,
      scrollLeft: 100
    }
  }

  onScrollHandle(e) {
    this.setState({
      scrollTop: e.detail.scrollTop
    })
  }

  public render (): JSX.Element {
    const { colorData, scrollTop, scrollLeft } = this.state

    return (
      <View className='page'>
        {/* S Header */}
        <DocsHeader title='Color 颜色'></DocsHeader>
        {/* E Header */}

        {/* S Body */}
        <ScrollView scrollY className='doc-body' scrollTop={scrollTop} onScroll={this.onScrollHandle.bind(this)} style={{position: 'absolute', left: 0, right: 0, top: 0, bottom: 0}}>
          <ScrollView scrollX scrollLeft={scrollLeft} style={{whiteSpace: 'nowrap', position: "fixed", top: 0, left: 0, right: 0, zIndex: 9099}}>
            横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动横向滚动
          </ScrollView>
          {colorData.map(item => (
            <View className='panel' key={item.type}>
              <View className='panel__title'>{item.type}</View>
              <View className='panel__content'>

                <View className='color-list'>
                  {item.data.map(color => (
                    <View className='color-item' key={color.hex}>
                      <View className='color-item__circle' style={`background: ${color.hex}`}>
                        <View className='inner-circle-1'></View>
                        <View className='inner-circle-2' style={`border-color: ${color.hex}`}></View>
                      </View>
                      <View className='color-item__info'>
                        <Text className='name'>{color.name}</Text>
                        <Text className='hex' selectable>{color.hex}</Text>
                      </View>
                    </View>
                  ))}
                </View>
              </View>
            </View>
          ))}
        </ScrollView>
        {/* E Body */}
      </View>
    )
  }
}

未能复现到该问题,如无更多信息,issue 将关闭。

@paulloo
Copy link
Author

paulloo commented Sep 17, 2020

onScrollHandle

是的,内部是scrollView 没有监听滚动事件,我试试看

@taro-bot2 taro-bot2 bot removed the to be closed label Sep 17, 2020
@paulloo
Copy link
Author

paulloo commented Sep 17, 2020

解决了,不能算bug吧,但存在一些使用上的限制,或者说写法上有些注意事项。总结下:
当两个ScrollView 嵌套时,最好都写上onScroll监听,要么就都别写。(外层onScrollHandle会同步变更给内部的ScrollTop或scrollLeft)

@sunflower8th
Copy link

taro3 小程序有同样问题

@ZakaryCode
Copy link
Contributor

taro3 小程序有同样问题

请认真阅读文档,查看组件使用方法。

备注,该问题已经关闭,如有类似问题可以提交新的 Issue 引用此问题。

@qwerlp
Copy link

qwerlp commented Dec 4, 2020

解决了,不能算bug吧,但存在一些使用上的限制,或者说写法上有些注意事项。
摘要下:当两个ScrollView嵌套时,最好都写上onScroll监听,或者就都别写。(外层onScrollHandle会同步变更给内部的ScrollTop或scrollLeft)

就是bug,我两个scrollviw,两个都写上onScroll监听,里面的那个监听还是会执行到外层scrollview的监听方法,即使写同一个方法,我通过传参判断,它也是会执行两遍,不传参数就会只一次,但是就没法判断是哪个盒子,taro3.x也不支持自定义属性,所以我现在根本没法判断是哪个盒子滚动。我的版本是3.0.11

@ZakaryCode
Copy link
Contributor

就是bug,我两个scrollviw,两个都写上onScroll监听,里面的那个监听还是会执行到外层scrollview的监听方法,即使写同一个方法,我通过传参判断,它也是会执行两遍,不传参数就会只一次,但是就没法判断是哪个盒子,taro3.x也不支持自定义属性,所以我现在根本没法判断是哪个盒子滚动。我的版本是3.0.11

请注意该 issue 讨论的范围限制于 2.x,如若 3.x 有同样的问题请在新的 issue 提交可复现的 demo,并引用该 issue。
已经关闭的 issue 不会有专门人的跟进。

@yuanbolin
Copy link

解决了,不能算bug吧,但存在一些使用上的限制,或者说写法上有些注意事项。
摘要下:当两个ScrollView嵌套时,最好都写上onScroll监听,或者就都别写。(外层onScrollHandle会同步变更给内部的ScrollTop或scrollLeft)

就是bug,我两个scrollviw,两个都写上onScroll监听,里面的那个监听还是会执行到外层scrollview的监听方法,即使写同一个方法,我通过传参判断,它也是会执行两遍,不传参数就会只一次,但是就没法判断是哪个盒子,taro3.x也不支持自定义属性,所以我现在根本没法判断是哪个盒子滚动。我的版本是3.0.11

我也遇到了这个问题,请问解决了吗

@lessonli
Copy link

就是bug,我两个scrollviw,两个都写上onScroll监听,里面的那个监听还是会执行到外层scrollview的监听方法,即使写同一个方法,我通过传参判断,它也是会执行两遍,不传参数就会只一次,但是就没法判断是哪个盒子,taro3.x也不支持自定义属性,所以我现在根本没法判断是哪个盒子滚动。我的版本是3.0.11

请注意该 issue 讨论的范围限制于 2.x,如若 3.x 有同样的问题请在新的 issue 提交可复现的 demo,并引用该 issue。 已经关闭的 issue 不会有专门人的跟进。

内层的scroview 需要 阻止冒泡事件 就好了

@ZakaryCode ZakaryCode added this to Done in H5 Aug 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-react Framework - React question Further information is requested T-h5 Target - 编译到 H5 V-2 Version - 2.x
Projects
Archived in project
H5
  
Done
Development

No branches or pull requests

6 participants