
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:
- (padrão) Mostrar um imagem em miniatura/pôster para o vídeo
- (passar o mouse) Mostra uma visualização de vídeo agregada e costurada (muito parecida com o esta postagem)
- (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!