在 SVG 中包含 JavaScript

问题描述 投票:0回答:4

我正在尝试通过将 JavaScript 嵌入到 SVG 中,使用 JavaScript 创建交互式 SVG 代码。我不知道这是否是正确的方法:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg"
onkeypress="move()">
<script type="text/javascript">
    <![CDATA[
    var x;
    var y;
    function move()
    {
        x = new Number(svg.getElementsByTagName("circle")[0].getAttribute("cx"));
        y = new Number (svg.getElementsByTagName("circle")[0].getAttribute("cy"));
        switch (event.keyCode)
        {
            case 119:
            y--;
            y = y.toString();
            svg.getElementsByTagName("circle").setAttribute("cy",y);
            break;
            case 115:
            y++;
            y = y.toString();
            svg.getElementsByTagName("circle").setAttribute("cy",y);
            break;
            case 97:
            x--;
            x = x.toString();
            svg.getElementsByTagName("circle").setAttribute("cx",x);
            break;
            case 100:
            x++;
            x = x.toString();
            svg.getElementsByTagName("circle").setAttribute("cx",x);
            break;
            default:
        }
    }
    ]]>
</script>
<rect x="0" y="0" height="500" width="500" style="stroke-width:1; stroke:black; fill:white"></rect>
<circle cx="250" cy="250" r="50" stroke="red" stroke-width="1" fill="red"></circle>
</svg>

本来应该有一个随 wasd 一起移动的球,但球却不动。我做错了什么?

javascript svg interactive
4个回答
75
投票

这是我编写的工作版本:

svg {
  height: 178px;
  width: 600px;
  border: solid 1px;
}
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
  <circle cx="250" cy="100" r="50" fill="red" />
  <script type="text/javascript"><![CDATA[
    var KEY = { w:87, a:65, s:83, d:68 };
    var moveSpeed = 5;
    var circle = document.getElementsByTagName("circle")[0];
    var x = circle.getAttribute('cx')*1,
        y = circle.getAttribute('cy')*1;
    document.documentElement.addEventListener('keydown',function(evt){
      switch (evt.keyCode){
        case KEY.w:
          circle.setAttribute('cy',y-=moveSpeed);
          // Alternatively:
          // circle.cy.baseVal.value = (y-=moveSpeed);
        break;
        case KEY.s:
          circle.setAttribute('cy',y+=moveSpeed);
        break;
        case KEY.a:
          circle.setAttribute('cx',x-=moveSpeed);
        break;
        case KEY.d:
          circle.setAttribute('cx',x+=moveSpeed);
        break;
      }
    },false);
  ]]></script>
</svg>

一些注意事项:

  1. 不要一次又一次地重新获取对圆的引用。让您的代码DRY可以使其更加健壮,减少输入,并且(在这种情况下)执行速度更快。

编辑:如果您无法根据上面的代码弄清楚如何执行此操作,请发布任何不适合您的代码。

  1. 不要依赖全局
    event
    对象;这是老IE的废话。使用传递给事件处理程序的事件对象。

编辑:如果您在代码中引用

event
而没有使用该名称的参数或局部变量,则您假设将存在一个全局
event
对象集。相反,请参阅我为您编写的代码,其中显示事件处理程序传递了一个
event
对象。通过给它一个名称,例如我给它命名为
evt
,您将收到一个特定于您的事件处理程序的事件对象。

  1. 由于您正在修改
    x
    y
    变量,因此无需每次按键时重新获取
    cx
    cy
    属性。

编辑:在您的原始代码和您接受的答案中,您已在事件处理程序之外声明

var x
,并且在事件处理程序的开头有
x = ...
,然后在其中一个事件中声明
x++
处理程序。您可以每次重新获取
x
的当前值(就像您所做的那样)然后
setAttribute(...,x+1)
,或者(就像我所做的那样)您只能在事件处理程序之前获取属性 once 的值,然后假设每次处理按键事件时该值都是正确的。

  1. 不要将 JavaScript 事件处理程序放在元素上,而是以编程方式附加它们。

编辑:在您的 SVG 标记中,您有:

<svg ... onkeypress="move()">
。在 HTML 中将行为与标记混合是一个非常糟糕的主意,在 SVG 中也是一个坏主意。不要使用
onfoo="..."
属性来描述元素上发生事件时应该发生的情况,而是使用
addEventListner()
通过代码附加事件处理程序,而无需编辑 SVG 标记。

  1. 在将数字设置为属性之前,无需将数字强制转换为字符串。

  2. 如果您希望它在所有浏览器中工作,请使用

    keydown
    和我上面提供的 ASCII 事件代码,而不是
    keypress
    和您使用的奇数。

编辑:您在另一篇文章中抱怨说您无法执行此操作,因为您希望在按住按键时重复处理事件处理程序。请注意,您想要的行为是通过我在 Chrome、Safari、Firefox 和 IE 中的示例代码实现的(我没有 Opera 来测试)。换句话说,

keydown
按您想要的方式工作,无论您认为它应该如何表现。

编辑 2:如果您想在文档顶部包含一个脚本块,在创建所有元素之前,您可以执行如下操作:

<svg ...>
  <script type="text/javascript">
    window.addEventListener('load',function(){
      var circle = ...;
      document.rootElement.addEventListener('keydown',function(evt){
        ...
      },false);
    },false);
  </script>
  ...
</svg>

外部函数只会在页面加载后运行,因此您可以确保存在引用它们的元素。


2
投票

您可以通过在 svg 标签中声明 script 标签来将脚本 js 添加到 svg 代码中:

<svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="40px" height="40px" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
     ...
  <script type="text/javascript">
        window.addEventListener('load',function(){
        alert('Hi')
        })
    </script>   

</svg>

1
投票

这适用于 Chrome。您遇到了一些错误,例如有时仅对 getElementsByTagName 建立索引。另外,最大的问题是 onkeypress 属性没有绑定。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg"
>
<script type="text/javascript">
    <![CDATA[

    var x;
    var y;
    function move()
    {
        x = new Number(document.getElementsByTagName("circle")[0].getAttribute("cx"));
        y = new Number (document.getElementsByTagName("circle")[0].getAttribute("cy"));
        switch (event.keyCode)
        {
            case 119:
            y--;
            y = y.toString();
            document.getElementsByTagName("circle")[0].setAttribute("cy",y);
            break;
            case 115:
            y++;
            y = y.toString();
            document.getElementsByTagName("circle")[0].setAttribute("cy",y);
            break;
            case 97:
            x--;
            x = x.toString();
            document.getElementsByTagName("circle")[0].setAttribute("cx",x);
            break;
            case 100:
            x++;
            x = x.toString();
            document.getElementsByTagName("circle")[0].setAttribute("cx",x);
            break;
            default:
        }
    }
    document.documentElement.addEventListener("keypress", move);
    ]]>
</script>
<rect x="0" y="0" height="500" width="500" style="stroke-width:1; stroke:black; fill:white"></rect>
<circle cx="250" cy="250" r="50" stroke="red" stroke-width="1" fill="red"></circle>
</svg>

1
投票

简单示例

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path d="M90,18c-90-45-115,102,0,69v-21l4-3h-23l-8,4h16v19c-80,15-65-106,2-63l-4,5l4-1z" fill="#CCC" stroke="#DDD" stroke-width="2" stroke-linejoin="round"/>
<path d="M87,15c-90-45-115,102,0,69v-21l4-3h-23l-8,4h16v19c-80,15-65-106,2-63l-4,5l4-1z" fill="#00F"/>
<script>
    alert("Hello world");
</script>
</svg>
© www.soinside.com 2019 - 2024. All rights reserved.