emaphp/magento2-module-vuewidget

Vue.js 小部件用于 Magento 2

安装: 0

依赖者: 0

建议者: 0

安全: 0

星标: 0

关注者: 2

分支: 0

开放问题: 0

语言:JavaScript

类型:magento2-module

1.1.0 2022-05-27 19:18 UTC

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 依赖。您可以使用 npmyarn

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 主页 中)。

New Widget

小部件通过名称包含;即,在 requirejs-config.js 中注册它们时使用的 id。在 组件 字段中尝试输入 VueHelloWorld。然后,在下面的表单中单击 添加 按钮。此组件支持一个名为 name 的单个 prop。输入 prop 非常简单,只需填写 名称 列表。然后,单击 保存

Widget Props

清除缓存并刷新页面。您应该能够在您选择的页面上查看小部件。

深入

添加组件

将组件添加到您的应用程序的过程将包括以下步骤

  • 使用 .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 个方法:hideremove

// 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_LibFancyButton 组件,我们将编写 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 许可证分发。