如何使图像滑块覆盖其容器?

时间:2019-05-06 23:29:44

标签: css reactjs responsive-design

我在一个简单的项目中工作,但是我为它制作的图像滑块存在一些问题。

问题 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时,容器不会破裂。

任何帮助都会很棒。

所有代码都是我的,因为我不使用滑块库,所以我无法提供滑块库

0 个答案:

没有答案