ReactNative项目OpenHarmony三方库集成实战:@react-native-oh-tpl/masked-view

欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net

📋 前言

遮罩效果是实现复杂 UI 视觉效果的重要技术手段。无论是渐变文字、镂空效果、还是创意动画,遮罩视图都能帮助开发者实现独特的视觉体验。@react-native-oh-tpl/masked-view 是 React Native 社区广泛使用的遮罩视图组件,支持自定义遮罩元素,是实现复杂 UI 效果的基础组件。

🎯 库简介

基本信息

  • 库名称 : @react-native-oh-tpl/masked-view
  • 版本信息 :
    • 0.2.9: 支持 RN 0.72 版本
  • 官方仓库: https://github.com/react-native-oh-library/masked-view
  • 主要功能 :
    • 🎭 遮罩视图效果
    • 🎨 支持自定义遮罩元素
    • 📐 灵活的布局控制
    • 📱 跨平台一致性表现
    • 🔗 可与其他组件组合使用

为什么需要 Masked View?

特性 手动实现 Masked View
遮罩效果 ❌ 需原生代码 ✅ 组件化实现
跨平台一致性 ❌ 表现差异 ✅ 统一效果
动态控制 ⚠️ 复杂实现 ✅ Props 控制
渐变文字 ⚠️ 需额外处理 ✅ 配合渐变组件
HarmonyOS支持 ❌ 不支持 ✅ 完整支持

典型应用场景

  1. 渐变文字效果 - 配合 LinearGradient 实现文字渐变
  2. 镂空效果 - 创建镂空的视觉元素
  3. 创意动画 - 实现复杂的遮罩动画
  4. 图片遮罩 - 为图片添加特殊形状

兼容性验证

在以下环境验证通过:

  • RNOH : 0.72.90; SDK : HarmonyOS 6.0.0 Release SDK; IDE : DevEco Studio 6.0.0.858; ROM: 6.0.0.112

📦 安装步骤

前置教程:在开始适配之前,如果您是新手,可以先阅读这篇文章了解ReactNative和OpenHarmony的搭建方式https://bxming.blog.csdn.net/article/details/156641198?spm=1001.2014.3001.5502

本文的完整代码运行需要适配另一个库:https://blog.csdn.net/2402_83107102/article/details/159163022

1. 使用 npm 安装

在项目根目录执行以下命令,本文基于 RN 0.72.90 版本开发:

bash 复制代码
# RN 0.72 版本推荐使用
npm install @react-native-oh-tpl/masked-view@0.2.9-0.2.2

# 或者使用 yarn
yarn add @react-native-oh-tpl/masked-view@0.2.9-0.2.2

2. 验证安装

安装完成后,检查 package.json 文件,应该能看到新增的依赖:

json 复制代码
{
  "dependencies": {
    "@react-native-oh-tpl/masked-view": "0.2.9-0.2.2",
    // ... 其他依赖
  }
}

🔧 HarmonyOS 平台配置 ⭐

由于 HarmonyOS 暂不支持 AutoLink,需要手动配置原生端代码。本文提供 HAR 包引入源码引入 两种方式,可根据实际需求选择。

1. 在工程根目录的 oh-package.json5 添加 overrides 字段

打开 harmony/oh-package.json5,添加以下配置:

json5 复制代码
{
  // ... 其他配置
  "overrides": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}

方式一:HAR 包引入(推荐)📦

HAR 包引入方式简单快捷,适合大多数场景。

💡 提示 :HAR 包位于三方库安装路径的 harmony 文件夹下。

2.1 在 entry/oh-package.json5 添加依赖

打开 harmony/entry/oh-package.json5,添加以下依赖:

json5 复制代码
"dependencies": {
  "@rnoh/react-native-openharmony": "0.72.90",
  + "@react-native-oh-tpl/masked-view": "file:../../node_modules/@react-native-oh-tpl/masked-view/harmony/masked_view.har"
}

2.2 同步依赖

点击 DevEco Studio 右上角的 sync 按钮,或者在终端执行:

bash 复制代码
cd harmony/entry
ohpm install

2.3 配置 CMakeLists.txt

打开 harmony/entry/src/main/cpp/CMakeLists.txt,添加以下配置:

cmake 复制代码
project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error- unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(WITH_HITRACE_SYSTRACE 1)
add_compile_definitions(WITH_HITRACE_SYSTRACE)

add_subdirectory("${RNOH_CPP_DIR}" ./rn)

