可以在呈现的 html 中使用带有模板的 VueJS SFC 组件吗?

Posted

技术标签:

【中文标题】可以在呈现的 html 中使用带有模板的 VueJS SFC 组件吗?【英文标题】:Possible to use VueJS SFC components with with template in rendered html? 【发布时间】:2018-03-18 17:56:58 【问题描述】:

我有使用单页应用和多页应用(经典网站)的经验。过去我在每个页面上都使用过 AngularJS 1.x,它很有用,因为所有组件都可以存在于单独的文件中,并在它们出现在每个页面上时执行。

我现在正在寻找 VueJS 来替代 AngularJS,但发现如何构建我的多页应用程序并不容易。

正如预期的那样,我想在所有页面上使用一些组件,而在少数页面上使用一些组件。

例子:

我使用 ES2015 遇到了 SFC - 单文件组件,看起来很有希望,但我的后端是 Java,它从 JSP 输出我的 html。看起来 .vue 文件是由 webpack 预编译的,但是如果我的模板仅在页面呈现时准备好,那将是不可能的吗?

如何构建一个解决方案,使每个组件都是模块化的,但在 html 中使用 x-template 并以某种方式将其附加到 .vue SFC,或者是否有其他方式可以使用 ES2015 导入的单独文件中的组件?

我希望这是有道理的,似乎无法弄清楚。

【问题讨论】:

你能举一个组件应该包含的内容/功能的例子吗? 我不太确定 Vue,但我们使用 React 做了类似的事情。即一个多页面应用程序,每个页面通过 scala 模板从后端呈现,并在所述 HTML 页面中引用我们的 React 入口点。即从前端的角度来看,每个页面都作为独立的反应应用程序运行,并由 webpack 单独捆绑。那是你要找的吗?还是我离题了? 【参考方案1】:

一种可能的方法是为 Vue 组件内联设置模板。所以这将是有一个像

这样的组件文件

Home.vue:

<script>
    export default 
        data() 
            return 
                msg: 'text',
            
        
    
</script>

将其作为 Vue 的全局组件导入(使用 require、import 等)

Vue.component('home', require('./components/Home.vue'));

在您的服务器生成的 HTML 中,您必须使用内联模板,它具有普通模板的所有灵活性

home.jsp:

<home inline-template>
    <h2 v-text="msg"></h2>
</home>

更新

我在 GitHub 上添加了一个示例here

【讨论】:

我不确定这是否可行,从我读到的 .vue 文件是 SFC 并且是预编译的,你能用一个简单的 github 示例演示这种方法吗? 我在帖子中添加了一个示例链接 你的例子很好。我可以运行内联模板并为每个组件使用 .vue 文件。 很遗憾 vue js 3 不再支持内联模板【参考方案2】:

如果我理解您的问题,您肯定想用 HTML 制作单个文件组件。

如果是这种情况,您应该使用 render() 函数和常规组件。

render 函数决定使用什么作为组件的模板:

<!DOCTYPE html>
<html>
<head>
    <title>Vue</title>
</head>
<body>

<div id="app">
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<script type="text/javascript">
    new Vue(
        el: '#app',
        render (createElement) 
            return createElement(
                template: '<div>Hello World</div>'
            )
        ,
    )
</script>
</body>
</html>

Hello World 渲染到屏幕上。

现在,让我们看看这个函数是如何反应的:

<script type="text/javascript">
    new Vue(
        el: '#app',
        data: 
            count: 0
        ,
        render (createElement) 
            return createElement(
                template: '<div>Hello World ' + this.count + '</div>'
            )
        ,
        created () 
            setTimeout(() => 
                this.count++
            , 2000)
        
    )
</script>

这里,2 秒后,&lt;div&gt;Hello World ' + this.count + '&lt;/div&gt; 中的计数器将从 0 递增到 1。

现在,如果我们想将模板与数据分开怎么办?

