普通视图

发现新文章,点击刷新页面。
今天 — 2025年12月22日首页

Electron无边框窗口如何拖拽以及最大化和还原窗口

作者 静待雨落
2025年12月22日 15:44

什么是无边框窗口

设置了frame: false,新建的窗口就没有边框了!

mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    frame: false, // 无边框核心配置
    webPreferences: {
      nodeIntegration: true, // 启用 Node 集成,允许渲染进程调用 Electron API
      contextIsolation: false // 关闭上下文隔离,简化调用
    }
  });

无边框窗口如何拖拽

Electron无边框窗口默认无法拖拽,需在 HTML 中给可拖拽区域添加 CSS 样式 -webkit-app-region: drag;(注意:按钮等可点击元素需设置 webkit-app-region: no-drag; 避免无法点击)。

// 可拖拽部分
.header {
    -webkit-app-region: drag;
}

// 不需要拖拽部分
.main {
    -webkit-app-region: no-drag;
}

如何最大化窗口和还原

Electron提供了窗口的最大化和还原窗口的api

    // 最大化窗口
    mainWindow.maximize()
    // 还原窗口
    mainWindow.unmaximize();

但是!在无边框窗口中使用mainWindow.maximize()最大化窗口并不能被还原,此时就需要其他方法来实现此功能。

首先判断是否处于全屏状态

// 兼容所有浏览器的全屏状态判断
function isDocumentFullScreen() {
  return !!document.fullscreenElement || 
         !!document.webkitFullscreenElement || // 对应 webkitIsFullScreen 的元素版
         !!document.mozFullScreenElement ||    // 对应 mozFullScreen 的元素版
         !!document.msFullscreenElement;
}

你在使用 TypeScript 时,调用 document.webkitFullscreenElementdocument.mozFullScreenElement 等厂商前缀全屏 API 出现类型错误,这是因为 TypeScript 的内置 DOM 类型定义中仅包含标准 API(如 document.fullscreenElement),未包含这些非标准的厂商前缀属性,以下是几种完整的解决方案,按推荐优先级排序:

一、方案 1:类型断言(Type Assertion)—— 快速解决单个属性报错

这是最简洁的临时解决方案,通过类型断言告诉 TypeScript 「该属性存在于 document 上」,忽略类型检查报错。

实现代码
// 兼容所有浏览器的全屏状态判断(TS 兼容写法)
function isDocumentFullScreen(): boolean {
  // 对 document 进行类型断言,指定为包含厂商前缀属性的任意类型
  const doc = document as any;
  return !!doc.fullscreenElement || 
         !!doc.webkitFullscreenElement || 
         !!doc.mozFullScreenElement || 
         !!doc.msFullscreenElement;
}

// 或直接对单个属性进行断言(更精准)
function isDocumentFullScreen精准版(): boolean {
  return !!document.fullscreenElement || 
         !!(document as { webkitFullscreenElement?: Element | null }).webkitFullscreenElement || 
         !!(document as { mozFullScreenElement?: Element | null }).mozFullScreenElement || 
         !!(document as { msFullscreenElement?: Element | null }).msFullscreenElement;
}
特点
  • 优点:快速便捷,无需额外配置,适合简单场景或临时调试。
  • 缺点:缺乏类型提示,若属性名拼写错误(如把 webkitFullscreenElement 写成 webkitFullScreenElement),运行时才会暴露问题。
二、方案 2:扩展全局 DOM 类型(推荐)—— 长期优雅解决

通过 TypeScript 的「全局类型扩展」功能,为 Document 接口补充厂商前缀属性的类型定义,既解决报错,又能获得类型提示,是长期项目的最优解。

