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!