当前位置: 首页 > news >正文

taro小程序如何实现新用户引导功能?

一、需求背景

1、需要实现小程序新功能引导
2、不使用第三方库(第三方组件试了几个,都是各种兼容性问题,放弃)

二、实现步骤

1、写一个公共的guide组件,代码如下
components/Guide/index.tsx文件

import React, { useEffect, useState } from "react";
import Taro from "@tarojs/taro";
import { View, Button } from "@tarojs/components";
import { AtCurtain } from "taro-ui";import "./index.less";interface Props {// 需要指引的整体元素,会对此块增加一个整体的蒙层,直接用guild元素包裹即可children: React.ReactNode;// 指引的具体domguildList: {content: string; // 指引内容id: string; // 指引的id  --eg:  'test'}[];// 是否默认对被引导的dom添加高亮,只对子元素的子元素动态添加类名【cur-guide】isAuto?: boolean;// 1、此字段只对isAuto为false时生效// 2、部分页面,需传入此字段微调整距离顶部的距离otherHeight?: number;// 此字段只对isAuto为false时生效// activeGuide值变化时触发,用来在isAuto为false时,告知外部需要高亮哪个dom,请外部根据此判断添加类明【cur-guide】onChange?: (activeGuideId) => void;
}interface TaroElementProps {className?: string;children?: React.ReactNode;props: {id: string;[key: string]: any;};
}
type TaroElement = React.ReactElement<TaroElementProps>;const Guide = (props: Props) => {const [isOpened, setIsOpened] = useState(true);const [activeGuide, setActiveGuide] = useState(0);const [tipPosition, setTipPosition] = useState({top: 0,left: 0,});useEffect(() => {if (!props.isAuto) {updatePosition();props.onChange?.(props.guildList[activeGuide]?.id);}}, [activeGuide]);const updatePosition = () => {Taro.nextTick(() => {if (!props.guildList[activeGuide]) return;const query = Taro.createSelectorQuery();query.select(`#${props.guildList[activeGuide].id}`).boundingClientRect().selectViewport().scrollOffset().exec((res) => {if (res && res[0] && res[1]) {// res[0] 是元素的位置信息// res[1] 是页面滚动的位置信息const rect = res[0];const scrollTop = res[1].scrollTop;// 计算元素距离顶部的实际距离(包含滚动距离)const actualTop = rect.top + scrollTop;setTipPosition({top:actualTop +rect.height -(props.otherHeight || 0) +12,left: rect.left + rect.width / 2,});}});});};const onPre = () => {if (activeGuide <= 0) {setActiveGuide(0);setIsOpened(false);return;}setActiveGuide(activeGuide - 1);};const onNext = () => {if (activeGuide >= props.guildList.length - 1) {setActiveGuide(props.guildList.length - 1);setIsOpened(false);return;}setActiveGuide(activeGuide + 1);};const renderTip = () => {return (<ViewclassName="cur-guide-tip"style={{top: `${tipPosition.top}px`,left: `${tipPosition.left}px`,}}><Button onClick={onPre}>上一步</Button><Button onClick={onNext}>下一步</Button></View>);};// 递归处理子元素,找到对应index的元素添加提示内容const enhanceChildren = (children: React.ReactNode) => {return React.Children.map(children, (child) => {if (!React.isValidElement(child)) return child;// 如果当前元素是数组(比如map渲染的列表),需要特殊处理if (child.props.children) {// 处理子元素const enhancedChildren = React.Children.map(child.props.children,(subChild) => {if (!React.isValidElement(subChild)) return subChild;const subChildProps = (subChild as TaroElement).props as any;const isCurrentActive =subChildProps.id === props.guildList[activeGuide]?.id;// 如果是当前激活的索引,为其添加提示内容if (isCurrentActive && isOpened) {const subChildProps = (subChild as TaroElement).props;return React.cloneElement(subChild as TaroElement, {className: `${subChildProps.className || ""} ${isCurrentActive ? "cur-guide" : ""}`,children: [...(Array.isArray(subChildProps.children)? subChildProps.children: [subChildProps.children]),renderTip(),],});}return subChild;});return React.cloneElement(child as TaroElement, {...child.props,children: enhancedChildren,});}return child;});};const renderBody = () => {return (<><View>{props.children}</View>{isOpened && renderTip()}</>);};const renderBodyAuto = () => {return <View>{enhanceChildren(props.children)}</View>;};return (<View className="fc-guide">{props.isAuto ? renderBodyAuto() : renderBody()}{isOpened && (<AtCurtain isOpened={isOpened} onClose={() => {}}></AtCurtain>)}</View>);
};
export default Guide;

components/Guide/index.less文件

.fc-guide {position: relative;.at-curtain {z-index: 20;.at-curtain__btn-close {display: none;}}// 这个是相对顶部距离的定位(isAuto为false时).cur-guide-tip {padding: 24px;background-color: #fff;position: absolute;z-index: 22;transform: translate(-50%, 0);}// 相对当前高亮元素的定位(isAuto为true时).cur-guide {background: #f5f5f5;position: relative;z-index: 22;.cur-guide-tip {bottom: 0 !important;left: 50% !important;transform: translate(-50%, 100% + 12px);}}
}

2、使用方式
a.isAuto为true时的传值结构
在这里插入图片描述
b.isAuto为false时
需要配合onChange事件将当前激活id传给父组件,然后父组件再根据当前激活id去选择高亮哪个dom元素(类名判断写在和id设置同一个dom上),然后给对应dom绑上’cur-guide‘类名即可

最终效果

在这里插入图片描述

http://www.lryc.cn/news/571368.html

相关文章:

  • 【数据结构】图论实战:DAG空间压缩术——42%存储优化实战解析
  • AI大模型初识(一):AI大模型的底层原理与技术演进
  • 数据库系统概论(二十)数据库恢复技术
  • Linux Kernel崩溃分析的法宝:Kdump+Crash(上)
  • 暴雨服务器成功中标洪湖市政府框架采购项目
  • 汽车 CDC威胁分析与风险评估
  • 解锁VSCode:从入门到精通的全攻略
  • ArcGIS Pro无插件加载(无偏移)天地图!一次添加长久使用
  • 【机器人学】2-5.七自由度机器人逆解-SRS型机器人【附MATLAB代码】
  • React19源码系列之Hooks (useEffect、useLayoutEffect、useInsertionEffect)
  • 电阻、电容、电感
  • 单片机 - STM32读取GPIO某一位时为什么不能直接与1判断为高电平?
  • 力扣面试题 17.05. 字母与数字
  • SpringBoot 通过集成 Flink CDC 来实时追踪 MySql 数据变动
  • 基于高性能的光频域反射(OFDR)分布式光纤传感解决方案
  • 爬虫技术:从基础到高级,探索数据抓取的奥秘
  • 深度融合数智化,百胜软件联合华为云加速零售行业转型升级
  • 【Manus第三篇-Prompt优化】两周实战,一套注意力视角的prompt优化框架,真的有用!
  • 【笔记】MSYS2 的 MinGW64 环境中正确安装 Python 相关环境管理工具 (Poetry、Virtualenv、Pipenv 和 UV)
  • 复现 apache HTTPD 换行解析漏洞(CVE-2017-15715)
  • ABP vNext + Sentry + ELK Stack:打造高可用异常跟踪与日志可视化平台
  • STM32的内部RC与外部晶振电路
  • python打卡day52
  • C++ 学习 多线程 2025年6月17日18:41:30
  • 插入排序C语言版
  • 容器部署springboot项目--入门
  • Vue-8-前端框架Vue之应用基础响应式数据和计算属性
  • 如何设计一个敏感词过滤系统
  • OpenCV 图像仿射变换之旋转
  • flutter的widget的执行顺序,单个组建的执行顺序