You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取<object>标签中SVG的宽度?Elm/JS方案求助

如何获取Elm中标签加载的SVG宽度?

场景说明

我通过标签加载SVG资源,HTML代码如下:

<object
   data="${content}"
   type="image/svg+xml"
></object>

对应Elm代码:

object
    [ Attr.attribute "data" "${content}"
    , Attr.type_ "image/svg+xml"
    ]
    []

问题

尝试用on "load"或on "change"事件监听SVG加载完成以获取宽度,但事件始终未触发。用img标签可正常获取宽度,但需要将SVG正确挂载到DOM中而非当作图片处理,且SVG体积过大无法转换为Elm SVG格式。


解决方案

优先方案:Elm + Port 实现

由于Elm无法直接访问<object>的contentDocument(跨文档限制),需要配合Port与JavaScript交互来实现:

  1. 定义Elm Port
port module Main exposing (..)

import Html exposing (Html, object)
import Html.Attributes as Attr
import Task

-- 通知Elm SVG加载完成
port svgLoaded : (() -> msg) -> Sub msg
-- 请求获取SVG宽度并接收返回结果
port getSvgWidth : String -> (Float -> msg) -> Cmd msg

type Msg
    = SvgLoaded
    | SvgWidthReceived Float

type alias Model =
    { svgWidth : Maybe Float
    }

init : (Model, Cmd Msg)
init =
    ( { svgWidth = Nothing }, Cmd.none )
  1. Elm视图与订阅
    给<object>添加唯一ID,并订阅加载完成事件:
view : Model -> Html Msg
view model =
    object
        [ Attr.id "svg-object"
        , Attr.attribute "data" "your-svg-resource-url"
        , Attr.type_ "image/svg+xml"
        ]
        []

subscriptions : Model -> Sub Msg
subscriptions model =
    svgLoaded (\_ -> SvgLoaded)
  1. 处理消息获取宽度
    在update中响应加载完成事件,调用Port获取宽度:
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
    case msg of
        SvgLoaded ->
            ( model, getSvgWidth "svg-object" SvgWidthReceived )
        SvgWidthReceived width ->
            ( { model | svgWidth = Just width }, Cmd.none )
  1. 配套JavaScript代码
    在HTML中添加JS逻辑,监听加载事件并返回宽度:
// 假设Elm应用实例为app
const svgObject = document.getElementById('svg-object');

// 监听SVG加载完成,通知Elm
svgObject.addEventListener('load', () => {
    app.ports.svgLoaded.send();
});

// 响应Elm的宽度请求
app.ports.getSvgWidth.subscribe((elementId) => {
    const objectEl = document.getElementById(elementId);
    if (objectEl && objectEl.contentDocument) {
        const svgEl = objectEl.contentDocument.querySelector('svg');
        // 可按需选择宽度类型:clientWidth(渲染宽度)/ viewBox.baseVal.width(视图框宽度)
        const width = svgEl.clientWidth;
        app.ports.getSvgWidth.send(width);
    } else {
        app.ports.getSvgWidth.send(0);
    }
});

备选方案:纯JavaScript实现

如果不需要Elm逻辑处理,可直接用JS监听加载事件获取宽度:

const svgObject = document.querySelector('object[type="image/svg+xml"]');
svgObject.addEventListener('load', () => {
    const svgEl = svgObject.contentDocument.querySelector('svg');
    // 获取渲染宽度
    const renderedWidth = svgEl.clientWidth;
    // 获取viewBox定义的宽度(若存在)
    const viewBoxWidth = svgEl.viewBox.baseVal.width;
    console.log('SVG渲染宽度:', renderedWidth);
});

内容的提问来源于stack exchange,提问作者user21112580

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 14:55:36