representación de html sin procesar desde dentro de vuejs

Aug 17 2020

https://codepen.io/AnonymousCaptain/pen/eYZZOyO

He hecho esto, pero necesito que mi "{{data.body}}" se interprete como HTML.

Soy un novato total y espero que alguien por ahí pueda ayudarme.

Hasta ahora me he golpeado la cabeza contra la pared digital mirando la directiva llamada v-html... pero no estoy seguro de si eso es lo que se supone que debo usar.

También he visto a personas hacer algo como:

Vue.component("aplicación", { plantilla:HTML

https://www.digitalocean.com/community/tutorials/vuejs-raw-html-bindingEsto podría ser lo que necesito?

Por favor, indícame una solución :)

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>

Respuestas

1 zuchmanski Aug 17 2020 at 19:29

Puedes usar v-htmlde esta manera:

<p v-html="data.body"></p>

Representará html dentro de la <p>etiqueta.

s4k1b Aug 17 2020 at 19:31

Si desea usar algún texto como html en vue, puede usarv-html

Aunque habrá una advertencia para no usar v-htmlporque usar esto hará que su aplicación sea propensa a ataques XSS.

Esta advertencia siempre estará ahí y está ahí por una buena razón. Para evitar ataques XSS, solo necesita desinfectar la cadena html que está insertando sin procesar. Este proceso de saneamiento eliminará cualquier cosa que pueda conducir a la ejecución de secuencias de comandos de HTML, evitando así los ataques XSS y para que pueda inyectar de forma segura conjuntos completos de nodos HTML en su DOM utilizando v-html.

DOMPurify , que ha sido revisado por varios expertos en seguridad, es una biblioteca adecuada para desinfectar su html sin procesar.