前言
最近手痒,想做一个自己的新标签页扩展。
经过一段时间的折腾,终于搞出了这个叫"瓦砾Tab"的扩展。主打的就是简约简单
先看看效果
项目架构
项目结构大概是这样的:
csharp
vue-quick-extension/
├── public/ # 静态资源
│ ├── manifest.json # Chrome扩展配置
│ ├── manifest-firefox.json # Firefox扩展配置
│ └── imgs/ # 背景图片
├── src/
│ ├── newtab/ # 新标签页模块
│ │ ├── App.vue # 主组件
│ │ ├── components/ # 各种组件
│ │ └── composables/ # 组合式API
│ └── styles/ # 全局样式
├── scripts/ # 构建脚本
├── vite.config.ts # Chrome构建配置
├── vite.config.firefox.ts # Firefox构建配置
└── package.json
核心功能实现
1. 搜索引擎切换
这个功能其实挺简单的,就是维护一个搜索引擎列表,然后根据用户选择拼接URL:
php
const searchEngines = ref([
{ name: 'Google', url: 'https://www.google.com/search?q=' },
{ name: '百度', url: 'https://www.baidu.com/s?wd=' },
{ name: '必应', url: 'https://www.bing.com/search?q=' },
{ name: 'GitHub', url: 'https://github.com/search?q=' }
])
const handleSearch = () => {
const query = searchQuery.value.trim()
// 判断是否为网址
if (query.includes('.') && !query.includes(' ')) {
const url = query.startsWith('http') ? query : `https://${query}`
window.location.href = url
} else {
// 使用搜索引擎
const searchUrl = currentEngine.value.url + encodeURIComponent(query)
window.location.href = searchUrl
}
}
2. 快捷链接管理
这个是比较复杂的功能,涉及到数据的增删改查,还有分类管理。我用了组合式API来封装:
typescript
export const useQuickLinks = () => {
const quickLinks = ref<QuickLink[]>([])
const categories = ref<Category[]>([])
// 按分类分组
const linksByCategory = computed(() => {
const grouped: Record<string, QuickLink[]> = {}
categories.value.forEach(category => {
grouped[category.id] = quickLinks.value
.filter(link => link.categoryId === category.id)
.sort((a, b) => a.order - b.order)
})
return grouped
})
// 添加链接
const addQuickLink = (linkData) => {
const newLink = {
...linkData,
id: generateId(),
createdAt: Date.now(),
updatedAt: Date.now()
}
quickLinks.value.push(newLink)
return newLink
}
// 其他CRUD操作...
}
3. 数据持久化
由于是浏览器扩展,数据都存在localStorage里。为了防止数据丢失,我做了容错处理:
javascript
const loadData = () => {
try {
const savedQuickLinks = localStorage.getItem(QUICKLINKS_KEY)
if (savedQuickLinks) {
quickLinks.value = JSON.parse(savedQuickLinks)
} else {
// 没有数据就用默认的
quickLinks.value = [...defaultQuickLinks]
}
} catch (error) {
console.error('加载数据失败:', error)
// 出错了也用默认数据
quickLinks.value = [...defaultQuickLinks]
}
}
4. 响应式设计
CSS这块主要用了Grid和Flexbox,再配合媒体查询做响应式:
css
.links-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
gap: 8px;
}
@media (max-width: 768px) {
.links-grid {
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}
}
多浏览器支持的坑
这个项目最大的挑战就是要同时支持Chrome和Firefox。两个浏览器的扩展API虽然大部分兼容,但manifest文件格式完全不同:
- Chrome用的是Manifest V3
- Firefox还是Manifest V2
所以我搞了两套构建配置:
javascript
// vite.config.ts - Chrome版本
export default defineConfig({
plugins: [
vue(),
{
name: 'copy-manifest',
generateBundle() {
this.emitFile({
type: 'asset',
fileName: 'manifest.json',
source: JSON.stringify(require('./public/manifest.json'), null, 2)
})
}
}
],
// ...
})
// vite.config.firefox.ts - Firefox版本
export default defineConfig({
build: {
outDir: 'dist-firefox',
// ...
}
// ...
})
构建和打包
为了方便开发和发布,我写了几个脚本:
json
{
"scripts": {
"dev": "vite",
"build:chrome": "vite build",
"build:firefox": "vite build --config vite.config.firefox.ts",
"build:all": "npm run build:chrome && npm run build:firefox",
"build:package": "node scripts/build-extension.js"
}
}
build:package
这个命令会自动构建两个版本,然后打包成zip文件,直接就能上传到应用商店了。
项目地址
代码已经开源,欢迎star和fork:
- GitHub: github.com/PBHAHAHA/Wa...
有什么问题欢迎在评论区讨论!
如果这篇文章对你有帮助,记得点个赞👍