如何创建同一JS对象的多个实例,分别控制CSS和DOM元素?

时间:2019-05-16 20:20:47

标签: javascript object

我正处于将对象创建为插件的早期阶段,该插件创建并控制一组{ "name": "pr_test_sql_error_catching", "properties": { "description": "Example pipeline showing how we can catch SQL errors", "activities": [ { "name": "PR_TEST_RAISE_ERROR", "description": "[dbo].[PR_TEST_RAISE_ERROR]", "type": "SqlServerStoredProcedure", "policy": { "timeout": "7.00:00:00", "retry": 0, "retryIntervalInSeconds": 30, "secureOutput": false, "secureInput": false }, "typeProperties": { "storedProcedureName": "[dbo].[PR_TEST_RAISE_ERROR]" }, "linkedServiceName": { "referenceName": "pr_us_programmatic_sql_db", "type": "LinkedServiceReference" } }, { "name": "PR_TEST_LOG_ERROR_CATCHING_When_successful", "description": "[dbo].[PR_TEST_LOG_ERROR_CATCHING]", "type": "SqlServerStoredProcedure", "dependsOn": [ { "activity": "PR_TEST_RAISE_ERROR", "dependencyConditions": [ "Succeeded" ] } ], "policy": { "timeout": "7.00:00:00", "retry": 0, "retryIntervalInSeconds": 30, "secureOutput": false, "secureInput": false }, "typeProperties": { "storedProcedureName": "[dbo].[PR_TEST_LOG_ERROR_CATCHING]", "storedProcedureParameters": { "log_table_name": { "value": "[pr_test_sql_error_catching]", "type": "String" }, "message": { "value": "success", "type": "String" } } }, "linkedServiceName": { "referenceName": "pr_sql_db", "type": "LinkedServiceReference" } }, { "name": "PR_TEST_LOG_ERROR_CATCHING_When_Errored", "type": "SqlServerStoredProcedure", "dependsOn": [ { "activity": "PR_TEST_RAISE_ERROR", "dependencyConditions": [ "Failed" ] } ], "policy": { "timeout": "7.00:00:00", "retry": 0, "retryIntervalInSeconds": 30, "secureOutput": false, "secureInput": false }, "typeProperties": { "storedProcedureName": "[dbo].[PR_TEST_LOG_ERROR_CATCHING]", "storedProcedureParameters": { "log_table_name": { "value": "[pr_test_sql_error_catching]", "type": "String" }, "message": { "value": { "value": "@activity('PR_TEST_RAISE_ERROR').output", "type": "Expression" }, "type": "String" } } }, "linkedServiceName": { "referenceName": "pr_sql_db", "type": "LinkedServiceReference" } } ] }, "type": "Microsoft.DataFactory/factories/pipelines" } DIV元素。目的是让多个实例执行相同的操作,但每个实例仅适用于自己的DIV和INPUT。

第一部分工作正常,如摘要中的黄点所示。

现在,仅当我创建第二个实例时,第一个(红点)才停止工作。第一个对象仍然存在,我可以寻址并设置其参数,只有应该管理的动画已停止。因此,当存在两个对象时,新输入的eventListener不能正常工作,或者我初始化该对象的方式是错误的。在这里我需要帮助。

我要问这个问题,然后再继续使对象的解析器更复杂,因为此后它应该解析并绘制更复杂的多个输入。

如何正确分离两个控制器实例?

摘要:

INPUT
function randomButton(button_id){
	if(button_id=='demo_1'){
		while(MyObject_1.val()==MyObject_1.rand()){}	
	}
	if(button_id=='demo_2'){
		end = MyObject_2.rand();
		start = (end-MyObject_2.rand()).toFixed(2);
		if(start<0){start=0;}
		MyObject_2.val(end+" , "+start);
	}
}

function alertObjectInfo(object){
	text = "";
    if (null == object || "object" != typeof object) return object;
    for (var attr in object) {
        if (object.hasOwnProperty(attr)) text += (object[attr]+"\n");
    }	
	alert(text);
}

