Exibindo mídia com HTML e JavaScript

Oct 02 2020

Tenho um site pessoal que uso para compartilhar vídeos e imagens com amigos. Abaixo está um gerador de mídia usando JavaScript e HTML. Seu principal objetivo é exibir uma imagem por vez com o clique de um botão, mas qualquer tipo de mídia pode ser exibida. Meu objetivo era criar uma página de carregamento rápido para conter todas as minhas mídias.

//VIDEO ARRAY
var oddvideo = [
  'video1',
  'video2',
  'video3',
  'video4',
  'video5',
];
//AUDIO ARRAY
var oddaudio = [
  'audio1',
  'audio2',
  'audio3',
  'audio4',
  'audio5',
];
//PHOTO ARRAY
var oddphoto = [
  'photo1',
  'photo2',
  'photo3',
  'photo4',
  'photo5',
];
//TEXT ARRAY
var oddtext = [
  'text1',
  'text2',
  'text3',
  'text4',
  'text5',
];

//RANDOM UNUSED ARRAY ITEMS
var Uvideo = [];
var Uaudio = [];
var Uphoto = [];
var Utext = [];
//OLD-NEW VARIABLES
var videoFor = 0;
var audioFor = 0;
var photoFor = 0;
var textFor = 0;
//NEW-OLD VARIABLES
var videoRev = oddvideo.length - 1;
var audioRev = oddaudio.length - 1;
var photoRev = oddphoto.length - 1;
var textRev = oddtext.length - 1;

//GENERATOR FUNCTION
function newThing() {
    //RANDOM MODE
    if(mode1.checked && (videoCheck.checked || audioCheck.checked || photoCheck.checked || textCheck.checked)) {
      if (videoCheck.checked) {
        if (!Uvideo.length) Uvideo = [...oddvideo];
        var randomY = Uvideo;
      }
      if (audioCheck.checked) {
        if (!Uaudio.length) Uaudio = [...oddaudio];
        var randomY = Uaudio;
      }
      if (photoCheck.checked) {
        if (!Uphoto.length) Uphoto = [...oddphoto];
        var randomY = Uphoto;
      }
      if (textCheck.checked) {
        if (!Utext.length) Utext = [...oddtext];
        var randomY = Utext;
      }
      var randomX = Math.floor(Math.random() * (randomY.length));
      var y = randomY;
      var x = randomX;
      document.getElementById("thingDisplay").innerHTML = y[x];
      // remove randomx from the unused array since it's been used now
      randomY.splice(randomX, 1);
}
//OLD-NEW MODE
if(mode2.checked && (videoCheck.checked || audioCheck.checked || photoCheck.checked || textCheck.checked)) {
    if(videoCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddvideo[videoFor];
        videoFor++;
        if (videoFor >= oddvideo.length) videoFor = 0;
    }
    if(audioCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddaudio[audioFor];
        audioFor++;
        if (audioFor >= oddaudio.length) audioFor = 0;
    }
    if(photoCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddphoto[photoFor];
        photoFor++;
        if (photoFor >= oddphoto.length) photoFor = 0;
    }
    if(textCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddtext[textFor];
        textFor++;
        if (textFor >= oddtext.length) textFor = 0;
    }
}
//NEW-OLD MODE
if(mode3.checked && (videoCheck.checked || audioCheck.checked || photoCheck.checked || textCheck.checked)) {
    if(videoCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddvideo[videoRev];
        videoRev--;
        if (videoRev < 0) videoRev = oddvideo.length - 1;
    }
    if(audioCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddaudio[audioRev];
        audioRev--;
        if (audioRev < 0) audioRev = oddaudio.length - 1;
    }
    if(photoCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddphoto[photoRev];
        photoRev--;
        if (photoRev < 0) photoRev = oddphoto.length - 1;
    }
    if(textCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddtext[textRev];
        textRev--;
        if (textRev < 0) textRev = oddtext.length - 1;
    }
}
}
<body>
  <div align="center" id='thingDisplay'></div>
  
  <div align="center">
    <button onclick="newThing()">New Thing</button>
  </div>
  
  <form id="mode">
    <label><input type="radio" name="modes" id="mode1"/></label>&nbsp;Random
    <br/><label><input type="radio" name="modes" id="mode2"/></label>&nbsp;Old&nbsp;-&nbsp;New
    <br/><label><input type="radio" name="modes" id="mode3"/></label>&nbsp;New&nbsp;-&nbsp;Old
  </form>

  <div align="right">
    <form id="categories" align="right">
      Video<label>&nbsp;<input type="radio" name="thing" id="videoCheck"/></label><br/>
      Audio<label>&nbsp;<input type="radio" name="thing" id="audioCheck"/></label><br/>
      Photo<label>&nbsp;<input type="radio" name="thing" id="photoCheck"/></label><br/>
      Text<label>&nbsp;<input type="radio" name="thing" id="textCheck"/></label>
    </form>
  </div>
