【问题标题】:Is it possible to render a PHP frontend into a Vue node?是否可以将 PHP 前端渲染到 Vue 节点中?
【发布时间】:2024-05-29 17:35:01
【问题描述】:

我有一个旧的 PHP 应用程序,我想慢慢迁移到 Vue。 PHP 应用程序以相当复杂的方式呈现一堆 HTML 和 javascript 文件,即

foo.js.php
...
<script src="mysite.com/some_js_file.js" />
...
const a = '<?=$variable_from_php?>';

所以最终浏览器显然不知道这些js文件是如何构造的,但是可以运行它们。我想做的是从外层 Vue 应用程序请求 index 页面以获取旧版应用程序的某个子部分,并将其渲染到 Vue 节点,作为一种微前端。当我请求每个索引时,它当然会包含一个标题,其中包含该微前端需要运行的许多其他导入(脚本/样式)。所以,这个问题有两个部分:1)在 Vue.使用v-html?框架? (请说没有 iframe)和 2)这种方法是否会出现任何安全问题(因为我基本上是说获取标头中的所有 JS 并运行它)。让我知道这个问题是否有意义。谢谢!

【问题讨论】:

  • 是否可以使用H-include 或网络组件(如micro-frontends.org)?
  • 您是否尝试将 PHP 动态生成的 HTML 渲染为 Vue 模板?或者您想在现有 PHP 生成的内容旁边添加新的 Vue 内容?
  • @ssc-hrep3 第一个,从 PHP 动态生成的 HTML。然而,就迁移而言,我想基本上只是盲目地将 Vue 组件的内容设置为这个 HTML,然后不再为它烦恼,因为它可以完全管理自己。
  • 没有很好的解决方案。脚本不由 v-html、innerHTML 或类似的处理。它们的元素应使用document.createElement("script") 显式创建。开箱即用的 jQuery html 支持此功能,如有必要,请使用它。即使处理了脚本,它们也不会以与原始页面相同的顺序进行评估,因为它们是以这种方式异步加载的。而且即使可行,Vue 应用也不应该是 SPA,因为您无法在页面之间进行适当的清理,会出现错误和内存泄漏。
  • 安全性由旧版应用决定。结果不能比它更容易受到攻击,但可能更容易受到攻击,这取决于如何利用这些黑客攻击新应用程序。就安全性和常识而言,iframe 是这里唯一直接的方式。

标签: javascript php html vue.js


【解决方案1】:

Vue.js 可以以两种不同的方式使用:对于更复杂的应用程序,您将使用构建过程并从源代码预编译模板,这些模板通常是单文件组件 SFC; *.vue 文件。然后模板将成为渲染函数,并且没有 HTML 最终出现在输出资产中。然而,还有另一种定义 Vue 组件的方法。您可以使用仅运行时的 Vue 包内联定义它们。对于迁移和较小的应用程序,建议使用这种方法。您需要包含编译器。另请参阅有关该主题的 Vue 文档 Vue v2Vue v3)。如果您将 Vue 作为模块导入并且缺少编译器,请参阅 here

如果您想将 PHP 动态生成的 HTML 渲染为 Vue 模板,则需要第二种方法。请记住,使用这种方法,您始终需要使生成的 PHP 输出与 Vue 组件同步。并且您需要完全信任您使用 PHP 生成的 HTML,否则您将面临注入风险。

然而,还有另一个问题:您需要将生成的 PHP 输出 HTML 作为 JavaScript 中的字符串,并且不应被浏览器解释(理想情况下)或再次从 DOM 中删除。因此,您需要(根据您的项目)决定如何生成 HTML,以便可以将其作为 JavaScript 字符串读取。以下是一些方法:

  1. 将 HTML 直接生成到页面中。然后,定义您要定位的元素,使用.innerHTML 获取 HTML 并从 HTML 中删除节点(缺点:您将渲染 HTML 两次,可能会产生短暂的视觉故障)。
  2. 通过 XHR 从单独的页面获取 HTML。您将直接将 HTML 作为字符串包含在响应中(参见例如fetch)。
  3. 围绕生成的 HTML 内容渲染 &lt;script type="text/x-template" id="static-html-content"&gt;&lt;/script&gt;。然后,您不需要将 HTML 作为字符串,您可以直接使用 id 作为参考(使用template: '#static-html-content')。见the documentation of X-Templates in Vue

然后,您可以使用仅运行时版本的 Vue 并定义您的组件。这是一个活生生的例子:

const Counter = {
  // retrieve and add your template string here
  template: `
  <div class="counter">
    This is a counter: {{ counter }}
    <button @click="counter++">Increase Counter</button>
  </div>
  `,
  data: function() {
    return {
      counter: 0
    }
  }
};

const App = {
  components: { Counter },
  template: `
    <div class="app">
      This is the app component.
      <hr />
      <counter />
    </div>
  `
};

new Vue({
  el: '#element',
  template: '<App />',
  components: { App }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="element"></div>

另一种方法是仅在具有v-html 属性的组件中呈现HTML 字符串。然而,这个解决方案的主要缺点是内容不是反应性的。您不能更改内部组件数据并期望模板对更改做出反应。因此,您错过了 Vue 的主要优势,但您并不仅限于与您的组件内部结构匹配的模板。


Vue 论坛也有类似的提问:link

【讨论】:

  • 这是关于服务器渲染模板的一个很好的解释,但它没有解决问题的重点,即如何处理这些模板中的脚本。
【解决方案2】:

也许你需要:一个模块 php 或组件作为 template.php(php server)

    export const templateOfAdvanceTemplatePage = `
  <div class="content edit-page management">
    <md-card class="page-card">
     <?php echo "My Component" ?>
    </md-card>
  </div>

从节点服务器

     import * as url from "url";

var templateOfAdvanceTemplatePage = url.parse("http://www.website.com/template.php");
    
    export default {
      template: templateOfAdvanceTemplatePage,
      ...
    }

更多信息导入vue here, php 为javascript file here

【讨论】: