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

taro3 hooks写法fixed定位的浮层无法阻止滚动穿透 #8329

Closed
darkfiredarkhalo opened this issue Dec 21, 2020 · 5 comments
Closed
Labels
F-react Framework - React T-weapp Target - 编译到微信小程序 V-3 Version - 3.x

Comments

@darkfiredarkhalo
Copy link

darkfiredarkhalo commented Dec 21, 2020

相关平台

微信小程序

小程序基础库: 2.14.0
使用框架: React

复现步骤

使用hooks随便写个页面,高度大于一屏(允许滚动), 然后使用自定义hook组件创建浮层, 在页面中使用hooks浮层组件, 在浮层上上下滑动, 示例代码如下:

  • 页面(index.tsx):
import React, { useState, useEffect } from 'react';
import { View, Text, ScrollView } from '@tarojs/components';
import Taro, { useRouter, useReady } from '@tarojs/taro';
import { useRule } from './RuleModal';
import './index.scss';

// 城市列表
const cityList = (): any[] => {
  let capitals: string[] = [];
  for (let i = 65; i < 91; i++) {
    capitals.push(String.fromCharCode(i))
  }
  let result: any[] = [];
  for (let i = 0; i < 200; i++) {
    result.push({
      cityName: `城市${i}`,
      cityCode: `code00${i}`,
      firstLetter: capitals[i%26]
    });
  }
  return result;
};
const queryCityList = (params: any): any => {
  console.log('请求params>>>', params);
  return new Promise((resolve) => {
    resolve({cityList: cityList()})
  });
};
export default () => {

  const router = useRouter();
  const params: any = router.params;
  const { lat=39.909, lon=116.397 } = params;
  console.log('接收的params>>>', params);
  // 自定义浮层组件
  const { showRule, RuleModal} = useRule();

  const initCity: {letter: string, cities: {cityCode: string, cityName: string}[]} = {letter: '#', cities: [{cityCode: '', cityName: '不限'}]};
  const [cityList, setCityList] = useState([initCity]);
  const [intoView, setIntoView] = useState('');



  useReady(()=>{
    Taro.hideShareMenu();
  });
  useEffect(()=>{
    getCityList();
  }, []);

  // 获取城市列表
  const getCityList = async() => {
    try{
      const res: {cityList:[]} = await queryCityList({lat, lon});
      console.log('获取城市列表结果>>>', res);
      setCityList(encodeCityData(res.cityList))
    }catch (e) {
      console.error('获取城市列表失败>>>', e);
    }
  };
  const encodeCityData = (cityList:[]) => {
    let result: any[] = [];
    let capitals: string[] = [];
    for (let i = 65; i < 91; i++) {
      capitals.push(String.fromCharCode(i))
    }
    capitals.forEach((item: string)=>{
      const cities = cityList.filter((it: any) => {
        return it.firstLetter === item;
      });
      (!!cities && cities.length>0) && result.push({
        letter: item,
        cities
      })
    });
    console.log('格式化后的城市>>', result);
    result.unshift(initCity);
    return result;
  };
  const renderHeader = () => {
    const latestCityItem = cityList[0];
    const latestCity = latestCityItem.cities[0];
    const cityName = latestCity.cityName;
    return(
      <View className={'header'}>
        <Text className={'label'}>最近城市</Text>
        <View className={'latestCityBox'} onClick={()=>onCityClick(latestCity)}>
          <Text>{cityName}</Text>
        </View>
      </View>
    )
  };
  const onCityClick = (item: any) => {
    console.log('点击的城市>>', item);
    showRule();
  };
  const renderCity = () => {
    return cityList.map((item: any, index: number) => {
          const {
            letter,
            cities
          } = item;
          return(
            <View className={'cityContent'} key={index} id={letter}>
              <View className={'letterBox'}>
                <Text>{letter}</Text>
              </View>
              <View className={'cityBox'}>
                {cities.map((city: any, cityIndex: number) => {
                  return(
                    <View key={`${index}_${cityIndex}`} className={'textItem'} style={{borderBottomColor: cityIndex===cities.length-1 ? 'transparent' : '#EBEBEB'}} onClick={()=>onCityClick(city)}>
                      <Text>{city.cityName || '--'}</Text>
                    </View>
                  )
                })}
              </View>
            </View>
          )
        })
  };
  const renderDefault = () => {
    return(
      <View className={'default'}>
        <Text>暂无城市</Text>
      </View>
    )
  };
  const onIndexClick = (e: any, letter: string) => {
    e.stopPropagation();
    console.log('onIndexClick>>>', letter);
    setIntoView(letter)
  };
  const renderIndex = () => {
    let capitals: string[] = [];
    for (let i = 65; i < 91; i++) {
      capitals.push(String.fromCharCode(i))
    }
    return(
      <View className={'indexView'}>
        {capitals.map((item: string, index: number) => {
          return(
            <View className={'indexItem'} key={index} onClick={(e)=>onIndexClick(e, item)}>
              <Text>{item}</Text>
            </View>
          )
        })}
      </View>
    )
  };
  console.log('scrollIntoView>>>', intoView);
  return (
    <View>
        <ScrollView scrollY={true} scrollIntoView={intoView} className={'cityContainer'}>
          {renderHeader()}
          {cityList.length>0 ? renderCity() : renderDefault()}
          {renderIndex()}
        </ScrollView>
        <RuleModal />
    </View>
  );
};
  • 页面(index.scss)
