• 微信小程序实现:点击标签滑动到相应内容,滚动内容切换相应标签


    实现: 随着向下滚动标签出现并横向滑动到某个tab相应标题选中,点击tab标题滑动到相应内容

    博客园不能录视频只能图片模拟成品,如果想要看视频效果留言给我

    实现如下:

    点击查看代码
    // index.tsx文件
    // 所涉及代码
    import React, { useEffect, useState } from 'react'
    import { View, Image, Video, Swiper, SwiperItem, Button, ScrollView } from '@tarojs/components'
    import { usePageScroll, createSelectorQuery, pageScrollTo, useReady, useRouter } from '@tarojs/taro'
    import { useThrottleFn } from 'ahooks'
    import c from 'classnames'
    import Skeleton from 'taro-skeleton'
    import MainLayout from '@/layout/MainLayout'
    import { fetchDeatil, IResourceList } from '@/apis/detail'
    import { projectArrs, ITaptaneTopArr } from './const'
    import './index.scss'
    
    const Detail: React.FC = () => {
      const [projectDetail, setProjectDetail] = useState<any>({})
      const [project, setProject] = useState({})
      const [tabFixed, setTabFixed] = useState(false)
      const [top, setTop] = useState(0)
      const [tabScrollTop, setScrollTop] = useState(0)
      const [taptaneTopArr, setTaptaneTopArr] = useState([])
      const [projectArr, setProjectArr] = useState(projectArrs)
      const [navScrollLeft, setNavScrollLeft] = useState(0)
    
      const query = createSelectorQuery()
      const router = useRouter()
    
      const scrollHanlder = res => {
        const { scrollTop } = res
        setTop(scrollTop)
        if (scrollTop > tabScrollTop) {
          setTabFixed(true)
        } else {
          setTabFixed(false)
        }
        for (let i = 0; i < projectArr.length; i++) {
          let currentTaptaneTop = 0
          let nextTaptaneTop = 0
          let currentItem = projectArr[i]
          if (i != projectArr.length - 1) {
            let nextItem = projectArr[i + 1]
            for (const list of taptaneTopArr) {
              if (currentItem.id === list.id) {
                currentTaptaneTop = list.taptaneTop
              }
              if (nextItem.id === list.id) {
                nextTaptaneTop = list.taptaneTop
              }
            }
            if (scrollTop >= currentTaptaneTop - 47 - 15 && scrollTop < nextTaptaneTop - 47 - 15) {
              if (i === 0) {
                setNavScrollLeft(-16 + Math.random())
              }
              currentItem.isSelected = true
            } else {
              currentItem.isSelected = false
            }
          } else {
            for (const list of taptaneTopArr) {
              if (currentItem.id === list.id) {
                currentTaptaneTop = list.taptaneTop
              }
            }
            if (scrollTop >= currentTaptaneTop - 47 - 15) {
              setNavScrollLeft(state => {
                currentItem.isSelected = true
                return 400 + Math.random()
              })
            } else {
              currentItem.isSelected = false
            }
          }
        }
        setProjectArr([...projectArr])
      }
    
      const { run } = useThrottleFn(scrollHanlder, { wait: 1 })
      usePageScroll(res => run(res))
    
      useReady(() => {
        // id是tabs距离顶部的距离
        query
          .select('#tabs')
          .boundingClientRect(res => {
            setScrollTop(res?.top)
          })
          .exec()
      })
    
      const { run: onTab } = useThrottleFn(
        e => {
          const { id } = e.target.dataset
          pageScrollTo({
            selector: `#${id}`,
            offsetTop: -40,
            // duration: 30
          })
        },
        { wait: 300 }
      )
    
      useEffect(() => {
        const id = Number(router.params.id)
        fetchDeatil(id).then((data: any) => {
          setProjectDetail(data.projectDetail)
          setProject(data.project)
          setTimeout(() => {
            const arr: ITaptaneTopArr[] = []
            projectArr.map(item => {
              query.select(`#${item.id}`).boundingClientRect(res => {
                arr.push({ id: item.id, taptaneTop: res.top })
              })
            })
            query.exec()
            setTaptaneTopArr(arr)
          }, 10)
        })
      }, [])
    
      return (
        <MainLayout className="detail">
          {project?.auditState == 2 && (
            <>
              <ScrollView
                className={c('scrollview', tabFixed ? 'tabtop' : '')}
                id="tabs"
                scrollX
                enhanced
                showScrollbar
                refresherDefaultStyle={'white'}
                scrollWithAnimation
                scrollAnchoring
                scrollLeft={navScrollLeft}
                onClick={onTab}
              >
                <View className="wrapView" style={{ paddingRight: 1 }}>
                  {projectArr.map((list, index) => (
                    <View
                      key={list.id}
                      data-id={list.id}
                      data-index={index}
                      className={c('tabtaneCls', list.isSelected ? 'active' : '')}
                    >
                      {list.title}
                    </View>
                  ))}
                </View>
              </ScrollView>
              {projectArr.map(item => (
                <Skeleton loading={false} title row={6} key={item.key}>
                  <View className="content" id={item.id}>
                    <View className="title">{item.title}</View>
                    <View className="table">
                      {item.lists.map(item => (
                        <View key={item.key} className="tr">
                          <View className="label">{item.label}</View>
                          <View className="value">{projectDetail[item.key]}</View>
                        </View>
                      ))}
                    </View>
                  </View>
                </Skeleton>
              ))}
              <View className="paceHolderBom">
                <View style={{ height: '150PX', background: '#fff' }} />
              </View>
            </>
          )}
        </MainLayout>
      )
    }
    
    export default Detail
    
    
    const.ts文件
    type Txt = number | string;
    
    export interface Idesc {
      label: string;
      key: string;
      render?: (text: Txt) => Txt;
    }
    
    const salaryArr: Idesc[] = [
      {
        label: '薪资',
        key: 'postSalary',
      },
      {
        label: '工资计算',
        key: 'salaryCalculationMethod',
      },
      {
        label: '发薪时间',
        key: 'payday',
      },
      {
        label: '多久转正',
        key: 'howLongCorrection'
      },
      {
        label: '发工资银行卡',
        key: 'bankCardName',
      },
      {
        label: '其他津贴',
        key: 'otherAllowances',
      },
      {
        label: '多久可以离职',
        key: 'howLongLeave',
      },
      {
        label: '提前多久打离职报告',
        key: 'advancePrintResignationReport',
      },
      {
        label: '工作需缴纳费用',
        key: 'workDeposit',
      },
      // {
      //   label: '更新日期',
      //   key: 'updateTime',
      //   render(text) {
      //     return moment(text).format('YYYY-MM-DD');
      //   },
      // },
      {
        label: '合同签订',
        key: 'contractSigningMethod',
      },
      {
        label: '企业福利',
        key: 'enterpriseWelfare'
      },
      {
        label: '是否有试用期',
        key: 'isProbationPeriod',
      },
    
      {
        label: '是否缴社保',
        key: 'isSocialSecurity',
        render(text) {
          return text;
        },
      },
      {
        label: '是否好离职',
        key: 'easyLeave',
      },
      {
        label: '是否有培训',
        key: 'isTraining',
      },
      {
        label: '自离是否有工资',
        key: 'selfLeaveSalary',
      },
      {
        label: '是否扣商报',
        key: 'isDeductBusinessDaily',
      },
    ];
    
    const requestArr: Idesc[] = [
      {
        label: '年龄',
        key: 'postSalary',
      },
      {
        label: '性别',
        key: 'salaryCalculationMethod',
      },
      {
        label: '学历',
        key: 'payday',
      },
      {
        label: '身高',
        key: 'howLongCorrection'
      },
      {
        label: '视力',
        key: 'bankCardName',
      },
      {
        label: '地域',
        key: 'otherAllowances',
      },
      // {
      //   label: '民族',
      //   key: 'howLongLeave',
      // },
      {
        label: '自离几次是黑名单',
        key: 'advancePrintResignationReport',
      },
      {
        label: '前几个月不能进厂',
        key: 'workDeposit',
      },
      {
        label: '超龄是否可以协调',
        key: 'contractSigningMethod',
      },
      {
        label: '残疾人是否可以',
        key: 'enterpriseWelfare'
      },
      {
        label: '纹身烟疤是否可以',
        key: 'isProbationPeriod',
      },
    
      {
        label: '身份证过期是否可以',
        key: 'isSocialSecurity',
        render(text) {
          return text;
        },
      }
    ];
    
    const workArr: Idesc[] = [
      {
        label: '工作性质',
        key: 'jobNature',
      },
      {
        label: '工作内容',
        key: 'workContent',
      },
      {
        label: '车间环境',
        key: 'workshopEnvironment',
      },
      {
        label: '岗位',
        key: 'whatPositions'
      },
      {
        label: '工作服',
        key: 'coverall',
      },
      {
        label: '生产产品',
        key: 'production',
      },
      {
        label: '工作方式',
        key: 'operationMode',
      },
      {
        label: '上班形式',
        key: 'workForm',
      },
      {
        label: '月休息天数',
        key: 'monthlyRestDays',
      },
      {
        label: '工作时间',
        key: 'workingHours',
      },
      {
        label: '是否流水线',
        key: 'isAssemblyLine'
      },
      {
        label: '是否双休',
        key: 'isWeekend',
      }
    ];
    
    const envArr: Idesc[] = [
      {
        label: '餐食提供',
        key: 'mealProvision',
      },
      {
        label: '餐食标准',
        key: 'mealStandard',
      },
      {
        label: '餐食扣款',
        key: 'mealDeductMethod',
      },
      {
        label: '餐食补助',
        key: 'mealAllowance'
      },
      {
        label: '住宿',
        key: 'accommodation',
      },
      {
        label: '外宿补贴',
        key: 'accommodationAllowance',
      },
      {
        label: '班车费用',
        key: 'shuttleBusCost',
      },
      {
        label: '水电费',
        key: 'waterAndElectricity',
      },
      {
        label: '是否可以刷卡吃饭',
        key: 'eatCard',
      },
      {
        label: '非工作时厂区可否吃饭',
        key: 'eatInFactory',
      },
      {
        label: '是否有班车',
        key: 'isShuttleBus'
      }
    ];
    
    const interviewArr: Idesc[] = [
      {
        label: '面试地点',
        key: 'collectionPlace',
      },
      {
        label: '面试时间',
        key: 'interviewTime',
      },
      {
        label: '面试后体检时间',
        key: 'physicalExaminationAfterInterview',
      },
      {
        label: '面试后报到时间',
        key: 'reportTimeAfterInterview'
      },
      {
        label: '报到资料',
        key: 'carryData',
      },
      {
        label: '工人到达时间',
        key: 'requiredArrivalTime',
      },
      {
        label: '面试资料',
        key: 'interviewInformation',
      },
      {
        label: '面试项目',
        key: 'interviewItems',
      },
      {
        label: '体检费用',
        key: 'physicalExaminationCostMethod',
      },
      {
        label: '体检医院',
        key: 'physicalExaminationHospital',
      },
      {
        label: '是否提供接站',
        key: 'isPickUpStation'
      },
      {
        label: '临时身份证可否',
        key: 'isTemporaryIdCard',
      },
      {
        label: '身份证消磁可否',
        key: 'isDegaussingIdCard'
      },
      {
        label: '是否查学信网',
        key: 'checkEducationNetwork',
      },
      {
        label: '是否查纹身烟疤',
        key: 'checkTattooScar'
      },
      {
        label: '是否查案底',
        key: 'checkCriminalRecord',
      },
      {
        label: '是否需要社会工证明',
        key: 'socialWorkerCertificate'
      },
      {
        label: '是否安排临时住宿',
        key: 'temporaryAccommodation',
      },
      {
        label: '是否需要体检',
        key: 'isPhysicalExamination'
      },
      {
        label: '自带体检报告健康证可否',
        key: 'selfPhysicalExaminationReport',
      },
      {
        label: '是否需要健康证',
        key: 'isHealthCertificate'
      }
    ];
    
    const firmArr: Idesc[] = [
      {
        label: '企业名称',
        key: '',
      },
      {
        label: '企业性质',
        key: 'enterpriseNature',
      },
      {
        label: '企业规模',
        key: 'enterpriseScale',
      },
      {
        label: '生产产品',
        key: 'enterpriseProduct'
      },
      {
        label: '乘车路线',
        key: 'busLine',
      },
      {
        label: '企业简介',
        key: 'enterpriseIntroduction',
      },
      {
        label: '周边是否有商场',
        key: 'nearbyMarket',
      },
      {
        label: '厂区是否偏僻',
        key: 'isFactoryRemote',
      },
      {
        label: '附近是否有幼儿园',
        key: 'nearbyKindergarten',
      }
    ];
    
    export const projectArrs = [
      {
        title: '薪资福利',
        lists: salaryArr,
        key: 'salary',
        id: 'salary',
        isSelected: false
      },
      {
        title: '招聘要求',
        lists: requestArr,
        key: 'request',
        id: 'request',
        isSelected: false
      },
      {
        title: '工作内容',
        lists: workArr,
        key: 'work',
        id: 'work',
        isSelected: false
      },
      {
        title: '食宿环境',
        lists: envArr,
        key: 'environment',
        id: 'environment',
        isSelected: false
      },
      {
        title: '面试体检',
        lists: interviewArr,
        key: 'interview',
        id: 'interview',
        isSelected: false
      },
      {
        title: '企业信息',
        lists: firmArr,
        key: 'firm',
        id: 'firm',
        isSelected: false
      }
    ]
    
    enum SalaryUnitType {
     MOON = 1,
     DAY,
     HOUR
    }
    
    export const salaryUnit = {
      [SalaryUnitType.MOON]: '/月',
      [SalaryUnitType.DAY]: '/日',
      [SalaryUnitType.HOUR]: '/时'
    }
    
    index.scss
    // 所涉及的样式
    .nav {
          display: none;
          background-color: #F6F6F6;
          border-top: 1PX solid rgba(0, 0, 0, 0.1);
          border-bottom: 1PX solid rgba(0, 0, 0, 0.1);
          .tabtaneCls{
            position: relative;
            font-size: 28px;
            font-weight: 400;
            color: #666666;
            line-height: 20px;
            &::after {
              position: absolute;
              right: 20px;
              bottom: -8PX;
              left: 20px;
              border-bottom: 2px solid transparent;
              transition: border-color .3s cubic-bezier(.645,.045,.355,1);
              content: "";
            }
          }
          .active {
            color:#FF6600;
            font-weight: bolder;
            &::after {
              border-bottom: 2PX solid #FF6600;
            }
          }
        }
      // }
      .scrollview {
        display: none;
        height: 94px;
        white-space: nowrap;
        z-index: 9999;
        // padding-left: 16PX;
        background-color: #F6F6F6;
        border-top: 1PX solid rgba(0, 0, 0, 0.1);
        // border-bottom: 1PX solid rgba(0, 0, 0, 0.1);
        .tabtaneCls {
          display: inline-block;
          line-height: 47PX;
          position: relative;
          font-size: 28px;
          font-weight: 400;
          color: #666666;
          &::after {
            position: absolute;
            right: 20px;
            bottom: 5PX;
            left: 20px;
            border-bottom: 2px solid transparent;
            transition: border-color .3s cubic-bezier(.645,.045,.355,1);
            content: "";
          }
          &:nth-child(1) {
            margin-left: 16PX;
          }
          &:nth-child(n+2) {
            margin-left: 20PX;
          }
          &:last-child{
            margin-right: 20PX;
          }
        }
        .active {
          color:#FF6600;
          font-weight: bolder;
          &::after {
            border-bottom: 2PX solid #FF6600;
          }
        }
      }
      .paceHolderBom {
        background: #fff;
        padding-bottom: calc(26PX + env(safe-area-inset-bottom))
      }
      .tabtop {
        display: flex;
        align-items: center;
        justify-content: space-around;
        margin-top: 6PX;
         100%;
        height: 94px;
        background: #FFFFFF;
        box-shadow: 0px 1px 0px 0px #E9E9E9;
        position: fixed;
        top: 0;
        margin-top: 0;
      }
      .wrapView::-webkit-scrollbar {
        display: none!important;
      }
    
  • 相关阅读:
    Python的网络编程 Socket编程
    Python之数据库模块安装 MySQLdb
    Python的内置函数
    Servlet及Tomcat介绍
    xml解析
    JDBC基础
    反射练习
    lambda和匿名内部类
    Object.wait()实现生产者消费者模式
    synchronized、lock及线程安全集合
  • 原文地址:https://www.cnblogs.com/wangwenhui/p/16129745.html
Copyright © 2020-2023  润新知