Alpine.js + Vue 的可能性

后端模板太缺交互,前后分离效率太低,Next.js狗屎一坨,于是我想到了这么一种可能性。
design-pattern
web-components
Author

XU HUI

Published

December 17, 2025

作为一个前端后端都写的社畜,深深感到现在前后端开发的割裂,分作两个项目怎么也不如一个项目顺手,若是分成前后端几个人来做那就更不必多说。

当然了也有一些方法,比如Next/Nuxt这类由前端库衍生出的全站框架,但这东西有多烂用过的都知道,且不说用JS写后端有多糟,就是前端体验也被大幅劣化了。

HTMX/Alpine.js这两个项目便是在这种背景下诞生的,直接增强HTML,让后端模板也能写出基本的交互,轻量且易用。

还有一个方案就是web-components了,但说实话体验较差,虽然可以很方便使用现有的组件库来加强后端模板,但自定义组件能力约等于0,而且shadow dom的存在使得样式管理极为便秘。

恰好此时我想到了另一样东西:Vue所宣称的“渐进式”。

demo1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
    <div id="app">
        <x-counter></x-counter>
    </div>

    <script>
        const { createApp, defineComponent } = Vue

        const Comp = defineComponent({
            template: `
                <div>
                    <p>{{ message }}</p>
                    <button @click="count++">点击了 {{ count }} 次</button>
                </div>
            `,
            data() {
                return {
                    message: 'Hello Vue!',
                    count: 0
                }
            }
        })
        
        createApp({
            components: { "x-counter": Comp }
        }).mount('#app')
    </script>
</body>
</html>

我估计许多人都不知道Vue是可以不走vite这些工具编译直接在浏览器用的,那么我就想到了一种可能性:用vue编写组件直接在浏览器中引入不就可以吗?缺编辑器支持就把vscode的customData整上,现在有AI辅助这也不是多大个事。

结果一上来我就卡住了,vue需要的数据怎么办,字符串数字啥的还好说,但对象数组这些怎么处理呢?

于是我想到了另一个办法,仅通过vue来复用代码,也就是组件化,数据控制使用别的方案例如alpine.js

demo2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
</head>
<body>
    <div id="app">
        <x-counter x-data="{ message: 'Hello Alpine!', count: 0 }"></x-counter>
    </div>

    <script>
        const { createApp, defineComponent } = Vue

        const Comp = defineComponent({
            template: `
                <div>
                    <p x-text="message"></p>
                    <button x-on:click="count++">点击了 <span x-text="count"></span> 次</button>
                </div>
            `,
            data() {
                return {
                    message: 'Hello Vue!',
                    count: 0
                }
            }
        })
        
        createApp({
            components: { "x-counter": Comp }
        }).mount('#app')
    </script>
</body>
</html>

这种方式似乎不怎么好处理稍复杂些的组件逻辑?事实上这种方式也可以使用预先编译好的vue组件,于是有了一种可能性:前端赋能后端。