hansontable编辑器--学习笔记

Handsontable 主要可以分为两大块,渲染器(负责显示数据)和编辑器(负责修改数据)。
由于渲染器的任务比较简单,只是获取单元格的值并将其作为HTML代码返回,所以它们可以是单个函数。而编辑器需要处理用户输入(即鼠标和键盘事件)、验证数据并根据验证结果进行操作,因此将所有这些功能放在一个函数中是不现实的,所以Handsontable编辑器是由编辑器类来表示。

接下来我们看下Handsontable Core是如何管理编辑器,编辑器生命周期是怎样的,最后是如何创建您自己的编辑器。

EditorManager

EditorManager是负责处理Handsontable中所有可用编辑器的类。Core需要与它使用EditorManager对象的编辑器进行交互。
第一次调用handsontable()构造函数之后,会在init()方法中实例化EditorManager对象。
EditorManager对象的引用在Handsontable实例中是私有的,因此不能在外部访问它。

EditorManager有4个主要任务

1:为活动单元选择适当的编辑器
当用户选择单元编辑器时,找到分配给这个单元的编辑器类,检查编辑器属性的值。
您可以全局地定义编辑器属性(针对表中的所有单元格)、每个列(针对列中的所有单元格)或单独地定义每个单元格

2:准备要显示的编辑器
当EditorManager获得编辑器类实例(编辑器对象)时,它将调用其准备方法。
prepare方法设置与所选单元格相关的编辑器对象属性,但不显示编辑器。
每次用户选择单元时,都会调用prepare。在某些情况下,可以为同一个单元多次调用它,而无需更改选择。

3:显示编辑器(基于用户行为)
编辑器准备好后,编辑器管理器将等待触发单元格edition的用户事件。
这些事件是:按下ENTER, 双击单元格,按F2,如果其中一个事件被触发,EditorManager将调用editor的beginEditing()方法,该方法将显示编辑器。

4:关闭编辑器(基于用户行为)。
当编辑器打开时,编辑器管理器等待应该结束单元格版本的用户事件。
这些事件:
点击另一个单元格(保存更改)
按ENTER (保存更改)
按ESC(中止)变化
按下ARROW UP, ARROW DOWN, ARROW LEFT, ARROW RIGHT(保存更改)
按下TAB(保存更改)
按下HOME,END (保存更改)
按PAGE UP, PAGE DOWN (保存更改)
如果任何这些事件被触发,EditorManager调用编辑finishEditing()方法,它应该保存更改(除非ESC键被按下)并关闭编辑器。

覆盖EditorManager默认行为

您可能想要更改导致编辑器打开或关闭的默认事件。
例如,您的编辑器可能使用箭头UP和箭头DOWN事件来执行一些操作(例如增加或减少单元格值),并且当用户按下这些键时,您不希望EditorManager关闭编辑器。这就是为什么EditorManager在处理用户事件之前在keydown hook之前运行。如果您注册了一个监听器,那么在事件对象EditorManager上调用stopImmediatePropagation()将不会执行它的默认动作。

您现在应该对EditorManager的工作原理有了更好的理解。让我们深入一点,看看每个编辑器类必须实现什么方法,以及这些方法做什么。

每个编辑器类必须实现什么方法

BaseEditor
Handsontable.editors.BaseEditor是一个抽象类,所有编辑类都应该继承它。它实现了一些基本的编辑器方法,并声明了一些应该由每个编辑器类实现的方法。
Common methods
常用方法,是由BaseEditor类实现的方法。它们包含了每个编辑器应该有的核心逻辑。大多数时候,你不应该用这些方法。但是,如果您正在创建一些更复杂的编辑器,您可能想要覆盖一些常用的方法,在这种情况下,您应该总是调用原始的方法,然后执行其他操作,特定于您的编辑器。

示例-覆盖通用方法