</body>

Algumas coisas a serem observadas ...

  • Organizo os arrays de JavaScript com o mais novo no topo e o mais antigo na parte inferior (com datas, ficaria assim:

    oddDate = ['Oct. 1', 'Oct. 2', 'Oct. 3', 'Oct. 4', 'Oct. 5']; 
    
  • O modo aleatório é pseudoaleatório e é projetado para exibir todos os itens do array uma vez antes de repetir um.

  • Os modos antigo-novo e novo-antigo movem-se pelas matrizes de cima para baixo e de baixo para cima , respectivamente.

  • Cada modo e categoria salva seu lugar quando você muda para um diferente. Por exemplo, digamos que você tenha o modo antigo-novo ativado e esteja no item 3 da categoria de texto. Você muda para a categoria de foto, percorre um pouco a matriz e retorna à categoria de texto. Ele exibirá o próximo item de onde você parou anteriormente - ou seja, o item 4 . O mesmo pode ser dito para alternar entre os três modos; eles são todos independentes uns dos outros. Isso é algo que eu gostaria de manter.

  • Uma preocupação é que o gerador e a página ficarão cada vez mais lentos à medida que continuo adicionando mais itens aos arrays, mas não tenho certeza se isso é legítimo. Na versão ao vivo, existem mais de 500 itens em cada matriz e mais serão adicionados ao longo do tempo.

Respostas

2 SᴀᴍOnᴇᴌᴀ Oct 08 2020 at 03:22

Feedback geral

Este código parece funcionar de forma aceitável, embora a semântica de "antigo - novo" pareça invertida.

O primeiro marcador nas notas afirma:

  • Organizo os arrays de JavaScript com o mais novo na parte superior e o mais antigo na parte inferior (com datas, seria assim: oddDate = ['01 de outubro', '2 de outubro', '3 de outubro', ' 4 ',' 5 de outubro '];)

Ainda assim, o terceiro marcador afirma:

  • Os modos antigo-novo e novo-antigo movem-se pelas matrizes de cima para baixo e de baixo para cima , respectivamente.

Isso parece contraditório, pois se o mais antigo estiver na parte inferior , a classificação antigo-novo deve começar no final da matriz.

O código JavaScript parece muito repetitivo - especialmente na função, newThing()mas também nos nomes das variáveis. Eu recomendo algumas mudanças descritas mais tarde, após a revisão.

Reveja

Javascript

Declarações de variáveis

O código usa alguns recursos específicos para ECMAScript-2015 (AKA ES-6) como a sintaxe de propagação . Com as variáveis ​​ES6 é aconselhável usar conste letlimitar o escopo das variáveis ​​e evitar bugs . Observe que constisso não significa imutabilidade, mas sim que tal variável não pode ser reatribuída.

Variáveis ​​globais

O código faz referência a elementos DOM usando as variáveis ​​criadas implicitamente a partir dos atributos de id - por exemplo,

if(mode1.checked && (videoCheck.checked || audioCheck.checked || photoCheck.checked || textCheck.checked)) {

Se você quiser testar a unidade do código JavaScript, isso pode dificultar.

Rótulos de entrada

Parece que todas as entradas de rádio são contidas por <label>entradas, o que é bom para acessibilidade (por exemplo, leitores de tela, capacidade do usuário de clicar no rótulo para focar / ativar a entrada), no entanto, o texto próximo a cada entrada não está dentro do rótulo. Parece inútil ter um rótulo se a entrada for a única coisa nele.

HTML

Manipuladores de eventos inline

O código configura manipuladores de eventos no código HTML:

<button onclick="newThing()">New Thing</button>

É melhor registrar manipuladores de eventos no JavaScript (por exemplo, usando newButton.addEventListenerpor vários motivos:

  1. A lógica pode ser separada da marcação - se vários colegas de equipe trabalharam no projeto, um poderia trabalhar no JavaScript enquanto o outro poderia trabalhar no HTML independentemente.
  2. Esses manipuladores podem poluir o namespace global, o que pode levar a um comportamento estranho .

Alinhando elementos filho

Os <div>elementos têm align="center"e align="right". Isso parece ser um atributo HTML 4 obsoleto e não é mais compatível com o HTML 5. Isso pode ser convertido em regras CSS . Observe que text-alignse aplica a blocos de contêineres 1 . Para centralizar elementos inline como imagens, vídeo, etc., o displaydeve ser definido como blocke margindefinido comoauto .

Vários elementos de formulário

Existem dois <form>elementos separados . Os dois podem ser combinados em um único formulário que contém todos os elementos.

Simplificando o código

As seguintes alterações, junto com as sugestões dos pontos de revisão acima, podem ser usadas para diminuir drasticamente o comprimento do código:

  • colocar opções em um objeto que pode conter o índice atual e tornar o objeto uma propriedade de um objeto onde o nome da propriedade (ou seja, chave) é o tipo de coisa - por exemplo

      const options = {
        video: {
          options: [ //VIDEO ARRAY
            'video1',
            'video2',
            'video3',
            'video4',
            'video5',
          ],
          currentIndex: -1
        },
        audio: {
          options: [ //AUDIO ARRAY
            'audio1',
            'audio2',
            'audio3',
            'audio4',
            'audio5',
          ],
          currentIndex: -1
        },
        photo: {
          options: [ //PHOTO ARRAY
            'photo1',
            'photo2',
            'photo3',
            'photo4',
            'photo5',
          ],
          currentIndex: -1
        },
        text: {
          options: [ //TEXT ARRAY
            'text1',
            'text2',
            'text3',
            'text4',
            'text5',
          ],
          currentIndex: -1
        },
      }
    
  • em vez de usar idatributos para os botões de opção, apenas forneça valueatributos

  • referenciar os elementos do formulário por meio de document.forms.elements

  • determinar quais botões de opção são selecionados por meio de RadioNodeList.value

  • use um <output>elemento para a exibição da coisa .

  • use uma classe para encapsular os índices, junto com métodos para obter um item com base no modo

class ThingList {
  constructor(items) {
    this.items = items;
    this.randomUnused = [...items];
    this.forwardIndex = 0;
    this.reverseIndex = items.length - 1;
  }
  forwardItem() {
    return this.items[this.forwardIndex++ % (this.items.length)];
  }
  randomItem() {
    if (!this.randomUnused.length) {
      this.randomUnused.push(...this.items);
    }
    const index = Math.floor(Math.random() * this.randomUnused.length)
    return this.randomUnused.splice(index, 1);
  }
  reverseItem() {
    if (this.reverseIndex < 0) {
      this.reverseIndex = this.items.length - 1;
    }
    return this.items[this.reverseIndex--];
  }
}
const options = {
  video: new ThingList([ //VIDEO ARRAY
    'video1',
    'video2',
    'video3',
    'video4',
    'video5',
  ]),
  audio: new ThingList([ //AUDIO ARRAY
    'audio1',
    'audio2',
    'audio3',
    'audio4',
    'audio5',
  ]),
  photo: new ThingList([ //PHOTO ARRAY
    'photo1',
    'photo2',
    'photo3',
    'photo4',
    'photo5',
  ]),
  text: new ThingList([ //TEXT ARRAY
    'text1',
    'text2',
    'text3',
    'text4',
    'text5',
  ])
}
const output = document.getElementsByTagName('output')[0];
//GENERATOR FUNCTION
function newThing() {
  if (!(document.forms.thingSelection.type.value in options)) {
    return false;
  }
  const list = options[document.forms.thingSelection.type.value];
  const method = document.forms.thingSelection.mode.value + 'Item';
  const item = list[method]();
  output.innerHTML = item;
}
document.getElementsByTagName('button')[0].addEventListener('click', newThing)
.center {
  text-align: center;
}

.right {
  text-align: right;
}
<div class="center"><output></output></div>

<div class="center">
  <button>New Thing</button>
</div>

<form name="thingSelection">
  <label><input type="radio" name="mode" value="random" />&nbsp;Random</label>
  <br /><label><input type="radio" name="mode" value="forward" />&nbsp;Old&nbsp;-&nbsp;New</label>
  <br /><label><input type="radio" name="mode" value="reverse" />&nbsp;New&nbsp;-&nbsp;Old</label>
  <div class="right">
    <label>Video&nbsp;<input type="radio" name="type" value="video" /></label><br />
    <label>Audio&nbsp;<input type="radio" name="type" value="audio" /></label><br />
    <label>Photo&nbsp;<input type="radio" name="type" value="photo" /></label><br />
    <label>Text&nbsp;<input type="radio" name="type" value="text" /></label>
  </div>
</form>