<script type="text/javascript">
    new Vue(
        el: '#app',
        render (createElement) 
            return createElement(
                template: '<div>Hello World  count </div>',
                data () 
                    return foo: 'bar'
                
            )
        
    )
</script>

此代码将显示Hello World bar

现在,让我们看看如果我们尝试通过 http 加载模板会发生什么。我们将使用axios 库来执行此操作。让我们创建一个 remote.html 文件来包含我们的 html 代码:

<div>
    I'm a remote component  foo 
</div>

现在,让我们尝试通过 Ajax 加载它:

<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.2/axios.min.js"></script>

<script type="text/javascript">
    new Vue(
        el: '#app',
        data: 
            template: null
        ,
        render (createElement) 
            return createElement(
                template: this.template ? this.template : '<div>Hello World  foo </div>',
                data () 
                    return foo: 'bar'
                
            )
        ,
        created () 
            axios(
                url: '/remote.html',
                method: 'get'
            ).then(response => 
                this.template = response.data
            )
        
    )
</script>

从浏览器加载remote.html 后,此代码将立即显示I'm a remote component foo

请注意,传递给 createElement 函数的对象实际上是一个组件结构。你可以对它使用相同的方法:

render (createElement) 
    return createElement(
        template: this.template ? this.template : '<div>Hello World  foo </div>',
        data () 
            return foo: 'bar'
        ,
        mounted () 
            alert('Hello from mounted')
        
    )

会在浏览器上触发alert

无论如何,这是一个包含嵌套组件的完整示例:

索引.html

<!DOCTYPE html>
<html>
<head>
    <title>Vue</title>
</head>
<body>

<div id="app">
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.2/axios.min.js"></script>

<script type="text/javascript">

    const headerComponent = 
        data () 
            return 
                template: '<div>Loading...</div>'
            
        ,
        render (createElement) 
            return createElement(
                template: this.template,
                data () 
                    return 
                        search: ''
                    
                
            )
        ,
        created () 
            axios('/header.html').then(response => 
                this.template = response.data
            )
        
    

    new Vue(
        el: '#app',
        data: 
            template: null
        ,
        render (createElement) 
            return createElement(
                template: this.template ? this.template : 'Loading...',
                data () 
                    return foo: 'bar'
                ,
                components: 
                    'my-header': headerComponent
                
            )
        ,
        created () 
            axios(
                url: '/remote.html',
                method: 'get'
            ).then(response => 
                this.template = response.data
            )
        
    )
</script>
</body>
</html>

header.html

<div>
    <label>Search</label>
    <input v-model="search" name=""> The search is:  search 
</div>

我不确定这真的是最好的方法,如果我真的在回答这个问题,但它会在列表中为您提供一些关于 Vue 如何处理渲染和组件的提示......

【讨论】:

一个页面由服务器返回 html 呈现(想想遗留),创建模块化组件(在自己的文件中)的最佳方法是什么,它使用已呈现的现有 DOM。 我认为我的回答是对问题的回应......如果你真的想用JSP渲染你的组件模板,使用渲染功能是关键。但是,这显然不是使用它的方式。 SPA 应用程序通常不使用 HTML 来交换数据,它应该使用更面向数据的文档类型,如 JSON 或 XML。所以你的 Java 应该开始返回 JSON 而不是 HTML :) 不幸的是,我需要使用现有的 html。我同意这并不理想,但 VueJS 将绑定到现有的 Dom。

以上是关于可以在呈现的 html 中使用带有模板的 VueJS SFC 组件吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 模板中的 JSON 中安全地使用带有 html 的 JSON

将带有外键的自定义标签呈现到模板问题中

WPF:带有 2 个(或更多!)ContentPresenters 的模板或 UserControl 以在“插槽”中呈现内容

使用带有 JavaScript 模板文字函数的 for 循环

在视图而不是模板中生成带有 Django 静态 url 的图像标签

带有 Python 2.7.6 和 Virtualenv 12.0.7 (OSX10,10.2) 的 Django 1.7.6 - 模板呈现模板语法错误