jQuery 轉原生 JavaScript 對應語法
網頁開發最近我嘗試將專案中的 jQuery 全部替換為原生 JavaScript,但發現這不是一個簡單的任務。除了更改語法外,許多依賴 jQuery 的套件也要尋找替代方案。 起初,我嘗試使用網路上的一些將 jQuery 轉換為 JavaScript 的工具,但這些工具大多存在一些缺陷,有些 jQuery 語法無法直接轉換,最後我還是必須手動一行一行檢查。
因此,最後我決定還是自己花時間慢慢重新調整程式碼,本文是我自己進行 jQuery 轉原生 JavaScript 語法時的筆記,希望能幫助到跟我一樣在進行換掉 jQuery 套件任務的開發人員。
相信換掉 jQuery 套件這項任務,應該很多開發人員都有遇到,不知道大家都是怎麼處理的呢?還是真的有工具可以處理,只是我沒找到而已呢?歡迎大家留言一起討論喔。
選擇元素
- 取得 body
-
$('body');
document.body;
- 基本選擇器
-
$('.class ul li a');
document.querySelectorAll('.class ul li a');
- ID 選擇器
-
$('#id');
document.querySelector('#id'); // 或 document.getElementById('id');
- Class 選擇器
-
$('.class');
document.querySelectorAll('.class'); // 或 document.getElementsByClassName('class');
- 屬性選擇器
-
$('a[target=_blank]');
document.querySelectorAll('a[target=_blank]');
- 尋找下一層
-
$item.find('li');
item.querySelectorAll('li');
- 往上層尋找
-
// 只往上找一層 $item.parent('div'); // 往上找到符合條件的元素就停止 $item.closest('div'); // 往上找到所有符合條件的元素 $item.parents('div');
// 只往上找一層,等於 $item.parent(); item.parentElement // 往上找到符合條件的元素就停止 item.closest('div'); // 往上找到所有符合條件的元素 // 原生沒有類似的寫法,需要自己寫 function 處理
- 兄弟選擇器
-
$('.find-siblings').siblings();
let item = document.querySelector('.find-siblings'); let siblings = item.parentNode.querySelectorAll(':scope > :not(.find-siblings)'); // 或 let item = document.querySelector('.find-siblings'); let siblings = [...item.parentNode.children].filter((child) => child !== item );
- 上一個元素 / 下一個元素
-
// 上一個元素 $item.prev(); // 下一個元素 $item.next();
// 上一個元素 item.previousElementSibling; // 下一個元素 item.nextElementSibling; item.previousElementSibling;
屬性
- 取得 / 設定 / 移除屬性
-
// 取得 foo 屬性值 $item.attr('foo'); // 設定 foo 屬性值為 bar $item.attr('foo', 'bar'); // 移除 foo 屬性 $item.removeAttr('foo');
// 取得 foo 屬性值 item.getAttribute('foo'); // 設定 foo 屬性值為 bar item.setAttribute('foo', 'bar'); // 移除 foo 屬性 item.removeAttribute('foo');
- 取得 data-* 值
-
$item.data('foo');
item.getAttribute('data-foo'); // 或 item.dataset['foo'];
- 設定 data-* 值
-
$item.data('foo', 'bar');
item.setAttribute('data-foo', 'bar'); // 或 item.dataset['foo'] = 'bar';
以上寫法還是稍微與 jQuery 不同,用 jQuery.data() 設定資料時,並不會在 element 增加 data-* 的屬性,但用 jQuery.data() 抓資料卻抓得到資料。 另外,用 jQuery.data() 設定資料,是沒辦法用原生語法抓取資料。
// 用 jQuery 設定 data-foo 為 bar,並不會在 $item 增加 data-foo 的屬性 $item.data('foo', 'bar'); // 可以使用 jQuery.data() 抓資料 // 回傳 bar $item.data('foo') // 無法用原生語法抓資料 // 回傳 null item.getAttribute('data-foo'); // 回傳 undefined item.dataset['foo'];
樣式 (CSS 及 Style)
- 取得樣式
-
// jQuery.css() 會取得最終套用的樣式,而不是取得元素中的 style 屬性設定 $item.css('color');
// 取得最終套用的樣式 item.ownerDocument.defaultView.getComputedStyle(item, null).color // 取得元素中的 style 屬性設定 item.style.color
- 設定樣式
-
$item.css("color", '#ff0000'); // 或 $item.css({color: '#ff0000'});
item.style.color = '#ff0000';
- add / remove / has / toggle Class
-
// add class $item.addClass(className); // remove class $item.removeClass(className); // has class $item.hasClass(className); // toggle class $item.toggleClass(className);
// add class item.classList.add(className); // remove class item.classList.remove(className); // has class item.classList.contains(className); // toggle class item.classList.toggle(className);
- Window height
-
$(window).height();
// 不含 scrollbar,與 jQuery 一致 window.document.documentElement.clientHeight; // 含 scrollbar window.innerHeight;
- Document height
-
$(document).height();
const body = document.body; const html = document.documentElement; const height = Math.max( body.offsetHeight, body.scrollHeight, html.clientHeight, html.offsetHeight, html.scrollHeight );
- Element height
-
$item.height();
function getHeight(item) { const styles = this.getComputedStyle(item); const height = item.offsetHeight; const borderTopWidth = parseFloat(styles.borderTopWidth); const borderBottomWidth = parseFloat(styles.borderBottomWidth); const paddingTop = parseFloat(styles.paddingTop); const paddingBottom = parseFloat(styles.paddingBottom); return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; } // 精確到整數 item.clientHeight; // 精確到小數 item.getBoundingClientRect().height;
- Position
-
$item.position();
{ left: item.offsetLeft, top: item.offsetTop }
- Offset
-
$item.offset();
function getOffset (item) { const box = item.getBoundingClientRect(); return { top: box.top + window.pageYOffset - document.documentElement.clientTop, left: box.left + window.pageXOffset - document.documentElement.clientLeft } }
- ScrollTop
-
// 取得目前卷軸位置 $(window).scrollTop(); // 移動捲軸到指定位置 $(window).scrollTop(0);
// 取得目前卷軸位置 window.scrollY; // 移動捲軸到指定位置 window.scrollTo({top: 0, behavior: 'smooth'});
DOM 操作
- get / set text
-
// Get text $item.text(); // Set text $item.text(string);
// Get text item.textContent; // Set text item.textContent = string;
- get / set html
-
// Get html $item.html(); // Set html $item.html(string);
// Get html item.innerHTML; // Set html item.innerHTML = string;
- 移除元素
-
$item.remove();
item.remove();
- Prepend
-
將元素插入另一個元素的最前端。
$el.prepend('<div>hello</div>');
// HTML string item.insertAdjacentHTML('afterbegin', '<div>hello</div>'); // Element item.insertBefore(newEle);
- Append
-
將元素插入另一個元素的最末端。
$item.append('<div>hello</div>');
// HTML string item.insertAdjacentHTML('beforeend', '<div>Hello</div>'); // Element item.appendChild(newEle);
- insertBefore
-
將元素插入另一個元素之前。
$item.insertBefore(selector);
// HTML string item.insertAdjacentHTML('beforebegin ', '<div>Hello</div>'); // Element const ele = document.querySelector(selector); if (ele.parentNode) { ele.parentNode.insertBefore(item, ele); }
- insertAfter
-
將元素插入另一個元素之後。
$item.insertAfter(selector);
// HTML string item.insertAdjacentHTML('afterend ', '<div>Hello</div>'); // Element const ele = document.querySelector(selector); if (ele.parentNode) { ele.parentNode.insertBefore(item, ele.nextSibling); }
- is
-
$item.is(selector);
item.matches(selector);
- clone
-
$item.clone();
item.cloneNode();
- wrap
-
$('.inner').wrap('<div class="wrapper"></div>');
Array.from(document.querySelectorAll('.inner')).forEach((ele) => { const wrapper = document.createElement('div'); wrapper.className = 'wrapper'; ele.parentNode.insertBefore(wrapper, ele); ele.parentNode.removeChild(ele); wrapper.appendChild(ele); });
- unwrap
-
$('.inner').unwrap();
Array.prototype.forEach.call(document.querySelectorAll('.inner'), (ele) => { let eleParentNode = ele.parentNode if(eleParentNode !== document.body) { eleParentNode.parentNode.insertBefore(ele, eleParentNode) eleParentNode.parentNode.removeChild(eleParentNode) } });
- 移除所有子結點 (empty)
-
$item.empty();
item.innerHTML = '';
- 解析 HTML/SVG/XML 字串
-
$(` <ol> <li>a</li> <li>b</li> </ol> <ol> <li>c</li> <li>d</li> </ol> `);
const range = document.createRange(); const parse = range.createContextualFragment.bind(range); parse(` <ol> <li>a</li> <li>b</li> </ol> <ol> <li>c</li> <li>d</li> </ol> `); // 單一元素可以使用以下方法 function htmlToDOM(html) { let div = document.createElement('div'); div.innerHTML = this.htmlMinify(html); return div.firstChild; } function htmlMinify(html) { return html ? html.replace(/\>[\r\n ]+\</g, "><").replace(/(<.*?>)|\s+/g, (m, $1) => $1 ? $1 : ' ').trim() : ''; } htmlToDOM(` <ol> <li>a</li> <li>b</li> </ol> `);
表單處理
- 取得 / 設定值
-
// 取得 ID 為 input 的值 $('#input').val(); // 設定 ID 為 input 的值為 name $('#input').val('name');
// 取得 ID 為 input 的值 document.getElementById('input').value; // 設定 ID 為 input 的值為 name document.getElementById('input').value = 'name';
- 取得勾選的 checkbox 或 radio
-
$('.checkbox:checked');
document.querySelectorAll('.checkbox:checked');
- 獲取焦點
-
$('#input').focus();
document.getElementById('input').focus();
Iframe
- Iframe contents
-
$iframe.contents();
iframe.contentDocument;
- Iframe Query
-
$iframe.contents().find('.css');
iframe.contentDocument.querySelectorAll('.css');
AJAX
直接改用 Fetch API,請參考以下網址:
事件
- document ready
-
$(document).ready(eventHandler);
document.addEventListener('DOMContentLoaded', eventHandler);
- 綁定 / 移除事件
-
// 綁定事件 $item.on(eventName, eventHandler); // 移除事件 $item.off(eventName, eventHandler);
// 綁定事件 item.addEventListener(eventName, eventHandler); // 移除事件 item.removeEventListener(eventName, eventHandler);
- trigger
-
$item.trigger('custom-event', {key1: 'data'});
if (window.CustomEvent) { const event = new CustomEvent('custom-event', {detail: {key1: 'data'}}); } else { const event = document.createEvent('CustomEvent'); event.initCustomEvent('custom-event', true, true, {key1: 'data'}); } item.dispatchEvent(event);
實用工具
- isArray
-
檢查是否為陣列。
$.isArray(array);
Array.isArray(array);
- inArray
-
指定值,在陣列中的索引值。
// 傳回索引值,-1 表示 item 不在 array $.inArray(item, array);
// 傳回索引值,-1 表示 item 不在 array array.indexOf(item); // 傳回 true 或 false array.includes(item);
- isNumeric
-
檢查是否為數字。
$.isNumeric(item);
function isNumeric(value) { return !isNaN(parseFloat(value)) && isFinite(value); }
- isFunction
-
檢查是否為函數。
$.isFunction(item);
function isFunction(item) { if (typeof item === 'function') { return true; } var type = Object.prototype.toString(item); return type === '[object Function]' || type === '[object GeneratorFunction]'; }
- isEmptyObject
-
檢查是否為空。
$.isEmptyObject(obj);
function isEmptyObject(obj) { return Object.keys(obj).length === 0; }
- isPlainObject
-
檢查是否為扁平物件 (使用 {} 或 new Object 建立)。
$.isPlainObject(obj);
function isPlainObject(obj) { if (typeof (obj) !== 'object' || obj.nodeType || obj !== null && obj !== undefined && obj === obj.window) { return false; } if (obj.constructor && !Object.prototype.hasOwnProperty.call(obj.constructor.prototype, 'isPrototypeOf')) { return false; } return true; }
- extend
-
合併多個物件內容。
$.extend({}, defaultOpts, opts);
Object.assign({}, defaultOpts, opts);
- merge
-
合併兩個陣列內容。
const newArray = $.merge(array1, array2);
// 不能去除重複 (與 jQuery 相同) const newArray = [...array1, ...array2]; // 不能去除重複 (與 jQuery 相同) function merge(...args) { return [].concat(...args) } const newArray = merge(array1, array2); // 可以去除重複 function merge(...args) { return Array.from(new Set([].concat(...args))) } const newArray = merge(array1, array2);
- trim
-
移除字串頭尾空白。
$.trim(string);
string.trim();
- each / map / grep
-
// each $.each(array, (index, value) => { }); // map $.map(array, (value, index) => { }); // grep $.grep(array, (value, index) => { });
// each array.forEach((value, index) => { }); // map array.map((value, index) => { }); // grep array.filter((value, index) => { });
- now
-
取得當前時間。
$.now();
Date.now();
- proxy
-
$.proxy(fn, context);
fn.bind(context);
- makeArray
-
將類似陣列的資料 (例如:HTMLCollection),轉換為真正的 JavaScript 陣列。
$.makeArray(arrayLike);
Array.prototype.slice.call(arrayLike); // 或 Array.from(arrayLike);
- contains
-
檢查 DOM 是否包含指定 DOM。
$.contains(item, child);
item !== child && item.contains(child);
- parseHTML
-
$.parseHTML(htmlString);
function parseHTML(string) { const context = document.implementation.createHTMLDocument(); const base = context.createElement('base'); base.href = document.location.href; context.head.appendChild(base); context.body.innerHTML = string; return Array.from(context.body.children); }
- parseJSON
-
$.parseJSON(str);
// String to JSON JSON.parse(str); // JSON to String JSON.stringify(json);
動畫
- Show / Hide / Toggle
-
// Show $item.show(); // Hide $item.hide(); // Toggle $item.toggle();
// Show item.style.display = 'block'; // Hide item.style.display = 'none'; // Toggle if (item.ownerDocument.defaultView.getComputedStyle(item, null).display === 'none') { item.style.display = 'block'; } else { item.style.display = 'none'; }
- FadeIn & FadeOut
-
// FadeIn $item.fadeIn(3000); // FadeOut $item.fadeOut(3000); // FadeTo $item.fadeTo('slow', 0.15); // FadeToggle $item.fadeToggle();
// FadeIn item.style.transition = 'opacity 3s'; item.style.opacity = '1'; // FadeOut item.style.transition = 'opacity 3s'; item.style.opacity = '0'; // FadeTo item.style.transition = 'opacity 3s'; item.style.opacity = '0.15'; // FadeToggle item.style.transition = 'opacity 3s'; const { opacity } = item.ownerDocument.defaultView.getComputedStyle(item, null); if (opacity === '1') { item.style.opacity = '0'; } else { item.style.opacity = '1'; }
- SlideUp & SlideDown
-
// SlideUp $item.slideUp(); // SlideDown $item.slideDown(); // SlideToggle $item.slideToggle();
// SlideUp const originHeight = '100px'; item.style.transition = 'height 3s'; item.style.height = '0px'; // SlideDown const originHeight = '100px'; item.style.transition = 'height 3s'; item.style.height = originHeight; // SlideToggle const originHeight = '100px'; item.style.transition = 'height 3s'; const { height } = item.ownerDocument.defaultView.getComputedStyle(item, null); if (parseInt(height, 10) === 0) { item.style.height = originHeight; } else { item.style.height = '0px'; }
- Animate
-
$item.animate({ params }, speed);
item.style.transition = 'all ' + speed; Object.keys(params).forEach((key) => { item.style[key] = params[key]; });
參考資料
本文絕大部分資料參考以下兩個網址,但有些語法我有經過修改。
0 則留言