您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
顯示台股主要股票資訊,每5分鐘更新,可顯示昨收價,漲跌顯色,整齊排版,可以自己在STOCKS新增股票,就可以無限增加。
// ==UserScript== // @name 台股浮窗(TWSE API) // @namespace issac // @version 1.0 // @description 顯示台股主要股票資訊,每5分鐘更新,可顯示昨收價,漲跌顯色,整齊排版,可以自己在STOCKS新增股票,就可以無限增加。 // @match *://*/* // @license GPL-3.0 License // @grant GM_xmlhttpRequest // @connect mis.twse.com.tw // ==/UserScript== (function() { 'use strict'; const stocks = [ { name: '加權指數', symbol: 'tse_t00.tw', id: 'price-index' }, { name: '台積電', symbol: 'tse_2330.tw', id: 'price-tsmc' }, { name: '聯發科', symbol: 'tse_2454.tw', id: 'price-mediatek' }, { name: '鴻海', symbol: 'tse_2317.tw', id: 'price-foxconn' } ]; const panel = document.createElement('div'); Object.assign(panel.style, { position: 'fixed', top: '100px', left: '0px', background: '#fff', border: '1px solid #aaa', borderRadius: '8px', boxShadow: '2px 2px 8px rgba(0,0,0,0.3)', zIndex: 999999, width: '320px', fontFamily: 'monospace', whiteSpace: 'nowrap', padding: '5px' }); const header = document.createElement('div'); header.textContent = '台股資訊(TWSE API v1.7)'; Object.assign(header.style, { background: '#333', color: '#fff', padding: '5px', cursor: 'move', textAlign: 'center', fontWeight: 'bold' }); const minBtn = document.createElement('button'); minBtn.textContent = '-'; Object.assign(minBtn.style, { float: 'right', background: '#555', color: 'white', border: 'none', cursor: 'pointer', padding: '0 6px' }); header.appendChild(minBtn); const refreshBtn = document.createElement('button'); refreshBtn.textContent = '⟳'; Object.assign(refreshBtn.style, { float: 'right', background: '#008CBA', color: 'white', border: 'none', cursor: 'pointer', padding: '0 6px', marginRight: '4px' }); header.appendChild(refreshBtn); panel.appendChild(header); const body = document.createElement('div'); Object.assign(body.style, { padding: '6px', fontSize: '13px', background: '#fff' }); stocks.forEach(s => { const row = document.createElement('div'); Object.assign(row.style, { display: 'grid', gridTemplateColumns: "1fr 1fr 1fr", alignItems: "center", marginBottom: '3px' }); const label = document.createElement('span'); label.style.textAlign = 'left'; label.textContent = s.name; const price = document.createElement('span'); price.id = s.id; price.style.textAlign = 'right'; price.textContent = '載入中…'; const closeLabel = document.createElement('span'); closeLabel.style.textAlign = 'right'; closeLabel.textContent = ''; row.appendChild(label); row.appendChild(price); row.appendChild(closeLabel); body.appendChild(row); }); const status = document.createElement('div'); status.id = 'status'; status.textContent = '最後更新:-'; Object.assign(status.style, { color: '#666', fontSize: '11px', marginTop: '5px', textAlign: 'right' }); body.appendChild(status); panel.appendChild(body); document.body.appendChild(panel); // 拖曳功能 (function dragElement(el) { const header = el.querySelector('div'); let pos1, pos2, pos3, pos4; header.onmousedown = function(e) { e.preventDefault(); pos3 = e.clientX; pos4 = e.clientY; document.onmouseup = close; document.onmousemove = drag; }; function drag(e) { e.preventDefault(); pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; el.style.top = (el.offsetTop - pos2) + "px"; el.style.left = (el.offsetLeft - pos1) + "px"; } function close() { document.onmouseup = null; document.onmousemove = null; } })(panel); // 收合功能 minBtn.addEventListener('click', () => { if (body.style.display === 'none') { body.style.display = 'block'; minBtn.textContent = '-'; } else { body.style.display = 'none'; minBtn.textContent = '+'; } }); refreshBtn.addEventListener('click', fetchQuotes); function fetchQuotes() { stocks.forEach(stock => { const url = `https://mis.twse.com.tw/stock/api/getStockInfo.jsp?ex_ch=${stock.symbol}&json=1&delay=0&_=${Date.now()}`; GM_xmlhttpRequest({ method: "GET", url: url, headers: { "User-Agent": "Mozilla/5.0", "Accept": "*/*", "Origin": "https://mis.twse.com.tw" }, onload: function(res) { try { const data = JSON.parse(res.responseText); const info = (data.msgArray && data.msgArray[0]) || null; const el = document.getElementById(stock.id); if (info && info.z && info.y) { let price = parseFloat(info.z); let closeYesterday = parseFloat(info.y); let changePct = ((price - closeYesterday) / closeYesterday * 100).toFixed(2); el.innerHTML = `<span style="color:${price >= closeYesterday ? 'red' : 'green'}">${price.toFixed(2)} (${changePct}%)</span> 昨收:${closeYesterday.toFixed(2)}`; } else { el.textContent = '無資料'; el.style.color = '#999'; } } catch (err) { console.error(stock.name + " 抓取失敗", err); document.getElementById(stock.id).textContent = '錯誤'; } }, onerror: function(err) { console.error(stock.name + " 抓取失敗", err); document.getElementById(stock.id).textContent = '錯誤'; } }); }); status.textContent = '最後更新:' + new Date().toLocaleTimeString(); } fetchQuotes(); setInterval(fetchQuotes, 5 * 60 * 1000); })();