Vue JS

Embora o React.js tenha atraído grande parte da atenção durante a última onda de frameworks JavaScript, o Vue.js tornou-se discretamente o favorito de muitos desenvolvedores que consideram o React excessivamente complexo e não querem lidar com as ferramentas do Webpack. Com o Vue, basta incluir o arquivo JavaScript do Vue na página, criar alguns modelos e pronto: um retorno aos dias originais da estrutura JavaScript.


Cloudinary, o incrível serviço de armazenamento e entrega de mídia, fornece APIs em praticamente todas as linguagens para ajudar os desenvolvedores a usar seu serviço, incluindo Node.js, Python, PHP, React etc. Eu queria dar uma olhada no Vue e achei que não haveria melhor maneira de fazer isso do que criar componentes centrados em mídia com a ajuda da API do Cloudinary. Meu objetivo era criar um componente de vídeo que espelhasse o que se vê em muitos sites centrados em vídeo: carregar uma miniatura, reproduzir a visualização ao passar o mouse e, finalmente, reproduzir o vídeo quando clicado. Vamos lá!




Observação rápida: o componente Vue.js que estou criando para esta postagem poderia ser mais otimizado (use um único <video> , trocar controles, transições animadas, etc.), mas quero manter esta publicação o mais simples e focada possível. O objetivo principal é ilustrar como o Cloudinary e o Vue.js são complementares um ao outro e ambos são incrivelmente fáceis de usar!


Componente Vue


Eu queria criar um componente porque, assim como o React, eles são facilmente contidos e reutilizáveis. Vamos começar dando uma olhada no modelo do componente.


Modelo de componente


Ver o esqueleto HTML fornecerá uma visão do que estaremos manipulando:



<div v-on:mouseenter="showPreview()" v-on:mouseleave="hidePreview()" class="cloudinary-video-item" :style="dimensions">
  <div class="cloudinary-video-item-image">
    <img :src="https://davidwalsh.name/poster" :width="width" :height="height" alt="Video Preview">
  </div>
  <div class="cloudinary-video-item-active">
    <video ref="previewVideo" autoplay loop :width="width" :height="height"></video>
  </div>
  <div class="cloudinary-video-item-video">
    <video ref="fullVideo" autoplay controls :width="width" :height="height"></video>
  </div>
  <svg
     v-on:click="play()"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:cc="http://creativecommons.org/ns#"
     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
     xmlns:svg="http://www.w3.org/2000/svg"
     xmlns="http://www.w3.org/2000/svg"
     id="play-icon"
     version="1.1"
     height="50"
     width="50"
     viewBox="0 0 1200 1200">
    <path
       d="M 600,1200 C 268.65,1200 0,931.35 0,600 0,268.65 268.65,0 600,0 c 331.35,0 600,268.65 600,600 0,331.35 -268.65,600 -600,600 z M 450,300.45 450,899.55 900,600 450,300.45 z"
       id="path16995" />
  </svg>
</div>


Nosso componente tem quatro elementos filhos imediatos: três elementos que são mostrados ou exibidos com base em um estado CSS e um ícone SVG “play”. Os estados são:

  1. (padrão) Mostrar um imagem em miniatura/pôster para o vídeo
  2. (passar o mouse) Mostra uma visualização de vídeo agregada e costurada (muito parecida com o esta postagem)
  3. (ativo) Mostra o vídeo inteiro


Esses estados serão manipulados por métodos de componentes que alteram o state do elemento raiz; sua visibilidade será manipulada pelo seletor CSS correspondente a cada estado;

Propriedades do componente


Com o objetivo de manter esse componente simples, limitei o número de propriedades apenas àquelas que são realmente necessárias:



