save
This commit is contained in:
63
public/migrate.html
Normal file
63
public/migrate.html
Normal file
@@ -0,0 +1,63 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Migrate Data</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
async function readIndexedDB() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open('type-words', 1); // 你的数据库名
|
||||
request.onsuccess = function (event) {
|
||||
const db = event.target.result;
|
||||
const tx = db.transaction(['typing-word-dict', 'typing-word-setting', 'typing-word-files'], 'readonly');
|
||||
const result = {};
|
||||
|
||||
let count = 0;
|
||||
const keys = ['typing-word-dict', 'typing-word-setting', 'typing-word-files'];
|
||||
keys.forEach((storeName) => {
|
||||
const store = tx.objectStore(storeName);
|
||||
const allRequest = store.getAll();
|
||||
allRequest.onsuccess = function (e) {
|
||||
result[storeName] = e.target.result;
|
||||
count++;
|
||||
if (count === keys.length) {
|
||||
resolve(result);
|
||||
}
|
||||
};
|
||||
allRequest.onerror = function (e) {
|
||||
result[storeName] = null;
|
||||
count++;
|
||||
if (count === keys.length) resolve(result);
|
||||
};
|
||||
});
|
||||
};
|
||||
request.onerror = function (e) {
|
||||
resolve({});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 监听 postMessage
|
||||
window.addEventListener('message', async (e) => {
|
||||
if (e.data && e.data.type === 'requestData') {
|
||||
const local = {};
|
||||
['PracticeSaveWord', 'PracticeSaveArticle'].forEach(key => {
|
||||
local[key] = localStorage.getItem(key) || null;
|
||||
});
|
||||
|
||||
const indexed = await readIndexedDB();
|
||||
|
||||
// 回复新域名
|
||||
e.source.postMessage({
|
||||
type: 'responseData',
|
||||
localStorageData: local,
|
||||
indexedDBData: indexed
|
||||
}, e.origin);
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -10,9 +10,9 @@
|
||||
<meta name="keywords"
|
||||
content="Type Words, Typing Word, Type Words 官网, 官方网站, 英语打字练习, 单词跟打, 文章跟打, 键盘练习, 英语学习, 文章学习, 打字练习软件, 单词记忆工具, 英语学习软件, 背单词神器, 英语肌肉记忆, 键盘工作者, 免费英语学习, 音标发音, 默写练习, 在线学英语, CET-4, CET-6, TOEFL, IELTS, GRE, GMAT, SAT, 考研英语, 专四专八, 程序员英语, JavaScript API, Node.js API, Java API, Linux命令, 编程词汇, 技术英语, VSCode插件, 开源项目, GitHub趋势榜, V2EX热搜, Gitee GVP, 少数派推荐, 英语打字训练, WPM统计, 准确率分析, 商务英语, BEC, 雅思听力, 日语学习, 多语言学习, 英语口语练习, 单词拼写训练">
|
||||
|
||||
<meta name="author" content="zyronon" />
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<link rel="canonical" href="https://typewords.cc/" />
|
||||
<meta name="author" content="zyronon"/>
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1"/>
|
||||
<link rel="canonical" href="https://typewords.cc/"/>
|
||||
|
||||
<!-- Open Graph(用于社交媒体分享,微信/QQ/知乎/Facebook 等) -->
|
||||
<meta property="og:title" content="Type Words 官网 - 英语打字练习平台">
|
||||
@@ -31,22 +31,22 @@
|
||||
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.png"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<!-- 苹果设备(iOS Safari)在用户添加到主屏时显示的图标-->
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/favicon.png" />
|
||||
<!-- 设置浏览器地址栏颜色(在 Android Chrome 特别明显)。-->
|
||||
<meta name="theme-color" content="#818CF8" />
|
||||
<!-- 苹果设备(iOS Safari)在用户添加到主屏时显示的图标-->
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/favicon.png"/>
|
||||
<!-- 设置浏览器地址栏颜色(在 Android Chrome 特别明显)。-->
|
||||
<meta name="theme-color" content="#818CF8"/>
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
|
||||
<!-- 阻止 iOS 自动把数字识别为电话号码。-->
|
||||
<!-- HandheldFriendly 和 MobileOptimized 是旧手机浏览器的优化提示(现在作用不大)。-->
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta name="HandheldFriendly" content="True" />
|
||||
<meta name="MobileOptimized" content="320" />
|
||||
<!-- 阻止 iOS 自动把数字识别为电话号码。-->
|
||||
<!-- HandheldFriendly 和 MobileOptimized 是旧手机浏览器的优化提示(现在作用不大)。-->
|
||||
<meta name="format-detection" content="telephone=no"/>
|
||||
<meta name="HandheldFriendly" content="True"/>
|
||||
<meta name="MobileOptimized" content="320"/>
|
||||
|
||||
<!-- referrer 控制请求来源信息-->
|
||||
<meta name="referrer" content="origin-when-cross-origin" />
|
||||
<!-- color-scheme 告诉浏览器支持亮/暗模式-->
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
<!-- referrer 控制请求来源信息-->
|
||||
<meta name="referrer" content="origin-when-cross-origin"/>
|
||||
<!-- color-scheme 告诉浏览器支持亮/暗模式-->
|
||||
<meta name="color-scheme" content="light dark"/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
@@ -243,7 +243,7 @@
|
||||
.bottom {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin:1rem 0 2rem 0;
|
||||
margin: 1rem 0 2rem 0;
|
||||
width: 100%;
|
||||
padding-top: 1.5rem;
|
||||
border-top: 1px solid #c4c4c4;
|
||||
@@ -306,6 +306,7 @@
|
||||
toggleEl('.mask')
|
||||
toggleEl('#wechatDialog')
|
||||
}
|
||||
|
||||
function toggleQQDialog() {
|
||||
toggleEl('.mask')
|
||||
toggleEl('#qqDialog')
|
||||
@@ -323,6 +324,66 @@
|
||||
toggleEl('#qqDialog', true)
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function migrateFromOldDomain() {
|
||||
return new Promise((resolve) => {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.style.display = 'none';
|
||||
iframe.src = 'https://2study.top/migrate.html';
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
// 接收数据
|
||||
window.addEventListener('message', async function handler(e) {
|
||||
if (e.data && e.data.type === 'responseData') {
|
||||
// 写入 localStorage
|
||||
const localData = e.data.localStorageData;
|
||||
for (const key in localData) {
|
||||
if (localData[key] !== null) localStorage.setItem(key, localData[key]);
|
||||
}
|
||||
|
||||
// 写入 IndexedDB
|
||||
const indexedData = e.data.indexedDBData;
|
||||
const request = indexedDB.open('type-words', 1);
|
||||
request.onupgradeneeded = function (event) {
|
||||
const db = event.target.result;
|
||||
// 建 store
|
||||
['typing-word-dict', 'typing-word-setting', 'typing-word-files'].forEach(name => {
|
||||
if (!db.objectStoreNames.contains(name)) {
|
||||
db.createObjectStore(name, {autoIncrement: true});
|
||||
}
|
||||
});
|
||||
};
|
||||
request.onsuccess = function (event) {
|
||||
const db = event.target.result;
|
||||
const tx = db.transaction(['typing-word-dict', 'typing-word-setting', 'typing-word-files'], 'readwrite');
|
||||
for (const storeName in indexedData) {
|
||||
const store = tx.objectStore(storeName);
|
||||
const items = indexedData[storeName];
|
||||
if (items) {
|
||||
items.forEach(item => store.put(item));
|
||||
}
|
||||
}
|
||||
tx.oncomplete = function () {
|
||||
resolve(true);
|
||||
window.removeEventListener('message', handler);
|
||||
iframe.remove();
|
||||
};
|
||||
};
|
||||
|
||||
// 发送请求
|
||||
iframe.contentWindow.postMessage({type: 'requestData'}, 'https://2study.top');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (location.href === 'https://typewords.cc/') {
|
||||
migrateFromOldDomain().then(() => {
|
||||
console.log('数据迁移完成!');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
@@ -458,7 +519,13 @@
|
||||
</div>
|
||||
|
||||
<div class="icon" onclick="toggleQQDialog()">
|
||||
<svg viewBox="0 0 24 24" width="1.4em" height="1.4em"><g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M12 2a6.285 6.285 0 0 0-6.276 5.937l-.146 2.63a28 28 0 0 0-.615 1.41c-1.24 3.073-1.728 5.773-1.088 6.032c.335.135.913-.426 1.566-1.432a6.67 6.67 0 0 0 1.968 3.593c-1.027.35-1.91.828-1.91 1.33c0 .509 2.48.503 4.239.5h.001c.549-.002 1.01-.008 1.38-.057a6.7 6.7 0 0 0 1.76 0c.37.05.833.055 1.382.056c1.76.004 4.239.01 4.239-.499c0-.502-.883-.979-1.909-1.33a6.67 6.67 0 0 0 1.967-3.586c.65 1.002 1.227 1.56 1.56 1.425c.64-.259.154-2.96-1.088-6.032a28 28 0 0 0-.607-1.395l-.147-2.645A6.285 6.285 0 0 0 12 2"/></g></svg>
|
||||
<svg viewBox="0 0 24 24" width="1.4em" height="1.4em">
|
||||
<g fill="none">
|
||||
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/>
|
||||
<path fill="currentColor"
|
||||
d="M12 2a6.285 6.285 0 0 0-6.276 5.937l-.146 2.63a28 28 0 0 0-.615 1.41c-1.24 3.073-1.728 5.773-1.088 6.032c.335.135.913-.426 1.566-1.432a6.67 6.67 0 0 0 1.968 3.593c-1.027.35-1.91.828-1.91 1.33c0 .509 2.48.503 4.239.5h.001c.549-.002 1.01-.008 1.38-.057a6.7 6.7 0 0 0 1.76 0c.37.05.833.055 1.382.056c1.76.004 4.239.01 4.239-.499c0-.502-.883-.979-1.909-1.33a6.67 6.67 0 0 0 1.967-3.586c.65 1.002 1.227 1.56 1.56 1.425c.64-.259.154-2.96-1.088-6.032a28 28 0 0 0-.607-1.395l-.147-2.645A6.285 6.285 0 0 0 12 2"/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="icon" onclick="toggleXhsDialog()">
|
||||
<svg viewBox="0 0 24 24" width="1.4em" height="1.4em">
|
||||
@@ -492,7 +559,7 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div><a href="https://beian.miit.gov.cn/" target="_blank">蜀ICP备2025157466号</a></div>
|
||||
<div><a href="https://beian.miit.gov.cn/" target="_blank">蜀ICP备2025157466号-2</a></div>
|
||||
</div>
|
||||
|
||||
<div class="mask" onclick="closeDialog()"></div>
|
||||
|
||||
10
src/App.vue
10
src/App.vue
@@ -77,10 +77,10 @@ async function init() {
|
||||
|
||||
onMounted(init)
|
||||
|
||||
let transitionName = $ref('go')
|
||||
const route = useRoute()
|
||||
watch(() => route.path, (to, from) => {
|
||||
return transitionName = ''
|
||||
// let transitionName = $ref('go')
|
||||
// const route = useRoute()
|
||||
// watch(() => route.path, (to, from) => {
|
||||
// return transitionName = ''
|
||||
// console.log('watch', to, from)
|
||||
// //footer下面的5个按钮,对跳不要用动画
|
||||
// let noAnimation = [
|
||||
@@ -97,7 +97,7 @@ watch(() => route.path, (to, from) => {
|
||||
// const fromDepth = routes.findIndex(v => v.path === from)
|
||||
// transitionName = toDepth > fromDepth ? 'go' : 'back'
|
||||
// console.log('transitionName', transitionName, toDepth, fromDepth)
|
||||
})
|
||||
// })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
Reference in New Issue
Block a user