我在一个简单的项目中工作,但是我为它制作的图像滑块存在一些问题。
问题 container lost his ratio after 2500px w image doesn't preserves his aspect ratio 我的声誉不足,无法以正确的方式发布图片
图片无法随容器缩放。
当容器变大时,滑块会移到一侧,而不是覆盖
当容器变小时,滑块将不保持其宽高比。
代码说明
我正在使用React.js,在这种情况下,我是我自己的Carousel功能组件。
使用CSS模块。
使用CSS网格。
轮播代码:
CSS
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.CarouselContainer {
/* width: 600px;
overflow: hidden;
max-width: 100%; */
}
.CarouselSlide {
display: flex;
}
img {
object-fit: cover;
/* width: 100%; */
height: 100%;
}
.PrevBtn {
position: absolute;
top: 50%;
z-index: 10;
left: 5%;
font-size: 30px;
color: white;
cursor: pointer;
background-color: transparent;
border: none;
}
.PrevBtn:disabled {
opacity: 0.3;
}
.PrevBtn:focus {
outline: 0;
}
.NextBtn {
position: absolute;
top: 50%;
z-index: 10;
right: 5%;
font-size: 30px;
color: white;
cursor: pointer;
background-color: transparent;
border: none;
}
.NextBtn:disabled {
opacity: 0.3;
}
.NextBtn:focus {
outline: 0;
}
.Like {
position: absolute;
top: 2%;
z-index: 10;
right: 2%;
color: white;
cursor: pointer;
font-size: 50px;
background-color: transparent;
border: none;
color: rgba(255, 90, 95, 0.9);
}
.Like:focus {
outline: 0;
}
.Dislike {
position: absolute;
top: 2%;
z-index: 10;
right: 2%;
color: white;
cursor: pointer;
font-size: 50px;
background-color: transparent;
border: none;
color: rgba(8, 1, 1, 0.6);
}
.Dislike:focus {
outline: 0;
}
JavaScript:
import React, { useEffect, useRef, useState } from 'react';
import { FaArrowLeft, FaArrowRight, FaHeart } from 'react-icons/fa';
import classes from './carousel.module.css';
const Carousel = ({ id, likeState, onLike }) => {
// states
const [counter, setCounter] = useState(0);
const [nodeChildren, setNodeChildren] = useState();
// references
const carouselSlide = useRef();
const prevBtn = useRef();
const nextBtn = useRef();
// button actions
const nextImage = () => {
setNodeChildren(carouselSlide.current.childNodes[0].clientWidth);
carouselSlide.current.style.transform = 'transform 0.4s ease-in-out';
setCounter(counter + 1);
carouselSlide.current.style.transform = `translateX(${-nodeChildren *
counter}px)`;
};
const prevImage = () => {
setNodeChildren(carouselSlide.current.childNodes[0].clientWidth);
carouselSlide.current.style.transform = 'transform 0.4s ease-in-out';
setCounter(counter - 1);
carouselSlide.current.style.transform = `translateX(${-nodeChildren *
counter}px)`;
};
const likeHandler = () => {
onLike({ type: 'LIKE', id });
};
useEffect(() => {
carouselSlide.current.style.transform = `translateX(${-nodeChildren *
counter}px)`;
}, [counter, nodeChildren]);
let likeClasses = [classes.Dislike];
if (likeState.boolean) {
likeClasses = [classes.Like];
}
return (
<div>
<div className={classes.CarouselContainer}>
<button
className={classes.PrevBtn}
ref={prevBtn}
onClick={prevImage}
disabled={counter === 0}
>
<FaArrowLeft />
</button>
<button
className={classes.NextBtn}
ref={nextBtn}
onClick={nextImage}
disabled={counter === 4}
>
<FaArrowRight />
</button>
<button className={likeClasses} onClick={likeHandler}>
<FaHeart />
</button>
<div className={classes.CarouselSlide} ref={carouselSlide}>
<img src="images/1.jpg" alt="" />
<img src="images/2.jpg" alt="" />
<img src="images/3.jpg" alt="" />
<img src="images/4.jpg" alt="" />
<img src="images/5.jpg" alt="" />
</div>
</div>
</div>
);
};
export default Carousel;
容器代码
CSS
* {
font-family: "Roboto", sans-serif;
box-sizing: border-box;
outline-style: none;
}
:focus {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
span {
vertical-align: baseline;
position: relative;
top: -0.4em;
font-size: 1.3vw;
}
.Container {
width: 80%;
display: grid;
/* grid-template-columns: minmax(100px, 3fr) minmax(150px, 7fr); */
grid-template-columns: 30% 70%;
grid-template-rows: 24vw;
grid-template-areas: "image info";
margin: 25px auto;
}
.Images {
background-color: lightcyan;
grid-area: image;
overflow: hidden;
max-height: 600px;
max-width: 600px;
position: relative;
}
/* .Images:first-child {
max-height: 100%;
display: none;
} */
/* .Carousel {
max-width: 100%;
height: auto;
} */
.Info {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 7fr 3fr 2fr;
grid-template-areas:
"text"
"value"
"list";
}
.Info h1 {
color: #1598f6;
font-size: 1.8vw;
margin: 0.5em 1em 0.2em;
}
.Info h1 + p {
font-size: 1.3vw;
color: #747373;
margin: 1em 1.2em;
}
.Info h1 + p + p {
font-size: 1.4vw;
color: #605e5e;
margin: 1em 1.2em 0em;
line-height: 1.5em;
}
.Price {
display: grid;
grid-template-columns: 1fr 2fr;
}
.Price p:first-child,
.InputPrice {
/* margin: 0 auto; */
margin-left: 0.8em;
font-size: 2.3vw;
color: #000000;
font-weight: bold;
align-self: center;
}
.Price p:nth-child(2) {
font-size: 1.6vw;
color: #1598f6;
font-weight: bold;
align-self: center;
margin-left: 1vw;
}
.Description {
background-color: #e9e9e9;
display: grid;
grid-template-columns: 2fr 1fr;
grid-template-areas: "info contact";
}
.Description ul {
grid-area: info;
width: 80%;
display: flex;
list-style-type: none;
padding: 0;
justify-items: center;
margin: auto 1em;
}
.Description li {
font-size: 1.2vw;
color: #000000;
font-weight: bold;
justify-self: center;
margin: 0 auto;
}
.Description li > span {
font-size: 1vw;
}
.Description p {
grid-area: contact;
margin: auto;
font-size: 1.6vw;
color: #1598f6;
font-weight: bold;
cursor: pointer;
}
.InputPrice {
display: grid;
grid-template-columns: 4fr 1fr;
align-items: center;
border: none;
}
.InputPrice input,
button {
border: none;
height: 3vw;
font-size: 1vw;
border: 1px solid #757575;
border-right-color: transparent;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.InputPrice button {
color: black;
background-color: rgba(21, 152, 246, 0.8);
}
.InputPrice button:disabled {
background-color: rgba(238, 238, 238, 1);
}
@media only screen and (max-width: 800px) {
.Container {
width: 80%;
grid-template-columns: 1fr;
grid-template-rows: 80vw 80vw;
grid-template-areas:
"image"
"info";
margin: 0 auto;
position: relative;
}
.Info {
grid-template-columns: 100%;
grid-template-rows: 7fr 3fr;
grid-template-areas:
"text"
"value";
}
.Info h1 {
margin: 0.5em auto 0.2em;
width: 95%;
font-size: 4.5vw;
text-align: left;
}
.Info h1 + p {
font-size: 3vw;
width: 95%;
margin: 1em auto;
}
.Info h1 + p + p {
font-size: 3.5vw;
width: 95%;
margin: 1em auto;
text-align: justify;
}
.Price {
position: absolute;
top: 70vw;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
}
.Price p:first-child {
font-size: 3.3vw;
color: white;
}
.Price p:nth-child(2) {
font-size: 2.5vw;
color: white;
margin-left: 1em;
}
.Description {
background-color: transparent;
}
.Description ul {
width: 100%;
position: absolute;
top: -1.5em;
left: -2em;
padding: 0;
}
.Description li {
font-size: 2.4vw;
color: white;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
}
.Description li > span {
font-size: 2vw;
}
.Description p {
margin: 2em 0;
font-size: 3.6vw;
}
}
JavaScript代码
import React, { useReducer, useState, useRef } from 'react';
import { FaMapMarkerAlt } from 'react-icons/fa';
import classes from './Department.module.css';
import Carousel from '../Carousel/carousel';
const Department = ({ price, mtrs, id, boolean }) => {
// reducers
const storeReducer = (state, action) => {
switch (action.type) {
case 'LIKE':
localStorage.setItem(action.id, !state.boolean);
return { ...state, boolean: !state.boolean };
case 'NEW_PRICE':
console.log(state);
localStorage.setItem(`${action.id}-price`, action.price);
return { ...state, price: action.price };
default:
return state;
}
};
const initialState = {
boolean,
price,
};
// states
const [inputValue, setInputValue] = useState(false);
const [store, dispatch] = useReducer(storeReducer, initialState);
const [inputIsValid, setInputIsValid] = useState(false);
// ref
const priceRef = useRef();
// handlers
const inputHandler = () => setInputValue(!inputValue);
const inputValidationHandler = event => {
if (
isNaN(parseInt(priceRef.current.value)) ||
event.target.value.trim() === ''
) {
setInputIsValid(false);
} else {
setInputIsValid(true);
}
};
const priceChangeHandler = () => {
console.log(parseInt(priceRef.current.value));
dispatch({
type: 'NEW_PRICE',
id,
price: parseInt(priceRef.current.value),
});
setInputValue(false);
};
// price render variable
let priceEleType = (
<p onClick={inputHandler}>
US
{store.price
.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
})
.slice(0, -3)}
</p>
);
if (inputValue)
priceEleType = (
<div className={classes.InputPrice}>
<input
type="text"
placeholder="Price"
maxLength={7}
ref={priceRef}
onChange={inputValidationHandler}
style={{
backgroundColor: inputIsValid
? 'transparent'
: 'rgba(255, 90, 95, 0.2)',
}}
autoFocus
/>
<button
type="button"
onClick={priceChangeHandler}
disabled={!inputIsValid}
>
Add
</button>
</div>
);
return (
<div className={classes.Container}>
<div className={classes.Images}>
<Carousel
id={id}
likeState={store}
onLike={dispatch}
className={classes.Carousel}
/>
{/* <img src="images/2.jpg" alt="" />
<img src="images/2.jpg" alt="" /> */}
</div>
<div className={classes.Info}>
<div className={classes.Text}>
<h1>
Si vas a utilizar un pasaje de Lorem Ipsum, necesitas estar seguro
</h1>
<p>
<FaMapMarkerAlt />
{` Juan Francisco Seguí 3900, Palermo Chico, Pal...`}
</p>
<p>
Lorem Ipsum es simplemente el texto de relleno de las imprentas y
archivos de texto Lorem Ipsum ha sido el texto de relleno estándar
de las industrias desde el año 1500, cuando un impresor (N. del T.
persona que se dedica a la imprenta)
</p>
</div>
<div className={classes.Price}>
{priceEleType}
<p>
US$ $/m<span>2</span>{' '}
{parseInt(store.price / mtrs).toLocaleString()}
</p>
</div>
<div className={classes.Description}>
<ul>
<li>
{mtrs}m<span>2</span>
</li>
<li>3 dormitorios</li>
<li>2 baños</li>
<li>2 cocheras</li>
</ul>
<p className={classes.Contact}>CONTACTAR</p>
</div>
</div>
</div>
);
};
export default Department;
代码很长,但是我想最重要的部分是css。
尝试
我尝试过使用max / min-height / width,定义width-heigh,对象适合,创建新容器,在jsx代码中移动滑块。
老实说,我已经尝试了StackOverflow中的几乎所有答案。
预期行为
container working, but the image doesn't preserves the aspect ratio 我的声誉不足,无法以正确的方式发布图片
图像缩放并保留其长宽比。
当屏幕宽度大于2500px时,容器不会破裂。
任何帮助都会很棒。
所有代码都是我的,因为我不使用滑块库,所以我无法提供滑块库