React Native Popup实现示例

 更新时间:2022年05月18日 11:19:46   作者:KidLau  
本文主要介绍了React Native Popup实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

React Native 官方提供了 Modal 组件,但 Modal 是属于全屏的弹出层,当 Modal 显示时,操作区域只有 Modal 里的元素,而且焦点会被 Modal 劫持。虽然移动端不常见,但有些场景还是希望可以用轻量级一点的 Popup

在 React Native 里,元素的层级是不可以被穿透的,子元素无论如何都不能遮挡父元素。所以选择了在顶层添加 Popup,设置绝对定位,显示时根据指定元素来动态调整 Popup 的位置的方案。

具体实现

Popup 会有显示或隐藏两种状态,使用一个 state 来控制。

const Component = () => {
  const [visible, setVisible] = useState(false);
  
  return (
    <>
      {visible && <></>}
    </>
  );
};

Popup 的 属于视图类组件,UI 结构包括:

  • 一个作为容器的 View,由于 iOS 有刘海,所以在 iOS 上需要使用 SafeAreaView 来避免被刘海遮挡。同时添加一个点击事件监听当点击时关闭 Popup
  • 一个指向目标对象的三角形。
  • 一个包裹内容的 View

由于 Popup 的位置和内容是动态的,所以需要两个 state 存储相关数据。

  • 一个存储位置相关的 CSS。
  • 一个存储动态内容。
const Component = ({ style, ...other }) => {
  const [visible, setVisible] = useState(false);
  const [popupStyle, setPopupStyle] = useState({});
  const [content, setContent] = useState(null);
  
  const onPress = useCallback(() => {
    setVisible(false);
  }, []);
  
  return (
    <>
      {visible &&
        createElement(
          Platform.OS === 'ios' ? SafeAreaView : View,
          {
            style: {
              ...styles.popup,
              ...popupStyle,
            },
          },
          <TouchableOpacity onPress={onPress}>
            <View style={styles.triangle} />
            <View style={{ ...styles.content, ...style }} {...other}>
              {content}
            </View>
          </TouchableOpacity>,
        )}
    </>
  );
};

const styles = StyleSheet.create({
  popup: {
    position: 'absolute',
    zIndex: 99,
    shadowColor: '#333',
    shadowOpacity: 0.12,
    shadowOffset: { width: 2 },
    borderRadius: 4,
  },
  triangle: {
    width: 0,
    height: 0,
    marginLeft: 12,
    borderLeftWidth: 8,
    borderLeftColor: 'transparent',
    borderRightWidth: 8,
    borderRightColor: 'transparent',
    borderBottomWidth: 8,
    borderBottomColor: 'white',
  },
  content: {
    backgroundColor: 'white',
  },
});

因为是全局的 Popup,所以选择了一个全局变量来提供 Popup 相关的操作方法。

如果全局 Popup 不适用,可以改成在需要时插入 Popup 并使用 ref 来提供操作方法。

目标元素,动态内容和一些相关的可选配置都是在调用 show 方法时通过参数传入的,

useEffect(() => {
  global.$popup = {
    show: (triggerRef, render, options = {}) => {
      const { x: offsetX = 0, y: offsetY = 0 } = options.offset || {};
      triggerRef.current.measure((x, y, width, height, left, top) => {
        setPopupStyle({
          top: top + height + offsetY,
          left: left + offsetX,
        });
        setContent(render());
        setVisible(true);
      });
    },
    hide: () => {
      setVisible(false);
    },
  };
}, []);

完整代码

import React, {
  createElement,
  forwardRef,
  useState,
  useEffect,
  useCallback,
} from 'react';
import PropTypes from 'prop-types';
import {
  View,
  SafeAreaView,
  Platform,
  TouchableOpacity,
  StyleSheet,
} from 'react-native';