// CustomEditor是一个类函数,继承了BaseEditor
CustomEditor.prototype.prepare = function(row, col, prop, td, originalValue, cellProperties){
  // 调用原方法…… 
  Handsontable.editors.BaseEditor.prototype.prepare.apply(this, arguments);
  // ......然后做一些特定于你的定制编辑器
  this.customEditorSpecificProperty = 'foo';
};

有7种常用的方法。下面将对它们进行描述。

prepare(row: Number, col: Number, prop: String, td: HTMLTableCellElement, cellProperties: Object)
为每个单元格准备编辑器,设置大多数实例属性。
Returns: undefined

beginEditing(initialValue: ‘String’ [optional] )
将编辑器值设置为initialValue。如果initialValue未定义,则编辑器值设置为原始单元格值。在内部调用open()方法。
Returns: undefined

finishEditing(revertToOriginal: ‘Boolean’ [optional], ctrlDown: Boolean [optional], callback: Function)
在内部调用saveValue()和expdeditor()

discardEditor(validationResult: Boolean)
当单元格验证结束时调用。如果成功地保存了新值(validationResult被设置为true或者允许无效属性为true),它调用close()方法,否则调用focus()方法并保持编辑器打开。
Returns: undefined

saveValue(val: Mixed, ctrlDown: Boolean)
尝试将val保存为新的单元格值。在内部执行验证。如果按下ctrl键,新值将被设置为所有选定的单元格。
Returns: undefined

isOpened()
编辑器是打开就返回true,编辑器关闭就返回false.
Returns: Boolean

extend()
Returns: Function –继承当前类的类函数。返回的类的原型方法可以安全地重写,而不需要更改父类的原型。

例——继承BaseEditor并覆盖其方法

var CustomEditor = Handsontable.editors.BaseEditor.prototype.extend();
// 这不会改变BaseEditor.prototype.beginEditing()
CustomEditor.prototype.beginEditing = function() {};

例——从另一个编辑器继承

var CustomTextEditor = Handsontable.editors.TextEditor.prototype.extend();
 //CustomTextEditor使用由TextEditor实现的所有方法. 
// 您可以安全地覆盖任何方法,而不影响原始的TextEditor.

注意:这是一个与编辑单元的过程无关的实用方法.

Editor specific methods 编辑特定的方法

编辑器的具体方法是在BaseEditor中没有实现的方法。为了工作,每个编辑器类都必须实现这些方法。

init()
当创建编辑器类的新实例时调用方法。这在每个表实例中最多发生一次,因为所有的编辑器都是表实例中的单例。您应该使用这种方法来执行在编辑器生命周期中可以重用的任务。最常见的操作是创建编辑器的HTML结构。方法不需要返回任何值。

getValue()
返回当前编辑器的值,这是应该保存为新单元值的值。

setValue(newValue: ‘Mixed’)
将编辑器值设置为newValue。
例如,假设我们正在实现一个DateEditor,它通过显示日历来帮助选择日期。getValue()和setValue()方法可以这样工作

CalendarEditor.prototype.getValue = function() {
  return calendar.getDate(); // 返回当前选定的日期,例如"2013/09/15"
};
CalendarEditor.prototype.setValue = function(newValue) {
  calendar.highlightDate(newValue); // 日历上给定日期的高亮
};

open()
显示编辑器。

CustomEditor.prototype.open = function() {
  this.editorDiv.style.display = '';
};

close()
在改变了单元格值之后,隐藏编辑器。

CustomEditor.prototype.close = function() {
  this.editorDiv.style.display = 'none';
};

focus()
当用户想要通过选择另一个单元来关闭编辑器时,这个方法就会被调用,而编辑器中的值不会验证(并且允许无效是错误的)。

CustomEditor.prototype.focus = function() {
  this.editorInput.focus();
};

常见的编辑属性

