Prefácio
Quando visitei um determinado site sem querer, fiquei profundamente atraído pelo efeito carrossel em sua página inicial. Por meio da depuração do navegador, finalmente entendi o princípio de implementação e finalmente escrevi uma cópia por mim mesmo Demo
. O efeito final é o seguinte :( o código-fonte está no final)
Efeito plano:
Efeito 3D:
Este carrossel corta a imagem em várias partes, depois reproduz as partes cortadas com efeitos de animação por sua vez e, por fim, costura-as em uma nova imagem.
No processo de recuperação da pilha de tecnologia front-end, parece que não há tecnologia que possa cortar diretamente a imagem e dividi-la em várias partes. O efeito de corte de imagem que normalmente aplicamos é usado apenas canvas
para simular a geração.
Por meio de minha própria depuração, descobri que esta imagem do carrossel usa uma canvas
maneira mais simples de obter o mesmo efeito de corte.
Em seguida, prossiga do mais superficial para o mais profundo, passo a passo, para revelar o princípio de implementação.
Efeito plano
Vamos começar com o efeito plano, primeiro escreva um html
diagrama geral de carrossel, a estrutura é a seguinte:
<div class="main" id="el">
<div class="item">
<img src="./img/1.jpg" />
</div>
<div class="item">
<img src="./img/2.jpg" />
</div>
<div class="item">
<img src="./img/3.jpg" />
</div>
</div>
el
É o contêiner externo, que contém três fotos do carrossel.
Se quisermos fazer um efeito de animação, temos que seguir um passo.
- Gere ou faça com que os
dom
elementos sejam animados dom
Adicione efeitos de animação ao elemento
Agora diminua a animação do efeito plano e observe cuidadosamente suas características, conforme mostrado na figura a seguir:
html
Esta fatia da imagem não é encontrada no código original , o que significa que os elementos a serem animados precisam ser gerados por nós e adicionados ao documento da página para renderização.
Se a imagem de configuração será cortada em 5
partes, então geramos uma estrutura de imagem de fatia é a seguinte:
<div class="main" id="el">
<div class="item">
<img src="./img/1.jpg" />
</div>
<div class="item">
<img src="./img/2.jpg" />
</div>
<div class="item">
<img src="./img/3.jpg" />
</div>
<!--做动画的dom元素-->
<div class="hook">
<div><img src="./img/2.jpg" /></div>
<div><img src="./img/2.jpg" /></div>
<div><img src="./img/2.jpg" /></div>
<div><img src="./img/2.jpg" /></div>
<div><img src="./img/2.jpg" /></div>
</div>
</div>
Na página original, js
gerando uma classe chamada período hook
de html片段
, como um modo de posicionamento absolute
.
hook
Há cinco div
, respectivamente, mostram 2.jpg
o problema corte imagem correspondente enfrentando agora é como deixar este 5
um div
foram para escalar esta imagem uma parte dela?
Se a configuração hook
do recipiente exterior tem uma largura total de 1000px
sub-elemento de 5
número div
médio de 200px
pode ser fornecida por uma segunda deixar div
só mostram img
os segundos recortes.
<div style="position:absolute;width:200px;left:200px;overflow:hidden">
<img src="./img/2.jpg" style="position:absolute;width:500%;left:-200px"/>
</div>
Desde a largura total da camada externa 1000px
, corte em 5
partes cada uma div
representando 200px
(na codificação real 200
por meio de js
calculado) e, em seguida, movido para a direita 200px
ocupando a segunda posição da fatia.
img
A atribuição da width
soma left
é o ponto chave, e seu valor específico também é calculado pela largura total e pelo número de fatias.
width
Defina como 500%
, o que significa que a largura da imagem é igual ao 1000px
contêiner externo e, em seguida, mova para a esquerda 200px
. Como o pai está div
definido overflow:hidden
, imagine o efeito e ele aparecerá.
Esses processos mencionados acima devem ser js
emendados e calculados em uma string html字符串
, semelhante ao seguinte:
for(i=0;i<n;i++){ //循环i次,n(总共将图片切成n份),unit_width对应每一个切块的宽度
html += `
<div
style="position:absolute;
width:${unit_width}px;
top:-100%;
left:${ i * unit_width};
overflow:hidden">
<img src="${src}"
style="position:absolute;
width:${n*100}%;
left:${-i * unit_width}px"/>
</div>
`
}
5
Após a conclusão da div
costura, coloque-o <div class="hook"></div>
nele e adicione-o à renderização do documento da página.O dom
elemento final gerado é o elemento a ser animado a seguir.
Uma vez que 5
um div
conjunto de posicionamento e top
valor absolutos é definido -100%
, eles, uma vez renderizados, estão na posição superior da página.
O próximo efeito de animação é muito fácil de conseguir, só precisamos div
adicionar um a cada no loop acima transition:top linear 0.25s
.
Assim que 5
a div
renderização for concluída, podemos js
definir dinamicamente em cada um div
dos top
valores de 0
animação que é acionado, cada página div
deslizando lentamente para baixo a partir do topo.
Espere até que todo o processo de animação seja finalizado, teremos hook
este uso js
gerado dom
removido, e que deve ser exibido item
(contendo imagens estáticas do original dom
) é definido para exibir oculto a partir deste ponto todo o processo de animação está concluído.
Efeito 3D
O efeito planar é relativamente simples de implementar, e o 3D
efeito lançando requer uma compreensão css
dos 3d
atributos em primeiro lugar.
Revisão de propriedade 3d
rotateX
: Em torno do X
eixo de rotação, a Lenovo 单杠运动
.
rotateY
: Em torno do Y
eixo de rotação, a Lenovo 钢管舞
.
rotateZ
: Em torno do Z
eixo de rotação, a Lenovo 老式钟表盘
.
Os três atributos acima costumam ser muito contatados, então não vou repeti-los. A seguir, focaremos nos 3d
atributos.
.container{
perspective: 1200px;
perspective-origin: right center;
.wrapper {
transform-style: preserve-3d;
transform:translateZ(-100px);
}
}
O contêiner externo container
contém um filho wrapper
. O filho é o 3d
elemento específico a ser animado, portanto, deve definir uma propriedade transform-style: preserve-3d
.
Somente quando está definido o preserve-3d
elemento pode mostrar seu 3d
efeito.
translateZ
E translateX
, translateY
estes dois atributos não são os mesmos. translateX
Está prestes a mudança no plano, translateY
é movido no plano vertical.
translateZ
É um 3d
atributo. Não faz deslocamentos para cima, para baixo, para a esquerda e para a direita no plano, mas faz deslocamentos para dentro ou para fora da direção perpendicular ao plano.
translateZ(-100px)
Isso significa que o elemento foi movido para o interior da tela 100px
. De acordo com a regra de perto, grande, longe, pequeno, o efeito visual final do elemento é 100px
reduzido como um todo. Se for positivo , ele se moverá para o fora da tela 100px
, e o efeito visual do elemento é ampliado.
translateZ
preserve-3d
Aplicar apenas no elemento com o atributo definido terá efeito, de modo que preserve-3d
todos os 3d
atributos podem ter efeito.
block
É 3d
o dom
elemento a ser transformado , portanto, precisa ser definido preserve-3d
e transform
transformado.O elemento pai é container
equivalente a um palco e block
pode ser considerado um ator de performance de palco.
perspective
Representa a distância entre o público e o palco. É concebível perspective
que quanto menor o valor, mais próximo o público está do palco, e a cena no palco será vista com mais clareza.
Correspondendo à cena real, perspective
correspondendo à dom
distância entre os elementos aos olhos do usuário, quanto maior a distância, quanto mais distante, wrapper
menor e menos claro o interior. Pelo contrário, quanto perspective
maior quanto maior, wrapper
maior será a aparência e mais claros os detalhes internos.
perspective-origin
Pode-se entender se o usuário está sentado na posição esquerda, posição intermediária ou posição direita do auditório para assistir à apresentação no palco, e o efeito do campo visual é diferente.
Agora, de volta ao tópico, continue a estudar 3d
o diagrama de carrossel do efeito flip. Ao diminuir o tempo de animação, observe seus detalhes, conforme mostrado na figura a seguir:
Ao observar a imagem acima, percebi rapidamente que os elementos a serem animados não estão disponíveis na página atual e precisam ser js
gerados dinamicamente por nós.
O elemento de animação é um cubo que contém dois efeitos de movimento. Um é mover para a esquerda e o outro é virar para a frente. Mover para a esquerda é fácil de fazer, defina-o para um left
valor de mudança dinâmica de posicionamento absoluto . RotateX(-90deg)
pode ser feito definindo Arrived (equivalente ao grau de X
inversão ao longo do eixo 90
).
O efeito de animação do cubo não é difícil de conseguir, a dificuldade está em como gerar tal cubo.
Desenhar cubo
Na cena atual, o cubo só precisa desenhar quatro faces: superior, frontal, esquerda e direita. A parte superior é armazenada para a próxima imagem a ser carrossel, a frente é armazenada para a imagem exibida no momento, e a esquerda e a direita são preto. O fundo é preenchido para tornar a imagem mais tridimensional, a html
estrutura é a seguinte:
<div class="wrapper">
<div class="left"></div>
<div class="right"></div>
<div class="front"><img src="1.jpg"></div>
<div class="up"><img src="2.jpg"></div>
</div>
A left
, right
, front
e up
são definidas para o posicionamento absoluto, largura e altura são preenchidos com o elemento pai, left
e top
configuração 0
.
front
É o rosto diretamente à frente, é originalmente exibido no plano e não há necessidade de nenhum processamento.
left
Para posicionar o ponto central no canto superior esquerdo, o grau de y
renderização ao longo do eixo 90
formará o lado.
.left {
transform-origin: 0% 0%;
transform: rotateY(90deg);
background-color: #333;
}
right
Você precisa mover toda a largura para a direita e girar ao longo do eixo y 90
para formar o lado direito.
html += `
... //js中dom字符串拼接
<div class="right" style="transform: translateX(${unit_width}px) rotateY(90deg);">
...
</div>
...
`
up
A superfície primeiro define o ponto central no canto esquerdo inferior, gira em torno do X
eixo 90
e depois sobe toda a altura para formar o topo.
.up{
transform-origin: 0% 100%;
}
html += `
... //js中dom字符串拼接
<div class="up" style="transform: rotateX(90deg) translateZ(${container_height}px);">
...
</div>
...
`
A dom
estrutura dessas quatro faces js
é dividida internamente e colocada no wrapper
pai correspondente.Como div
mencionado acima , os atributos wrapper
precisam ser configurados internamente preserve-3d
e os wrapper
elementos são os elementos realmente animados dom
.
wrapper
Depois do elemento é encapsulado, isto é lançada para dentro do elemento fase container
, e os atributos e container
são ajustados .3d
perspective
perspective-origin
Um container
corresponde a uma fatia do cubo, e o html
fio formado por todos os cubos recortados é colocado no documento da página e renderizado, desta forma os dom
elementos animados são gerados.
Adicionar animação flip
Os dom
elementos que executam a animação foram gerados e renderizados na página. De acordo com a análise anterior, adicionar um atributo a cada cubo ( wrapper
correspondente div
) rotateX(-90deg)
pode fazer o cubo girar. Os resultados são os seguintes:
wrapper
Além disso, o rotateX(-90deg)
atributo é realmente invertido para a frente, mas a posição final não está perto do solo.
A causa do acidente foi porque se wrapper
tratava de um cubo, não um simples plano, mas também continha quatro planos.Agora, quando o cubo é girado, a posição do seu centro é muito importante.
wrapper
A altura de está 100%
cheia de todo o pai. Através de testes, descobriu-se que a transformação do atributo do cubo é na verdade baseada na frente ( front
face). O ponto central do cubo está localizado no front
meio da front
altura da face .Se a altura da face for 600px
, então Ao 300px
desenhar um X
eixo, gire todo o cubo ao longo deste eixo.Se a front
altura da superfície for 800px
, então o cubo irá 400px
girar ao longo do eixo.
Agora volte ao caso acima, front
a altura da face é configurada para 100%
preencher o elemento pai, então o cubo vai desenhar um eixo no meio e virar para frente 90
, então haverá um vazio abaixo. Não podemos deixar o cubo Vire e pare no ar, Para encontrar uma maneira de colocá-lo de volta no chão.
De acordo com o que eu disse antes, o cubo usa a front
superfície como superfície de referência. Depois de inverter o 90
grau, a front
superfície vai para o fundo. Então você quer que o cubo se mova para baixo, porque ele está front
voltado para o fundo neste momento , e você só precisa configurá-lo translateZ(contrainer_height/2)
para mover o cubo para baixo. Metade da altura é fixada na parte inferior.
Embora essa configuração possa garantir que o cubo virado seja preso na parte inferior, a imagem dentro dele é deformada.
Porque quando o cubo é configurado rotateX(-90deg)
para virar para a frente, ele é realmente movido para frente. De acordo com as regras de quase grande e muito pequeno, o efeito visual da imagem é ampliado. Para resolver este problema, primeiro use o cubo translateZ(-contrainer_height/2)
para empurrar metade da altura para dentro e depois deixar o cubo virar para frente, para que o problema de alongamento da imagem seja resolvido, o código é o seguinte:
while ((el = eles.shift())) {
//el对应着每个立方体的dom
//立方体先沿Z轴往后推一半高度,再朝前做翻转,翻转完后向下移动一半高度贴底
el.style.transform = `translateZ(${
-this.container_height / 2
}px) rotateX(-90deg) translateZ(${this.container_height / 2}px)`;
...
}
Depois que o efeito flip for concluído, descobriremos que o cubo está voltado para nós e girando, não podemos ver o lado direito do cubo com um fundo preto right
, então ele parecerá muito adimensional.
Eu apresentei um atributo antes perspective-origin:right center
. É como o público sentado do lado direito do auditório, e o palco é tão largo quanto o auditório, e há uma gaiola de ferro no palco voltada para a frente do público. Neste momento, o campo de visão do público só pode ver Na frente da gaiola de ferro, se a gaiola for empurrada para o lado esquerdo do palco, o cliente sentado do lado direito do público não pode ver apenas a frente da gaiola de ferro , mas ele também pode ver o lado direito da gaiola de ferro.
Da mesma forma, para que o cubo pareça mais tridimensional ao ser virado, o fundo preto à direita pode ser exibido durante a animação. Para isso, é necessário mover o cubo para a esquerda , além perspective-origin
do suporte de atributos, o cubo O efeito tridimensional invertido aparece.
Se você deseja que o cubo se mova para a esquerda, você só precisa obter os dom
elementos do cubo e left
atribuí- los dinamicamente.