在 SVG 中包含 JavaScript

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5378559/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:56:24  来源:igfitidea点击:

Including JavaScript in SVG

javascriptsvginteractive

提问by mortalc

I am trying to create an interactive SVG code with JavaScript, by embedding the JavaScript in the SVG. I don't know if this is the right way to do this:

我正在尝试通过将 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>

It is supposed to have a ball that moves with wasd, but the ball doesn't move. What am I doing wrong?

它应该有一个与 wasd 一起移动的球,但球没有移动。我究竟做错了什么?

回答by Phrogz

Here is a working version as I would write it:

这是我编写的工作版本:

<!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="250" 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>

Some notes:

一些注意事项:

  1. Don't re-get the reference to the circle again and again. Making your code DRYmakes it more robust, less typing, and (in this case) faster to execute.

    Edit: If you cannot figure out how to do this given my code above, post any code that is not working for you.

  2. Don't rely on a global eventobject; that's old IE nonsense. Use the event object passed to your event handler.

    Edit: If you reference eventin your code with no parameter or local variable by that name, you are assuming that there will be a global eventobject set. Instead, see the code I wrote for you, which shows that the event handler is passed an eventobject. By giving that a name, such as I gave it the name evt, you are receiving an event object specific to your event handler.

  3. Since you are modifying the xand yvariables, there's no need to re-get the cxand cyattributes each key press.

    Edit: In your original code and the answer you accepted, you have declared var xoutside your event handler, and you have x = ...at the start of your event handler, and then x++in one of the event handlers. You can either re-get the current value of xeach time (as you did) and then setAttribute(...,x+1), or (as I did) you can only fetch the value of the attribute oncebefore the event handlers and then assume that this value is correct each time you handle the key event.

  4. Don't put your JavaScript event handlers on your elements, attach them programmatically.

    Edit: In your SVG markup you have: <svg ... onkeypress="move()">. Mixing your behavior with your markup is a really bad idea in HTML, and a bad idea in SVG. Instead of using onfoo="..."attributes to describe what should happen when an event occurs on an element, instead use addEventListner()to attach the event handlers via code, without editing your SVG markup.

  5. There's no need to coerce the numbers to strings before setting them as attributes.

  6. Use keydownand the ASCII event codes I supplied above instead of keypressand the odd numbers you were using if you want it to work in all browsers.

    Edit: You complained in another postthat you cannot do this because you want the event handler to be processed repeatedly as the key is held down. Note that your desired behavior is achieved with my sample code in Chrome, Safari, Firefox, and IE (I don't have Opera to test). In other words keydownworks as you wanted, despite how you thought it should behave.

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

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

  2. 不要依赖一个全局event对象;那是旧的 IE 废话。使用传递给事件处理程序的事件对象。

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

  3. 由于您正在修改xy变量,因此无需在每次按键时重新获取cxcy属性。

    编辑:在您的原始代码和您接受的答案中,您已var x在事件处理程序之外声明,并且x = ...在事件处理程序的开头,然后x++在事件处理程序之一中声明。您可以重新获取x每次的当前值(如您所做的那样)然后setAttribute(...,x+1),或者(如我所做的那样)您只能在事件处理程序之前获取一次属性的值,然后假设该值每次都是正确的你处理关键事件。

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

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

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

  6. 如果您希望它在所有浏览器中工作,请使用keydown我在上面提供的 ASCII 事件代码,而不是keypress您使用的奇数。

    编辑:您在另一篇文章中抱怨说您不能这样做,因为您希望在按住键时重复处理事件处理程序。请注意,您想要的行为是通过我在 Chrome、Safari、Firefox 和 IE 中的示例代码实现的(我没有要测试的 Opera)。换句话说keydown,无论您认为它应该如何表现,都可以按您的意愿工作。

Edit 2: If you want to include a script block at the top of your document, before all elements have necessarily been created, you can do something like the following:

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

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

The outer function will only run once the page has loaded, so you can be sure that the elements exist to reference them.

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

回答by Josh Pearce

This works in Chrome. You had a few errors, like indexing getElementsByTagName only sometimes. Plus the big problem was that the onkeypress attribute wasn't binding.

这适用于 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>

回答by BERGUIGA Mohamed Amine

you can add script js into svg code by declare script tag into svg tag:

您可以通过将脚本标签声明为 svg 标签来将脚本 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>