k3ssen/vue-bundle

为 Symfony (4.4, 5, 6) 应用程序提供的捆绑包,使得结合 Twig 和 Vue 变得简单

v0.1.0 2022-07-12 16:04 UTC

This package is auto-updated.

Last update: 2024-09-12 21:03:25 UTC


README

一个小的 SymfonyBundle,使得结合 Twig 和 Vue 变得简单。

而不是使用繁琐的 data-* 属性或为几乎任何东西创建 API-endpoint,此捆绑包允许您通过在 Twig 中调用 {{ vue_data('someVariable', someObjectOrValue) }} 将数据传递给 vue。可以通过使用 v_model 表单选项在 Vue 中使用表单数据。有关更多详细信息,请参阅使用方法

支持的版本

  • PHP 7.4 和 8
  • Symfony 4.4, 5 和 6
    较旧版本可能也能工作,但这些版本未经过检查,因为它们不再维护。
  • Vue 2 和 3
    此捆绑包主要提供后端逻辑,不受 Vue 版本的限制。这些不同版本需要略微不同的代码才能使此捆绑包正常工作。更多内容请参阅下面的文档。

设置 - 快速入门

安装捆绑包: composer require k3ssen/vue-bundle

您可能希望使用带有 Symfony Encore 的 VueJs 设置(有关详细信息,请参阅下方的使用 Encore 设置),但为了快速尝试此捆绑包,您可以在 Twig 代码中使用下面的 include-script(如果您想使用版本 2,请将 3 替换为 2

{% include '@Vue/_vue3_script.html.twig' %}

这将激活 id 为 app 的元素上的 vue,因此您需要设置此 id 的元素。

示例

如果您使用 Symfony 的 MakerBundle 运行 php bin/console maker:controller Dashboard,您应该有一个 template/dashboard/index.html.twig 文件。您可以用以下内容替换 body 块

{% block body %}
    <div id="app">
        {{ vue_data('count', 1) }}
        <button @click="count++" v-text="'Counter: ' + count"></button>
    </div>
    {% include '@Vue/_vue3_script.html.twig' %}
{% endblock %}

这将导致在点击按钮时计数器增加。

使用 Encore 设置

您可以在 Symfony 的指南中找到有关安装 Encore启用 Vue 的详细信息。

1. 安装 encore

composer require symfony/webpack-encore-bundle

2. 启用 Vue.js

webpack.config.js 中启用 Vue

    // ...
    Encore
        // ...
        .enableVueLoader(() => {}, {
            runtimeCompilerBuild: true,
            useJsx: true
        })
    // ...

提示

  • 您可能还希望取消注释 webpack.config.js 中的 // enableSassLoader 以使用 scss(这也可以用于 vue 组件)。
  • 如果您想使用 TypeScript,还应该取消注释 //.enableTypeScriptLoader()
    • 请确保将 assets/app.js 重命名为 assets/app.js 以防止在 yarn watch 期间出现一些讨厌的异常

3. 安装资产

运行 yarn install 然后运行 yarn dev。您可能需要安装一些额外的包。您可以按照这些说明重新运行 yarn dev 直到完成。

注意:截至编写,Encore 建议安装 vue@^2.5 并使用适当的加载器。如果您想使用 Vue 3,应删除或使用不同的版本约束条件为 vue 包。

4. Twig vue-javascript 设置

服务器端数据必须传递给 vue,这可以通过全局 window 对象实现。例如,您可以在 base.html.twig 中添加以下代码

<div id="app">
    {% block body %}{% endblock %}
</div>
<script>
    window.vueData = {{ get_vue_data() | raw }};
    window.vueStoreData = {{ get_vue_store() | raw }};
</script>

以下内容是相关的

  • 您想使用 Vue 的内容应包装在具有 "app" id 的元素中。
  • window.vueDatawindow.vueStoreData 必须在您的内容之后创建。(在代码后使用 vue_add() 不会有任何效果)。
  • window.vueDatawindow.vueStoreData 必须在加载 app.js 之前创建。Encore 默认使用 defer 在 script 标签上,在这种情况下,这应该可以正常工作。

5. 创建 Vue 实例

最后,必须创建一个使用此数据的 vue-instance。打开您的 assets/app.js 以添加一些代码(见下文)。

Vue2

import Vue from 'vue';

const vue = window.vue ?? {};

// Read the data of the already existing vue-object into a variable.
const vueObjectData = typeof vue.data === 'function' ? vue.data(): (vue.data ?? {});
// Merge the vueData with the already existing vueObjectData
vue.data = () => Object.assign(window.vueData ?? {}, vueObjectData);

// Uncomment line below to use different default delimiters (only applies to the global vue-object you use in Twig)
// vue.delimiters ??= ['${', '}$'];

// Create a reactive global $store variable that can be used in all components.
Vue.prototype.$store = Vue.observable(window.vueStoreData ?? {});

vue.el ??= '#app';
new Vue(vue);

Vue3

import { createApp, reactive  } from 'vue';

const vue = window.vue ?? {};

// Read the data of the already existing vue-object into a variable.
const vueObjectData = typeof vue.data === 'function' ? vue.data(): (vue.data ?? {});
// Merge the vueData with the already existing vueObjectData
vue.data = () => Object.assign(window.vueData ?? {}, vueObjectData);

// Uncomment line below to use different default delimiters (only applies to the global vue-object you use in Twig)
// vue.delimiters ??= ['${', '}$'];

const app = createApp(vue);

// Create a reactive global $store variable that can be used in all components.
app.config.globalProperties.$store = reactive(window.vueStoreData ?? {});

app.mount(vue.el ?? '#app');

Typescript
如果您使用 Typescript,则应编辑 app.ts。您可以使用类似的代码,但需要对编译器做一些修改。

使用方法

使用全局 Vue 对象

复杂的 Vue 逻辑应编写在 Vue 组件中,但有时您想在 Twig 中进行相对简单的 Vue 操作,而无需任何麻烦。

通过使用全局对象,这变得相当简单

{% extends 'base.html.twig' %}

{% block body %}
    <div id="app">
        <h1>Seconds passed: ${ seconds }$</h1>
        <p v-if="seconds > 5">
            More than 5 seconds have passed.
        </p>
    </div>
    <script>
        vue = {
            delimiters: ['${', '}$'],
            data: () => ({
                seconds: 0,
            }),
            mounted() {
                setInterval(() => this.seconds++, 1000);
            },
        }
    </script>
{% endblock %}

将服务器端数据传递到 Vue

当您想将实体等服务器端数据传递到 Vue 时,您可能需要像这样的东西

<script>
    vue = {
        data: () => ({
            someObject: {{ someObject | json_encode | raw }},
        })
    }
</script>

这可以正常工作,但对于只需提供数据的简单场景来说,这有点过于冗长。

为了使这更简单、更简洁,此捆绑包添加了这些 Twig 函数

  • vue_add('someObject', someObject)
    实际上,这与上面的代码有相同的效果。
  • vue_store('someObject', someObject)
    为了创建一个全局的 $store.someObject 变量,可以在所有组件中访问。
  • vue('someObject', someObject)
    与 vue_add 的功能相同,但它返回键,因此您可以直接将其用作属性。
  • someObject|vue
    一个类似于 vue 函数的 twig 过滤器,但它允许您省略对象的键名。

在表单中使用 v_model

一个典型的情况是您有一个表单,您想在其中使用一些 Vue 逻辑。

此捆绑包添加了一个 VueFormTypeExtension,它提供了一个 v_model 选项,这使得在表单字段中添加 v-model 并将数据提供给 Vue 变得非常容易。

例如,您的控制器操作可以包含以下代码来构建表单

$form = $this->createForm(TextType::class, null, [
    'v_model' => 'name',
]);

然后在 Twig 中,您可以使用 name 变量作为 Vue 数据。

{{ form_start(form) }}
{{ form_widget(form) }}
<button :disabled="!name">Submit</button>
{{ form_end(form) }}

其他服务器端数据

如果您有其他要提供给 Vue 的数据,您可以使用 VueDataStorage 服务。

这最终归结为该服务内部的一个数组,该数组被转换为可用于 Vue 的 json 对象。