終于有人對 jQuery下手了,一鍵移除項目對它的依賴
大家好,我是 零一 。雖然現(xiàn)在很多前端項目都在用Vue、React,但依賴jquery的項目也不少,尤其是年代比較久遠的項目,那些還正在維護jquery項目的你,是否想將jquery從你的項目中移除?畢竟這個庫那么大,你能用到的代碼也就只有15%~30%,而且jquery對各個瀏覽器的兼容性也做了很大的處理(代碼量up up),但其實很多老項目也不會去考慮兼容很邊緣的瀏覽器了,所以其實jquery中兼容處理的代碼也沒太大必要
最近新發(fā)現(xiàn)了一個有意思的工具,僅上線2周,就有 600+
的Star,它說能幫助你的項目脫離對jquery的依賴,感覺是個不錯的想法,一起來看看吧~
使用方式
這個工具的名字叫 replace-jquery ,據(jù)說是能幫你從項目中自動查找所有用到的jquery方法,并生成一套原生js的方法去替代
先來搞一個極簡的jquery項目
index.html
main.js
測試一下頁面的功能,是OK的
接下來我們用 replace-jquery 工具試著移除一下 main.js
中的jquery代碼
先全局下載一下
- npm install -g replace-jquery
然后在項目目錄使用,語法為 replace-jquery 目標(biāo)js文件 生成的js文件
- replace-jquery main.js newMain.js
該工具會自動找到你文件中所有用到的jquery方法。此處有一個確認(rèn)的步驟,你可以選擇想要替換哪些方法(默認(rèn)是全選的)
按回車鍵即可完成替換,并生成新的文件
- export class Utils {
- constructor(selector) {
- this.elements = Utils.getSelector(selector);
- this.element = this.get(0);
- return this;
- }
- on(events, listener) {
- events.split(' ').forEach((eventName) => {
- this.each((el) => {
- const tNEventName = Utils.setEventName(el, eventName);
- if (!Array.isArray(Utils.eventListeners[tNEventName])) {
- Utils.eventListeners[tNEventName] = [];
- }
- Utils.eventListeners[tNEventName].push(listener);
- // https://github.com/microsoft/TypeScript/issues/28357
- if (el) {
- el.addEventListener(eventName.split('.')[0], listener);
- }
- });
- });
- return this;
- }
- remove() {
- this.each((el) => {
- el.parentNode.removeChild(el);
- });
- return this;
- }
- css(css, value) {
- if (value !== undefined) {
- this.each((el) => {
- Utils.setCss(el, css, value);
- });
- return this;
- }
- if (typeof css === 'object') {
- for (const property in css) {
- if (Object.prototype.hasOwnProperty.call(css, property)) {
- this.each((el) => {
- Utils.setCss(el, property, css[property]);
- });
- }
- }
- return this;
- }
- const cssProp = Utils.camelCase(css);
- const property = Utils.styleSupport(cssProp);
- return getComputedStyle(this.element)[property];
- }
- static getSelector(selector, context) {
- if (selector && typeof selector !== 'string') {
- if (selector.length !== undefined) {
- return selector;
- }
- return [selector];
- }
- context = context || document;
- // For performance reasons, use getElementById
- // eslint-disable-next-line no-control-regex
- const idRegex = /^#(?:[\w-]|\\.|[^\x00-\xa0])*$/;
- if (idRegex.test(selector)) {
- const el = document.getElementById(selector.substring(1));
- return el ? [el] : [];
- }
- return [].slice.call(context.querySelectorAll(selector) || []);
- }
- get(index) {
- if (index !== undefined) {
- return this.elements[index];
- }
- return this.elements;
- }
- each(func) {
- if (!this.elements.length) {
- return this;
- }
- this.elements.forEach((el, index) => {
- func.call(el, el, index);
- });
- return this;
- }
- static setEventName(el, eventName) {
- // Need to verify https://stackoverflow.com/questions/1915341/whats-wrong-with-adding-properties-to-dom-element-objects
- const elementUUId = el.eventEmitterUUID;
- const uuid = elementUUId || Utils.generateUUID();
- // eslint-disable-next-line no-param-reassign
- el.eventEmitterUUID = uuid;
- return Utils.getEventName(eventName, uuid);
- }
- static setCss(el, prop, value) {
- // prettier-ignore
- let cssProperty = Utils.camelCase(prop);
- cssProperty = Utils.styleSupport(cssProperty);
- el.style[cssProperty] = value;
- }
- static camelCase(text) {
- return text.replace(/-([a-z])/gi, (s, group1) => group1.toUpperCase());
- }
- static styleSupport(prop) {
- let vendorProp;
- let supportedProp;
- const capProp = prop.charAt(0).toUpperCase() + prop.slice(1);
- const prefixes = ['Moz', 'Webkit', 'O', 'ms'];
- let div = document.createElement('div');
- if (prop in div.style) {
- supportedProp = prop;
- } else {
- for (let i = 0; i < prefixes.length; i++) {
- vendorProp = prefixes[i] + capProp;
- if (vendorProp in div.style) {
- supportedProp = vendorProp;
- break;
- }
- }
- }
- div = null;
- return supportedProp;
- }
- static generateUUID() {
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
- // eslint-disable-next-line no-bitwise
- const r = (Math.random() * 16) | 0;
- // eslint-disable-next-line no-bitwise
- const v = c === 'x' ? r : (r & 0x3) | 0x8;
- return v.toString(16);
- });
- }
- static getEventName(eventName, uuid) {
- return `${eventName}__EVENT_EMITTER__${uuid}`;
- }
- }
- Utils.eventListeners = {};
- export default function $utils(selector) {
- return new Utils(selector);
- }
簡單看了一下,似乎就是把我們用到的jquery方法替換成了簡單的原生方法,并封裝在 Utils
這個類中,那么我們每次調(diào)用 $("xxx")
時,其實就是在調(diào)用該類上的方法,那么對這個文件做一些修改
- // 此處刪除export
- class Utils {
- // ...省略一些代碼
- }
- Utils.eventListeners = {};
- // 此處刪除 export default,并將函數(shù) $utils改成 $
- function $(selector) {
- return new Utils(selector);
- }
這樣就相當(dāng)于我們在全局模擬jquery定義了一個 $
方法。此時html文件中的jquery引用就可以刪除了,并把我們剛才生成的文件引進來
再去頁面中嘗試操作dom,可以看到效果跟之前一樣,成功!
補充
如果你想用該工具生成jquery所有api的替代文件,即生成一個 super-mini-jquery
,你可以這么做
- replace-jquery --build-all super-mini-jquery.js
將代碼混淆丑化以后大概只有10kb
因為這個工具剛發(fā)布才2個星期不到,只實現(xiàn)了大部分的jquery代碼替換,比如 ajax
暫時是沒辦法替換的,你如果嘗試去替換,工具也會提醒你
無法替換ajax
總的來說,這個工具想法不錯,希望后期能支持更多的語法替換!