Render-HTML aus Vuejs heraus rendern
https://codepen.io/AnonymousCaptain/pen/eYZZOyO
Ich habe das gemacht, aber ich brauche mein "{{data.body}}", um als HTML interpretiert zu werden.
Ich bin absoluter Neuling und hoffe, dass mir jemand da draußen helfen kann.
Bisher habe ich meinen Kopf gegen die digitale Wand geschlagen, als ich mir die Direktive namens v-html angesehen habe ... aber ich bin mir nicht sicher, ob ich das verwenden soll.
Ich habe auch Leute gesehen, die so etwas getan haben:
Vue.component("app", { Vorlage:HTML
https://www.digitalocean.com/community/tutorials/vuejs-raw-html-bindingDas ist vielleicht das, was ich brauche?
Bitte weisen Sie mich auf eine Lösung hin :)
new Vue({
el: '#magiccardapp',
data: {
message: 'Hello',
tabs: {
'Title 1': {
subtitle: 'some text here',
title: 'Awesome Title',
body: 'Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!',
img_1: 'https://placedog.net/320/180/?random',
img_2: 'https://placedog.net/320/180/?random'
},
'Title 2': {
subtitle: 'some cool text here',
title: 'This is great',
body: 'Lorem ipsasdfasdfasd alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!',
img_1: 'https://placedog.net/320/180/',
img_2: 'https://placedog.net/320/180/'
},
'Title 3': {
subtitle: 'some epic text here',
title: 'Look I\'m a title!',
body: 'Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam aliasdfasdfaas architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!',
img_1: 'https://cdn.mos.cms.futurecdn.net/QjuZKXnkLQgsYsL98uhL9X-320-80.jpg',
img_2: 'https://aldf.org/wp-content/uploads/2018/06/sad-dog-1846066_1920-320x180.jpg'
},
'Title 4': {
subtitle: 'some other text here',
title: 'LOREM IPSUM?',
body: 'Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!',
img_1: 'https://cdn.mos.cms.futurecdn.net/QjuZKXnkLQgsYsL98uhL9X-320-80.jpg',
img_2: 'https://aldf.org/wp-content/uploads/2018/06/sad-dog-1846066_1920-320x180.jpg'
},
},
activeTab: 'Title 1',
},
computed:{
tabContent() {
return this.tabs[this.activeTab];
},
},
methods: {
setTabActive(tab) {
this.activeTab = tab;
}
},
components:{
'TabContent': {
props: {
data: Object,
},
}
},
})
/*tabs*/
magiccarddeck {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
grid-gap: 1rem 1rem;
align-items: center;
max-width: 1000px;
padding: 1rem 1rem;
font-family: "Open Sans",
sans-serif;
text-align: center;
}
magiccard:hover {
transform: scale(1.05);
border-radius: 0.25rem;
overflow: hidden;
transition: 1s;
-webkit-transition: 1s;
}
.line {
height: 2px;
width: 100%;
margin: auto;
background-color: #c38e3d;
}
magiccard {
background: ghostwhite;
border-radius: 0.25rem;
overflow: hidden;
transition: 1s;
-webkit-transition: 1s;
cursor: pointer;
height: 100%;
color: black;
border: 0.3rem solid #c38e3d;
height: max-content;
filter: brightness(50%);
}
magiccard:hover {
filter: brightness(100%);
}
magiccard.active {
cursor: unset;
transform: scale(1.05);
filter: brightness(100%);
}
magiccard h3 {
justify-content: center;
letter-spacing: 4px;
margin: 0px;
color: black;
font-weight: 400;
font-size: 20px;
line-height: 90%;
padding-left: 0%;
padding-top: 3%;
padding-bottom: 3%;
border-radius: 20px;
}
magiccard p {
line-height: 1.6;
}
/* BOTTOM */
section {
font-family: "Open Sans",
sans-serif;
font-weight: 800;
color: ghostwhite;
font-size: 12px;
}
#workshopgrid {
padding: 1rem 1rem;
max-width: 1000px;
justify-self: center;
}
workshopbox {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
border: 0.3rem solid #c38e3d;
border-radius: 0.5rem;
background: ghostwhite;
padding: 1rem 2rem;
grid-template-areas:
'text'
'img';
}
@media (min-width: 800px) {
workshopbox {
grid-template-columns: 3fr 1fr;
grid-template-areas:
'text img';
}
workshopdescription {
border-right-style: groove;
padding-right: 2%;
}
workshopimg {
padding-left: 1rem;
}
}
@media (max-width: 799px) {
workshopbox {}
workshopdescription {
border-bottom-style: groove;
}
workshopimg {
padding-top: 1rem;
}
}
.workshoptext {
grid-area: 1 / 1 / 2 / 2;
grid-area: text;
margin: 0px;
color: black;
font-weight: 400;
font-size: 15px;
line-height: 100%;
padding-top: 3%;
padding-bottom: 2%;
}
workshopdescription {
grid-area: 1 / 1 / 2 / 2;
grid-area: text;
margin: 0px;
color: black;
font-weight: 400;
font-size: 15px;
line-height: 100%;
padding-top: 3%;
padding-bottom: 2%;
}
workshopdescription h1 {
line-height: initial;
}
workshopimg {
grid-area: 1 / 2 / 2 / 3;
grid-area: img;
display: grid;
grid-gap: 1rem;
color: black;
align-content: center;
/* border-left: 1px solid; */
justify-content: center;
}
/*transitions*/
.fade-enter-active > *,
.fade-leave-active > * {
transition-duration: 200ms;
transition-property: opacity, transform;
transition-timing-function: cubic-bezier(0.6, 0.15, 0.35, 0.8);
}
.fade-enter > *,
.fade-leave-to > * {
opacity: 0;
transform: translateY(40px);
}
.fade-enter-active > *:nth-child(2) {
transition-delay: 100ms;
}
.fade-enter-active > *:nth-child(3) {
transition-delay: 200ms;
}
.fade-leave-active > *:nth-child(1) {
transition-delay: 200ms;
}
.fade-leave-active > *:nth-child(2) {
transition-delay: 100ms;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<main id="magiccardapp">
<magiccarddeck>
<magiccard v-for="(tab, tabName) in tabs" :key="tabName" @click="setTabActive(tabName)" :class="{'active': tabName === activeTab}">
<h3 class="tab-copy">{{ tabName }}</h3>
<div class="line"></div>
{{tab.subtitle}}
</magiccard>
</magiccarddeck>
<section id="workshopgrid">
<workshopbox>
<workshopdescription>
<transition name="fade" mode="out-in" appear :duration="500">
<tab-content v-for="(tabContent, t) in tabs" :data="tabContent" :key="'content'+t" v-if="t === activeTab" inline-template>
<div class="content">
<h1>{{data.title}}</h1>
<p>{{data.body}}</p>
</div>
</tab-content>
</transition>
</workshopdescription>
<tab-content v-for="(tabContent, t) in tabs" :data="tabContent" :key="'workshopimg'+t" v-if="t === activeTab" inline-template>
<workshopimg>
<img :src="data.img_1">
<img :src="data.img_2">
</workshopimg>
</tab-content>
</workshopbox>
</section>
</main>
Antworten
Sie können auf v-htmldiese Weise verwenden:
<p v-html="data.body"></p>
Es wird HTML innerhalb des <p>Tags rendern.
Wenn Sie Text als HTML in vue verwenden möchten, können Sie verwendenv-html
Obwohl es eine Warnung geben wird, es nicht zu verwenden, v-htmlda dies Ihre App anfällig für XSS-Angriffe macht.
Diese Warnung wird immer da sein und hat einen guten Grund. Um XSS-Angriffe zu verhindern, müssen Sie nur Ihre HTML-Zeichenfolge bereinigen, die Sie roh einfügen. Dieser Bereinigungsprozess entfernt alles, was zur Skriptausführung aus HTML führen könnte, und verhindert so XSS-Angriffe, sodass Sie mit v-html.
DOMPurify , das von verschiedenen Sicherheitsexperten überprüft wurde, ist eine geeignete Bibliothek zum Bereinigen Ihres Roh-HTML.