# 添加 MaskedView 模块(HAR方式)
+ add_subdirectory("${OH_MODULES}/@react-native-oh-tpl/masked-view/src/main/cpp" ./masked-view)

file(GLOB GENERATED_CPP_FILES "./generated/*.cpp")

add_library(rnoh_app SHARED
    ${GENERATED_CPP_FILES}
    "./PackageProvider.cpp"
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)

# 链接 MaskedView 库
+ target_link_libraries(rnoh_app PUBLIC rnoh_masked_view)

2.4 修改 PackageProvider.cpp

打开 harmony/entry/src/main/cpp/PackageProvider.cpp,添加:

cpp 复制代码
#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
+ #include "MaskedPackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<RNOHGeneratedPackage>(ctx),
        + std::make_shared<MaskedPackage>(ctx),
    };
}

方式二:源码引入 📁

源码引入方式适合需要调试或修改原生代码的场景。

2.1 复制源码到 harmony 工程根目录

<RN工程>/node_modules/@react-native-oh-tpl/masked-view/harmony 目录下的源码 masked_view 复制到 harmony(鸿蒙壳工程)工程根目录下。

2.2 在 build-profile.json5 添加模块

打开 harmony/build-profile.json5,添加以下模块:

json5 复制代码
modules: [
  // ... 其他模块
  + {
  +   name: 'masked_view',
  +   srcPath: './masked_view',
  + }
]

💡 提示 :如果存在 build-profile.template.json5 文件,也需要同步添加上述模块配置。

2.3 修改 masked_view/oh-package.json5

打开 harmony/masked_view/oh-package.json5,修改 react-native-openharmony 版本与项目版本一致:

json5 复制代码
{
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}

2.4 在 entry/oh-package.json5 添加依赖

打开 harmony/entry/oh-package.json5,添加以下依赖:

json5 复制代码
"dependencies": {
  "@rnoh/react-native-openharmony": "0.72.90",
  + "@react-native-oh-tpl/masked-view": "file:../masked_view"
}

2.5 同步依赖

点击 DevEco Studio 右上角的 sync 按钮,或者在终端执行:

bash 复制代码
cd harmony/entry
ohpm install

2.6 配置 CMakeLists.txt

打开 harmony/entry/src/main/cpp/CMakeLists.txt,添加以下配置:

cmake 复制代码
project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error- unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(WITH_HITRACE_SYSTRACE 1)
add_compile_definitions(WITH_HITRACE_SYSTRACE)

add_subdirectory("${RNOH_CPP_DIR}" ./rn)

# 添加 MaskedView 模块(源码方式)
+ add_subdirectory("${OH_MODULES}/@react-native-oh-tpl/masked-view/src/main/cpp" ./masked-view)

file(GLOB GENERATED_CPP_FILES "./generated/*.cpp")

add_library(rnoh_app SHARED
    ${GENERATED_CPP_FILES}
    "./PackageProvider.cpp"
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)

# 链接 MaskedView 库
+ target_link_libraries(rnoh_app PUBLIC rnoh_masked_view)

2.7 修改 PackageProvider.cpp

打开 harmony/entry/src/main/cpp/PackageProvider.cpp,添加:

cpp 复制代码
#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
+ #include "MaskedPackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<RNOHGeneratedPackage>(ctx),
        + std::make_shared<MaskedPackage>(ctx),
    };
}

同步并运行 🚀

3. 同步依赖

点击 DevEco Studio 右上角的 sync 按钮,或者在终端执行:

bash 复制代码
cd harmony/entry
ohpm install

然后编译、运行即可。

📖 API 详解

🔷 核心概念

MaskedView 的工作原理是:遮罩元素定义可见区域,子元素只在该区域内显示

复制代码
┌─────────────────────────────┐
│      MaskedView 容器        │
│  ┌─────────────────────┐    │
│  │   maskElement       │    │  ← 遮罩元素(定义可见区域)
│  │   (Text: "ABC")     │    │
│  └─────────────────────┘    │
│                             │
│  ┌─────────────────────┐    │
│  │   子元素            │    │  ← 子元素(只在遮罩区域内显示)
│  │   (渐变背景)        │    │
│  └─────────────────────┘    │
└─────────────────────────────┘

🔷 核心属性(Props)

1. maskElement - 遮罩元素 ⭐

maskElement 是 MaskedView 最核心的属性,用于定义遮罩的形状和内容。

typescript 复制代码
maskElement: React.ReactElement;
类型 必填 说明
ReactElement 定义遮罩形状的 React 元素

