k3ssen / vue-bundle
为 Symfony (4.4, 5, 6) 应用程序提供的捆绑包,使得结合 Twig 和 Vue 变得简单
Requires
- php: >=7.4.0
- twig/twig: >=1.40.0
Suggests
- ext-json: *
- symfony/webpack-encore-bundle: >=1.7.0
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.vueData
和window.vueStoreData
必须在您的内容之后创建。(在代码后使用vue_add()
不会有任何效果)。window.vueData
和window.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 对象。