使用JavaScript

时间:2016-07-13 05:40:27

标签: javascript class svg this

我甚至可以在广场上添加收听功能,提醒我这是我的名字'点击后。

我的问题是: 我需要执行animate功能,而不是仅仅发出警报,以便每个项目在点击它时开始移动



var NS="http://www.w3.org/2000/svg";     
var SVG=function(h,w){
    var svg=document.createElementNS(NS,"svg");
    svg.width=w;
    svg.height=h;
return svg;
}
var svg=SVG(1200,1500);
document.body.appendChild(svg);


var rect=function(x,y,h,w,fill,name){
    var SVGObj= document.createElementNS(NS,"rect");
    SVGObj.x.baseVal.value=x;
    SVGObj.y.baseVal.value=y;
    SVGObj.width.baseVal.value=w;
    SVGObj.height.baseVal.value=h;
    SVGObj.setAttribute("height",h);
    SVGObj.style.fill=fill;
    SVGObj["my-name"] = name;
    SVGObj.name = name;
return SVGObj;
}


for (var i = 0; i < 100; i++) {
    var x = Math.random() * 500,
        y = Math.random() * 300;
  
    var r= rect(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16),'this is my name');
    r.addEventListener('click', ()=>alert(r.name));  // or r["my-name"]
    svg.appendChild(r);
}

var animate=function(obj){
    obj.x.baseVal.value+=1;
    obj.y.baseVal.value+=1;
 }
&#13;
&#13;
&#13;

3 个答案:

答案 0 :(得分:1)

为了使这项工作正常,你应该将事件传递给回调函数,然后使用event.target来获取被点击的元素。

您的初始代码不起作用的原因是您传递了r变量,该变量未包含在任何函数范围内,因此当您实际单击矩形时r始终等于最后添加的元素。 为了避免将来发生这种情况,您应该阅读closureshoisting

var NS="http://www.w3.org/2000/svg";     
var SVG=function(h,w){
    var svg=document.createElementNS(NS,"svg");
    svg.width=w;
    svg.height=h;
return svg;
}
var svg=SVG(1200,1500);
document.body.appendChild(svg);


var rect=function(x,y,h,w,fill,name){
    var SVGObj= document.createElementNS(NS,"rect");
    SVGObj.x.baseVal.value=x;
    SVGObj.y.baseVal.value=y;
    SVGObj.width.baseVal.value=w;
    SVGObj.height.baseVal.value=h;
    SVGObj.setAttribute("height",h);
    SVGObj.style.fill=fill;
    SVGObj["my-name"] = name;
    SVGObj.name = name;
return SVGObj;
}


for (var i = 0; i < 100; i++) {
    var x = Math.random() * 500,
        y = Math.random() * 300;
  
    var r= rect(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16),'this is my name');
    r.addEventListener('click', (e)=>animate(e));  // or r["my-name"]
    svg.appendChild(r);
}
var animate=function(e){
    e.target.x.baseVal.value+=1;
    e.target.y.baseVal.value+=1;
 }

答案 1 :(得分:1)

您应该在animate(e.target)内拨打r.addEventListener('click',(e)=>...),如下所示。您应该将e.target作为参数传递给函数,否则您将自行传递事件,并且事件没有xy属性。

var NS="http://www.w3.org/2000/svg";     
var SVG=function(h,w){
    var svg=document.createElementNS(NS,"svg");
    svg.width=w;
    svg.height=h;
return svg;
}
var svg=SVG(1200,1500);
document.body.appendChild(svg);


var rect=function(x,y,h,w,fill,name){
    var SVGObj= document.createElementNS(NS,"rect");
    SVGObj.x.baseVal.value=x;
    SVGObj.y.baseVal.value=y;
    SVGObj.width.baseVal.value=w;
    SVGObj.height.baseVal.value=h;
    SVGObj.setAttribute("height",h);
    SVGObj.style.fill=fill;
    SVGObj["my-name"] = name;
    SVGObj.name = name;
return SVGObj;
}


for (var i = 0; i < 100; i++) {
    var x = Math.random() * 500,
        y = Math.random() * 300;
  
    var r= rect(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16),'this is my name');
    r.addEventListener('click', function(e){
      console.log(e.target.name);
      console.log(e.target.x.baseVal.value);
      animate(e.target); // Pass the event's target as argument
      console.log(e.target.x.baseVal.value);
    });  
    svg.appendChild(r);
}
var animate=function(obj){
    obj.x.baseVal.value+=1;
    obj.y.baseVal.value+=1;
 }

我还添加了一些console.log()语句来显示动画对象的结果,因为有时很难看到1px移动:

答案 2 :(得分:1)

感谢@Maksyum和@Angelos,我发现以下方法可以正常工作,因此我使用e.target重新构建模块而不是this。在为我的案例标记最合适的选项之前,我会进一步评估这两个选项,如果有人对此方法感兴趣或有任何意见,请在此处提及。

&#13;
&#13;
var NS="http://www.w3.org/2000/svg";     
var SVG=function(h,w){
    var svg=document.createElementNS(NS,"svg");
    svg.width=w;
    svg.height=h;
return svg;
}
var svg=SVG(1200,1500);
document.body.appendChild(svg);


function myRect(x,y,h,w,fill,name){
   this.name=name;
   this.SVGObj= document.createElementNS(NS,"rect");
   this.SVGObj.x.baseVal.value=x;
   this.SVGObj.y.baseVal.value=y;
   this.SVGObj.width.baseVal.value=w;
   this.SVGObj.height.baseVal.value=h;
   this.SVGObj.style.fill=fill;
   this.SVGObj.addEventListener("click",this,false);
   this.handleEvent= function(evt){
      switch (evt.type){
        case "click":
          //  alert(this.name); // this.animate();
          var move = setInterval(()=>this.animate(),100);
        break;
      }
    }
/* Use either this.animate or myRect.prototype.animate for the animation, As I prefer using the prototype function the `this` method here is inactive
    this.animate=function(){
       this.SVGObj.x.baseVal.value+=1;
       this.SVGObj.y.baseVal.value+=1;
 }
*/
return this.SVGObj;
}

myRect.prototype.animate = function() {
   this.SVGObj.x.baseVal.value+=1;
   this.SVGObj.y.baseVal.value+=1;
};

for (var i = 0; i < 100; i++) {
    var x = Math.random() * 500,
        y = Math.random() * 300;
  
    var r= new myRect(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16),'this is my name');
    svg.appendChild(r);
}
&#13;
&#13;
&#13;

<强>更新 我发现使用ES6(ECMAScript 2015)中提供的JavaScript类可以获得相同的内容,下面是使用类的完整代码:

&#13;
&#13;
var NS="http://www.w3.org/2000/svg";     
var SVG=function(h,w){
    var svg=document.createElementNS(NS,"svg");
    svg.width=w;
    svg.height=h;
return svg;
}
var svg=SVG(1200,1500);
document.body.appendChild(svg);

class myRect {
  constructor(x,y,h,w,fill,name) {
   this.name=name;
   this.SVGObj= document.createElementNS(NS,"rect");
   self = this.SVGObj;
      self.x.baseVal.value=x;
      self.y.baseVal.value=y;
      self.width.baseVal.value=w;
      self.height.baseVal.value=h;
      self.style.fill=fill;
      self.addEventListener("click",this,false);
  }

/* Use either get or Object.defineProperty of a prototype to make the getter / return of the shape/node, As i prefer using the prototype function the `get` method here is inactive
 
  get node() {
    return this.SVGObj;
  }
*/
}

Object.defineProperty(myRect.prototype, "node", {
get: function() {
    return this.SVGObj;
}
/* you can use this for making setter also if required, like below
,
  set: function(value) {
  name = value;
}
*/
});

/* OR another way to define getter / setter using Object property:
var pattern = {
get: function () {
    return this.SVGObj;
},
set: function () {
    name = value;
}
};

Object.defineProperty(myRect.prototype, 'node', pattern);  // myRect.prototype === this
*/

myRect.prototype.handleEvent= function(evt){
self = this.SVGObj;
  switch (evt.type){
    case "click":
       // alert(this.name); // this.animate();    
       if (typeof self.moving == 'undefined' || self.moving == false) self.moving = true;
       else self.moving = false;
 
     if(self.moving == true)
       self.move = setInterval(()=>this.animate(),100);
       else{
       clearInterval(self.move); 
       self.parentNode.removeChild(self);
       }        
    break;
    default:
    break;
 }
}  

myRect.prototype.step = function(x,y) {
   return svg.createSVGTransformFromMatrix(svg.createSVGMatrix().translate(x,y));
}

myRect.prototype.animate = function() {
       self = this.SVGObj;
              self.transform.baseVal.appendItem(this.step(1,1));
   // Or the below can be used instead of the custom function `step`
   //    self.x.baseVal.value+=1;
   //    self.y.baseVal.value+=1;
};

for (var i = 0; i < 100; i++) {
    var x = Math.random() * 500,
        y = Math.random() * 300;
  
    var r= new myRect(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16),'this is my name');
    svg.appendChild(r.node);
}
&#13;
&#13;
&#13;