const Component = ({ style, ...other }, ref) => {
  const [visible, setVisible] = useState(false);
  const [popupStyle, setPopupStyle] = useState({});
  const [content, setContent] = useState(null);

  const onPress = useCallback(() => {
    setVisible(false);
  }, []);

  useEffect(() => {
    global.$popup = {
      show: (triggerRef, render, options = {}) => {
        const { x: offsetX = 0, y: offsetY = 0 } = options.offset || {};
        triggerRef.current.measure((x, y, width, height, left, top) => {
          setPopupStyle({
            top: top + height + offsetY,
            left: left + offsetX,
          });
          setContent(render());
          setVisible(true);
        });
      },
      hide: () => {
        setVisible(false);
      },
    };
  }, []);

  return (
    <>
      {visible &&
        createElement(
          Platform.OS === 'ios' ? SafeAreaView : View,
          {
            style: {
              ...styles.popup,
              ...popupStyle,
            },
          },
          <TouchableOpacity onPress={onPress}>
            <View style={styles.triangle} />
            <View style={{ ...styles.content, ...style }} {...other}>
              {content}
            </View>
          </TouchableOpacity>,
        )}
    </>
  );
};

Component.displayName = 'Popup';

Component.prototype = {};

const styles = StyleSheet.create({
  popup: {
    position: 'absolute',
    zIndex: 99,
    shadowColor: '#333',
    shadowOpacity: 0.12,
    shadowOffset: { width: 2 },
    borderRadius: 4,
  },
  triangle: {
    width: 0,
    height: 0,
    marginLeft: 12,
    borderLeftWidth: 8,
    borderLeftColor: 'transparent',
    borderRightWidth: 8,
    borderRightColor: 'transparent',
    borderBottomWidth: 8,
    borderBottomColor: 'white',
  },
  content: {
    backgroundColor: 'white',
  },
});

export default forwardRef(Component);

使用方法

  • 在入口文件页面内容的末尾插入 Popup 元素。

    // App.jsx
    import Popup from './Popup';
    
    const App = () => {
      return (
        <>
          ...
          <Popup />
        </>
      );
    };
  • 使用全局变量控制。

    // 显示
    $popup.show();
    // 隐藏
    $popup.hide();

到此这篇关于React Native Popup实现示例的文章就介绍到这了,更多相关React Native Popup内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • ReactQuery 渲染优化示例详解

    ReactQuery 渲染优化示例详解

    这篇文章主要为大家介绍了ReactQuery 渲染优化示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • 详解react应用中的DOM DIFF算法

    详解react应用中的DOM DIFF算法

    这篇文章主要介绍了react应用中的DOM DIFF算法,帮助大家更好的理解和学习使用react,感兴趣的朋友可以了解下
    2021-04-04
  • React Native第三方平台分享的实例(Android,IOS双平台)

    React Native第三方平台分享的实例(Android,IOS双平台)

    本篇文章主要介绍了React Native第三方平台分享的实例(Android,IOS双平台),具有一定的参考价值,有兴趣的可以了解一下
    2017-08-08
  • React TypeScript 应用中便捷使用Redux Toolkit方法详解

    React TypeScript 应用中便捷使用Redux Toolkit方法详解

    这篇文章主要为大家介绍了React TypeScript 应用中便捷使用Redux Toolkit方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • Electron+React进行通信的方法

    Electron+React进行通信的方法

    electron其实是一个桌面应用程序,不是一个标准的前端web程序,所有没有什么请求的发生,控制台network看不到请求,而是只能通过console.log去打印查看,而且通信协议使用的不是http而是gRPC协议,这篇文章主要介绍了Electron+React如何进行通信,需要的朋友可以参考下
    2022-06-06
  • 详解使用React制作一个模态框

    详解使用React制作一个模态框

    这篇文章主要介绍了详解使用React制作一个模态框,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • 模块化react-router配置方法详解

    模块化react-router配置方法详解

    这篇文章主要介绍了模块化react-router配置方法详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-06-06
  • react项目中如何引入国际化

    react项目中如何引入国际化

    在React项目中引入国际化可以使用第三方库来实现,本文主要介绍了react项目中如何引入国际化,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • react-intl实现React国际化多语言的方法

    react-intl实现React国际化多语言的方法

    这篇文章主要介绍了react-intl实现React国际化多语言的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • 简易的redux createStore手写实现示例

    简易的redux createStore手写实现示例

    这篇文章主要介绍了简易的redux createStore手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10

最新评论