.cityContainer {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  width: 100%;
  min-height: 100%;
  height: auto;
  .header {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    width: 100%;
    height: 212px;
    background: #F7F7F7;
    .label {
      font-size: 28px;
      font-weight: 400;
      color: #7A7A7A;
      line-height: 40px;
      margin:  0 0 24px 34px;
    }
    .latestCityBox {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      margin-left: 34px;
      background: #FFFFFF;
      border-radius: 6px;
      border: 1px solid #E1E1E1;
      height: 80px;
      padding: 0 56px;
      image {
        margin-right: 10px;
        width: 24px;
        height: 30px;
      }
      text {
        font-size: 28px;
        font-weight: 400;
        color: #1A1A1A;
      }
    }
  }
  .cityContent {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    width: 100%;
    background: #fff;
    height: auto;
    .letterBox {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: flex-start;
      width: 100%;
      height: 52px;
      background: #EBEBEB;
      text {
        font-size: 28px;
        font-weight: 400;
        color: #7A7A7A;
        margin-left: 34px;
      }
    }
    .cityBox {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      justify-content: flex-start;
      padding: 0 56px 0 34px;
      width: calc(100% - 90px);
      .textItem {
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: flex-start;
        width: 100%;
        height: 88px;
        border-bottom: 2px solid #EBEBEB;
        text {
          font-size: 30px;
          font-weight: 400;
          color: #1A1A1A;
          line-height: 42px;
        }
      }
    }
  }
  .default {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: calc(100% - 114px);
    image {
      width: 400px;
      height: 252px;
      margin-bottom: 52px;
    }
    text {
      font-size: 30px;
      font-weight: 400;
      color: #7A7A7A;
      line-height: 42px;
    }
  }
  .indexView {
    position: fixed;
    top: 200px;
    right: 0;
    width: 44px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    .indexItem {
      width: 44px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      text {
        font-size: 22px;
        color: #1A1A1A;
      }
    }
  }
}
  • 自定义浮层组件(index.tsx)
import React, { useState} from 'react';
import {View, Text, ITouchEvent, Image} from '@tarojs/components';
import Taro from '@tarojs/taro';
import './index.scss';

