APP内嵌H5开发记录

几个关键点points

  1. 线上的东西不要去堆了,要改就改到两个新的配置,应该是渐进式的去增加,而不是breaking的先把它改掉 - 尤其是路径那种的,去请求配置化的
  2. 但凡是没有use xxx包裹住的代码,都放入到外层或者用ref带上,
    不然每次render 就生成一次

首先,这个东西是h5嵌入的,但是实际上是在app内打开,因为有一些经常会变动的东西会更改,尤其是现实的销售活动,再去发版本可谓是相当麻烦,而h5就很好的解决了这点,

其实还是有点区别,但是我作为前端以前没做过h5的我硬是没看出来过……

1. 通信的技术方案

通信是使用的js bridge,公司内统一封装了具体的包,适配flutter

通常情况下是可以直接调用一些方法,如直接closeWebView,或者open WebView(open的话可以直接打开,自带侧边栏)purchase之类的也可以去移动端接收

css 相关

1.vw自动转换

postcss-px-to-viewport 用这个包,所有css里写的px自动会变成vw,这非常好!不要用tailwind来了(这可比tw要好多了!!!!)

安装了 stylelint,那么说 style得驼峰命名

但是问题是,内联样式的px无法被转换。写到css里就好了(这时候就很需要cursor 来帮我写类名了,一个个写好累啊啊)

2. 一个很丑的按钮按下去效果,

需要给全部的数据都设置取消这个值。-webkit-tap-highlight-color: transparent;

其他那几个none其实没用,不然就会有个按下效果,很丑

*,
*::after,
*::before {
  outline: none;
  -webkit-tap-highlight-color: transparent;
  user-select: none;

  &:active {
    outline: none;
  }
}

3. header边距(又踩坑)

最开始,想用 —safe-area-inset-top来做,后面发现, 这个东西在ios非常好,但是安卓没有,后面反正也就是用了客户端传递过来的值
最开始觉得
CSS提供了env()constant()函数来获取安全区域的边距。
需要使用safe-area-inset-top这个环境变量。类似的还有safe-area-inset-bottomsafe-area-inset-leftsafe-area-inset-right,分别对应四个方向的安全区域距离。

但是这个后面发现ios有效,安卓无效,后面还是拿的客户端传递过来的值。 -- 使用了post css px to view,所以不能行内设置而是要给根元素设置上一个变量,去注入的话就能实现转换。

解决方案:

document.documentElement.style.setProperty(
    '--safe-area-top',
    (Number(searchParams.get('statusBarHeight')) || '0') + 'px',
  );

这个东西直接改了根元素的值,
var(—safe-area) 直接用

最开始查到还有一个解决方案是给: root 打变量,后面发现,得是:root而不是#root,:root默认是到全局的那么全局的东西都有而#root都是局部
不要管这个了, #root反而不对。不如直接用。

打包相关

1. 环境变量

