可以在呈现的 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 秒后,<div>Hello World ' + this.count + '</div>
中的计数器将从 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 - 模板呈现模板语法错误