const rules = [
  {title: '一、哇哈哈哈是什么', data: [
      {title: '哇哈哈哈的来源', content: '哇哈哈哈来源于大自然中一种生物分泌............巴拉巴拉'},
      {title: '哇哈哈哈的作用', content: '哇哈哈哈来源于大自然中一种生物分泌............巴拉巴拉'},
    ]
  },
  {title: '二、参与方式', data: [
      {title: '参与条件1', content: '巴拉巴拉'},
      {title: '参与条件2', content: '巴拉巴拉},
    ]
  },
];


export const useRule = () => {
  const [visible, setVisible] = useState(false);

  const showRule = () => {
    setVisible(true);
  };
  const hideRule = () => {
    setVisible(false);
  };
  // 阻止滑动穿透
  const handleTouchMove = (e: ITouchEvent) => {
    e.preventDefault();
    e.stopPropagation();
    return false;
  };
const renderRules = () => {
    return rules.map((item: any, index: number) => {
      const {
        title='',
        data=[]
      } = item;
      return(
        <View className={'textBox-component-rule'} key={index} style={{marginBottom: index<rules.length-1?Taro.pxTransform(46):0}}>
          <Text className={'label-component-rule'}>{title||'--'}</Text>
          {data.map((subItem: any, subIndex: number)=>{
            return(
              <View className={'textBox-component-rule'} key={subIndex}>
                <Text className={'subTitle-component-rule'}>{`${subIndex+1}.${subItem.title}`}</Text>
                <Text className={`${subIndex===data.length-1?'desc-component-rule mb46-component-rule':'desc-component-rule mb16-component-rule'}`}>{subItem.content}</Text>
              </View>
            )
          })}
        </View>
      )
    });
  };
  const RuleModal = () => {
    if(visible){
      return (
        <View className="modal-cover" onTouchMove={handleTouchMove} catch-move>
          <View className={'ruleContainer-component-rule'}>
            <Text className={'title-component-rule'}>介绍及规则</Text>
            {renderRules()}
          </View>
          <View onClick={hideRule} className={'close-btn-component-rule'}>
            <Text>X</Text>
          </View>
        </View>
      )
    }
      return <View />
  };

  return {
    showRule,
    hideRule,
    RuleModal
  };
};
  • 自定义浮层组件(index.scss)
.modal-cover {
  position: fixed;
  bottom: 0;
  right: 0;
  left: 0;
  top: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.5);
  z-index: 100;
}
.ruleContainer-component-rule {
  background: #FFFFFF;
  border-radius: 16px;
  border: 2px solid #979797;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  padding: 48px 34px 60px 38px;
  height: calc(884px - 108px);
  overflow-y: scroll;
  text{
    width: 600px;
    word-break:break-all;
  }
  .textBox-component-rule {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
  }
  .title-component-rule {
    font-size: 32px;
    font-weight: 500;
    color: #1A1A1A;
    line-height: 44px;
    margin-bottom: 36px;
    text-align: center;
  }
  .label-component-rule {
    margin-bottom: 26px;
    font-size: 28px;
    font-weight: 500;
    color: #FF316C;
    line-height: 40px;
  }
  .subTitle-component-rule {
    font-size: 28px;
    font-weight: 400;
    color: #1A1A1A;
    line-height: 40px;
    margin-bottom: 14px;
  }
  .desc-component-rule {
    font-size: 24px;
    font-weight: 400;
    color: #7A7A7A;
    line-height: 34px;
  }
  .mb16-component-rule {
    margin-bottom: 16px;
  }
  .mb46 {
    margin-bottom: 46px;
  }
}
.close-btn-component-rule {
  width: 42px;
  height: 42px;
  border-radius: 21px;
  margin-top: 36px;
  overflow: hidden;
  image {
    width: 42px;
    height: 42px;
    border-radius: 21px;
  }
}

期望结果

使用catch-move或者catchTouchMove或者onTouchMove可以阻止滚动事件穿透到page

实际结果

使用catch-move或者catchTouchMove或者onTouchMove都不能阻止滚动事件穿透到page

环境信息

Taro CLI 3.0.3 environment info:
System:
      OS: macOS 10.15.7
      Shell: 3.2.57 - /bin/bash
    Binaries:
      Node: 12.16.3 - /usr/local/bin/node
      Yarn: 1.22.4 - /usr/local/bin/yarn
      npm: 6.14.8 - /usr/local/bin/npm
    npmPackages:
      @tarojs/cli: 3.0.18 => 3.0.18 
      @tarojs/components: 3.0.18 => 3.0.18 
      @tarojs/mini-runner: 3.0.18 => 3.0.18 
      @tarojs/react: 3.0.18 => 3.0.18 
      @tarojs/runtime: 3.0.18 => 3.0.18 
      @tarojs/taro: 3.0.18 => 3.0.18 
      @tarojs/webpack-runner: 3.0.18 => 3.0.18 
      babel-preset-taro: 3.0.18 => 3.0.18 
      eslint-config-taro: 3.0.18 => 3.0.18 
      react: ^16.10.0 => 16.14.0 
@taro-bot2 taro-bot2 bot added F-react Framework - React T-weapp Target - 编译到微信小程序 V-3 Version - 3.x labels Dec 21, 2020
@darkfiredarkhalo
Copy link
Author

darkfiredarkhalo commented Dec 21, 2020

@iamxiyang
Copy link

我看更新记录上面显示,在最新版本中 view组件 可以增加 catchMove 属性阻止滚动穿透,你可以试试

@Chen-jj
Copy link
Contributor

Chen-jj commented Dec 22, 2020

@Binbiubiubiu
Copy link
Contributor

可以试试 一层View catchMove 里面套个ScrollView

@biluochun
Copy link

image
你们都解决了嘛。我这怎么都不行。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-react Framework - React T-weapp Target - 编译到微信小程序 V-3 Version - 3.x
Projects
None yet
Development

No branches or pull requests

5 participants