/* start of of the plug-in code */
var MyPlugin = ( function (element, id) {
	
	if(id===undefined){ // if no ID is provided genetate a hex string as ID
		id = ("OBJ-"+(new Date).getTime().toString(16)+"_"+(new Date).getMilliseconds().toString(16));
	}

	element.addEventListener('change', function () {
		/* this part of the code will only run if the element input value is changed */
		parser.input = this.value;
		parser.run();
		object.draw(parser.result);
	});
	
	defaults = [];
	defaults['size']	= 24;
	defaults['radius']	= 12;
	defaults['padding']	= 4;
	defaults['bgcolor']	= 'orange';
	defaults['color']	= 'yellow';
	defaults['transition']	= '1s';
		
	/* the part below is the parser engine that converts the input  */
	parser = {
	  input  : null,
	  result : null,
	  mode   : 'single', // default is single
	  run : ( function( value ) {
		  
		if(value){this.input = value;} // use value as new input if a value is provided
				
		if(this.mode==='single' || this.mode==false || this.mode===undefined){
			// parse as a single floating point value 
			this.mode = 'single'; // reset mode in case it was undefined
			this.result = parseFloat(this.input);
			if(this.result > 1){this.result = 1;}
			if(this.result < 0){this.result = 0;}
			return this.result;
		}
	
		if(this.mode==='double' || this.mode==2){
			// parse as two seperete floating point values 
			/* to be continued */
		}
	
	  })
	};

	/* the code below creates an object we can talk to and that will manage sprites  */
	var object = {
	  id		: id,			// optional identifier string useful for debugging
	  init  	: false,		// the switch to test if initialise is already done
	  element  	: element,		// the html element we take out input from 
	  sprites	: [],			// the array of sprite elements generated by this object 
	  parser 	: parser,		// the input parser engine
	  	  
	  /* the object's internal functions */
	  draw : function() { 
		/* the main to draw and move all sprites */
		if(this.init==false){alert('error: object is not properly initialised');return false;}
		
		this.sprites[1].style.width = (this.parser.result*100)+"%";
	  },
		
	  show : function() { 
	  	/* the show all sprites function */
		  element.parentNode.style.display = 'inline';
	  },
	  
	  hide : function() { 
	  	/* the hide all sprites function */
		  element.parentNode.style.display = 'none';
	  },
	  
	  val : function( value ) { 
	  /* the set or get value function */
	  	 if(value===undefined){
			 return element.value;
		 }else{
			element.value = value;
			element.dispatchEvent(new Event('change'));
		 }
	  },
	  
	  rand : function( maxVal, minVal, decVal ) { 
	  /* create and set a random value */
	  	 if(minVal===undefined){minVal = 0;} // default minimum value
	  	 if(maxVal===undefined){maxVal = 1;} // default maximum value
	  	 if(decVal===undefined){decVal = 2;} // default decimal precision
	  	 if(maxVal < minVal){ // invert minimum and maximum if incorrect
		 	offVal = maxVal;
			maxVal = minVal;
			minVal = offVal;
		 }
		 offVal = 1; // set or reset offVal
			for (i = 0; i < decVal; i++) { 
			  offVal = offVal/10;
			}
		 r = (Math.random())*((maxVal+offVal)-(minVal)) + minVal;
		 	if(r>maxVal){r=maxVal;}
		 p = Math.pow(10, decVal);
		 r = Math.floor(r*p) / p;
		 element.value = r;
		 element.dispatchEvent(new Event('change'));
		 return r;
	  },
	  
	  initialise : function() {

		if(this.init==false){
		 /* this part will initialise everything with default values once */			
			wrapper = element.parentNode;
			
			container = document.createElement("div");
			
			container.style.backgroundColor = defaults['bgcolor'];
			container.style.height = defaults['size']+'px';
			container.style.padding = defaults['padding']+'px';
			container.style.boxSizing = 'border-box';
			
			relativeRad = (defaults['size']/2)+'px';
			container.style.borderRadius = (relativeRad+' '+relativeRad+' '+relativeRad+' '+relativeRad);
			
			wrapper.appendChild(container);
			this.sprites.push(container);
			
			mover = document.createElement("div");
			
			mover.style.backgroundColor = 'inherit';
			mover.align = 'right'; // not yet controled by defaults
			mover.style.width = '0%'; // start at 0% always
			mover.style.minWidth = (defaults['size']-(defaults['padding']*2))+'px';
			mover.style.transition = defaults['transition'];
			
			container.appendChild(mover);
			this.sprites.push(mover);
			
			sprite = document.createElement("div");

			sprite.style.backgroundColor = defaults['color'];
			sprite.style.height = (defaults['size']-(defaults['padding']*2))+'px';
			sprite.style.width = (defaults['size']-(defaults['padding']*2))+'px';
			sprite.style.minWidth = (defaults['size']-(defaults['padding']*2))+'px';
			sprite.style.display = 'block';
			sprite.style.boxSizing = 'border-box';
			
			relativeRad = (defaults['size']/3)+'px';

			sprite.style.borderRadius = (relativeRad+' '+relativeRad+' '+relativeRad+' '+relativeRad);
			sprite.style.transition = defaults['transition'];
			sprite.innerHTML = '&nbsp;';
			
			mover.appendChild(sprite);
			this.sprites.push(sprite);
			
			this.init = true;
			return this.init;
		}
	  }
	  
	};

	object.initialise();
	return object;
	
});
/* end of of the plug-in code */


