官网适配移动端与 PC 端实战遇到的问题总结

背景

基于 Next.js + Ant Design + UnoCSS 创建的纯前端项目,本期需要将已有的 PC 页面兼容移动端,并创建一个新的产品展示页面,一并兼容移动端。


具体实现

1. 已有 PC 页面实现移动端

利用 Cursor → Figma 的 MCP,配置本项目 Rule 如下:

你是一名高级前端工程师,需要基于 UI 设计稿实现前端网页交互。

本项目为 Next.js + @ant-design 搭建的纯前端官网项目,已实现 PC 端页面,现在需要根据 UI 设计稿,实现移动端页面。所有的数据资源,与 PC 端保持一致,页面跳转交互也一样,只是样式有些差异。完成页面代码时,以优先参考 UI,交互以及数据参考 PC 端对应页面实现。

用户会在每次会话中给到 Figma UI 设计稿 MCP 描述。

接着让 Cursor 后台跑,每个页面都新建一个会话,以防上下文过长。

2. 新建功能页面

  1. 将 PC 端设计稿复制后丢给 Cursor,AI 会根据设计稿生成一个大概页面,人工再进行调整。(稍微复杂的 UI,其实相当于重画)
  2. 画完后,让 Cursor 再生成移动端,再进行调整。

遇到的问题

问题一:移动端设备兼容

移动端不同设备宽度不同,需要适配。解决方案是编写 pxToVw 方法,将 px 转为 vw

问题二:测试服部署

由于移动端样式与 PC 相差较大,所以直接写了两套代码。部署测试服后无法加载成功,排查过程如下:

现象

根目录生成了 pc.htmlmobile.html,原有的 index.html 消失了。

原因
  • PC 文件夹命名为 (pc)(带括号),Next.js 会自动忽略该路由路径。
  • 本项目 Next.js 配置为静态导出:output: 'export'
  • Nginx 配置中默认指向 index.htmlpc/index.html,无法正确匹配。
解决方案

Step 1: 配置 next.config 文件中 trailingSlash: true,使 PC 与 Mobile 主页打包后分别为:

  • pc/index.html
  • mobile/index.html

Step 2: 修改后仍然不成功,需要配置 Nginx 根据设备类型指向不同的入口文件:

javascript 复制代码
map $http_user_agent $is_mobile {
    default 0;
    ~*(Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera\ Mini) 1;
}

map $is_mobile $device_prefix {
    0 /pc;
    1 /mobile;
}

map $is_mobile $ua_index_fallback {
    0 /pc/index.html;
    1 /mobile/index.html;
}

map $uri $index_fallback {
    default $ua_index_fallback;
    ~^/pc(/|$) /pc/index.html;
    ~^/mobile(/|$) /mobile/index.html;
}

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;
    server_name_in_redirect off;
    root   /usr/share/nginx/html;
    index  index.html;

    # 已带前缀的路径,直接处理
    location ~ ^/(pc|mobile) {
        add_header Cache-Control no-cache;
        add_header X-Device-Prefix $device_prefix always;
        add_header X-Is-Mobile $is_mobile always;
        add_header X-Uri $uri always;
        add_header X-Request-Filename $request_filename always;

        # Next.js trailingSlash:true 模式,优先尝试目录的 index.html
        try_files $uri $uri/index.html $uri.html $index_fallback;
    }

    # 静态资源直接处理
    location ~ \.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff2?|ttf|otf|map|json)$ {
        try_files $uri =404;
    }

    # _next、api 等 Next.js 资源
    location ~ ^/(?:_next|api) {
        try_files $uri =404;
    }

    location / {
        # 根路径重写到对应端首页
        if ($uri = /) {
            rewrite ^ $device_prefix/ last;
        }
        # 其他路径加前缀后重新匹配(保留尾斜杠)
        rewrite ^(.*)$ $device_prefix$1 last;
    }

    # 增加缓存配置
    location ~* .*\.(?:htm|html)$ {
        add_header Cache-Control no-cache;
    }

    error_page 500 502 503 504 /50x.html;
}

