基于 Vue3 的 VBoxes-UI 搭建
基于 Vue3 的 VBoxes-UI 搭建
vboxes-ui 是 vboxes 服务的网页 UI 负责展示从 vboxes 服务请求到的环境数据。而 vboxes 通过分析目录下的所有 .box 文件并将其归类到不同的环境当中去,然后提供不同的接口供网页的数据查询与展示、Vagrant CLI 的数据请求和 .box 文件下载。
vboxe-ui 采用的是 Vue3 框架,配合 Schade-Vue 和 TailwindCSS 的组件与样式创建的一个简单前端网页,目前还处在开发中。
完整项目开发周期可能持续一个月以上,设置一些关键节点能够很好的维持项目的推进。比如完成 vboxes 关键接口或完成 vboxe-ui 创建(等待接口测试)等等。设置节点也方便记录与总结。一口气完成中大型的项目的开发目前来看有点吃力,不仅考验耐力也考验体力[汗]。
以下是已完成内容的实现记录。
VMBoxCard 组件
通过接口请求到的数据是一组相同的数据格式,根据 Vue 的设计思路只需要定义其中一个显示组件,完整数据集的展示直接套用这个组件即可。VMBoxCard 需要展示数据格式参考如下:
{
"name": "ubuntu-focal-desktop-en-qt",
"date": 1750553587,
"author": "vboxes",
"description": "Ubuntu Focal Desktop Environment for Qt Development",
"site": "http://127.0.0.1:9321/api",
"url": "http://127.0.0.1:9321/api/ubuntu-focal-desktop-en-qt",
"vagrantfile": "Vagrant.configure(\"2\") do |config|\n config.vm.box = \"ubuntu-focal-qt\"\n config.vm.box_url = \"http://127.0.0.1:9321/api/ubuntu-focal-desktop-en-qt\"\n\n config.vm.provider \"virtualbox\" do |vb|\n vb.gui = true\n vb.cpus = 4\n vb.memory = \"2048\"\n end\n\n config.vm.provision \"shell\", inline: <<-SHELL\n apt-get update\n SHELL\nend"
}通过上面的 json 数据再结合 AI 就能很轻松地搞定(实际调试和改进花了不少功夫[笑哭])。
AI 可能并不能一次就能做到我们想要的,需要提供必要的提示,然后修改测试。所以 AI 尚且还不能完全接替人工开发。如果从开发者的角度考虑,反而能够为开发者节省大量的时间——不论是设计、实现、问题的排查都比传统的人工加搜索引擎高效得多。因此它更像是个更高级的搜索引擎。
为了优化 VMBoxCard 组件对 Vagrantfile 文件内容的展示和业务需求(代码拷贝和下载),实现了 CodeBlock 组件,完整的 VMBoxCard 组件代码如下:
<template>
<div
class="rounded-2xl shadow p-6 bg-white space-y-4 cursor-pointer hover:ring-2 hover:ring-blue-300 transition"
@dblclick="expanded = !expanded"
>
<h2 class="text-2xl font-semibold text-gray-800">{{ box.name }}</h2>
<div class="flex flex-wrap items-center gap-x-6 text-sm text-gray-500">
<div class="flex items-center gap-1">
<UserRound class="inline-block w-4 h-4 mr-1" /> {{ box.author }}
</div>
<div class="flex items-center gap-1">
<Calendar class="inline-block w-4 h-4 mr-1" /> {{ formattedDate }}
</div>
<div class="flex items-center gap-1">
<Globe class="inline-block w-4 h-4 mr-1" />
<a :href="box.site" target="_blank" class="underline break-all">{{ box.site }}</a>
</div>
</div>
<p class="text-gray-600 leading-relaxed">{{ box.description || '无描述信息' }}</p>
<p class="text-xs italic text-gray-400">💡 单击卡片查看或隐藏 Vagrantfile</p>
<Transition name="fold">
<div
v-if="expanded"
class="overflow-hidden transition-all duration-500 ease-in-out"
>
<CodeBlock :code="box.vagrantfile" language="ruby" filename="Vagrantfile" />
</div>
</Transition>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import CodeBlock from './CodeBlock.vue'
import { UserRound, Calendar, Globe } from 'lucide-vue-next'
const { box } = defineProps({
box: Object
})
const expanded = ref(false)
const formattedDate = computed(() => {
const date = new Date(box.date * 1000)
return date.toLocaleDateString()
})
</script>VMBoxList 组件
通过向服务请求数据,然后使用 v-for 关键字迭代数据集即可,向 VMBoxCard 传递数据可以通过 :box 属性完成,该属性已在 VMBoxCard 组件中定义。
因为接口比较简单,直接使用 fetch() ,内容如下:
<template>
<div class="grid gap-6">
<VMBoxCard v-for="box in boxes" :key="box.name" :box="box" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import VMBoxCard from './VMBoxCard.vue'
const boxes = ref<object[]>([])
fetch('/api')
.then((response) => response.json())
.then((data) => {
boxes.value = data.infos
})
.catch((error) => console.error('Error fetching data:', error))
</script>测试过程中接口地址开和发服务器地址不一致(二者非同一个进程,甚至不在同一台设备上),会出现浏览器同源策略的限制,导致无法获取到接口数据情况。解决同源限制的方式有很多,这里使用的是代理的方式。
编辑 vite.config.js 配置文件,添加指向接口服务反向代理即可解决该问题了。配置文件示例如下:
import { defineConfig } from 'vite'
// 省略的包引用
// https://vite.dev/config/
export default defineConfig({
// 省略的内容
server: {
proxy: {
'/api': {
target: 'http://127.0.0.1:9321',
changeOrigin: true,
//rewrite: (path) => path.replace(/^\/api/, ''),
}
}
}
})运行服务端,等待数据解析完成,最终呈现效果如下

题外话——尝试使用模版文件来启动环境,成功运行 [开心]。

待续
目前的网页部分页仅仅只是完成了基础信息的展示,虽然网页端的核心功能仅限于数据展示,但必然不仅仅是列表信息,除此之外还有搜索与过滤、帮助、文件列表和 .box 文件下载。这只是开始,更多功能还需 vboxes 服务的配合来完成。
参考
- ChatGPT
- Vue.js - 渐进式 JavaScript 框架 | Vue.js
- 开发服务器选项 | Vite 官方中文文档
- 《Vue.js 3 + TypeScript 完全指南》