工作原理

  • 遮罩元素中的不透明区域将成为可见区域
  • 遮罩元素中的透明区域将被隐藏
  • 子元素只会在遮罩定义的区域内显示

使用示例

typescript 复制代码
import MaskedView from '@react-native-masked-view/masked-view';
import { Text, View } from 'react-native';

// 文字遮罩
<MaskedView
  style={{ flex: 1 }}
  maskElement={
    <View style={{ backgroundColor: 'transparent', alignItems: 'center' }}>
      <Text style={{ fontSize: 50, fontWeight: 'bold', color: 'black' }}>
        MASK
      </Text>
    </View>
  }
>
  {/* 子元素 - 只会在文字区域内显示 */}
  <View style={{ backgroundColor: '#FF6B6B', flex: 1 }} />
</MaskedView>
2. style - 容器样式 📐

style 用于定义 MaskedView 容器的样式。

typescript 复制代码
style?: StyleProp<ViewStyle>;

常用样式属性

属性 类型 说明
width number/string 容器宽度
height number/string 容器高度
flex number 弹性布局

使用示例

typescript 复制代码
<MaskedView
  style={{ width: 200, height: 100 }}
  maskElement={
    <View style={{ backgroundColor: 'transparent' }}>
      <Text style={{ fontSize: 40, color: 'black' }}>Hello</Text>
    </View>
  }
>
  <View style={{ backgroundColor: '#4ECDC4', flex: 1 }} />
</MaskedView>
3. androidRenderingMode - 安卓渲染模式 ⚠️

⚠️ HarmonyOS 不支持: 此属性仅在 Android 平台有效

typescript 复制代码
androidRenderingMode?: 'software' | 'hardware';
说明 HarmonyOS 支持
software 软件渲染
hardware 硬件渲染

💻 完整代码示例

下面是一个完整的示例,展示了 MaskedView 的各种应用场景:

typescript 复制代码
import React from 'react';
import {
  View,
  Text,
  StyleSheet,
  ScrollView,
  SafeAreaView,
} from 'react-native';
import MaskedView from '@react-native-masked-view/masked-view';
import LinearGradient from 'react-native-linear-gradient';

