如何在另一个 vue 应用程序中包含 vue 应用程序?

Dav*_*SEY 4 javascript vue.js vuejs2

我目前被要求生成将包含在不同客户网站中的小部件。

让我们这样说:

例子

有2个约束:

  1. 禁止使用 iframe
  2. 客户网站可以使用任何技术(PHP、React、Angular、Vue.js、JQuery 等)来完成

由于请求的小部件应该是交互式的,我想使用 javascript 框架来开发它(我想到了 Vue.js)。

但是,我认为这可能会导致一些冲突(甚至破坏客户的网站),例如,如果客户的网站已经在使用另一个版本的 Vue.js。

我花了几个小时寻找和思考解决方案,但期望使用 iframe 我没有找到任何东西......

=> 有没有办法将 Vue.js 应用程序包含在另一个 Vue.js 应用程序(或 React、Angular 等)中?

在此先感谢您的帮助。

And*_*hiu 14

我现在的公司通常在我们客户的网页中提供嵌入式应用程序。注意:虽然下面的例子是用 编写的.ts,但它在.js.

在测试了各种方法(Vue 非常灵活)之后,我们最终做了以下事情:

该方法受mapbox-gl的模型启发,适用于 Vue。
基本原则很简单:将整个应用程序导出为一个干净的 JS 类(通过单个脚本导入)并运行

new SomeClass(selector, config);
Run Code Online (Sandbox Code Playgroud)

为此,我通常创建一个 someClass.ts文件(main.ts通常会完成这项工作),但会导出一个类:

new SomeClass(selector, config);
Run Code Online (Sandbox Code Playgroud)

注:进行此晶莹剔透:以上的进口是必要的(即:axiosi18n,等等-这只是一个例子)。做你main.ts(或main.js)通常在做的事情。然后创建Instance、注入配置、导出类以及您可能需要的任何命名导出Instance

以上已经完成了工作(如果您使用build下面指定的命令构建它),但您还必须适应main.ts导入此类并在服务时呈现应用程序:

import Vue from 'vue';
import App from './App.vue';
import store from './store';
import i18n from '@/plugins/i18n';
import VA from 'vue-axios';
import axios from 'axios';
import store from './store';
...

Vue.use(VA, axios);
Vue.config.productionTip = false;

const Instance = new Vue({
  store,
  i18n,
  components: { App },
  data: () => ({ config: {} }),
  render: function(createElement) {
    return createElement('app', {
      props: { config: this.config }
    });
  }
});

export default class SomeClass {
  constructor(selector: string, config: SomeClassConfig) {
    Vue.set(Instance, 'config', {
      ...config,
      // id is optional. but allows setting the app's `id` dynamically to same `id`
      // as the context page placeholder (which app replaces), for consistency
      // for this, you have to assign `config.id` to App's `$el` in its `mounted()`
      id: selector.replace('#', '')
      // or document.querySelector(selector).id || 'someClassApp'
    });
    Instance.$mount(selector);
    return Instance;
  }
}

// optional exports, used for type inheritance throughout the app
export const { $http, $t, $store } = Instance;
Run Code Online (Sandbox Code Playgroud)

而且public/index.html是这样的:

import SomeClass from '@/someClass';

export default new SomeClass('#devhook', {
 // config object
});

const app = document.querySelector('#devhook');
if (app instanceof HTMLElement) {
  app.addEventListener('some-event', function(e) {
    if (e instanceof CustomEvent) {
      console.log(e.detail);
      // you can test events emitted for context app here...
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

构建命令是:

vue-cli-service build --target lib --name SomeClass --inline-css --inline-vue src/someClass.ts
Run Code Online (Sandbox Code Playgroud)

请注意,我们正在导出src/someClass.ts. 你最终会得到一个名为SomeClass.umd.js.

此外,将此设置添加到config.vue.js

configureWebpack: {
  output: {
    libraryExport: 'default'
  }
}
Run Code Online (Sandbox Code Playgroud)

将使您无需.default()在上下文页面中导入类即可初始化该类。如果没有上面的 webpack 选项,你需要像这样初始化它:

new Someclass.default(selector, config);
Run Code Online (Sandbox Code Playgroud)

其他一切都很标准。

现在上下文页面只需要导入.umd.js,实例化应用程序

new SomeClass(selector, config)
Run Code Online (Sandbox Code Playgroud)

...并在渲染元素上添加一个或多个侦听器。

.umd.js出口可以从外部服务器提供服务,很明显,可以从进口npm包。

您不必--inline-css--inline-vue如果单独加载它们更有意义(即:Vue 可能已经存在于上下文页面中)。此外,我经常依赖上下文页面中已经存在的库(您希望重用尽可能多的库),使用vue.config.js

configureWebpack: {
  externals: {
    lodash: 'window._'
  }
}
Run Code Online (Sandbox Code Playgroud)

执行此操作时,请记住添加一个指向 lodash/jquery/whatever cdn in 的脚本public/index.html,以便在服务/开发时加载它,就像在上下文页面中一样。

最后,demo.html(用于展示 prod 构建)看起来像这样:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="./favicon.ico">
    <!-- VueJS -->
    <script src="https://cdn.jsdelivr.net/npm/vue@latest/dist/vue.min.js"></script>
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="devhook"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

当然,您必须在应用程序脚本 ( ./SomeClass.umd.min.js)之前向其中添加所有外部组件(如果您使用了任何外部组件)。不要defer他们。该应用程序希望在window它启动时加载它们。

至于冲突,你不应该有任何冲突。Vue 在未成年人之间高度兼容,因此您可以简单地使用上下文页面的 Vue(而不是内联它)。此外,Vue 2 语法应该与 Vue 3 完全兼容(例如,您可以使用 Vue 3 运行 Vue 2 应用程序,而无需对其进行任何更改 - 我们将看到)。