emaphp / magento2-module-vuewidget
Vue.js 小部件用于 Magento 2
Requires
- magento/module-widget: >100.0.0
This package is not auto-updated.
Last update: 2024-09-29 05:57:11 UTC
README
Vue 2 小部件用于 Magento 2。
关于
这是一个用于构建和显示使用 Vue.js v2 制作的 Magento 2 模块骨架。它附带一个简单的构建流程,以帮助您快速开始。
要求
本模块假定您正在运行 Magento >=2.2。您还需要安装 Rollup。
快速开始
进入 app/code/ 目录并克隆仓库
cd app/code/ && git clone https://github.com/emaphp/magento2-module-vuewidget Vue/Widget
安装 Node 依赖。您可以使用 npm 或 yarn
cd Vue/Widget && npm install
现在进行首次开发构建。这将编译 assets/ 文件夹中的一些通用组件及其依赖项
npm run dev
返回主应用程序文件夹并启用模块
php bin/magento module:enable Vue_Widget --clear-static-content
php bin/magento setup:upgrade && php bin/magento setup:di:compile
清除缓存
php bin/magento cache:clean
用法
以管理员身份登录。转到 商店 > 设置 > 配置。您应该在底部看到一个名为 Vue 小部件 的新选项。现在,从主菜单转到 内容 > 元素 > 小部件。单击 添加小部件。在 设置 部分,单击 类型 字段。底部应该出现一个 Vue 小部件 选项。然后,选择小部件应包含的区域(例如,在 CMS 主页 中)。
小部件通过名称包含;即,在 requirejs-config.js 中注册它们时使用的 id。在 组件 字段中尝试输入 VueHelloWorld。然后,在下面的表单中单击 添加 按钮。此组件支持一个名为 name 的单个 prop。输入 prop 非常简单,只需填写 名称 和 值 列表。然后,单击 保存。
清除缓存并刷新页面。您应该能够在您选择的页面上查看小部件。
深入
添加组件
将组件添加到您的应用程序的过程将包括以下步骤
- 使用
.vue语法编写组件。将其放入assets/frontend/components文件夹。 - 使用
rollup编译组件。 - 部署资源和清除缓存。
本模块假定您已经熟悉构建 Vue.js 组件,因此我们只涵盖第二个步骤。默认情况下,Magento 无法理解使用 .vue 扩展名(或任何使用 ES6/ES7)的文件。为了解决这个问题,此仓库包含一个构建系统,允许您将这些文件转换为可以在页面上通过 RequireJS 包含的内容。该过程从定义需要转换的文件开始。该信息可以在 rollup.config.js 中找到。此文件的结构非常简单:一个包含应转换哪些文件以及需要哪些插件的数组的文件。在 assets/frontend/components/ 中创建一个名为 VueCounter.vue 的文件,并放入以下内容
<!-- File: assets/frontend/components/VueCounter.vue --> <template> <button class="action primary" type="button" title="Vue Counter" v-on:click="increment"> <span>Count: {{count}}</span> </button> </template> <script> export default { data () { return { count: 0 } }, methods: { increment: function () { this.count++; } } } </script>
现在,为了将此文件转换为纯 JavaScript,我们需要在 rollup.config.js 中添加一个额外的条目。它应该看起来像这样
{ input: './assets/frontend/components/VueCounter.vue', output: { file: './view/frontend/web/js/components/VueCounter.js', format: 'iife', name: 'bundle', }, plugins: [ babel({ exclude: 'node_modules/**' }), resolve(), commonjs(), vue(), magento2() ] }
此条目告诉 rollup 转换文件并将结果内容放在 view/frontend/web/js/components/VueCounter.js 中。打开终端并运行以下命令(确保您位于模块目录中)
npm run build
rollup 现在将分别运行每个入口并生成每个包。此构建系统内部使用 rollup-plugin-magento2 将每个包封装成可以用 RequireJS 导入的东西。一旦这个过程完成,您的模块就被编译,现在可以作为小部件使用。
我们将在 requirejs-config.js 中添加以下行来为这个组件创建一个新的别名
// File: view/frontend/requirejs-config.js var config = { map: { '*': { 'VueCounter': 'Vue_Widget/js/components/VueCounter' } } };
现在,以管理员身份登录并重复 快速入门 指南中描述的步骤。当到达 小部件选项 部分,只需在 组件 字段中输入 VueCounter。清除缓存并重新加载页面。
Vue 块
小部件很好,但它们有点受限。例如,您无法直接从 PHP 传递属性。因此,提供了一个扩展脚本 vueapp 作为替代方案。vueapp 允许您将 Vue 组件注入到常规 HTML 块中。以这种方式使用时,块充当组件容器。任何显示在其中的组件都必须列在 components 属性中
<!-- File: view/frontend/templates/vue-block-example.phtml --> <div id="vue-block-example"> <vue-customer-greeting name="<?php echo $this->getCustomerName() ?>" /> </div> <script type="text/x-magento-init"> { "#vue-block-example": { "vueapp": { "components": [ "VueCustomerGreeting" ] } } } </script>
此示例介绍了一个简单的问候组件,它从 PHP 读取属性。该组件应如下所示
<!-- File: assets/frontend/components/VueCustomerGreeting.vue --> <template> <h5>Hello {{name}}! Welcome to our store.</h5> </template> <script> export default { props: [ 'name' ] }; </script>
我们将此组件注册为 VueCustomerGreeting
// File: view/frontend/requirejs-config.js var config = { map: { '*': { 'VueCustomerGreeting': 'Vue_Widget/js/components/VueCustomerGreeting' } } };
块类的作用是初始化需要提供给组件的任何值。
<?php // File: Block/Widget/VueBlockExample.php namespace Vue\Widget\Block\Widget; use Magento\Framework\View\Element\Template; use Magento\Widget\Block\BlockInterface; use Vue\Widget\Logger\Logger; class VueBlockExample extends Template implements BlockInterface { protected $logger; public function __construct( Template\Context $context, Logger $logger, array $data = [] ) { $this->logger = $logger; parent::__construct($context, $data); } public function getCustomerName() { $this->logger->debug('Getting customer name...'); return 'Guest'; } }
Vue 块只是普通的 .phtml 块,因此它们通过 XML 布局系统包含。下面的示例将此块添加到首页。
<!-- File: view/frontend/layout/cms_index_index.xml --> <?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> <referenceContainer name="main"> <container name="vue-block-example" htmlTag="div" after="-"> <block class="Vue\Widget\Block\Widget\VueBlockExample" name="vue.block.example" template="Vue_Widget::vue-block-example.phtml"/> </container> </referenceContainer> </body> </page>
将此新组件添加到 rollup.config.js 中的入口列表。运行 npm run build,重建布局并清除缓存。您现在应该能够看到更改。
数据提供者
有时您需要将数据作为数组/对象传递给组件。将它们编码为属性可能最初有效,但对于每个值来说有点繁琐。为了将复杂数据传递给组件,我们将使用在 Vue 组件中常用的通用模式,称为 数据提供者。数据提供者 是一种 依赖注入 形式,允许您在块内的所有组件之间共享一组数据。每当您在 vueapp 初始化器上设置 provider 属性时,都会生成此对象。
<!-- File: view/frontend/templates/data-provider-example.phtml --> <div id="data-provider-example"> <data-provider-component /> </div> <script type="text/x-magento-init"> { "#data-provider-example": { "vueapp": { "components": [ "DataProviderComponent" ], "provider": { "categories": <?php echo json_encode($this->getCategories()) ?>, "author": <?php echo json_encode($this->getAuthor(), JSON_FORCE_OBJECT) ?> } } } } </script>
这两个值将由块实例直接提供。
<?php // File: Block/Widget/DataProviderExample.php namespace Vue\Widget\Block\Widget; use Magento\Framework\View\Element\Template; use Magento\Widget\Block\BlockInterface; use Vue\Widget\Logger\Logger; class DataProviderExample extends Template implements BlockInterface { public function __construct( Template\Context $context, Logger $logger, array $data = [] ) { $this->logger = $logger; parent::__construct($context, $data); } public function getCategories() { return [ 'Pants', 'T-Shirts', 'Shoes', 'Ties' ]; } public function getAuthor() { return [ 'name' => "Emma", 'role' => "Developer", 'github' => "https://github.com/emaphp", ]; } }
现在,为了从我们组件中访问这些值,我们将调用 $provider 属性上的 get 方法。
const { categories, author } = this.$provider.get();
您也可以指定一个属性键。
// Single key const categories = this.$provider.get('categories'); // [ 'Pants', 'T-Shirts', ... ]
键可以表示为路径。
// Path const role = this.$provider.get('author.role'); // "Developer"
占位符
Vue 块可以在其布局中包含一个占位符以提供临时的 UI。这些将在组件初始化后自动删除。占位符元素有以下属性
- 它们需要将它们的
role属性设置为placeholder。 - 它们必须是应用容器的直接子元素。
<!-- File: view/frontend/templates/placeholder-example.phtml --> <div id="placeholder-example"> <h3 role="placeholder">Loading...</h3> <slow-widget></slow-widget> </div> <script type="text/x-magento-init"> { "#placeholder-example": { "vueapp": { "components": [ "SlowWidget" ] } } } </script>
在某些情况下,您可能希望进一步延迟删除占位符(例如,在从服务器获取数据后)。可以通过将 placeholderMixin 混合添加到主组件中来实现。此混合注入了一个 $placeholder 属性,该属性提供了 2 个方法:hide 和 remove。
// File: assets/frontend/components/CustomPlaceholderComponent.vue import placeholderMixin from '../mixins/placeholderMixin'; export default { mixins: [ placeholderMixin ], mounted() { // Fetch data fetch('https://api.spacexdata.com/v3/launches/latest') .then(response => response.json()) .then(data => { // ... this.$placeholder.hide(); }); } };
由于我们现在直接处理占位符,我们需要在 vueapp 初始化器上包含一个额外的属性
<!-- File: view/frontend/templates/custom-placeholder.phtml --> <div id="custom-placeholder"> <h3 role="placeholder">Loading...</h3> <custom-placeholder-component></custom-placeholder-component> </div> <script type="text/x-magento-init"> { "#custom-placeholder": { "vueapp": { "components": [ "CustomPlaceholderComponent" ], "placeholder": "custom" } } } </script>
通过设置此属性,应用现在将忽略块体内的任何占位符元素,允许您手动处理它。
事件
占位符也可能受给定事件的影响。为了实现这一点,我们需要提供一个与 event:action 语法匹配的 placeholder 值
<!-- File: view/frontend/templates/placeholder-event.phtml --> <div id="placeholder-event"> <h3 role="placeholder">Loading...</h3> <placeholder-event-component /> </div> <script type="text/x-magento-init"> { "#placeholder-event": { "vueapp": { "components": [ "PlaceholderEventComponent" ], "placeholder": "loaded:hide" } } } </script>
当触发 loaded 事件时,组件将调用占位符对象的 hide 方法。还有一个可用的 remove 方法。
// File: assets/frontend/components/CustomPlaceholderComponent.vue import placeholderMixin from '../mixins/placeholderMixin'; export default { mixins: [ placeholderMixin ], mounted() { // Fetch data fetch('https://api.spacexdata.com/v3/launches/latest') .then(response => response.json()) .then(data => { // ... this.$emit('loaded'); }); } };
您还可以指定一个自定义方法。该方法需要在 methods 中声明,并接受一个表示占位符节点的单个参数。
<!-- File: view/frontend/templates/placeholder-event.phtml --> <script type="text/x-magento-init"> { "#placeholder-event": { "vueapp": { "components": [ "PlaceholderEventComponent" ], "placeholder": "loaded:fadeOut" } } } </script>
// File: assets/frontend/components/PlaceholderEventComponent.vue export default { methods: { fadeOut(placeholder) { placeholder.classList.add('animate', 'fadeOutDown'); } } }
导入 Magento 模块
有时您需要访问由 Magento 提供的 JavaScript 模块。例如,您可能需要使用 jQuery 在 DOM 上生成更改,或者使用 Underscore 进行计算。我们可以通过提供额外的选项来实现这一点。在 rollup.config.js 中使用的 Magento 插件支持一个名为 virtualDir 的选项,允许我们模拟对 JavaScript 模块的通用导入。不会执行实际导入。相反,脚本在转换后声明它依赖于那些导入的模块。以下示例显示了设置 virtualDir 选项的条目
{ input: './assets/frontend/components/ImportExampleWidget.vue', output: { file: './view/frontend/web/js/components/ImportExampleWidget.js', format: 'iife', name: 'bundle', }, plugins: [ babel({ exclude: 'node_modules/**' }), resolve(), commonjs(), vue(), magento2({ virtualDir: 'magento' }), ] }
现在,当导入 JavaScript 模块时,请将模块的名称以 虚拟目录 为前缀。您需要在开始处添加额外的 @ 符号。
// File: assets/frontend/components/ImportExampleWidget.vue import $ from '@magento/jquery'; import { debounce } from '@magento/underscore';
一旦转换,脚本将把您从 虚拟目录 中导入的任何模块添加到依赖项列表中。这样,我们确保脚本仅在加载了那些脚本之后运行。
组件库
另一种巧妙的技术是将所有组件放在单个文件中。这对于您在不同页面上大量重用组件的情况非常有用。库脚本看起来像这样
// File: assets/frontend/fancy_lib.js import Vue from '@magento/vue'; import FancyButton from './components/FancyButton.vue'; import FancyCard from './components/FancyCard.vue'; export default { FancyButton, FancyCard };
然后我们在 rollup.config.js 中添加以下条目
{ input: './assets/frontend/fancy_lib.js', output: { file: './view/frontend/web/js/fancy_lib.js', format: 'iife', name: 'bundle', }, plugins: [ babel({ exclude: 'node_modules/**' }), resolve(), commonjs(), vue(), magento2({ virtualDir: "magento" }), ] }
然后我们在 requirejs-config.js 中创建以下别名
var config = { map: { '*': { 'Fancy_Lib: 'Vue_Widget/js/fancy_lib' } } };
为了检索库中的组件,我们将添加一个特殊的语法元素。要检索来自 Fancy_Lib 的 FancyButton 组件,我们将编写 Fancy_Lib::FancyButton。此规则适用于小部件和应用程序。
<!-- File: view/frontend/templates/library-example.phtml --> <div id="library-example"> <fancy-button></fancy-button> </div> <script type="text/x-magento-init"> { "#library-example": { "vueapp": { "components": [ "Fancy_Lib::FancyButton" ] } } } </script>
附加功能
生产构建
要为所有脚本(包括 Vue.js)生成优化后的构建,请运行 npm run prod。这将使用 Tercer 打包所有资产,这将减小其大小。
如果您想进一步自定义构建过程,我建议您查看 这篇文章。
管理小部件
此模块已包含一个名为 WidgetProps 的管理小部件,您可以在 assets/adminhtml/components 中找到它。这个小部件负责在数据库中存储组件属性。如果您计划更改或添加更多管理小部件,请确保正确清除 adminhtml 缓存(位于 pub/static/adminhtml/THEME_DIR)。否则,您在开发期间可能看不到任何更改。
作为附加说明,Magento_Widget 模块中的 Widget\Instance 类已被覆盖,以便在将属性推送到前端时提供对象作为属性。有关详细信息,请查看 Vue\Widget\Model\Widget\Intance 类。
日志
此模块实现了一个简单的记录器类,可以通过依赖注入注入到任何块中。许多示例使用此类来生成调试消息。您可以在 var/log/vuewidget.log 中找到这些消息。记得在开始之前激活 开发者模式。
变更日志
- 1.0.0:第一个版本。
- 1.1.0:添加:支持生产构建。
许可
Vue.js 由 Evan You 版权所有,并按 MIT 许可证分发。此仓库中包含的其他所有内容均按 MIT 许可证分发。