关键点:rewrite ... last vs 重定向

其中核心配置:

javascript 复制代码
location / {
    if ($uri = /) {
        rewrite ^ $device_prefix/ last;
    }
    rewrite ^(.*)$ $device_prefix$1 last;
}

使用 rewrite ... last 可实现 Nginx 内部重定向,即 HTTP 只需要请求一次。

起初使用 redirectpermanent 重定向,都跳转失败。

对比表格
特性 permanent (301) last (内部重写)
地址栏 ✅ 会变化 ❌ 不变
浏览器 看到并缓存重定向 完全不知道
HTTP 请求 2 次(原请求 + 新请求) 1 次
状态码 301 200
SEO 权重转移 不影响
性能 稍慢(多一次请求) 更快
为什么 redirect / permanent 会失败?

因为 Nginx 中 Ingress 配置使用通配符,Host 配置的是内网域名redirectpermanent 都会取 Ingress 中的 Host,导致域名错误。而 last 是 Nginx 内部重写,不会改变地址栏

失败流程:

用户请求: Host: 外部域名.cn

Ingress\] 改成内部域名 ↓ 转发给后端: Host: 内部域名.cn ↓ \[Nginx 容器

附运维架构

┌───────────────────────────────────────────────────────┐

│ 公网 │

│ 用户浏览器 │

https://外部域名.cn

└────────────────────┬──────────────────────────────────┘

↓ DNS 解析到公网 IP

┌───────────────────────────────────────────────────────┐

│ Kubernetes 集群边界 │

│ [Ingress Controller] │

│ - 公网 IP: 47.x.x.x │

│ - TLS 证书处理 │

│ - 应该设置: proxy_set_header Host $host; │

└────────────────────┬──────────────────────────────────┘

↓ 内部 HTTP 转发

┌───────────────────────────────────────────────────────┐

│ 内网 (Kubernetes 内部网络) │

│ [Service: nginx-service] │

│ - ClusterIP: 10.**.x.x │

│ - 内部 DNS: nginx-service.default.svc.cluster.local │

│ │

│ [Pod: Nginx 容器] │

│ - Pod IP: 172.x.x.x │

│ - hostname: 内部域名.cn

└───────────────────────────────────────────────────────┘

相关推荐
小杨同学呀呀呀呀6 天前
Ant Design Vue <a-timeline>时间轴组件失效解决方案
前端·javascript·vue.js·typescript·anti-design-vue
编程猪猪侠9 天前
Vue3 + Ant Design Vue 实现 Table 表格嵌套 Radio 单选框
javascript·vue.js·anti-design-vue
小贵子的博客1 个月前
Ant Design Vue <a-table>
前端·javascript·vue.js·anti-design-vue
Sun_小杰杰哇1 个月前
Dayjs常用操作使用
开发语言·前端·javascript·typescript·vue·reactjs·anti-design-vue
licongmingli1 个月前
vue2 基于虚拟dom的下拉选择框,保证大数据不卡顿,仿antd功能和样式
大数据·前端·javascript·vue.js·anti-design-vue
暴富的Tdy2 个月前
【使用 Vue2 脚手架创建项目并实现主题切换功能涵盖Ant-Design-Vue2/Element-UI】
vue.js·elementui·anti-design-vue·vue切换主题
史上最菜开发2 个月前
Ant Design Vue V1.7.8版本,a-input 去空格
javascript·vue.js·anti-design-vue
添加shujuqudong1如果未回复2 个月前
探索 MI - UKF 多新息无迹卡尔曼滤波在电池电量 SOC 估算中的应用
anti-design-vue
咨询QQ276998852 个月前
Flac3d中高效自动化Plot窗口命令流程序:自由设定Legend,一键式管理颜色、显示项目...
anti-design-vue