步骤 1:创建类型声明文件(如 global.d.ts

在项目根目录或 src 目录下创建 .d.ts 后缀的类型声明文件(TS 会自动识别该类型文件,无需手动引入):

// global.d.ts
declare global {
  interface Document {
    // 补充 WebKit/Blink 内核厂商前缀属性
    webkitFullscreenElement?: Element | null;
    // 补充 Gecko 内核厂商前缀属性(注意:S 大写,与标准 API 有差异)
    mozFullScreenElement?: Element | null;
    // 补充 Trident 内核厂商前缀属性
    msFullscreenElement?: Element | null;

    // 可选:若需使用旧版布尔值属性,也可补充对应类型
    webkitIsFullScreen?: boolean;
    mozFullScreen?: boolean;
  }
}

// 必须导出空对象,标识这是一个模块
export {};
步骤 2:配置 tsconfig.json(确保类型文件被识别)

确保 tsconfig.json 中包含该类型文件的路径(默认情况下,"include" 会覆盖 src 下所有 .ts/.d.ts 文件,若已配置可跳过):

{
  "compilerOptions": {
    "target": "ES6",
    "module": "CommonJS",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "typeRoots": ["./node_modules/@types", "./src/types"] // 若类型文件放在 src/types 下,需配置此路径
  },
  "include": ["src/**/*", "global.d.ts"] // 包含全局类型声明文件
}
步骤 3:正常使用代码(无报错且有类型提示)
// 此时 TS 不会报错,且能自动提示对应属性
function isDocumentFullScreen(): boolean {
  return !!document.fullscreenElement || 
         !!document.webkitFullscreenElement || 
         !!document.mozFullScreenElement || 
         !!document.msFullscreenElement;
}
特点
  • 优点:类型安全、有代码提示,一劳永逸,适合长期维护的项目。
  • 缺点:需要额外创建类型文件,初次配置略繁琐。

补充说明

  1. 厂商前缀 API 已逐步被废弃,若项目无需兼容老旧浏览器,推荐直接使用标准 API document.fullscreenElement,无需额外处理类型问题。
  2. 若使用方案 2 后仍报错,可重启 TS 语言服务(VS Code 中可按 Ctrl+Shift+P,输入「TypeScript: Restart TS Server」)。
  3. 类型声明文件中,属性添加 ? 表示可选属性(因为并非所有浏览器都存在这些属性),符合实际兼容场景。

进入全屏

if (!isFull) { // 进入全屏
    let element = document.documentElement;
    if (element.requestFullscreen) {
        element.requestFullscreen();
    } else if (element.msRequestFullscreen) {
        element.msRequestFullscreen();
    } else if (element.mozRequestFullScreen) {
        element.mozRequestFullScreen();
    } else if (element.webkitRequestFullscreen) {
        element.webkitRequestFullscreen();
    }
}
  • 逻辑:先获取页面根元素 document.documentElement(即 <html> 标签,通常让整个页面进入全屏),再优先调用标准 API,降级调用厂商前缀方法:

    • element.requestFullscreen():标准进入全屏方法(需指定 “要全屏的元素”)。
    • element.msRequestFullscreen():IE / 旧版 Edge 的进入全屏方法。
    • element.mozRequestFullScreen():Firefox 的进入全屏方法(注意命名是 RequestFullScreen)。
    • element.webkitRequestFullscreen():Chrome/Safari 的进入全屏方法。

退出全屏

if (isFull) {// 退出全屏
    if (document.exitFullscreen) {
        document.exitFullscreen();
    } else if (document.msExitFullscreen) {
        document.msExitFullscreen();
    } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen();
    } else if (document.webkitExitFullscreen) {
        document.webkitExitFullscreen();
    }
}
  • 逻辑:优先调用标准 API,若浏览器不支持,则降级调用对应厂商前缀的 “退出全屏” 方法:

    • document.exitFullscreen():标准退出全屏方法。
    • document.msExitFullscreen():IE / 旧版 Edge 的退出全屏方法。
    • document.mozCancelFullScreen():Firefox 的退出全屏方法(注意命名是 CancelFullScreen)。
    • document.webkitExitFullscreen():Chrome/Safari 的退出全屏方法。
昨天以前首页

如何在Taro项目中使用axios

作者 静待雨落
2025年12月19日 17:25

Axios 默认使用 XMLHttpRequest 或 Node.js 的 http 模块,这在某些小程序端可能不支持:

  • ✅ H5 端:完全支持
  • ✅ React Native 端:需要配置适配器
  • ❌ 微信/支付宝等小程序端不支持(因为小程序环境没有 XMLHttpRequest

对于需要在多端使用 Axios 的项目,可以配置适配器:

pnpm install axios @tarojs/taro
// utils/axiosAdapter.js
import axios from 'axios'
import Taro from '@tarojs/taro'

// 创建自定义适配器
const taroAdapter = (config) => {
  return new Promise((resolve, reject) => {
    Taro.request({
      url: config.url,
      method: config.method?.toUpperCase() || 'GET',
      data: config.data || config.params,
      header: config.headers,
      success: (response) => {
        resolve({
          data: response.data,
          status: response.statusCode,
          statusText: 'OK',
          headers: response.header,
          config: config,
          request: null
        })
      },
      fail: (error) => {
        reject(error)
      }
    })
  })
}

// 创建 Axios 实例
const instance = axios.create({
  adapter: taroAdapter,
  baseURL: 'https://api.example.com',
  timeout: 10000,
})

// 请求拦截器
instance.interceptors.request.use(
  (config) => {
    // 添加 token
    const token = Taro.getStorageSync('token')
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`
    }
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

// 响应拦截器
instance.interceptors.response.use(
  (response) => {
    return response.data
  },
  (error) => {
    // 统一错误处理
    Taro.showToast({
      title: '请求失败',
      icon: 'error'
    })
    return Promise.reject(error)
  }
)

export default instance
❌
❌