本来说环境变量都是默认给放到 根目录底下的。不然就要额外指定(这个 和 next还不太一样感觉,next是直接 在env/下面的就能读到,

此外,next的前缀是NEXT

NEXT_PUBLIC_APP_ENV=beta

rs build的默认就是 PUBLIC,不过也可以自定义。
默认情况下,publicVars是以PUBLIC_ 为前缀的变量

图片
不过,也可以不用这么搞,现在项目里,只是用PUBLIC_ENV=dev 来作为区分的,

注意后面的—mode


    "dev": "PUBLIC_ENV=local rsbuild dev --mode development",
    "build:dev": "PUBLIC_ENV=dev rsbuild build --mode production",
    "build:prod": "PUBLIC_ENV=prod rsbuild build --mode production",

这个 public env 才是真的在local里用到的,dev 是运行 build是开发

后面那个参数 看下面 其实可以这样的⬇️

不同模式对比

模式 典型特征 建议场景
development 1. 保留调试信息
2. 不压缩代码
3. 启用热更新
本地开发
production 1. 代码压缩
2. 移除日志
3. 启用 Tree-Shaking
生产环境构建
test 1. 保留部分调试信息
2. 可能包含测试专用配置
测试环境构建

2. 打包平铺

这个由于没有安装路由(这是为什么),所以entry是自己指定的,嗯,只是读取了文件下pages下面,而且没有/components

const getEntries = async () => {
  const entryFiles = await glob('./src/pages/**/index.{ts,tsx,js,jsx}');
  const entries = Object.fromEntries(
    entryFiles
      .filter((path) => !path.includes('/components'))
      .map((file) => {
        const entryName = path.basename(path.dirname(file));
        return [entryName, `./${file}`];
      }),
  );
  return entries;
};

还有就是打包之后测试环境访问不到,

排查是不是nginx问题? 本地看看— 发现是结构问题,这时候
图片
要加上 outputStructure: 'nested', 才能平铺


export default defineConfig({
  html: {
    template: './index.html',
    templateParameters: {
      process,
    },
    outputStructure: 'nested',
  },
  1. 路由

因为没安装,所以得。手动写,而注意底下是一个* ,两个**会匹配任意,是不对的。


  const getEntries = async () => {
    const entryFiles = await glob('./src/pages/*/index.{ts,tsx,js,jsx}');
    const entries = Object.fromEntries(
      entryFiles.map((file) => {
        const entryName = path.basename(path.dirname(file));
        return [entryName, `./${file}`];
      }),
    );
    return entries;
  };

3. 打点

如果你们app内就在用神策,天然就会自动打通 文档在这里⬇️

https://manual.sensorsdata.cn/sa/docs/tech_sdk_client_link/v0300

需要传入到同一个url里,开启

app_js_bridge: true,

神策的使用方法

进入【数据管理】- 【实时导入数据查询】

然后查询那里,搜索,查询就行了,ctrl f有重新写过,反正搜出来的是最新的。嗯好,然后命中了会高亮好像仅此而已

这个开始刷新。。。反正okok就这样

swiper js

有个很狗屎的问题。10个已购买列表,他

Charles抓包 代理到本地

这样调试非常好!!!!直接在手机上用ok。注意charlse只是试用版说是30分钟内自动关闭,但是这个没什么。还是很好用的

在ios端很流畅可以开启代理。

首先ios端的wifi这里,设置成手动 这个写到csdn上去了先这样

其他经验

其他

其实经常变动的东西就用图片。。。。。用图片没什么不好,因为一大块都是这样,经常变动,emmmm.

加上没有交互。。没有交互所以没必要

search params这个 ,进入页面的时候就能拿到,所以说他不需要在use effect里。直接写就行,不然要在use effect的话多一次渲染

上滑自动隐藏,下滑显示,不是 bro 这个ai写的嗨挺好的

哎呀,踏着怎么写的,我怎么写不出来, 就是lastScrollY得换成ref,因为并没有在视图里用到。

 const [isHidden, setIsHidden] = useState(false);
  const [lastScrollY, setLastScrollY] = useState(0);

  useEffect(() => {
    const handleScroll = () => {
      const currentScrollY = window.scrollY;

      // 滚动方向判断
      if (currentScrollY > lastScrollY && currentScrollY > 50) {
        setIsHidden(true); // 向下滑动隐藏
      } else if (currentScrollY < lastScrollY) {
        setIsHidden(false); // 向上滑动显示
      }

      setLastScrollY(currentScrollY);
    };

    // 添加防抖优化
    const debouncedScroll = () => {
      window.requestAnimationFrame(handleScroll);
    };

    window.addEventListener('scroll', debouncedScroll, { passive: true });
    return () => window.removeEventListener('scroll', debouncedScroll);
  }, [lastScrollY]);

字体

需要先预加载才能再使用,注意font-family之间要有逗号

font-family: Outfit, sans-serif;

posted @ 2025-07-25 15:41  send/me/a/cat  阅读(26)  评论(0)    收藏  举报