所有下面提到的属性都可以通过编辑器实例获得。this object (e.g. this.instance).
nstance `Object:Handsontable.Core’
这个编辑器对象所属的Handsontable实例。在类构造函数中设置,编辑器的整个生命周期都是不变的。

row Number
活动单元格行索引。在每个prepare()方法调用中更新。

col Number
活动单元格列索引。在每个prepare()方法调用中更新。

prop String
与活动单元相关的属性名称(仅在数据源是对象数组时相关)。在每个prepare()方法调用中更新

TD HTMLTableCellNode
活动单元的节点对象。在每个prepare()方法调用中更新。

cellProperties ‘Object’
表示活动单元格属性的对象。在每个prepare()方法调用中更新。

如何创建自定义编辑器

基本上,您可以从头开始构建一个新的编辑器,通过创建一个新的编辑器类,它继承了BaseEditor,或者如果您只是想增强现有的编辑器,您可以扩展它的类,并且只覆盖它的一些方法。
我们将研究这两种方法。我们将创建一个全新的SelectEditor,它使用列表来改变单元格的值。我们还将创建一个PasswordEditor,它的工作方式与普通的TextEditor完全一样,只是它显示了一个密码输入而不是textarea。

PasswordEditor——扩展现有的编辑器
TextEditor是默认情况下在Handsontable中可用的最复杂的编辑器。它显示了一个 它会自动改变大小以适应它的内容。我们想要创造一个 PasswordEditor 它保留了所有这些功能,但显示了 而不是 .
我们需要创建一个新的编辑器类,它继承自TextEditor。然后重写一些方法,用input:password替换textareao。幸运的是,textarea和password具有相同的API,因此,我们所要做的就是替换负责创建HTML元素的代码。如果你看一看TextEditor init()方法,你会注意到它调用内部 createElements(),方法,该方法创建在编辑器初始化期间将其附加到DOM。

var PasswordEditor = Handsontable.editors.TextEditor.prototype.extend();

PasswordEditor.prototype.createElements = function () {
  // // 调用原始create element方法
  Handsontable.editors.TextEditor.prototype.createElements.apply(this, arguments);

  // 创建密码输入并更新相关属性
  this.TEXTAREA = document.createElement('input');
  this.TEXTAREA.setAttribute('type', 'password');
  this.TEXTAREA.className = 'handsontableInput';
  this.textareaStyle = this.TEXTAREA.style;
  this.textareaStyle.width = 0;
  this.textareaStyle.height = 0;

  // Replace textarea with password input
  Handsontable.dom.empty(this.TEXTAREA_PARENT);
  this.TEXTAREA_PARENT.appendChild(this.TEXTAREA);
};

就是这样!你现在可以使用你的新编辑器。

var hot = new Handsontable(document.getElementById('container'), {
  data: someData,
  columns: [
    {
      type: 'text'
    },
    {
      editor: PasswordEditor
      // 如果您想使用字符串'password'而不是通过实际的编辑器类检查“注册编辑器"
    }
  ]
});

现在让我们从头开始构建新的编辑器。

SelectEditor——从头创建编辑器
我们将构建一个完整的功能编辑器,它允许用户使用标准的输入来从预定义的中选择一个单元格值。作为一个额外的特性,我们将添加一种功能,可以使用箭头向上和向下键来改变当前选择的选项。
我们需要做的事情
1:创建一个继承自Handsontable.editors.BaseEditor的新类。
2:添加 并附加到DOM。
3:通过在单元格属性中传递的选项数组填充填充函数。
4:实现方法
getValue()
setValue()
open()
close()
focus()
5:覆盖默认的EditorManager行为,因此按下箭头和向下的键不会关闭编辑器,而是改变当前选择的值。
6:注册编辑器。

创建新的编辑器
我们所要做的就是调用BaseEditor.prototype.extend()函数,该函数将返回继承BaseEditor的新函数类。

var SelectEditor = Handsontable.editors.BaseEditor.prototype.extend();

第一步:创建 并将其附加到DOM

三个可能的地方我们可以把创建 元素的函数放到DOM中
init() method
prepare() method
open() method

选择最佳解决方案的关键是了解何时调用这些方法。
init()方法:在编辑器类对象的创建过程中被调用。这在每个表实例中最多发生一次,因为一旦创建对象,它就会在每次EditorManager请求这个编辑器类实例时重用(参见Singleton模式)。

prepare()方法: 每当用户选择具有这个特定编辑器类作为编辑器属性的单元时,就会调用方法 .因此,如果我们把SelectEditor设置为整个列的编辑器,那么在本专栏中选择任何单元格都会调用 prepare()方法.换句话说,这种方法在表生命周期中可以被调用数百次,特别是在处理大数据时。prepare()的另一个重要方面,它不应该显示编辑器(它是open的工作)。显示编辑器是由用户事件触发的,例如按下ENTER、F2或双击一个单元格,因此,在调用prepare()和实际显示编辑器之间有一段时间。然而,prepare()所执行的操作应该尽可能快地完成,以提供最好的用户体验。

open()方法:当需要显示编辑器时,将调用该方法。在大多数情况下,该方法应该更改CSS显示属性以阻止或执行类似的操作。用户期望在事件(按下适当的键或双击单元格)被触发后,编辑器将会显示出来,所以open()方法应该尽可能快地工作。

了解所有这些之后,将负责创建输入的代码放在init()方法中的某个位置是最合理的。DOM操作被认为是相当昂贵的(关于资源消耗)操作,因此最好在编辑器的整个生命周期中执行一次并重用生成的HTML节点。

SelectEditor.prototype.init = function() {
  // 创建分离的节点,添加CSS类并确保它不可见
  this.select = document.createElement('SELECT');
  Handsontable.dom.addClass(this.select, 'htSelectEditor');
  this.select.style.display = 'none';

  // 通过将节点附加到保存表的容器,将节点附加到DOM
  this.instance.rootElement.appendChild(this.select);
};
.htSelectEditor {
  padding: 5px 7px;
  position: absolute;
  /*
   * 这个技巧允许在WebKit浏览器中修改<select>
   */
  -webkit-appearance: menulist-button !important;
}

第二步:填充option

在前面的步骤中,我们实现了一个创建输入并将其附加到DOM的函数。您可能注意到,我们没有编写任何代码来创建元素,因此如果我们显示列表,它将是空的。
我们希望能够像这样定义一个选项列表

var hot = new Handsontable(document.getElementById('container'), {
  data: someData,
  columns: [
    {
      editor: SelectEditor,
      selectOptions: ['option1', 'option2', 'option3']
    }
  ]
});

即使我们可以得到这个数组,我们也只能用选项填充列表一次,如果我们在“init”函数中这样做的话。如果使用SelectEditor有多个列,并且每个列都有自己的选项列表,该怎么办?甚至可能同一列中的两个单元格可以有不同的选项列表(级联配置——还记得吗?)很明显,我们必须为代码创建一个更好的位置,为我们的列表创建项目。
剩下prepare ()和open()两个位置。后一种方法更容易实现,但如前所述,open()应该尽可能快地工作,创建节点(如果select包含长列表选项的话),并将它们附加到DOM可能是耗时的。因此,prepare()似乎是做这种工作更安全的地方。唯一需要记住的是,当重写prepare()时,我们应该始终调用BaseEditor的原始方法。prepare()设置一些重要的属性,其他编辑器方法使用这些属性。

// 在prepare()方法中创建 option
SelectEditor.prototype.prepare = function() {
  // 记住调用父方法
  Handsontable.editors.BaseEditor.prototype.prepare.apply(this, arguments);

  var selectOptions = this.cellProperties.selectOptions;
  var options;

  if (typeof selectOptions == 'function') {
    options = this.prepareOptions(selectOptions(this.row,
    this.col, this.prop))
  } else {
    options = this.prepareOptions(selectOptions);
  }
  Handsontable.dom.empty(this.select);

  for (var option in options) {
    if (options.hasOwnProperty(option)) {
      var optionElement = document.createElement('OPTION');
      optionElement.value = option;
      Handsontable.dom.fastInnerHTML(optionElement, options[option]);
      this.select.appendChild(optionElement);
    }
  }
}; 
SelectEditor.prototype.prepareOptions = function(optionsToPrepare) {
  var preparedOptions = {};

  if (Handsontable.helper.isArray(optionsToPrepare)) {
    for(var i = 0, len = optionsToPrepare.length; i < len; i++) {
      preparedOptions[optionsToPrepare[i]] = optionsToPrepare[i];
    }
  } else if (typeof optionsToPrepare == 'object') {
    preparedOptions = optionsToPrepare;
  }

  return preparedOptions;
};

第三步:实现编辑特定的方法

大部分工作已经完成。现在我们只需要实现所有编辑器的特定方法。幸运的是,我们的编辑器非常简单,所以这些方法只需要几行代码。

SelectEditor.prototype.getValue = function() {
  return this.select.value;
};

SelectEditor.prototype.setValue = function(value) {
  this.select.value = value;
};

SelectEditor.prototype.open = function() {
  var width = Handsontable.dom.outerWidth(this.TD);
  var height = Handsontable.dom.outerHeight(this.TD);
  var rootOffset = Handsontable.dom.offset(this.instance.rootElement);
  var tdOffset = Handsontable.dom.offset(this.TD);

  // 设置select尺寸以匹配单元格大小
  this.select.style.height = height + 'px';
  this.select.style.minWidth = width + 'px';

  // 确保列表位置与单元格位置匹配
  this.select.style.top = tdOffset.top - rootOffset.top + 'px';
  this.select.style.left = tdOffset.left - rootOffset.left + 'px';
  this.select.style.margin = '0px';

  // 显示select
  this.select.style.display = '';
};

SelectEditor.prototype.close = function() {
  this.select.style.display = 'none';
};

getValue()、setValue()和close()的实现是不言自明的,但是open()需要一些注释。首先,实现假设在prepare()中放置负责用option填充列表的代码。其次,在显示列表之前,我们设置它的高度和最小宽度,以匹配相应单元格的大小。这是一个可选的步骤,但是没有它,编辑器将根据浏览器有不同的大小。也许比较好的是限制的最大高度。最后,将附加到末尾。

最后一步
此时,我们应该有一个可以使用的编辑器。将代码放在页面的某个地方,并将SelectEditor类函数作为编辑器属性的值传递。

/*
 * 编辑器的代码在这里
 */
var hot = new Handsontable(document.getElementById('container'), {
  data: someData,
  columns: [
    {},
    {
      editor: SelectEditor,
      selectOptions: ['option1', 'option2', 'option3']
    }
  ]
});

向上箭头和向下箭头以改变选定的值。

我们知道我们的编辑器可以工作,但是让我们再对它进行一个调整。当前,当编辑器打开时,用户按下箭头或箭头向下编辑器关闭,选择移动一个单元格或向下。如果按上下箭头键改变当前选择的值,不是很好吗?用户可以导航到单元格,点击ENTER,选择想要的值并通过再次点击ENTER保存更改。听起来不错,但是如何覆盖默认行为呢? 毕竟,是编辑器决定何时关闭编辑器。
别担心。尽管您没有直接访问EditorManager实例,但是仍然可以重写它的行为。在EditorManager开始处理键盘事件之前,它就会触发beforeKeyDown钩子。如果任何侦听函数在事件对象编辑器上调用stopinstanatepropagation()方法,将不会进一步处理该事件。因此,我们所要做的就是注册一个beforeKeyDown侦听器函数,它检查箭头或箭头是否被按下,如果是这样,就停止事件传播,并相应地改变当前所选的值()。
我们需要记住的是,当我们的编辑器被打开时,监听器应该只工作。我们希望保留其他编辑器的默认行为,以及在没有打开编辑器时。这就是为什么注册侦听器最合理的地方是open()方法,close()方法应该包含将删除侦听器的代码。

监听器函数是这样的:

var onBeforeKeyDown = function(event) {
  var instance = this; // 监听函数的上下文总是设置为Handsontable。code实例
  var editor = instance.getActiveEditor();
  var selectedIndex = editor.select.selectedIndex;

  Handsontable.dom.enableImmediatePropagation(event);

  switch (event.keyCode) {
    case Handsontable.helper.keyCode.ARROW_UP:
      var previousOption = editor.select.options[selectedIndex - 1];

      if (previousOption) { // 如果之前的option存在
        editor.select.value = previousOption.value; // 其标记为select
      }

      event.stopImmediatePropagation(); // 阻止EditorManager 处理此事件
      event.preventDefault(); //防止浏览器向上滚动页面
      break;

    case Handsontable.helper.keyCode.ARROW_DOWN:
      var nextOption = editor.select.options[selectedIndex + 1];

      if (nextOption) { // 如果之前的option存在
        editor.select.value = nextOption.value; // 其标记为select
      }
      event.stopImmediatePropagation(); // 阻止EditorManager 处理此事件
      event.preventDefault(); // 防止浏览器向上滚动页面
      break;
}

调用getActiveEditor()方法,该方法返回活动编辑器.
活动编辑器是最近才调用prepare()方法的编辑器。例如,如果您选择一个单元格,其中的编辑器是Handsontable。TextEditor,然后getActiveEditor()将返回这个编辑器类的一个对象。如果然后选择一个单元格(可能在另一列中),编辑器是Handsontable。DateEditor, active editor更改,现在getActiveEditor()将返回DateEditor类的一个对象。
现在我们要做的就是注册监听器。

SelectEditor.prototype.open = function() {
  var width = Handsontable.dom.outerWidth(this.TD);
  var height = Handsontable.dom.outerHeight(this.TD);
  var rootOffset = Handsontable.dom.offset(this.instance.rootElement);
  var tdOffset = Handsontable.dom.offset(this.TD);

  this.select.style.height = height + 'px';
  this.select.style.minWidth = width + 'px';
  this.select.style.top = tdOffset.top - rootOffset.top + 'px';
  this.select.style.left = tdOffset.left - rootOffset.left + 'px';
  this.select.style.margin = '0px';
  this.select.style.display = '';

  // 注册监听器
  this.instance.addHook('beforeKeyDown', onBeforeKeyDown);
};

SelectEditor.prototype.close = function() {
  this.select.style.display = 'none';
  // 删除侦听器
  this.instance.removeHook('beforeKeyDown', onBeforeKeyDown);
};

此外,由于最近覆盖(固定列、行、头文件等)的位置发生了变化,我们需要设置css转换属性。我们将使用Handsontable。Dom的getCssTransform和resetCssTransform来获得正确的值.

SelectEditor.prototype.open = function() {
  var width = Handsontable.dom.outerWidth(this.TD);
  // 重要的组布局一起阅读以获得更好的性能。
  var height = Handsontable.dom.outerHeight(this.TD);
  var rootOffset = Handsontable.dom.offset(this.instance.rootElement);
  var tdOffset = Handsontable.dom.offset(this.TD);
  var editorSection = this.checkEditorSection();
  var cssTransformOffset;

  switch(editorSection) {
    case 'top':
      cssTransformOffset = Handsontable.dom.getCssTransform(this.instance.view.wt.wtScrollbars.vertical.clone.wtTable.holder.parentNode);
      break;
    case 'left':
      cssTransformOffset = Handsontable.dom.getCssTransform(this.instance.view.wt.wtScrollbars.horizontal.clone.wtTable.holder.parentNode);
      break;
    case 'corner':
      cssTransformOffset = Handsontable.dom.getCssTransform(this.instance.view.wt.wtScrollbars.corner.clone.wtTable.holder.parentNode);
      break;
  }
  var selectStyle = this.select.style;

  if (cssTransformOffset && cssTransformOffset !== -1) {
    selectStyle[cssTransformOffset[0]] = cssTransformOffset[1];
  } else {
    Handsontable.dom.resetCssTransform(this.select);
  }

  selectStyle.height = height + 'px';
  selectStyle.minWidth = width + 'px';
  selectStyle.top = tdOffset.top - rootOffset.top + 'px';
  selectStyle.left = tdOffset.left - rootOffset.left + 'px';
  selectStyle.margin = '0px';
  selectStyle.display = '';

  this.instance.addHook('beforeKeyDown', onBeforeKeyDown);
};

SelectEditor.prototype.checkEditorSection = function() {
  if (this.row < this.instance.getSettings().fixedRowsTop) {
    if (this.col < this.instance.getSettings().fixedColumnsLeft) {
      return 'corner';
    } else {
      return 'top';
    }
  } else {
    if (this.col < this.instance.getSettings().fixedColumnsLeft) {
      return 'left';
    }
  }
};

注册一个编辑

在创建编辑器时,一个好主意是为它分配一个别名,该别名将引用这个特定的编辑器类。Handsontable默认定义了11个别名。

autocomplete for Handsontable.editors.AutocompleteEditor
base for Handsontable.editors.BaseEditor
checkbox for Handsontable.editors.CheckboxEditor
date for Handsontable.editors.DateEditor
dropdown for Handsontable.editors.DropdownEditor
handsontable for Handsontable.editors.HandsontableEditor
numeric for Handsontable.editors.NumericEditor
password for Handsontable.editors.PasswordEditor
select for Handsontable.editors.SelectEditor
text for Handsontable.editors.TextEditor
time for Handsontable.editors.TimeEditor

它为用户提供了一种方便的方式来定义在更改某些单元格的值时应该使用哪个编辑器。用户不需要知道哪个类负责显示编辑器,他甚至不需要知道有任何类。更重要的是,您可以更改与别名关联的类,而无需更改定义表的代码。
To register your own alias use Handsontable.editors.registerEditor() function. It takes two arguments:
editorName -表示编辑器的字符串
editorClass - 将由编辑名表示的类
如果您想在alias select下注册SelectEditor,您必须调用它

Handsontable.editors.registerEditor('select', SelectEditor);

明智地选择别名。如果在已注册的名称下注册编辑器,目标类将被覆盖

Handsontable.editors.registerEditor('text', MyNewTextEditor);

// 现在“text”别名指向MyNewTextEditor类,而不是Handsontable.editors.TextEditor

因此,除非您有意覆盖现有的别名,否则请尝试选择一个惟一的名称。

向专用名称空间添加编辑器

为了使事情井然有序,您可以使用handsontable.editor将编辑器注册到编辑器集合中。registerEditor方法。通过这种方式,您可以在表定义期间使用编辑器,而其他用户将可以方便地访问您的编辑器,以防他们希望对其进行扩展。

(function(Handsontable){
  var CustomEditor = Handsontable.editors.BaseEditor.prototype.extend();

  // ...编辑器代码

  // And at the end
  Handsontable.editors.registerEditor('custom', CustomEditor);

})(Handsontable);

从现在开始,您可以像这样使用CustomEditor

var hot = new Handsontable(document.getElementById('container'), {
  data: someData,
  columns: [
    {
      editor: Handsontable.editors.CustomEditor
    }
  ]
}); 

扩展定制编辑器也很容易。

var AnotherEditor = Handsontable.editors.getEditor('custom').prototype.extend();

请记住,您选择的名称没有限制,但是要明智地选择,不要覆盖现有的编辑器。尽量保持名字的独特性。

注册一个别名

最后的操作是在某个别名下注册编辑器,这样用户就可以很容易地引用它,而无需现在使用实际的类名。
总之,一个准备充分的编辑器应该是这样的

(function(Handsontable){
  var CustomEditor = Handsontable.editors.BaseEditor.prototype.extend();

  // ...编辑器代码的其余部分

  // 注册别名
  Handsontable.editors.registerEditor('theBestEditor', CustomEditor);

})(Handsontable);

从现在开始,您可以像这样使用CustomEditor

var hot = new Handsontable(document.getElementById('container'), {
  data: someData,
  columns: [
    {
      editor: 'theBestEditor'
    }
  ]
}); 

猜你喜欢

转载自blog.csdn.net/qianqianyixiao1/article/details/80925480
今日推荐