function MaskedViewDemo() {
  return (
    <SafeAreaView style={styles.container}>
      <ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollContent}>
        <Text style={styles.title}>🎭 MaskedView 演示</Text>

        {/* 1. 基础文字遮罩 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>1️⃣ 基础文字遮罩</Text>
          <Text style={styles.description}>文字作为遮罩,子元素只在文字区域显示</Text>
          <MaskedView
            style={styles.maskedView}
            maskElement={
              <View style={styles.maskElementContainer}>
                <Text style={styles.maskText}>MASK</Text>
              </View>
            }
          >
            <View style={styles.redBackground} />
            <View style={styles.yellowBackground} />
          </MaskedView>
        </View>

        {/* 2. 渐变文字效果 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>2️⃣ 渐变文字效果</Text>
          <Text style={styles.description}>配合 LinearGradient 实现渐变文字</Text>
          <MaskedView
            style={styles.gradientMaskedView}
            maskElement={
              <View style={styles.maskElementContainer}>
                <Text style={styles.gradientMaskText}>渐变文字</Text>
              </View>
            }
          >
            <LinearGradient
              colors={['#667eea', '#764ba2']}
              start={{ x: 0, y: 0.5 }}
              end={{ x: 1, y: 0.5 }}
              style={styles.gradient}
            />
          </MaskedView>
        </View>

        {/* 3. 多色渐变文字 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>3️⃣ 多色渐变文字</Text>
          <Text style={styles.description}>使用多个颜色创建丰富的渐变效果</Text>
          <MaskedView
            style={styles.multiColorMaskedView}
            maskElement={
              <View style={styles.maskElementContainer}>
                <Text style={styles.multiColorMaskText}>RAINBOW</Text>
              </View>
            }
          >
            <LinearGradient
              colors={['#FF6B6B', '#FFE66D', '#4ECDC4', '#45B7D1', '#A78BFA']}
              start={{ x: 0, y: 0.5 }}
              end={{ x: 1, y: 0.5 }}
              style={styles.gradient}
            />
          </MaskedView>
        </View>

        {/* 4. 形状遮罩 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>4️⃣ 形状遮罩</Text>
          <Text style={styles.description}>使用形状作为遮罩</Text>
          <View style={styles.shapeContainer}>
            {/* 圆形遮罩 */}
            <MaskedView
              style={styles.circleMask}
              maskElement={
                <View style={styles.circleShape} />
              }
            >
              <LinearGradient
                colors={['#f093fb', '#f5576c']}
                style={styles.gradient}
              />
            </MaskedView>

            {/* 矩形遮罩 */}
            <MaskedView
              style={styles.rectMask}
              maskElement={
                <View style={styles.rectShape} />
              }
            >
              <LinearGradient
                colors={['#4facfe', '#00f2fe']}
                style={styles.gradient}
              />
            </MaskedView>
          </View>
        </View>

        {/* 5. 实际应用场景 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>5️⃣ 实际应用场景</Text>
      
          {/* 启动页标题 */}
          <View style={styles.applicationCard}>
            <MaskedView
              style={styles.appTitleMask}
              maskElement={
                <View style={styles.maskElementContainer}>
                  <Text style={styles.appTitleText}>欢迎使用</Text>
                </View>
              }
            >
              <LinearGradient
                colors={['#667eea', '#764ba2']}
                start={{ x: 0, y: 0.5 }}
                end={{ x: 1, y: 0.5 }}
                style={styles.gradient}
              />
            </MaskedView>
            <Text style={styles.applicationLabel}>启动页标题</Text>
          </View>

          {/* 营销活动 */}
          <View style={styles.applicationCard}>
            <MaskedView
              style={styles.appTitleMask}
              maskElement={
                <View style={styles.maskElementContainer}>
                  <Text style={styles.marketingText}>限时特惠</Text>
                </View>
              }
            >
              <LinearGradient
                colors={['#FF6B6B', '#FFE66D']}
                start={{ x: 0, y: 0.5 }}
                end={{ x: 1, y: 0.5 }}
                style={styles.gradient}
              />
            </MaskedView>
            <Text style={styles.applicationLabel}>营销活动标题</Text>
          </View>
        </View>

        {/* 6. 组合效果 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>6️⃣ 组合效果</Text>
          <Text style={styles.description}>多层遮罩叠加效果</Text>
          <MaskedView
            style={styles.combinedMask}
            maskElement={
              <View style={styles.maskElementContainer}>
                <Text style={styles.combinedMaskText}>COMBO</Text>
              </View>
            }
          >
            <View style={styles.layer1} />
            <View style={styles.layer2} />
            <View style={styles.layer3} />
          </MaskedView>
        </View>
      </ScrollView>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  scrollView: {
    flex: 1,
  },
  scrollContent: {
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#333',
    textAlign: 'center',
    marginBottom: 30,
  },
  section: {
    backgroundColor: '#fff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 16,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#333',
    marginBottom: 8,
  },
  description: {
    fontSize: 14,
    color: '#666',
    marginBottom: 16,
  },
  maskedView: {
    width: '100%',
    height: 80,
  },
  maskElementContainer: {
    backgroundColor: 'transparent',
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  maskText: {
    fontSize: 50,
    fontWeight: 'bold',
    color: 'black',
  },
  redBackground: {
    width: '100%',
    height: 40,
    backgroundColor: '#fe4b83',
  },
  yellowBackground: {
    width: '100%',
    height: 40,
    backgroundColor: '#F5DD90',
  },
  gradientMaskedView: {
    width: '100%',
    height: 60,
  },
  gradientMaskText: {
    fontSize: 40,
    fontWeight: 'bold',
    color: 'black',
  },
  gradient: {
    flex: 1,
  },
  multiColorMaskedView: {
    width: '100%',
    height: 70,
  },
  multiColorMaskText: {
    fontSize: 48,
    fontWeight: 'bold',
    color: 'black',
  },
  shapeContainer: {
    flexDirection: 'row',
    justifyContent: 'space-around',
  },
  circleMask: {
    width: 80,
    height: 80,
  },
  circleShape: {
    width: 80,
    height: 80,
    borderRadius: 40,
    backgroundColor: 'black',
  },
  rectMask: {
    width: 80,
    height: 80,
  },
  rectShape: {
    width: 80,
    height: 80,
    backgroundColor: 'black',
  },
  applicationCard: {
    alignItems: 'center',
    paddingVertical: 16,
    marginBottom: 12,
    backgroundColor: '#fafafa',
    borderRadius: 8,
  },
  appTitleMask: {
    width: '100%',
    height: 50,
  },
  appTitleText: {
    fontSize: 36,
    fontWeight: 'bold',
    color: 'black',
  },
  marketingText: {
    fontSize: 32,
    fontWeight: '800',
    color: 'black',
  },
  applicationLabel: {
    fontSize: 12,
    color: '#999',
    marginTop: 8,
  },
  combinedMask: {
    width: '100%',
    height: 80,
  },
  combinedMaskText: {
    fontSize: 48,
    fontWeight: 'bold',
    color: 'black',
  },
  layer1: {
    width: '100%',
    height: 30,
    backgroundColor: '#FF6B6B',
  },
  layer2: {
    width: '100%',
    height: 25,
    backgroundColor: '#4ECDC4',
  },
  layer3: {
    width: '100%',
    height: 25,
    backgroundColor: '#45B7D1',
  },
});

export default MaskedViewDemo;

⚠️ 注意事项与最佳实践

1. 遮罩元素设置

typescript 复制代码
// ✅ 推荐:遮罩元素使用透明背景
<MaskedView
  maskElement={
    <View style={{ backgroundColor: 'transparent' }}>
      <Text style={{ color: 'black' }}>遮罩文字</Text>
    </View>
  }
>
  {/* 子元素 */}
</MaskedView>

// ❌ 不推荐:遮罩元素使用不透明背景
<MaskedView
  maskElement={
    <View style={{ backgroundColor: 'white' }}>
      <Text>遮罩文字</Text>
    </View>
  }
>
  {/* 子元素 */}
</MaskedView>

2. 配合 LinearGradient 使用

MaskedView 最常见的用法是与 LinearGradient 配合实现渐变文字:

typescript 复制代码
<MaskedView
  style={{ height: 60 }}
  maskElement={
    <View style={{ backgroundColor: 'transparent', alignItems: 'center' }}>
      <Text style={{ fontSize: 40, fontWeight: 'bold', color: 'black' }}>
        渐变文字
      </Text>
    </View>
  }
>
  <LinearGradient
    colors={['#667eea', '#764ba2']}
    start={{ x: 0, y: 0.5 }}
    end={{ x: 1, y: 0.5 }}
    style={{ flex: 1 }}
  />
</MaskedView>

3. 性能优化建议

  • 避免复杂遮罩: 遮罩元素尽量简单,避免嵌套过多组件
  • 合理设置尺寸: 避免过大的遮罩区域
  • 复用组件: 对于重复使用的遮罩效果,封装为独立组件

4. 常见问题排查

问题 1: 遮罩不显示

  • 检查 maskElement 是否正确设置
  • 确认遮罩元素的颜色设置正确(不透明区域应为遮罩区域)
  • 检查子元素是否有内容

问题 2: 渐变效果不正确

  • 确认 LinearGradient 的方向设置
  • 检查 colors 数组是否正确

问题 3: 文字边缘模糊

  • 检查遮罩元素的字体大小
  • 确认容器的尺寸设置合理

📊 API 支持情况总览

属性支持

属性 说明 HarmonyOS 支持
maskElement 遮罩元素
style 容器样式
androidRenderingMode 安卓渲染模式

📝 总结

通过集成 @react-native-oh-tpl/masked-view,我们为项目添加了强大的遮罩视图能力。该组件是实现渐变文字、镂空效果等复杂 UI 的基础组件,配合 LinearGradient 可以创建精美的视觉效果。

相关推荐
摸鱼的春哥2 小时前
Agent教程20:更适合编程工具的记忆方案——情景摘要
前端·javascript·后端
架构师李肯3 小时前
TypeScript与React全栈实战:从架构搭建到项目部署,避开常见陷阱
react.js·架构·typescript
Hamm10 小时前
不想花一分钱玩 OpenClaw?来,一起折腾这个!
javascript·人工智能·agent
Setsuna_F_Seiei11 小时前
AI 对话应用之 JS 的流式接口数据处理
前端·javascript·ai编程
英俊潇洒美少年11 小时前
react如何实现 vue的$nextTick的效果
javascript·vue.js·react.js
隔壁小邓15 小时前
前端Vue项目打包部署实战教程
前端·javascript·vue.js
TON_G-T15 小时前
javascript中 Iframe 处理多端通信、鉴权
开发语言·前端·javascript
周淳APP15 小时前
【JS之闭包防抖节流,this指向,原型&原型链,数据类型,深浅拷贝】简单梳理啦!
开发语言·前端·javascript·ecmascript
kyriewen15 小时前
console.log 骗了我一整个通宵:原来它才是时间旅行者
前端·javascript·chrome