Vue.component('cloudinary-video', {
  props: {
    account: { type: String, required: true, default: 'david-wash-blog' },
    alias: { type: String, required: true },
    // These can be strings as they come in as attributes
    width: { type: String, default: 400 },
    height: { type: String, default: 300 }
  },


Perceba que a API de transformação do Cloudinary é tão poderosa que eu poderia adicionar dezenas de propriedades para aproveitar todo o seu poder, mas esta postagem se transformaria em um romance! Há algumas outras propriedades que exigem valores computados com base nas propriedades simples, portanto, vamos criá-las também:



computed: {
  dimensions: function() {
    return `width:${this.width}px; height:${this.height}px;`;
  },
  poster: function() {
    return `http://res.cloudinary.com/${this.account}/video/upload/${this.alias}.jpg`;
  },
  preview: function() {
    return `http://res.cloudinary.com/${this.account}/video/upload/so_0,du_2/l_video:${this.alias},fl_splice,so_12/du_2/fl_layer_apply/l_video:${this.alias},fl_splice,so_24/du_2/fl_layer_apply/l_video:${this.alias},fl_splice,so_36/du_2/fl_layer_apply/l_video:${this.alias},fl_splice,so_48/du_2/fl_layer_apply/l_video:${this.alias},fl_splice,so_80/du_2/fl_layer_apply/${this.alias}.mp4`;
  },
  fullVideo: function() {
    return `http://res.cloudinary.com/${this.account}/video/upload/${this.alias}.mp4`;
  }
},


As propriedades computadas podem fazer referência a propriedades simples, que são muito utilizadas neste componente.


Métodos de componentes


Os métodos do componente serão empregados para acionar a funcionalidade durante a mouseenter, mouseleave, e click eventos:



methods: {
  play: function () {
    // Hide the preview
    this.hidePreview();
    // Set the state to "play" to show full video element
    this.$el.setAttribute('state', 'playing');
    // Set the full video element src
    this.$refs.fullVideo.src = this.fullVideo;
  },
  showPreview: function() {
    // If the full video is loaded and playing, ignore this event
    if(this.$el.getAttribute('state') === 'playing') {
      return;
    }
    // Update state for CSS / component's child element visibility
    this.$el.setAttribute('state', 'preview');
    // Set the preview video source
    this.$refs.previewVideo.src = this.preview;
  },
  hidePreview: function() {
    // If the full video is loaded and playing, ignore this event
    if(this.$el.getAttribute('state') === 'playing') {
      return;
    }
    // Update state for CSS / component's child element visibility
    this.$el.setAttribute('state', '');
    // Stop the video
    this.$refs.previewVideo.pause();
  }
},


Embora eu use o atributo state , saiba que não estou usando o Flux ou qualquer outro utilitário de gerenciamento de estado – o atributo simplesmente representa qual dos três estados do componente deve ser mostrado ou ocultado.


Componente CSS


O CSS necessário para esse componente parece muito grande, mas ele gerencia principalmente o layout simples, bem como o “estado”: mostrar e ocultar cada elemento filho do componente, conforme necessário:



.cloudinary-video-item {
  position: relative;
}

.cloudinary-video-item > div {
  position: absolute;
  top: 0;
  left: 0;
}

.cloudinary-video-item img {
  display: block;
}

.cloudinary-video-item svg {
  position: absolute;
  top: 40%;
  left: 45%;
  cursor: pointer;
  opacity: 0.6;
}
.cloudinary-video-item svg:hover {
  opacity: 0.9;
}

/* Default / image only state */
.cloudinary-video-item .cloudinary-video-item-active,
.cloudinary-video-item .cloudinary-video-item-video {
  display: none;
}

/* Preview state */
.cloudinary-video-item[state=preview] .cloudinary-video-item-active {
  display: block;
}
.cloudinary-video-item[state=preview] .cloudinary-video-item-image {
  display: none;
}

/* Playing state */
.cloudinary-video-item[state=playing] .cloudinary-video-item-video {
  display: block;
}
.cloudinary-video-item[state=playing] .cloudinary-video-item-image,
.cloudinary-video-item[state=playing] .cloudinary-video-item-active,
.cloudinary-video-item[state=playing] svg {
  display: none;
}


Há uma quantidade razoável lá, mas a minificação dificilmente deixaria um rastro!


Usando o componente


Com cada suporte em props contendo um valor padrão, exceto pelo alias de mídia, é claro, o uso do componente pode ser simples:



<!-- simplest usage -->
<cloudinary-video alias="cartoon"></cloudinary-video>

<!-- customized usage -->
<cloudinary-video
  account="david-wash-blog"
  alias="cartoon"
  width="640"
  height="360">
</cloudinary-video>


E, por fim, adicionando um new Vue para dar início a tudo:



new Vue({ el: '#video-holder' })


É assim que é fácil criar um componente Vue.js para sua mídia do Cloudinary!




Fechamento


Criar um componente Vue que usa vários tipos de mídia gerada a partir de uma única fonte foi fácil graças ao Cloudinary. O Cloudinary gerou a imagem de amostra, o pôster do vídeo, o vídeo de visualização e entregou rapidamente esses recursos, bem como o vídeo de origem. A API simples do Vue tornou a criação do componente Cloudinary divertida e com pouco código. Estou ansioso para brincar com o Vue e o Cloudinary para criar alguns componentes de mídia realmente poderosos!