Extend ES6 plugin to jQuery prototype

2019-03-11 07:27发布

问题:

I would like ask some help because i can't convert my classic jQuery (v2) plugin in ES6 with module and class.

In ECMAScript 5, we can attach jQuery plugin into jQuery prototype like this :

app.js - jQuery loaded via HTML <script> tag

$.fn.myPlugin = function() {};
$('div').myPlugin();

And it works :) . In ES6, I would write something like this:

myPlugin.es6 :

import $ from 'jquery';

export default class myPlugin extends $ {
 // Could i use constructor() method ???
}

app.es6 :

import $ from 'jquery';
import myPlugin from 'myPlugin.es6';

$('div').myPlugin();

And finally, it's not working ...
I've search and no people ask this question before.
I use Babel to transpile ES6 into ES5.

回答1:

$.fn is just an object. There is no magic upon adding a new property to the prototype of $. So, the code $.fn.myPlugin = function() {} is equal to $.prototype.myPlugin = function() {}.

$.fn === $.prototype; // true

To be able to call a function on the $ object in a standard way ($('div').func()), you need to add this function to the $ object.

You're not adding it in your es6 code.

Thus,

import $ from 'jquery';

export default class myPlugin extends $ {
 // Could i use constructor() method ???
}

Means (almost)

var myPlugin = function() {};

myPlugin.prototype = Object.create($.prototype);

return { default: myPlugin };

I'm not sure you should extend $.fn, but maybe you need it.

And with

import $ from 'jquery';
import myPlugin from 'myPlugin.es6';

it means

var $ = require('jquery');
var myPlugin = require('myPlugin'); // a reference to the 'export.default' object from 'myPlugin.es6'

Therefore, there is no connection between $.fn object and myPlugin function.

You should create the connection somewhere. It could be in a special module like plugins where you'll inject all needed plugins into the $.fn object:

import $ from 'jquery';
import plugin1 from 'plugin1.es6'; // should contain 'name'
import plugin2 from 'plugin2.es6';
...
import plugin10 from 'plugin10.es6';

[plugin1, plugin2, ..., plugin10].forEach(plugin => $.fn[plugin.name] = plugin);

Or you could add an 'initialize' method to the exported object in 'myPlugin.es6', and call it before first use: init($) { $.fn.myPlugin = myPlugin; }

And so on.



回答2:

You install new methods on the jQuery prototype in ES6 just as you always did. Nothing has changed for them. You're not going to subclass jQuery, so it makes no sense to use class or extends.

// myPlugin.es6:
import $ from 'jquery';

$.fn.myPlugin = function() {
    …
};

// app.es6:
import $ from 'jquery';
import 'myPlugin.es6';

$('div').myPlugin();