#Vue
Addfox 完全支持 Vue 3,可以使用 .vue 单文件组件开发扩展。
#安装
创建项目时选择 Vue 模板:
pnpm create addfox-app --framework vue或在现有项目中安装:
pnpm add @addfox/rsbuild-plugin-vuenpm install @addfox/rsbuild-plugin-vueyarn add @addfox/rsbuild-plugin-vuebun add @addfox/rsbuild-plugin-vue#配置
// addfox.config.ts
import { defineConfig } from "addfox";
import { pluginVue } from "@addfox/rsbuild-plugin-vue";
export default defineConfig({
plugins: [pluginVue()],
});#项目结构
app/
├── background/
│ └── index.ts
├── content/
│ └── index.ts
├── popup/
│ ├── App.vue
│ ├── index.html
│ └── index.ts
├── options/
│ ├── App.vue
│ ├── index.html
│ └── index.ts
└── manifest.json#示例代码
#Popup
<!-- app/popup/App.vue -->
<template>
<div class="popup">
<h1>{{ title }}</h1>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const title = ref('Hello Vue!');
const count = ref(0);
const increment = () => {
count.value++;
};
</script>
<style scoped>
.popup {
padding: 16px;
min-width: 200px;
}
h1 {
font-size: 18px;
margin-bottom: 12px;
}
button {
padding: 8px 16px;
background: #42b883;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>// app/popup/index.ts
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app');<!-- app/popup/index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>Popup</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./index.ts" data-addfox-entry></script>
</body>
</html>#Content Script
// app/content/index.ts
import { createApp } from 'vue';
import ContentApp from './ContentApp.vue';
// 创建挂载点
const container = document.createElement('div');
container.id = 'my-extension-root';
document.body.appendChild(container);
createApp(ContentApp).mount(container);<!-- app/content/ContentApp.vue -->
<template>
<div class="content-widget">
<p>Hello from Vue Content Script!</p>
</div>
</template>
<style scoped>
.content-widget {
position: fixed;
bottom: 20px;
right: 20px;
background: white;
padding: 16px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 9999;
}
</style>#状态管理
#Pinia
pnpm add pinia// app/stores/counter.ts
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
}),
actions: {
increment() {
this.count++;
},
},
});// app/popup/index.ts
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
const app = createApp(App);
app.use(createPinia());
app.mount('#app');#VueUse
pnpm add @vueuse/core<script setup>
import { useStorage } from '@vueuse/core';
// 自动同步到 chrome.storage
const count = useStorage('count', 0);
</script>#与 Chrome API 交互
<script setup lang="ts">
import { ref, onMounted } from 'vue';
const tabs = ref<chrome.tabs.Tab[]>([]);
onMounted(async () => {
tabs.value = await chrome.tabs.query({});
});
const activateTab = (tabId: number) => {
chrome.tabs.update(tabId, { active: true });
};
</script>
<template>
<ul>
<li
v-for="tab in tabs"
:key="tab.id"
@click="activateTab(tab.id!)"
>
{{ tab.title }}
</li>
</ul>
</template>#CSS 方案
#Tailwind CSS
pnpm add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p/* app/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;<template>
<div class="p-4 bg-gray-100">
<h1 class="text-xl font-bold text-blue-600">Hello Tailwind!</h1>
</div>
</template>#Scoped CSS
Vue 单文件组件天然支持 scoped CSS:
<style scoped>
.button {
background: #42b883;
}
/* 深度选择器 */
:deep(.child) {
color: red;
}
</style>
