[英]How to load Vue Component with InertiaJS in Laravel 8 Modules
[英]Laravel Inertiajs: How to render a generated Vue String To Html on Server side or frontend
我已经实现了一个联系人公式,其中站点管理员可以使用基本的 laravel 和刀片模板从他的管理面板编辑整个公式。
现在我想在 inertiajs (vuejs) 中实现相同的功能。
我制作了一个工具来创建必要的 vue 代码。 所以现在我想在服务器端呈现此代码或在加载站点时动态呈现它。
我对 vue 仍然不是很熟悉,但我已经看到一些像 vue3-runtime-template 这样的库,但它们没有用。
我要呈现的代码如下所示:
<Field
classes="transition duration-500 ease-in-out opacity-100 text-center required">
<label>
Was ist das Thema Ihres Anliegens?
</label>
<div class="grid justify-center">
<div class="flex mt-3 flex-row items-center space-x-4">
<Input type="radio" id="offer" name="category"
:value="'offer'"
classes="opacity-0 absolute left-1/2 peer"
v-model="form.category"
/>
<Label for="offer"
classes="px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full"
>
Fragen zum Angebot
</Label>
</div>
<div class="flex mt-3 flex-row items-center space-x-4">
<Input type="radio" id="business" name="category"
:value="'business'"
classes="opacity-0 absolute left-1/2 peer"
v-model="form.category"
/>
<Label for="business"
classes="px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full"
>
Geschäftliche Anfrage
</Label>
</div>
<div class="flex mt-3 flex-row items-center space-x-4">
<Input type="radio" id="technical" name="category"
:value="'technical'"
classes="opacity-0 absolute left-1/2 peer"
v-model="form.category"
/>
<Label for="technical"
classes="px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full"
>
Technische Probleme
</Label>
</div>
<div class="flex mt-3 flex-row items-center space-x-4">
<Input type="radio" id="other" name="category"
:value="'other'"
classes="opacity-0 absolute left-1/2 peer"
v-model="form.category"
/>
<Label for="other"
classes="px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full"
>
Sonstiges
</Label>
</div>
</div>
</Field>
我已经尝试过的:
v-runtime-template、vue3-runtime-template、v-html 和这个。 以下方法的问题是我无法分别呈现 htmlBefore 和 htmlAfter。
<Field v-for="(children, index) in fields" :key="index"
classes="transition duration-500 ease-in-out text-center"
:class="index === 0 ? 'opacity-100' : 'hidden opacity-0'"
>
<component :is="child.componentType" v-for="(child) in children" v-bind="child" />
</Field>
data() {
return {
fields: [
[
{
htmlBefore: '<label for="category">' +
' Was ist das Thema Ihres Anliegens?' +
' </label>' +
' <div class="grid justify-center">' +
' <div class="flex mt-3 flex-row items-center space-x-4">',
componentType: "Input",
type: "radio",
id: "offer",
name: "category",
value: "offer",
classes: "opacity-0 absolute left-1/2 peer",
model: this.form.category,
},
{
componentType: "Label",
forInput: "offer",
classes: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
labelText: "Fragen zum Angebot",
htmlAfter: "</div>",
},
{
htmlBefore: '<div class="flex mt-3 flex-row items-center space-x-4">',
componentType: "Input",
type: 'radio',
id: 'business',
name: 'category',
value: "business",
classes: "opacity-0 absolute left-1/2 peer",
model: this.form.category,
},
{
componentType: "Label",
forInput: "business",
classes: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
labelText: "Geschäftliche Anfrage",
htmlAfter: "</div>",
},
{
htmlBefore: '<div class="flex mt-3 flex-row items-center space-x-4">',
componentType: "Input",
type: 'radio',
id: 'technical',
name: 'category',
value: "technical",
classes: "opacity-0 absolute left-1/2 peer",
model: this.form.category,
},
{
componentType: "Label",
forInput: "technical",
classes: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
labelText: "Technische Probleme",
htmlAfter: "</div>",
},
{
htmlBefore: '<div class="flex mt-3 flex-row items-center space-x-4">',
componentType: "Input",
type: 'radio',
id: 'other',
name: 'category',
value: "other",
classes: "opacity-0 absolute left-1/2 peer",
model: this.form.category,
},
{
componentType: "Label",
forInput: "other",
classes: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
labelText: "Sonstiges",
htmlAfter: "</div> </div>",
},
],
[
{
componentType: "Textarea",
classes: "w-full h-80 resize-none !text-wonder-blue mt-2 rounded-2xl placeholder-shown:border-wonder-blue",
name: "message",
minLength: 5,
maxLength: 5000,
placeholder: "Hier haben Sie genug Platz, um mir Ihr Anliegen zu schildern",
model: this.form.message,
},
],
[
{
htmlBefore: '<div class="grid space-y-4">' +
' <div class="grid xl:grid-cols-2 xl:space-x-4 w-full">',
componentType: "Input",
name: "firstname",
placeholder: "Vorname*",
classes: "mt-4",
model: this.form.firstname
},
{
componentType: "Input",
name: "lastname",
placeholder: "Nachname*",
classes: "mt-4",
model: this.form.lastname,
htmlAfter: "</div>",
},
{
componentType: "Input",
isRequired: false,
name: "company",
placeholder: "Unternehmen",
model: this.form.company,
},
{
componentType: "Input",
isRequired: false,
name: "website",
placeholder: "Website",
model: this.form.website,
},
{
componentType: "Input",
isRequired: false,
name: "phone",
placeholder: "Telefonnummer",
model: this.form.phone,
},
{
componentType: "Input",
type: "email",
name: "email",
placeholder: "E-Mail Adresse*",
model: this.form.email,
},
{
htmlBefore: '<div class="grid xl:grid-rows-2 w-full">',
componentType: "Input",
type: "hidden",
name: "subscribe_newsletter",
model: this.form.subscribe_newsletter,
classes: "hidden",
value: 0,
},
{
htmlBefore: '<div class="flex mt-3 flex-row items-center space-x-4">',
componentType: "Input",
type: "checkbox",
name: "subscribe_newsletter",
model: this.form.subscribe_newsletter,
classes: "form-checkbox !px-2 !hover:ring-none",
value: 1,
isRequired: false,
},
{
componentType: "Label",
forInput: "subscribe_newsletter",
labelText: "Newsletter abonnieren",
htmlAfter: "</div>",
},
{
htmlBefore: '<div class="flex mt-3 flex-row items-center space-x-4">',
componentType: "Input",
type: "checkbox",
name: "privacy_policy",
model: this.form.privacy_policy,
classes: "form-checkbox !px-2 !hover:ring-none",
value: 1,
isRequired: false,
},
{
componentType: "Label",
forInput: "privacy_policy",
labelText: "Datenschutzerklärung zustimmen*",
htmlAfter: "</div> </div> </div>",
},
],
],
},
},
你可以在你的 vue 文件中使用v-html
并将html
放在那里你可以在 vue文档中看到
我已经解决了这样的问题:
//Vue 组件渲染动态创建的联系表单字段
<Field v-for="(children, index) in fields" :key="index"
class="transition duration-500 ease-in-out text-center"
:class="index === 0 ? 'opacity-100' : 'hidden opacity-0'"
>
<variable-render v-for="(child) in children" v-bind="child"/>
</Field>
//要渲染的联系表单字段
fields: [
[
{
componentType: "FormLabel",
forInput: "category",
labelText: "Was ist das Thema Ihres Anliegens?"
},
{
componentType: "div",
class: "grid justify-center",
children: [
{
componentType: "div",
class: "flex mt-3 flex-row items-center space-x-4",
children: [
{
componentType: "FormInput",
type: "radio",
id: "offer",
name: "category",
value: "offer",
class: "opacity-0 absolute left-1/2 peer",
model: this.form.category,
},
{
componentType: "FormLabel",
forInput: "offer",
class: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
labelText: "Fragen zum Angebot",
},
]
},
{
componentType: "div",
class: "flex mt-3 flex-row items-center space-x-4",
children: [
{
componentType: "FormInput",
type: "radio",
id: "business",
name: "category",
value: "business",
class: "opacity-0 absolute left-1/2 peer",
model: this.form.category,
},
{
componentType: "FormLabel",
forInput: "business",
class: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
labelText: "Geschäftliche Anfrage",
},
]
},
{
componentType: "div",
class: "flex mt-3 flex-row items-center space-x-4",
children: [
{
componentType: "FormInput",
type: "radio",
id: "technical",
name: "category",
value: "technical",
class: "opacity-0 absolute left-1/2 peer",
model: this.form.category,
},
{
componentType: "FormLabel",
forInput: "technical",
class: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
labelText: "Technische Probleme",
},
]
},
{
componentType: "div",
class: "flex mt-3 flex-row items-center space-x-4",
children: [
{
componentType: "FormInput",
type: "radio",
id: "other",
name: "category",
value: "other",
class: "opacity-0 absolute left-1/2 peer",
model: this.form.category,
},
{
componentType: "FormLabel",
forInput: "other",
class: "px-6 hover:cursor-pointer md:px-52 py-3 rounded-lg border border-online-blue peer-checked:text-white peer-checked:bg-wonder-blue peer-hover:text-white peer-hover:bg-wonder-blue w-full",
labelText: "Sonstiges",
},
]
},
]
},
],
],
//变量渲染器.vue
<script>
import {h, resolveComponent} from 'vue';
export default {
name: "VariableRender",
props: {
componentType: String,
children: {
type: Array,
default: undefined
},
},
methods: {
makeVNodeTree(childObject) {
if (Array.isArray(childObject)) {
let childArray = [];
for (let i = 0; i < childObject.length; i++) {
if (childObject[i].children !== undefined) {
let {componentType, children, route, makeVNodeTree, ...newChildObject} = childObject[i];
if(!this.tagIsValid(childObject[i].componentType)){
childArray.push(h(resolveComponent(childObject[i].componentType), newChildObject, this.makeVNodeTree(childObject[i].children)));
} else {
childArray.push(h(childObject[i].componentType, newChildObject, this.makeVNodeTree(childObject[i].children)));
}
} else{
let {componentType, route, makeVNodeTree, ...newChildObject} = childObject[i];
if(!this.tagIsValid(childObject[i].componentType)){
childArray.push(h(resolveComponent(childObject[i].componentType), newChildObject));
} else {
childArray.push(h(childObject[i].componentType, newChildObject));
}
}
}
return childArray;
}
if (childObject.children !== undefined) {
let {children, componentType, route, makeVNodeTree, ...newChildObject} = childObject;
if(!this.tagIsValid(childObject.componentType)){
return h(resolveComponent(childObject.componentType), newChildObject, this.makeVNodeTree(childObject.children));
}
return h(childObject.componentType, newChildObject, this.makeVNodeTree(childObject.children));
}
let {componentType, route, makeVNodeTree, children, ...newChildObject} = childObject;
if(!this.tagIsValid(childObject.componentType)){
return h(resolveComponent(childObject.componentType), newChildObject);
}
return h(childObject.componentType, newChildObject);
},
tagIsValid(tag) {
let tagChecked = document.createElement(tag).toString();
return tagChecked !== "[object HTMLUnknownElement]";
}
},
render() {
return this.makeVNodeTree(
{
componentType: this.componentType,
children: this.children
}
);
}
,
}
</script>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.