Определите пользовательский виджет пользовательского интерфейса jQuery в TypeScript
В настоящее время мы смотрим на перевод нашего проекта JavaScript на TypeScript. Наше приложение в значительной степени опирается на пользовательские разработанные виджеты jQuery UI.
В нашей текущей базе кода мы используем механизм глубоких копий, чтобы наследовать от определений виджетов, позволяя нам, например, объявить общий TableWidget
, а также OrdersTableWidget
, который определяет более конкретные функции.
Поэтому я хотел бы определить мои определения виджетов как классы TypeScript, а затем привязать экземпляр этих классов к jQuery.
Например
class MyWidget {
options: WidgetOptions;
_init(){
// general initialization
}
}
class MySecondWidget extends MyWidget {
_init(){
super._init();
// specific initialization
}
}
И затем
$.widget("MyNameSpace.MyWidget", new MyWidget());
$.widget("MyNameSpace.MySeWidget", new MyWidget());
Кроме того, я хотел бы обозначить свои пользовательские виджеты как реализации определения jQuery UI Widget
class MyWidget implements Widget {
options: WidgetOptions;
_init(){
// general initialization
}
}
поэтому я могу использовать следующий синтаксис в TypeScript:
$(selector).MyWidget(options);
Я знаю, что мне нужно работать с файлом определения (от DefinitelyTyped), однако я еще не нашел надежного источника, объясняющего, как я должен писать пользовательские jQuery UI Widgets в TypeScript. Кто-нибудь получил опыт с этим?
Любая помощь очень ценится, как всегда!
Ответы
Ответ 1
Я не уверен, что вы можете написать класс, реализующий интерфейс Widget
из-за отсутствия перегруженных конструкторов. Вы можете создать переменную, которая вводится интерфейсом Widget
.
Стандартный плагин jQuery будет представлять собой почти чистый JavaScript и не будет использовать модули или классы, поскольку он заканчивается завершением как часть jQuery, которая сама по себе не является модулем или классом.
Вот пустой плагин с именем plugin
, который выглядит как любой стандартный плагин jQuery, но вы можете видеть, что он использует систему типа TypeScript и расширяет интерфейс JQuery
, чтобы позволить ему быть вызванным.
/// <reference path="jquery.d.ts" />
interface JQuery {
plugin(): JQuery;
plugin(settings: Object): JQuery;
}
(function ($) {
function DoSomething(someParamater: string) : void {
}
$.fn.plugin = function (settings) {
var config = {
settingA: "Example",
settingB: 5
};
if (settings) {
$.extend(config, settings);
}
return this.each(function () {
});
};
})(jQuery);
Это будет вызвано обычным способом.
$('#id').plugin();
Итак, мой ответ: вы не можете делать то, что хотите, потому что добавляете к объявленным интерфейсам для jQuery, а не публикуете их как модули. Вы можете обернуть использование в модуле, например, адаптер, который абстрагирует аспект jQuery от использования в вашем TypeScript, или вы можете вызывать ваши классы изнутри плагина, но плагин или виджет действительно не вписываются в модуль или класс.
Ответ 2
Это может помочь получить базовый класс в typescript, из которого могут быть получены другие классы виджетов.
Его единственная цель - предоставить базовый класс, чтобы вы могли получить доступ к элементам базового класса, не прибегая к слабому типу.
Трюк заключается в том, чтобы удалить все члены во время выполнения (в конструкторе) - в противном случае вы столкнетесь с проблемами с наследованием, предоставляемыми виджетами factory. Например, метод option
будет переопределять оригинальный метод виджета, который не нужен: мы просто хотим иметь возможность его называть (статически типизированным способом).
class WidgetBase {
public element:JQuery;
constructor() {
// remove all members, they are only needed at compile time.
var myPrototype = (<Function>WidgetBase).prototype;
$.each(myPrototype, (propertyName, value)=>{
delete myPrototype[propertyName];
});
}
/**
* Calles the base implementation of a method when called from a derived method.
* @private
*/
public _super(arg1?:any, arg2?:any, arg3?:any, arg4?:any) {
}
/**
* @private
*/
public _superApply(arguments) {
}
/**
* Gets or sets the value of the widget option associated with the specified optionName.
*/
public option(optionName:string, value?:any):any {
}
// ... further methods from http://api.jqueryui.com/jQuery.widget/
}
Затем вы можете реализовать свой собственный виджетов следующим образом:
class SmartWidget extends WidgetBase {
constructor(){
super();
}
public _create() {
var mySmartOption = this.option('smart'); // compiles because of base class
this.beSmart(mySmartOption);
}
public _setOption(key:string, value:any) {
if (key === 'smart') {
this.beSmart(value);
}
this._super(key, value); // compiles because of base class
}
private beSmart(smartOne:any){
// ...
}
}
// register
jQuery.widget("myLib.smartWidget", new SmartWidget());
// assuming you are using https://github.com/borisyankov/DefinitelyTyped
declare interface JQuery{
smartWidget();
smartWidget(options:any);
smartWidget(methodName:string, param1?:any, param2?:any, param3?:any, param4?:any);
}
И, наконец, вы можете использовать свой виджет:
$(".selector").smartWidget({smart:"you"});