Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions packages/taro-components-react/src/components/image/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,49 @@ interface IProps extends React.HTMLAttributes<HTMLDivElement> {
lang?: string
}

// CDN脚本URL
const LEGO_CDN_URL = 'http://ossin.jd.com/swm-plus/h5Tag/tag.js'
// CDN脚本URL(按环境与可覆盖配置)
const LEGO_CDN_URL_DEV = 'http://ossin.jd.com/swm-plus/h5Tag/tag.js'
const LEGO_CDN_URL_PROD = 'https://storage.jd.com/static-frontend/h5-tag/1.0.0/tag.min.js'

const getLegoCdnUrl = (): string => {
// 允许通过全局变量覆盖
const override = (typeof window !== 'undefined' && (window as any).__TARO_IMAGE_LEGO_CDN_URL__)
if (override && typeof override === 'string') return override

// 允许通过 Taro 全局对象覆盖(与 window 同名变量)
const taroOverride = (typeof window !== 'undefined' && (window as any).Taro && (window as any).Taro.__TARO_IMAGE_LEGO_CDN_URL__)
if (taroOverride && typeof taroOverride === 'string') return taroOverride

// 基于环境选择
const isProd = (typeof process !== 'undefined' && process.env && process.env.NODE_ENV === 'production')
return isProd ? LEGO_CDN_URL_PROD : LEGO_CDN_URL_DEV
}

// 检查CDN脚本是否已加载
const isLegoScriptLoaded = (): boolean => {
return document.querySelector(`script[src="${LEGO_CDN_URL}"]`) !== null
const url = getLegoCdnUrl()
return document.querySelector(`script[src="${url}"]`) !== null
}

// 插入CDN脚本
const insertLegoScript = (): void => {
if (typeof document === 'undefined') return
if (isLegoScriptLoaded()) return

const script = document.createElement('script')
script.type = 'module'
script.src = LEGO_CDN_URL
script.src = getLegoCdnUrl()
document.head.appendChild(script)
}

// 解析lego协议URL
const parseLegoUrl = (src: string): { tagId: string, text: string } | null => {
if (!src.startsWith('lego://')) return null
const LEGO_PROTOCOL = 'lego://'
if (!src.startsWith(LEGO_PROTOCOL)) return null

try {
// 移除 'lego://' 前缀
const urlWithoutProtocol = src.substring(7)
const urlWithoutProtocol = src.slice(LEGO_PROTOCOL.length)

// 分割tagId和参数
const [tagId, params] = urlWithoutProtocol.split('?')
Expand Down
40 changes: 29 additions & 11 deletions packages/taro-components/src/components/image/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,56 @@ export type Mode =
| 'bottom left'
| 'bottom right'

// CDN脚本URL
const LEGO_CDN_URL = 'http://ossin.jd.com/swm-plus/h5Tag/tag.js'
// CDN脚本URL(按环境与可覆盖配置)
const LEGO_CDN_URL_DEV = 'http://ossin.jd.com/swm-plus/h5Tag/tag.js'
const LEGO_CDN_URL_PROD = 'https://storage.jd.com/static-frontend/h5-tag/1.0.0/tag.min.js'

const getLegoCdnUrl = (): string => {
// 允许通过全局变量覆盖
const override = (typeof window !== 'undefined' && (window as any).__TARO_IMAGE_LEGO_CDN_URL__)
if (override && typeof override === 'string') return override

// 允许通过 Taro 全局对象覆盖(与 window 同名变量)
const taroOverride = (typeof window !== 'undefined' && (window as any).Taro && (window as any).Taro.__TARO_IMAGE_LEGO_CDN_URL__)
if (taroOverride && typeof taroOverride === 'string') return taroOverride

// 基于环境选择
const isProd = (typeof process !== 'undefined' && (process as any).env && (process as any).env.NODE_ENV === 'production')
return isProd ? LEGO_CDN_URL_PROD : LEGO_CDN_URL_DEV
}

// 检查CDN脚本是否已加载
const isLegoScriptLoaded = (): boolean => {
return document.querySelector(`script[src="${LEGO_CDN_URL}"]`) !== null
const url = getLegoCdnUrl()
return document.querySelector(`script[src="${url}"]`) !== null
}

// 插入CDN脚本
const insertLegoScript = (): void => {
if (typeof document === 'undefined') return
if (isLegoScriptLoaded()) return

const script = document.createElement('script')
script.type = 'module'
script.src = LEGO_CDN_URL
script.src = getLegoCdnUrl()
document.head.appendChild(script)
}

// 解析lego协议URL
const parseLegoUrl = (src: string): { tagId: string; text: string } | null => {
if (!src.startsWith('lego://')) return null
const LEGO_PROTOCOL = 'lego://'
if (!src.startsWith(LEGO_PROTOCOL)) return null

try {
// 移除 'lego://' 前缀
const urlWithoutProtocol = src.substring(7)
const urlWithoutProtocol = src.slice(LEGO_PROTOCOL.length)

// 分割tagId和参数
const [tagId, params] = urlWithoutProtocol.split('?')

// 解析参数
const text = params ? new URLSearchParams(params).get('text') || '' : ''

return { tagId, text }
} catch (error) {
console.warn('Failed to parse lego URL:', src, error)
Expand Down Expand Up @@ -154,8 +172,8 @@ export class Image implements ComponentInterface {
if (isLegoMode && legoData) {
return (
<Host class={cls}>
<canvas-tag
tagId={legoData.tagId}
<canvas-tag
tagId={legoData.tagId}
text={legoData.text}
lang={lang}
{...nativeProps}
Expand Down
32 changes: 32 additions & 0 deletions packages/taro-components/src/components/image/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,35 @@
----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lint


## LEGO 模式与 CDN 配置

`src``lego://` 开头时,组件进入 LEGO 模式,内部不再渲染 `<img>`,而是渲染 `<canvas-tag>`

- 解析规则:`lego://{tagId}?text=...` → 传递 `tagId``text``lang``<canvas-tag>`
- 事件差异:不触发 `<img>``load/error`,请使用 `<canvas-tag>` 自身事件(若有)。

脚本注入:组件在 LEGO 模式下会按需为 H5 端注入 `tag.js`(type="module"),默认 CDN:

- 开发:`http://ossin.jd.com/swm-plus/h5Tag/tag.js`
- 生产:`https://storage.jd.com/static-frontend/h5-tag/1.0.0/tag.min.js`

可通过全局变量覆盖 CDN 地址(优先级从上到下):

1. `window.__TARO_IMAGE_LEGO_CDN_URL__`
2. `Taro.__TARO_IMAGE_LEGO_CDN_URL__`

示例:

```js
// 在应用启动时设置(H5)
window.__TARO_IMAGE_LEGO_CDN_URL__ = 'https://your-cdn.com/tag.min.js'
//
Taro.__TARO_IMAGE_LEGO_CDN_URL__ = 'https://your-cdn.com/tag.min.js'
```

说明:

- 若未设置覆盖变量,则根据 `process.env.NODE_ENV` 在内置 dev/prod CDN 之间选择。
- 组件已做脚本重复注入检查;在 SSR 场景访问 `window/document` 前有守卫。
Loading