/* MyPlugin init */
var MyObject_1 = new MyPlugin(document.getElementById("demo_input_1"),'Object_1');
var MyObject_2 = new MyPlugin(document.getElementById("demo_input_2"),'Object_2');

// test if we can address sprites of the first object after creating a second object
MyObject_1.sprites[2].style.backgroundColor = 'red';
.item-wrap{
	background-color: #999;
	border:0;
	border-radius: 8px;
	padding: 16px;
	margin-bottom: 8px;
}
.demo_input{
	border:0;
	color:white;
	font-size:18px;
	padding:8px;
	background-color:transparent;
	width:100%; 
	box-sizing:border-box; 
	text-align:left
}
.item-text{
	border:0;
	color:white;
	font-size:18px;
	font-family:Avenir, Tahoma, sans-serif;
	padding-left:4px;
	padding-top:8px;
	width:100%; 
	box-sizing:border-box; 
	text-align:left
}

预期结果是“ MyObject_1”将控制标记为ID“ demo_1_wrap”的DIV中的所有元素,第二个实例“ MyObject_2”将对标记为“ demo_2_wrap”的DIV进行相同操作。

2 个答案:

答案 0 :(得分:0)

此处根据最近的一些评论更改了代码。目前,此功能适用于Firefox 66版,但使用的是旧版浏览器(例如, Safari 9.1。此代码在this.element.addEventListener('change', () => {

行显示语法错误

如何通过向后兼容来解决最后一个问题?

更新的代码段:

function processButton(button_id) {
  if (button_id == 'demo_1') {
    window.MyObject_1.val(window.MyObject_1.rand());
  }
  if (button_id == 'demo_2') {
    var end = MyObject_2.rand();
    var start = (end - MyObject_2.rand()).toFixed(2);
    if (start < 0) {
      start = 0;
    }
    window.MyObject_2.val(end + " , " + start);
  }
  if (button_id == 'color_2') {
    var r = window.MyObject_2.rand(0, 4096, 0).toString(16);
    window.MyObject_2.val(window.MyObject_2.val() + ' , color:#' + r);

  }
  if (button_id == 'label_2') {
    window.MyObject_2.val(window.MyObject_2.val() + ' , label:%');
    window.MyObject_2.val(window.MyObject_2.val() + ' , labelcolor:black');
  }
}
window.processButton = processButton;

function alertObjectInfo(object) {
  text = "";
  if (null == object || "object" != typeof object) return object;
  for (var attr in object) {
    if (object.hasOwnProperty(attr)) text += (object[attr] + "\n");
  }
  alert(text);
}

window.alertObjectInfo = alertObjectInfo;

/* start of of the plug-in concept code */
var MyPlugin = function(element, id) {
  this.element = element;
  if (id === undefined) { // if no ID is provided genetate a hex string as ID
    this.id = (("OBJ_" + (new Date).getTime().toString(16) + "_" + (new Date).getMilliseconds().toString(16)));
  } else {
    this.id = id;
  }

  this.element.addEventListener('change', () => {
    /* this part of the code will only run if the element input value is changed */
    this.parser.run(this.element.value);
    console.log();
    this.draw();
  });

  this.defaults = [];
  this.defaults['size'] = 30;
  this.defaults['radius'] = 30;
  this.defaults['padding'] = 5;
  this.defaults['bgcolor'] = 'orange';
  this.defaults['color'] = 'yellow';
  this.defaults['transition'] = 888; // in milliseconds

  /* the part below is the parser engine that converts the input  */
  this.parser = {
    input: null,
    result: null,
    mode: null,
    run: (function(value) {

      if (value) {
        this.input = value; // use value as new input if a value is provided
      }

      /* auto detect parser mode based on input style */
      if (this.input.indexOf("]") >= 0) {
        this.mode = 'cumulative';
      } else if (this.input.indexOf(")") >= 0) {
        this.mode = 'nested';
      } else if (this.input.indexOf(",") >= 0) {
        this.mode = 'multi';
      } else {
        this.mode = 'single';
      }

      this.result = []

      if (this.mode === 'single' || this.mode == 1 || !this.mode) {
        // parse as a single floating point value 
        this.mode = 'single'; // reset mode in case it was undefined
        this.result.push(parseFloat(this.input));
        if (this.result[0] > 1) {
          this.result[0] = 1;
        }
        if (this.result[0] < 0) {
          this.result[0] = 0;
        }
      }

      if (this.mode === 'multi' || this.mode == 2) {
        // parse as seperate floating point values 
        this.mode = 'multi'; // reset mode in case it defined as 2
        let splitted;
        splitted = this.input.split(',');
        let opt = {};
        for (var i = 0, len = splitted.length; i < len; i++) {
          if (i < 2) {
            this.result.push(parseFloat(splitted[i]));
          } else {
            // if more than 2 values the rest are option parameters
            let arr = (splitted[i]).split(':');
            let key = arr[0].trim();
            let str = arr[1].trim();
            opt[key] = str;
          }
        }
        this.result[2] = opt; // add merged options to result
      }

      if (this.mode === 'nested' || this.mode == 3) {
        // parse as seperate floating point values 
        this.mode = 'nested'; // reset mode in case it defined as 3
        let splitted;
        /* to be continued */
      }

      if (this.mode === 'cumulative' || this.mode == 4) {
        // parse as seperate floating point values 
        this.mode = 'cumulative'; // reset mode in case it defined as 4
        let splitted;
        /* to be continued */
      }

      console.log(this.result);
      return this.result;

    })
  };
  this.init = false;
  this.sprites = [];
  
  this.draw = () => {
    /* the main function to draw and move all sprites */
    if (this.init == false) {
      alert('error: object is not properly initialised');
      return false;
    }
    console.log(this.sprites, this.parser.result)
    if (this.parser.mode === 'single') {
      this.sprites[1].style.width = (this.parser.result[0] * 100) + "%";
    }
    if (this.parser.mode === 'multi') {
      let end = this.parser.result[0];
      let start = this.parser.result[1];
      var opt = this.parser.result[2];
      let rel;
      if (end <= start) {
        rel = 0;
      } else {
        rel = ((end - start) / end).toFixed(2);
      }
      this.sprites[1].style.width = (end * 100) + "%";
      this.sprites[2].style.width = (rel * 100) + "%";

      // now process additional options
      if (!opt.label) {
        this.sprites[2].innerHTML = '&nbsp;';
      } else {
        let label = opt.label.replace("%", (parseInt(100 * (end - start))) + ' %');
        this.sprites[2].innerHTML = label;
      }
      // check for custom sprite color 
      if (opt.color) {
        this.sprites[2].style.backgroundColor = opt.color;
      }
      // check for custom text color 
      if (opt.labelcolor) {
        this.sprites[2].style.color = opt.labelcolor;
      }

    }
  }
  this.show = () => {
    this.element.parentNode.style.display = 'inline';
  }
  this.hide = () => {
    this.element.parentNode.style.display = 'none';
  }
  this.val = (value) => {
    if (!value) {
      return this.element.value;
    } else {
      this.element.value = value;
      this.element.dispatchEvent(new Event('change'));
    }
  }

  this.rand = (maxVal = 1, minVal = 0, decVal = 2) => {
    let offVal;
    if (maxVal < minVal) {
      offVal = maxVal;
      maxVal = minVal;
      minVal = offVal;
    }
    offVal = 1;
    for (i = 0; i < decVal; i++) {
      offVal = offVal / 10;
    }
    let r = (Math.random()) * ((maxVal + offVal) - (minVal)) + minVal;
    if (r > maxVal) {
      r = maxVal;
    }
    let p = Math.pow(10, decVal);
    r = Math.floor(r * p) / p;
    return r;
  }
  this.initialize = () => {
    if (!this.init) {
      this.wrapper = this.element.parentNode;
      this.container = document.createElement('div');
      this.container.style.backgroundColor = this.defaults['bgcolor'];
      this.container.style.padding = `${this.defaults['padding']}px`;
      this.container.style.boxSizing = 'border-box';
      let relativeRad = (this.defaults['size'] / 2) + 'px';
      this.container.style.borderRadius = (relativeRad + ' ' + relativeRad + ' ' + relativeRad + ' ' + relativeRad);
      this.wrapper.appendChild(this.container);
      this.sprites = this.sprites.concat(this.container);
      this.mover = document.createElement('div');
      this.mover.style.backgroundColor = 'transparent';

      this.mover.align = 'right';
      this.mover.style.width = '0%'
      this.mover.style.minWidth = (this.defaults['size'] - (this.defaults['padding'] * 2)) + 'px';
      this.mover.style.transition = parseInt(this.defaults['transition']) + 'ms';

      this.container.appendChild(this.mover);
      this.sprites = this.sprites.concat(this.mover);

      this.sprite = document.createElement('div');
      this.sprite.style.backgroundColor = this.defaults['color'];
      this.sprite.style.height = (this.defaults['size'] - (this.defaults['padding'] * 2)) + 'px';
      this.sprite.style.width = (this.defaults['size'] - (this.defaults['padding'] * 2)) + 'px';
      this.sprite.style.minWidth = (this.defaults['size'] - (this.defaults['padding'] * 2)) + 'px';
      this.sprite.style.display = 'block';
      this.sprite.style.boxSizing = 'border-box';
      this.sprite.className += " sprite-text";
      this.sprite.style.overflow = 'hidden';
      this.sprite.style.textAlign = 'center';
      this.sprite.style.top = (this.defaults['padding']);
      this.sprite.style.fontSize = parseInt(this.defaults['size'] - (this.defaults['padding'] * 3)) + 'px';
      this.sprite.style.padding = (this.defaults['padding'] / 2);
      relativeRad = (this.defaults['size'] / 2) + 'px';
      this.sprite.style.borderRadius = (relativeRad + ' ' + relativeRad + ' ' + relativeRad + ' ' + relativeRad);
      this.sprite.style.transition = parseInt(this.defaults['transition'] / 2) + 'ms';
      this.sprite.innerHTML = '&nbsp;';

      this.mover.appendChild(this.sprite);
      this.sprites = this.sprites.concat(this.sprite);
      this.init = true;
      return this.init;
    }
  }
  /* the part below finalizes the object setup  */
  this.initialize();
  return this;

};
/* end of of the plug-in code */


/* MyPlugin init */
window.MyObject_1 = new MyPlugin(document.getElementById("demo_input_1"), 'Object_1');
window.MyObject_2 = new MyPlugin(document.getElementById("demo_input_2"), 'Object_2');

// test if we can address sprites of the first object after creating a second object
MyObject_1.sprites[2].style.backgroundColor = 'green';
.item-wrap 
{ background-color: #999; border: 0; border-radius: 8px; padding: 16px; margin-bottom: 8px;}
.demo_input 
{ border: 0; color: white; font-size: 18px; padding: 8px; background-color: transparent; width: 100%; box-sizing: border-box; text-align: left}
.item-text 
{ border: 0; color: white; font-size: 18px; font-family: Avenir, Tahoma, sans-serif; padding-left: 4px; padding-top: 8px; width: 100%; box-sizing: border-box; text-align: left}
.sprite-text
{ font-family: Tahoma, sans-serif; text-align: center;}
<div class="item-wrap">
  <div class="item-text">
    <strong>Progress animation based on more values</strong><br>
    <small>The first value still sends the animation to a relative point between 0 and 1. 
	The second value streches the animated sprite to an offset starting point.</small><br>
  </div>
  <div id="demo_1_wrap" class="demo">
    <input id="demo_input_2" class="demo_input" type="text" value="0 , 0">
  </div>
  <p>
    <input type="button" name="show" value="show object" onClick="window.MyObject_2.show()">
    <input type="button" name="hide" value="hide object" onClick="window.MyObject_2.hide()">
    <input type="button" name="rand" value="set random" id="demo_2" onClick="window.processButton(this.id)">
    <input type="button" name="label" value="change color" id="color_2" onClick="processButton(this.id)">
    <input style="float:right" type="button" name="label" value="show label" id="label_2" onClick="window.processButton(this.id)">
  </p>
</div>
<div class="item-wrap">
  <div class="item-text">
    <strong>Progress animation based on a single input</strong><br>
    <small>The input value sends the animation to a relative point between 0 and 1. 
	Empty or wrong input does nothing, where 1 or higher shows the animation at 100%</small><br>
  </div>
  <div id="demo_1_wrap" class="demo">
    <input id="demo_input_1" class="demo_input" type="text" value="0" />
  </div>
  <p>
    <input type="button" name="show" value="show object" onClick="window.MyObject_1.show()">
    <input type="button" name="hide" value="hide object" onClick="window.MyObject_1.hide()">
    <input type="button" name="demo_" value="set random" id="demo_1" onClick="window.processButton(this.id)">
  </p>
</div>

答案 1 :(得分:0)

IE 11也显示了很多语法问题-为什么不使用常见的IIFE? (IIFEs on MDN)your error is just a listener parameter。 我的解决方法是至少在以下位置打开您的脚本

Line# in the script / new content
138  this.draw = function (){
179  this.show = function (){
182  this.hide = function (){
185  this.val = function(value) {
194  this.rand = function(maxVal, minVal,decVal) {
would tell no support for default parameters - maybe check for undefined(?)
214  this.initialize = function (){
219      this.container.style.padding = "${this.defaults['padding']}px";
(wrong quotations here)